All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFCv3 00/14] Unified plane support
@ 2014-03-19  0:22 Matt Roper
  2014-03-19  0:22 ` [RFCv3 01/14] SQUASH! drm/i915: Do not dereference pointers from ring buffer in evict event Matt Roper
                   ` (14 more replies)
  0 siblings, 15 replies; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

Previous revision and explanation of series:
   http://lists.freedesktop.org/archives/dri-devel/2014-March/055222.html

Main changes since last pass:
 * Added cursor plane support on i915.  Unfortunately it isn't possible to
   create nice generic helper functions that make use of the legacy API's for
   cursor planes as was done for primary planes; the legacy cursor ioctl's take
   a driver handle directly (e.g., from GEM) rather than a DRM framebuffer.
   With the unified plane support, we receive a DRM framebuffer via the SetPlane
   API, but have no way of turning that into a driver handle that can be passed
   to the legacy interfaces.
 * Updated msm and omapdrm to use their existing "private" planes as primary
   rather than using the primary helper functions.  (thanks Rob Clark!)
 * Fixed several s/crtc->fb/crtc->primary->fb/ conversions that were missed
   on the first pass (or new instances that popped up due to rebasing to
   the latest code).

I believe some of the next steps are:
 * Create some new read-only plane properties that describe in more detail the
   capabilities & limitations of various planes (max/min size, scaling
   capabilities, tiling restrictions, etc.) so that generic userspace
   compositors can make intelligent decisions about how best to use the various
   planes on the plane list.  If anyone has strong feelings on what these
   properties should look like, this would be a good time to start the
   discussion.
 * Update cursor support for the rest of the non-i915 drivers.  I believe the
   list of drivers that currently support cursors are: armada, ast, gma500,
   mgag200, msm, nouveau, radeon, vmwgfx, and qxl.
 * Update imx-drm's CRTC creation to use its existing private primary plane
   rather than using the primary helper function to create one.  
 * Provide patches for weston & xf86-video-modesetting that make use of the
   unified plane interface to make real-world testing of this patchset a
   bit easier.

Note that the first patch here is simply a build fix for current breakage of
the drm-intel-nightly branch of the drm-intel repo.


Matt Roper (14):
  SQUASH! drm/i915: Do not dereference pointers from ring buffer in
    evict event
  drm: Add support for multiple plane types
  drm: Add primary plane helpers
  drm/exynos: Restrict plane loops to only operate on overlay planes
  drm/i915: Restrict plane loops to only operate on overlay planes
  drm: Add plane type property
  drm: Specify primary plane at CRTC initialization (v2)
  drm: Replace crtc fb with primary plane fb (v2)
  drm: Allow userspace to ask for full plane list (universal planes)
  drm/i915: Rename similar plane functions to avoid confusion
  drm/i915: Intel-specific primary plane handling
  drm: Specify cursor plane at CRTC initialization
  drm/i915: Split cursor update code from cursor ioctl handling
  drm/i915: Add cursor handlers and create cursor at crtc init

 drivers/gpu/drm/armada/armada_crtc.c         |   4 +-
 drivers/gpu/drm/armada/armada_overlay.c      |   3 +-
 drivers/gpu/drm/ast/ast_mode.c               |  16 +-
 drivers/gpu/drm/bochs/bochs_kms.c            |   8 +-
 drivers/gpu/drm/cirrus/cirrus_mode.c         |  15 +-
 drivers/gpu/drm/drm_crtc.c                   | 441 +++++++++++++++----
 drivers/gpu/drm/drm_crtc_helper.c            |  21 +-
 drivers/gpu/drm/drm_fb_helper.c              |   9 +-
 drivers/gpu/drm/drm_ioctl.c                  |   5 +
 drivers/gpu/drm/exynos/exynos_drm_crtc.c     |   4 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c  |   6 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c    |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_display.c   |   2 +-
 drivers/gpu/drm/gma500/cdv_intel_dp.c        |   2 +-
 drivers/gpu/drm/gma500/cdv_intel_hdmi.c      |   3 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
 drivers/gpu/drm/gma500/gma_display.c         |  17 +-
 drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
 drivers/gpu/drm/gma500/mdfld_intel_display.c |  17 +-
 drivers/gpu/drm/gma500/oaktrail_crtc.c       |  13 +-
 drivers/gpu/drm/gma500/psb_intel_display.c   |   7 +-
 drivers/gpu/drm/gma500/psb_intel_lvds.c      |   2 +-
 drivers/gpu/drm/gma500/psb_intel_sdvo.c      |   2 +-
 drivers/gpu/drm/i915/i915_debugfs.c          |   4 +-
 drivers/gpu/drm/i915/i915_drv.h              |   5 +-
 drivers/gpu/drm/i915/i915_irq.c              |   4 +-
 drivers/gpu/drm/i915/i915_trace.h            |   2 +-
 drivers/gpu/drm/i915/intel_display.c         | 623 ++++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp.c              |   5 +-
 drivers/gpu/drm/i915/intel_drv.h             |   3 +-
 drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
 drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
 drivers/gpu/drm/i915/intel_pm.c              |  39 +-
 drivers/gpu/drm/i915/intel_sprite.c          |   2 +-
 drivers/gpu/drm/mgag200/mgag200_mode.c       |  33 +-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  33 +-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c    |   4 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  27 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c    |   4 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c      |  24 +-
 drivers/gpu/drm/nouveau/dispnv04/dfp.c       |   2 +-
 drivers/gpu/drm/nouveau/dispnv04/overlay.c   |   4 +-
 drivers/gpu/drm/nouveau/nouveau_display.c    |   8 +-
 drivers/gpu/drm/nouveau/nv50_display.c       |  21 +-
 drivers/gpu/drm/omapdrm/omap_crtc.c          |   2 +-
 drivers/gpu/drm/omapdrm/omap_plane.c         |   4 +-
 drivers/gpu/drm/qxl/qxl_display.c            |  15 +-
 drivers/gpu/drm/radeon/atombios_crtc.c       |  20 +-
 drivers/gpu/drm/radeon/r100.c                |   4 +-
 drivers/gpu/drm/radeon/radeon_connectors.c   |   2 +-
 drivers/gpu/drm/radeon/radeon_device.c       |   3 +-
 drivers/gpu/drm/radeon/radeon_display.c      |   9 +-
 drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +-
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c       |   4 +-
 drivers/gpu/drm/rcar-du/rcar_du_plane.c      |   3 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c    |   3 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c   |   2 +-
 drivers/gpu/drm/tegra/dc.c                   |   7 +-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c         |   4 +-
 drivers/gpu/drm/udl/udl_modeset.c            |   6 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c          |  14 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c          |  12 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c         |  12 +-
 drivers/staging/imx-drm/imx-drm-core.c       |   4 +-
 drivers/staging/imx-drm/ipuv3-plane.c        |   4 +-
 include/drm/drmP.h                           |   5 +
 include/drm/drm_crtc.h                       | 115 ++++-
 include/uapi/drm/drm.h                       |   8 +
 68 files changed, 1252 insertions(+), 488 deletions(-)

Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
-- 
1.8.5.1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [RFCv3 01/14] SQUASH! drm/i915: Do not dereference pointers from ring buffer in evict event
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19  0:22 ` [RFCv3 02/14] drm: Add support for multiple plane types Matt Roper
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

Build fix for drm-intel-nightly:  there is no 'dev' variable for
TP_fast_assign(); should be vm->dev.

Cc: intel-gfx@lists.freedesktop.org
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/i915_trace.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 93342a4..23c26f1 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -243,7 +243,7 @@ TRACE_EVENT(i915_gem_evict_vm,
 			    ),
 
 	    TP_fast_assign(
-			   __entry->dev = dev->primary->index;
+			   __entry->dev = vm->dev->primary->index;
 			   __entry->vm = vm;
 			  ),
 
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 02/14] drm: Add support for multiple plane types
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
  2014-03-19  0:22 ` [RFCv3 01/14] SQUASH! drm/i915: Do not dereference pointers from ring buffer in evict event Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19  0:22 ` [RFCv3 03/14] drm: Add primary plane helpers Matt Roper
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

The DRM core currently only tracks "overlay"-style planes.  Start
refactoring the plane handling to allow other plane types (primary and
cursor) to also be placed on the DRM plane list.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/drm_crtc.c      | 21 ++++++++++++++++-----
 drivers/gpu/drm/drm_fb_helper.c |  3 ++-
 include/drm/drm_crtc.h          | 19 ++++++++++++++++++-
 3 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 16ca28e..0983996 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1044,6 +1044,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
 	plane->format_count = format_count;
 	plane->possible_crtcs = possible_crtcs;
+	plane->type = DRM_PLANE_TYPE_OVERLAY;
 
 	/* private planes are not exposed to userspace, but depending on
 	 * display hardware, might be convenient to allow sharing programming
@@ -1051,7 +1052,9 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	 */
 	if (!priv) {
 		list_add_tail(&plane->head, &dev->mode_config.plane_list);
-		dev->mode_config.num_plane++;
+		dev->mode_config.num_total_plane++;
+		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+			dev->mode_config.num_overlay_plane++;
 	} else {
 		INIT_LIST_HEAD(&plane->head);
 	}
@@ -1081,7 +1084,9 @@ void drm_plane_cleanup(struct drm_plane *plane)
 	/* if not added to a list, it must be a private plane */
 	if (!list_empty(&plane->head)) {
 		list_del(&plane->head);
-		dev->mode_config.num_plane--;
+	        dev->mode_config.num_total_plane--;
+		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+			dev->mode_config.num_overlay_plane--;
 	}
 	drm_modeset_unlock_all(dev);
 }
@@ -1907,11 +1912,15 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 	 * This ioctl is called twice, once to determine how much space is
 	 * needed, and the 2nd time to fill it.
 	 */
-	if (config->num_plane &&
-	    (plane_resp->count_planes >= config->num_plane)) {
+	if (config->num_overlay_plane &&
+	    (plane_resp->count_planes >= config->num_overlay_plane)) {
 		plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 
 		list_for_each_entry(plane, &config->plane_list, head) {
+			/* Only advertise overlays to userspace for now. */
+			if (plane->type != DRM_PLANE_TYPE_OVERLAY)
+				continue;
+
 			if (put_user(plane->base.id, plane_ptr + copied)) {
 				ret = -EFAULT;
 				goto out;
@@ -1919,7 +1928,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 			copied++;
 		}
 	}
-	plane_resp->count_planes = config->num_plane;
+	plane_resp->count_planes = config->num_overlay_plane;
 
 out:
 	drm_modeset_unlock_all(dev);
@@ -4532,6 +4541,8 @@ void drm_mode_config_init(struct drm_device *dev)
 	dev->mode_config.num_connector = 0;
 	dev->mode_config.num_crtc = 0;
 	dev->mode_config.num_encoder = 0;
+	dev->mode_config.num_overlay_plane = 0;
+	dev->mode_config.num_total_plane = 0;
 }
 EXPORT_SYMBOL(drm_mode_config_init);
 
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 8787619..9c6251f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -291,7 +291,8 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 	drm_warn_on_modeset_not_all_locked(dev);
 
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head)
-		drm_plane_force_disable(plane);
+		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+			drm_plane_force_disable(plane);
 
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 27f828c..e69ada8 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -541,6 +541,12 @@ struct drm_plane_funcs {
 			    struct drm_property *property, uint64_t val);
 };
 
+enum drm_plane_type {
+	DRM_PLANE_TYPE_OVERLAY,
+	DRM_PLANE_TYPE_PRIMARY,
+	DRM_PLANE_TYPE_CURSOR,
+};
+
 /**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
@@ -553,6 +559,7 @@ struct drm_plane_funcs {
  * @fb: currently bound fb
  * @funcs: helper functions
  * @properties: property tracking for this plane
+ * @type: type of plane (overlay, primary, cursor)
  */
 struct drm_plane {
 	struct drm_device *dev;
@@ -570,6 +577,8 @@ struct drm_plane {
 	const struct drm_plane_funcs *funcs;
 
 	struct drm_object_properties properties;
+
+	enum drm_plane_type type;
 };
 
 /**
@@ -732,7 +741,15 @@ struct drm_mode_config {
 	struct list_head bridge_list;
 	int num_encoder;
 	struct list_head encoder_list;
-	int num_plane;
+
+	/*
+	 * Track # of overlay planes separately from # of total planes.  By
+	 * default we only advertise overlay planes to userspace; if userspace
+	 * sets the "universal plane" capability bit, we'll go ahead and
+	 * expose all planes.
+	 */
+	int num_overlay_plane;
+	int num_total_plane;
 	struct list_head plane_list;
 
 	int num_crtc;
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
  2014-03-19  0:22 ` [RFCv3 01/14] SQUASH! drm/i915: Do not dereference pointers from ring buffer in evict event Matt Roper
  2014-03-19  0:22 ` [RFCv3 02/14] drm: Add support for multiple plane types Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 11:28   ` Daniel Vetter
                     ` (2 more replies)
  2014-03-19  0:22 ` [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes Matt Roper
                   ` (11 subsequent siblings)
  14 siblings, 3 replies; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

When we expose non-overlay planes to userspace, they will become
accessible via standard userspace plane API's.  We should be able to
handle the standard plane operations against primary planes in a generic
way via the page flip handler and modeset handler.

Drivers that can program primary planes more efficiently, that want to
use their own primary plane structure to track additional information,
or that don't have the limitations assumed by the helpers are free to
provide their own implementation of some or all of these handlers.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/drm_crtc.c | 288 +++++++++++++++++++++++++++++++++++++++------
 include/drm/drm_crtc.h     |  81 +++++++++++++
 2 files changed, 330 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0983996..db54ae9 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1118,6 +1118,255 @@ void drm_plane_force_disable(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_force_disable);
 
+/*
+ * Checks that the framebuffer is big enough for the CRTC viewport
+ * (x, y, hdisplay, vdisplay)
+ */
+static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
+				   int x, int y,
+				   const struct drm_display_mode *mode,
+				   const struct drm_framebuffer *fb)
+
+{
+	int hdisplay, vdisplay;
+
+	hdisplay = mode->hdisplay;
+	vdisplay = mode->vdisplay;
+
+	if (drm_mode_is_stereo(mode)) {
+		struct drm_display_mode adjusted = *mode;
+
+		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
+		hdisplay = adjusted.crtc_hdisplay;
+		vdisplay = adjusted.crtc_vdisplay;
+	}
+
+	if (crtc->invert_dimensions)
+		swap(hdisplay, vdisplay);
+
+	if (hdisplay > fb->width ||
+	    vdisplay > fb->height ||
+	    x > fb->width - hdisplay ||
+	    y > fb->height - vdisplay) {
+		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
+			      fb->width, fb->height, hdisplay, vdisplay, x, y,
+			      crtc->invert_dimensions ? " (inverted)" : "");
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+/*
+ * Returns the connectors currently associated with a CRTC.  This function
+ * should be called twice:  once with a NULL connector list to retrieve
+ * the list size, and once with the properly allocated list to be filled in.
+ */
+static int get_connectors_for_crtc(struct drm_crtc *crtc,
+				   struct drm_connector **connector_list,
+				   int num_connectors)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_connector *connector;
+	int count = 0;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		if (connector->encoder && connector->encoder->crtc == crtc) {
+			if (connector_list != NULL && count < num_connectors)
+				*(connector_list++) = connector;
+
+			count++;
+		}
+
+	return count;
+}
+
+/**
+ * drm_primary_helper_update() - Helper for primary plane update
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler for primary planes.  This is handler
+ * is called in response to a userspace SetPlane operation on the plane with a
+ * non-NULL framebuffer.  We call the driver's pageflip handler to update the
+ * framebuffer.
+ *
+ * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
+ * return an error.
+ *
+ * Note that we assume most hardware can't reposition or scale the primary
+ * plane, so we require that crtc_x = crtc_y = 0 and that src_w/src_h match the
+ * current mode.  Drivers for hardware that don't have these restrictions can
+ * provide their own implementation rather than using this helper.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+			      struct drm_framebuffer *fb,
+			      int crtc_x, int crtc_y,
+			      unsigned int crtc_w, unsigned int crtc_h,
+			      uint32_t src_x, uint32_t src_y,
+			      uint32_t src_w, uint32_t src_h)
+{
+	struct drm_mode_set set = {
+		.crtc = crtc,
+		.fb = fb,
+		.mode = &crtc->mode,
+		.x = crtc_x,
+		.y = crtc_y,
+	};
+	struct drm_connector **connector_list;
+	struct drm_framebuffer *tmpfb;
+	int num_connectors, ret;
+
+	/* setplane API takes shifted source rectangle values; unshift them */
+	src_x >>= 16;
+	src_y >>= 16;
+	src_w >>= 16;
+	src_h >>= 16;
+
+	/* Primary planes are locked to their owning CRTC */
+	if (plane->possible_crtcs != drm_crtc_mask(crtc)) {
+		DRM_DEBUG_KMS("Cannot change primary plane CRTC\n");
+		return -EINVAL;
+	}
+
+	if (!crtc->enabled) {
+		DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n");
+		return -EINVAL;
+	}
+
+	ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb);
+	if (ret)
+		return ret;
+
+	/* Find current connectors for CRTC */
+	num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
+	BUG_ON(num_connectors == 0);
+	connector_list = kzalloc(num_connectors * sizeof(*connector_list),
+				 GFP_KERNEL);
+	if (!connector_list)
+		return -ENOMEM;
+	get_connectors_for_crtc(crtc, connector_list, num_connectors);
+
+	set.connectors = connector_list;
+	set.num_connectors = num_connectors;
+
+	/*
+	 * set_config() adjusts crtc->primary->fb; however the DRM setplane
+	 * code that called us expects to handle the framebuffer update and
+	 * reference counting; save and restore the current fb before
+	 * calling it.
+	 */
+	tmpfb = plane->fb;
+	ret = crtc->funcs->set_config(&set);
+	plane->fb = tmpfb;
+
+	kfree(connector_list);
+	return ret;
+}
+EXPORT_SYMBOL(drm_primary_helper_update);
+
+/**
+ * drm_primary_helper_disable() - Helper for primary plane disable
+ * @plane: plane to disable
+ *
+ * Provides a default plane disable handler for primary planes.  This is handler
+ * is called in response to a userspace SetPlane operation on the plane with a
+ * NULL framebuffer parameter.  We call the driver's modeset handler with a NULL
+ * framebuffer to disable the CRTC.
+ *
+ * Note that some hardware may be able to disable the primary plane without
+ * disabling the whole CRTC.  Drivers for such hardware should provide their
+ * own disable handler that disables just the primary plane (and they'll likely
+ * need to provide their own update handler as well to properly re-enable a
+ * disabled primary plane).
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_primary_helper_disable(struct drm_plane *plane)
+{
+	struct drm_mode_set set = {
+		.crtc = plane->crtc,
+		.fb = NULL,
+	};
+
+	if (plane->crtc == NULL || plane->fb == NULL)
+		/* Already disabled */
+		return 0;
+
+	return plane->crtc->funcs->set_config(&set);
+}
+EXPORT_SYMBOL(drm_primary_helper_disable);
+
+/**
+ * drm_primary_helper_destroy() - Helper for primary plane destruction
+ * @plane: plane to destroy
+ *
+ * Provides a default plane destroy handler for primary planes.  This handler
+ * is called during CRTC destruction.  We disable the primary plane, remove
+ * it from the DRM plane list, and deallocate the plane structure.
+ */
+void drm_primary_helper_destroy(struct drm_plane *plane)
+{
+	plane->funcs->disable_plane(plane);
+	drm_plane_cleanup(plane);
+	kfree(plane);
+}
+EXPORT_SYMBOL(drm_primary_helper_destroy);
+
+const struct drm_plane_funcs drm_primary_helper_funcs = {
+	.update_plane = drm_primary_helper_update,
+	.disable_plane = drm_primary_helper_disable,
+	.destroy = drm_primary_helper_destroy,
+};
+EXPORT_SYMBOL(drm_primary_helper_funcs);
+
+/**
+ * drm_primary_helper_create_plane() - Create a generic primary plane
+ * @dev: drm device
+ *
+ * Allocates and initializes a primary plane that can be used with the primary
+ * plane helpers.  Drivers that wish to use driver-specific plane structures or
+ * provide custom handler functions may perform their own allocation and
+ * initialization rather than calling this function.
+ */
+struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev)
+{
+	struct drm_plane *primary;
+	int ret;
+
+	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
+	if (primary == NULL) {
+		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
+		return NULL;
+	}
+
+	/* possible_crtc's will be filled in later by crtc_init */
+	ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
+			     legacy_modeset_formats,
+			     ARRAY_SIZE(legacy_modeset_formats),
+			     DRM_PLANE_TYPE_PRIMARY);
+	if (ret) {
+		kfree(primary);
+		primary = NULL;
+	}
+
+	return primary;
+}
+EXPORT_SYMBOL(drm_primary_helper_create_plane);
+
 static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 {
 	struct drm_property *edid;
@@ -2185,45 +2434,6 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 }
 EXPORT_SYMBOL(drm_mode_set_config_internal);
 
-/*
- * Checks that the framebuffer is big enough for the CRTC viewport
- * (x, y, hdisplay, vdisplay)
- */
-static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
-				   int x, int y,
-				   const struct drm_display_mode *mode,
-				   const struct drm_framebuffer *fb)
-
-{
-	int hdisplay, vdisplay;
-
-	hdisplay = mode->hdisplay;
-	vdisplay = mode->vdisplay;
-
-	if (drm_mode_is_stereo(mode)) {
-		struct drm_display_mode adjusted = *mode;
-
-		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
-		hdisplay = adjusted.crtc_hdisplay;
-		vdisplay = adjusted.crtc_vdisplay;
-	}
-
-	if (crtc->invert_dimensions)
-		swap(hdisplay, vdisplay);
-
-	if (hdisplay > fb->width ||
-	    vdisplay > fb->height ||
-	    x > fb->width - hdisplay ||
-	    y > fb->height - vdisplay) {
-		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
-			      fb->width, fb->height, hdisplay, vdisplay, x, y,
-			      crtc->invert_dimensions ? " (inverted)" : "");
-		return -ENOSPC;
-	}
-
-	return 0;
-}
-
 /**
  * drm_mode_setcrtc - set CRTC configuration
  * @dev: drm device for the ioctl
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index e69ada8..f43fa92 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -581,6 +581,87 @@ struct drm_plane {
 	enum drm_plane_type type;
 };
 
+extern int drm_primary_helper_update(struct drm_plane *plane,
+				     struct drm_crtc *crtc,
+				     struct drm_framebuffer *fb,
+				     int crtc_x, int crtc_y,
+				     unsigned int crtc_w, unsigned int crtc_h,
+				     uint32_t src_x, uint32_t src_y,
+				     uint32_t src_w, uint32_t src_h);
+extern int drm_primary_helper_disable(struct drm_plane *plane);
+extern void drm_primary_helper_destroy(struct drm_plane *plane);
+extern const struct drm_plane_funcs drm_primary_helper_funcs;
+extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev);
+
+/*
+ * This is the list of formats that have historically been accepted by the
+ * modeset API.  The primary plane helpers use this list by default, but
+ * individual drivers may provide their own primary plane initialization
+ * that provides a more hw-specific format list.
+ */
+const static uint32_t legacy_modeset_formats[] = {
+       DRM_FORMAT_C8,
+       DRM_FORMAT_RGB332,
+       DRM_FORMAT_BGR233,
+       DRM_FORMAT_XRGB4444,
+       DRM_FORMAT_XBGR4444,
+       DRM_FORMAT_RGBX4444,
+       DRM_FORMAT_BGRX4444,
+       DRM_FORMAT_ARGB4444,
+       DRM_FORMAT_ABGR4444,
+       DRM_FORMAT_RGBA4444,
+       DRM_FORMAT_BGRA4444,
+       DRM_FORMAT_XRGB1555,
+       DRM_FORMAT_XBGR1555,
+       DRM_FORMAT_RGBX5551,
+       DRM_FORMAT_BGRX5551,
+       DRM_FORMAT_ARGB1555,
+       DRM_FORMAT_ABGR1555,
+       DRM_FORMAT_RGBA5551,
+       DRM_FORMAT_BGRA5551,
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_BGR565,
+       DRM_FORMAT_RGB888,
+       DRM_FORMAT_BGR888,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_RGBX8888,
+       DRM_FORMAT_BGRX8888,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_ABGR8888,
+       DRM_FORMAT_RGBA8888,
+       DRM_FORMAT_BGRA8888,
+       DRM_FORMAT_XRGB2101010,
+       DRM_FORMAT_XBGR2101010,
+       DRM_FORMAT_RGBX1010102,
+       DRM_FORMAT_BGRX1010102,
+       DRM_FORMAT_ARGB2101010,
+       DRM_FORMAT_ABGR2101010,
+       DRM_FORMAT_RGBA1010102,
+       DRM_FORMAT_BGRA1010102,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_VYUY,
+       DRM_FORMAT_AYUV,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_NV21,
+       DRM_FORMAT_NV16,
+       DRM_FORMAT_NV61,
+       DRM_FORMAT_NV24,
+       DRM_FORMAT_NV42,
+       DRM_FORMAT_YUV410,
+       DRM_FORMAT_YVU410,
+       DRM_FORMAT_YUV411,
+       DRM_FORMAT_YVU411,
+       DRM_FORMAT_YUV420,
+       DRM_FORMAT_YVU420,
+       DRM_FORMAT_YUV422,
+       DRM_FORMAT_YVU422,
+       DRM_FORMAT_YUV444,
+       DRM_FORMAT_YVU444,
+};
+
 /**
  * drm_bridge_funcs - drm_bridge control functions
  * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (2 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 03/14] drm: Add primary plane helpers Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 11:51   ` Daniel Vetter
  2014-03-19  0:22 ` [RFCv3 05/14] drm/i915: " Matt Roper
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

Before we add additional types of planes to the DRM plane list, ensure
that existing loops over all planes continue to operate only on
"overlay" planes and ignore primary & cursor planes.

Cc: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 06f1b2a..2fa2685 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -127,6 +127,9 @@ static void disable_plane_to_crtc(struct drm_device *dev,
 	 * (encoder->crtc)
 	 */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+		if (plane->type != DRM_PLANE_TYPE_OVERLAY)
+			continue;
+
 		if (plane->crtc == old_crtc) {
 			/*
 			 * do not change below call order.
@@ -247,6 +250,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
 
 	/* all planes connected to this encoder should be also disabled. */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+		if (plane->type != DRM_PLANE_TYPE_OVERLAY)
+			continue;
+
 		if (plane->crtc == encoder->crtc)
 			plane->funcs->disable_plane(plane);
 	}
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 05/14] drm/i915: Restrict plane loops to only operate on overlay planes
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (3 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19  0:22 ` [RFCv3 06/14] drm: Add plane type property Matt Roper
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

Before we add additional types of planes to the DRM plane list, ensure
that existing loops over all planes continue to operate only on
"overlay" planes and ignore primary & cursor planes.

Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 6 ++++++
 drivers/gpu/drm/i915/intel_pm.c      | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c6743f0..048052a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3535,6 +3535,9 @@ static void intel_enable_planes(struct drm_crtc *crtc)
 	struct intel_plane *intel_plane;
 
 	list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+		if (intel_plane->base.type != DRM_PLANE_TYPE_OVERLAY)
+			continue;
+
 		if (intel_plane->pipe == pipe)
 			intel_plane_restore(&intel_plane->base);
 }
@@ -3546,6 +3549,9 @@ static void intel_disable_planes(struct drm_crtc *crtc)
 	struct intel_plane *intel_plane;
 
 	list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+		if (intel_plane->base.type != DRM_PLANE_TYPE_OVERLAY)
+			continue;
+
 		if (intel_plane->pipe == pipe)
 			intel_plane_disable(&intel_plane->base);
 }
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 1d0f346..3a1b569 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2132,6 +2132,9 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
 		struct intel_plane *intel_plane = to_intel_plane(plane);
 
+		if (plane->type != DRM_PLANE_TYPE_OVERLAY)
+			continue;
+
 		if (intel_plane->pipe == pipe)
 			p->spr = intel_plane->wm;
 
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 06/14] drm: Add plane type property
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (4 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 05/14] drm/i915: " Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 11:31   ` Daniel Vetter
  2014-03-19  0:22 ` [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2) Matt Roper
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

Add a plane type property to allow userspace to distinguish plane types.
The type of the plane will now be established at drm_plane_init() time
(replacing the 'priv' parameter previously used).

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/armada/armada_overlay.c    |  3 +-
 drivers/gpu/drm/drm_crtc.c                 | 65 ++++++++++++++++++++----------
 drivers/gpu/drm/exynos/exynos_drm_plane.c  |  4 +-
 drivers/gpu/drm/i915/intel_sprite.c        |  2 +-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c  |  4 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c  |  4 +-
 drivers/gpu/drm/nouveau/dispnv04/overlay.c |  4 +-
 drivers/gpu/drm/omapdrm/omap_plane.c       |  4 +-
 drivers/gpu/drm/rcar-du/rcar_du_plane.c    |  3 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c |  2 +-
 drivers/gpu/drm/tegra/dc.c                 |  3 +-
 drivers/staging/imx-drm/ipuv3-plane.c      |  4 +-
 include/drm/drm_crtc.h                     |  3 +-
 13 files changed, 70 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index c5b06fd..ef68c42 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -444,7 +444,8 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
 				  dplane);
 
 	drm_plane_init(dev, &dplane->base, crtcs, &armada_plane_funcs,
-		       armada_formats, ARRAY_SIZE(armada_formats), false);
+		       armada_formats, ARRAY_SIZE(armada_formats),
+		       DRM_PLANE_TYPE_OVERLAY);
 
 	dplane->prop.colorkey_yr = 0xfefefe00;
 	dplane->prop.colorkey_ug = 0x01010100;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index db54ae9..8e869d6 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -121,6 +121,15 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] =
 
 DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
 
+static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
+{
+	{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
+	{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
+	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
+};
+
+DRM_ENUM_NAME_FN(drm_get_plane_type, drm_plane_type_enum_list)
+
 /*
  * Optional properties
  */
@@ -1007,7 +1016,7 @@ EXPORT_SYMBOL(drm_encoder_cleanup);
  * @funcs: callbacks for the new plane
  * @formats: array of supported formats (%DRM_FORMAT_*)
  * @format_count: number of elements in @formats
- * @priv: plane is private (hidden from userspace)?
+ * @type: type of plane (overlay, primary, cursor)
  *
  * Inits a preallocate plane object created as base part of a driver plane
  * object.
@@ -1019,7 +1028,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		   unsigned long possible_crtcs,
 		   const struct drm_plane_funcs *funcs,
 		   const uint32_t *formats, uint32_t format_count,
-		   bool priv)
+		   enum drm_plane_type type)
 {
 	int ret;
 
@@ -1044,20 +1053,16 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
 	plane->format_count = format_count;
 	plane->possible_crtcs = possible_crtcs;
-	plane->type = DRM_PLANE_TYPE_OVERLAY;
+	plane->type = type;
 
-	/* private planes are not exposed to userspace, but depending on
-	 * display hardware, might be convenient to allow sharing programming
-	 * for the scanout engine with the crtc implementation.
-	 */
-	if (!priv) {
-		list_add_tail(&plane->head, &dev->mode_config.plane_list);
-		dev->mode_config.num_total_plane++;
-		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-			dev->mode_config.num_overlay_plane++;
-	} else {
-		INIT_LIST_HEAD(&plane->head);
-	}
+	list_add_tail(&plane->head, &dev->mode_config.plane_list);
+	dev->mode_config.num_total_plane++;
+	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+		dev->mode_config.num_overlay_plane++;
+
+	drm_object_attach_property(&plane->base,
+				   dev->mode_config.plane_type_property,
+				   plane->type);
 
  out:
 	drm_modeset_unlock_all(dev);
@@ -1081,13 +1086,13 @@ void drm_plane_cleanup(struct drm_plane *plane)
 	drm_modeset_lock_all(dev);
 	kfree(plane->format_types);
 	drm_mode_object_put(dev, &plane->base);
-	/* if not added to a list, it must be a private plane */
-	if (!list_empty(&plane->head)) {
-		list_del(&plane->head);
-	        dev->mode_config.num_total_plane--;
-		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-			dev->mode_config.num_overlay_plane--;
-	}
+
+	BUG_ON(list_empty(&plane->head));
+
+	list_del(&plane->head);
+	dev->mode_config.num_total_plane--;
+	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+		dev->mode_config.num_overlay_plane--;
 	drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
@@ -1388,6 +1393,21 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 	return 0;
 }
 
+static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
+{
+	struct drm_property *type;
+
+	/*
+	 * Standard properties (apply to all planes)
+	 */
+	type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+					"TYPE", drm_plane_type_enum_list,
+					ARRAY_SIZE(drm_plane_type_enum_list));
+	dev->mode_config.plane_type_property = type;
+
+	return 0;
+}
+
 /**
  * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
  * @dev: DRM device
@@ -4744,6 +4764,7 @@ void drm_mode_config_init(struct drm_device *dev)
 
 	drm_modeset_lock_all(dev);
 	drm_mode_create_standard_connector_properties(dev);
+	drm_mode_create_standard_plane_properties(dev);
 	drm_modeset_unlock_all(dev);
 
 	/* Just to be sure */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index fcb0652..7943dd3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -263,14 +263,16 @@ struct drm_plane *exynos_plane_init(struct drm_device *dev,
 {
 	struct exynos_plane *exynos_plane;
 	int err;
+	enum drm_plane_type type;
 
 	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
 	if (!exynos_plane)
 		return NULL;
 
+	type = priv ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 	err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
 			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
-			      priv);
+			      type);
 	if (err) {
 		DRM_ERROR("failed to initialize plane\n");
 		kfree(exynos_plane);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 336ae6c..630485c 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -1145,7 +1145,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 	ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
 			     &intel_plane_funcs,
 			     plane_formats, num_plane_formats,
-			     false);
+			     DRM_PLANE_TYPE_OVERLAY);
 	if (ret)
 		kfree(intel_plane);
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 1e893dd..afa9c67 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -222,6 +222,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
 	struct drm_plane *plane = NULL;
 	struct mdp4_plane *mdp4_plane;
 	int ret;
+	enum drm_plane_type type;
 
 	mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL);
 	if (!mdp4_plane) {
@@ -237,9 +238,10 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
 	mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats,
 			ARRAY_SIZE(mdp4_plane->formats));
 
+	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 	drm_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
 			mdp4_plane->formats, mdp4_plane->nformats,
-			private_plane);
+			type);
 
 	mdp4_plane_install_properties(plane, &plane->base);
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 0ac8bb5..651baac 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -357,6 +357,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 {
 	struct drm_plane *plane = NULL;
 	struct mdp5_plane *mdp5_plane;
+	enum drm_plane_type type;
 	int ret;
 
 	mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
@@ -373,9 +374,10 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 	mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
 			ARRAY_SIZE(mdp5_plane->formats));
 
+	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 	drm_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
 			mdp5_plane->formats, mdp5_plane->nformats,
-			private_plane);
+			type);
 
 	mdp5_plane_install_properties(plane, &plane->base);
 
diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
index ab03f77..0b4f35d 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
@@ -276,7 +276,7 @@ nv10_overlay_init(struct drm_device *device)
 
 	ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */,
 			     &nv10_plane_funcs,
-			     formats, num_formats, false);
+			     formats, num_formats, DRM_PLANE_TYPE_OVERLAY);
 	if (ret)
 		goto err;
 
@@ -456,7 +456,7 @@ nv04_overlay_init(struct drm_device *device)
 
 	ret = drm_plane_init(device, &plane->base, 1 /* single crtc */,
 			     &nv04_plane_funcs,
-			     formats, 2, false);
+			     formats, 2, DRM_PLANE_TYPE_OVERLAY);
 	if (ret)
 		goto err;
 
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 046d5e6..d4179b2 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -384,6 +384,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 	struct omap_plane *omap_plane;
 	struct omap_overlay_info *info;
 	int ret;
+	enum drm_plane_type type;
 
 	DBG("%s: priv=%d", plane_names[id], private_plane);
 
@@ -413,8 +414,9 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 	omap_plane->error_irq.irq = omap_plane_error_irq;
 	omap_irq_register(dev, &omap_plane->error_irq);
 
+	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 	drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs,
-			omap_plane->formats, omap_plane->nformats, private_plane);
+			omap_plane->formats, omap_plane->nformats, type);
 
 	omap_plane_install_properties(plane, &plane->base);
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 3fb69d9..27f1531 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -499,7 +499,8 @@ int rcar_du_planes_register(struct rcar_du_group *rgrp)
 
 		ret = drm_plane_init(rcdu->ddev, &plane->plane, crtcs,
 				     &rcar_du_plane_funcs, formats,
-				     ARRAY_SIZE(formats), false);
+				     ARRAY_SIZE(formats),
+				     DRM_PLANE_TYPE_OVERLAY);
 		if (ret < 0)
 			return ret;
 
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
index 060ae03..2b03fff 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
@@ -257,7 +257,7 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
 
 	ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
 			     &shmob_drm_plane_funcs, formats,
-			     ARRAY_SIZE(formats), false);
+			     ARRAY_SIZE(formats), DRM_PLANE_TYPE_OVERLAY);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 9336006..76e5b22 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -137,7 +137,8 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
 
 		err = drm_plane_init(drm, &plane->base, 1 << dc->pipe,
 				     &tegra_plane_funcs, plane_formats,
-				     ARRAY_SIZE(plane_formats), false);
+				     ARRAY_SIZE(plane_formats),
+				     DRM_PLANE_TYPE_OVERLAY);
 		if (err < 0) {
 			kfree(plane);
 			return err;
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 34b642a..7975369 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -355,6 +355,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
 {
 	struct ipu_plane *ipu_plane;
 	int ret;
+	enum drm_plane_type type;
 
 	DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
 		      dma, dp, possible_crtcs);
@@ -369,10 +370,11 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
 	ipu_plane->dma = dma;
 	ipu_plane->dp_flow = dp;
 
+	type = priv ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 	ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
 			     &ipu_plane_funcs, ipu_plane_formats,
 			     ARRAY_SIZE(ipu_plane_formats),
-			     priv);
+			     type);
 	if (ret) {
 		DRM_ERROR("failed to initialize plane\n");
 		kfree(ipu_plane);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index f43fa92..74f4943 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -852,6 +852,7 @@ struct drm_mode_config {
 	struct list_head property_blob_list;
 	struct drm_property *edid_property;
 	struct drm_property *dpms_property;
+	struct drm_property *plane_type_property;
 
 	/* DVI-I properties */
 	struct drm_property *dvi_i_subconnector_property;
@@ -960,7 +961,7 @@ extern int drm_plane_init(struct drm_device *dev,
 			  unsigned long possible_crtcs,
 			  const struct drm_plane_funcs *funcs,
 			  const uint32_t *formats, uint32_t format_count,
-			  bool priv);
+			  enum drm_plane_type type);
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern void drm_plane_force_disable(struct drm_plane *plane);
 
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2)
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (5 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 06/14] drm: Add plane type property Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 11:41   ` Daniel Vetter
  2014-03-20  5:43   ` Inki Dae
  2014-03-19  0:22 ` [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2) Matt Roper
                   ` (7 subsequent siblings)
  14 siblings, 2 replies; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

Add primary plane as a parameter to drm_crtc_init() and update all
existing DRM drivers to use a helper-provided primary plane.

v2: Update msm & omap drivers to use existing "private" planes as primary
    planes instead of helper  [Rob Clark]

Tested-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/armada/armada_crtc.c       | 4 +++-
 drivers/gpu/drm/ast/ast_mode.c             | 4 +++-
 drivers/gpu/drm/bochs/bochs_kms.c          | 4 +++-
 drivers/gpu/drm/cirrus/cirrus_mode.c       | 4 +++-
 drivers/gpu/drm/drm_crtc.c                 | 9 ++++++++-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c   | 4 +++-
 drivers/gpu/drm/gma500/psb_intel_display.c | 4 +++-
 drivers/gpu/drm/i915/intel_display.c       | 4 +++-
 drivers/gpu/drm/mgag200/mgag200_mode.c     | 4 +++-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c   | 5 ++++-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c   | 5 ++++-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    | 4 +++-
 drivers/gpu/drm/nouveau/nv50_display.c     | 4 +++-
 drivers/gpu/drm/omapdrm/omap_crtc.c        | 2 +-
 drivers/gpu/drm/qxl/qxl_display.c          | 4 +++-
 drivers/gpu/drm/radeon/radeon_display.c    | 4 +++-
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c     | 4 +++-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c  | 3 ++-
 drivers/gpu/drm/tegra/dc.c                 | 4 +++-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c       | 4 +++-
 drivers/gpu/drm/udl/udl_modeset.c          | 4 +++-
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        | 4 +++-
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       | 4 +++-
 drivers/staging/imx-drm/imx-drm-core.c     | 4 +++-
 include/drm/drm_crtc.h                     | 5 +++++
 25 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index d8e3982..0a14d24 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -1030,6 +1030,7 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
 {
 	struct armada_private *priv = dev->dev_private;
 	struct armada_crtc *dcrtc;
+	struct drm_plane *primary;
 	void __iomem *base;
 	int ret;
 
@@ -1086,7 +1087,8 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
 
 	priv->dcrtc[dcrtc->num] = dcrtc;
 
-	drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &dcrtc->crtc, primary, &armada_crtc_funcs);
 	drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
 
 	drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index cca063b..44f0d32 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -626,13 +626,15 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
 static int ast_crtc_init(struct drm_device *dev)
 {
 	struct ast_crtc *crtc;
+	struct drm_plane *primary;
 	int i;
 
 	crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
 	if (!crtc)
 		return -ENOMEM;
 
-	drm_crtc_init(dev, &crtc->base, &ast_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &crtc->base, primary, &ast_crtc_funcs);
 	drm_mode_crtc_set_gamma_size(&crtc->base, 256);
 	drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs);
 
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 62ec7d4..182f5c9 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -129,8 +129,10 @@ static void bochs_crtc_init(struct drm_device *dev)
 {
 	struct bochs_device *bochs = dev->dev_private;
 	struct drm_crtc *crtc = &bochs->crtc;
+	struct drm_plane *primary;
 
-	drm_crtc_init(dev, crtc, &bochs_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, crtc, primary, &bochs_crtc_funcs);
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 	drm_crtc_helper_add(crtc, &bochs_helper_funcs);
 }
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 530f78f..449246f 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -381,6 +381,7 @@ static void cirrus_crtc_init(struct drm_device *dev)
 {
 	struct cirrus_device *cdev = dev->dev_private;
 	struct cirrus_crtc *cirrus_crtc;
+	struct drm_plane *primary;
 	int i;
 
 	cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
@@ -390,7 +391,8 @@ static void cirrus_crtc_init(struct drm_device *dev)
 	if (cirrus_crtc == NULL)
 		return;
 
-	drm_crtc_init(dev, &cirrus_crtc->base, &cirrus_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &cirrus_crtc->base, primary, &cirrus_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
 	cdev->mode_info.crtc = cirrus_crtc;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8e869d6..0feb66cc 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -697,6 +697,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
  * drm_crtc_init - Initialise a new CRTC object
  * @dev: DRM device
  * @crtc: CRTC object to init
+ * @primary: Primary plane for CRTC
  * @funcs: callbacks for the new CRTC
  *
  * Inits a new object created as base part of a driver crtc object.
@@ -705,7 +706,8 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
  * Zero on success, error code on failure.
  */
 int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
-		   const struct drm_crtc_funcs *funcs)
+		  struct drm_plane *primary,
+		  const struct drm_crtc_funcs *funcs)
 {
 	int ret;
 
@@ -726,6 +728,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
 	dev->mode_config.num_crtc++;
 
+	crtc->primary = primary;
+	primary->possible_crtcs = 1 << drm_crtc_index(crtc);
+
  out:
 	drm_modeset_unlock_all(dev);
 
@@ -2439,6 +2444,8 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 
 	ret = crtc->funcs->set_config(set);
 	if (ret == 0) {
+		crtc->primary->crtc = crtc;
+
 		/* crtc->fb must be updated by ->set_config, enforces this. */
 		WARN_ON(fb != crtc->fb);
 	}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 6f3400f..507abd5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -323,6 +323,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
 	struct exynos_drm_crtc *exynos_crtc;
 	struct exynos_drm_private *private = dev->dev_private;
 	struct drm_crtc *crtc;
+	struct drm_plane *primary;
 
 	exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
 	if (!exynos_crtc)
@@ -342,7 +343,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
 
 	private->crtc[nr] = crtc;
 
-	drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, crtc, primary, &exynos_crtc_funcs);
 	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
 	exynos_drm_crtc_attach_mode_property(crtc);
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index c8841ac..c8f833d 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -491,6 +491,7 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct gma_crtc *gma_crtc;
+	struct drm_plane *primary;
 	int i;
 	uint16_t *r_base, *g_base, *b_base;
 
@@ -511,7 +512,8 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
 	}
 
 	/* Set the CRTC operations from the chip specific data */
-	drm_crtc_init(dev, &gma_crtc->base, dev_priv->ops->crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &gma_crtc->base, primary, dev_priv->ops->crtc_funcs);
 
 	/* Set the CRTC clock functions from chip specific data */
 	gma_crtc->clock_funcs = dev_priv->ops->clock_funcs;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 048052a..21d12a9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10586,13 +10586,15 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc;
+	struct drm_plane *primary;
 	int i;
 
 	intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
 	if (intel_crtc == NULL)
 		return;
 
-	drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
 	for (i = 0; i < 256; i++) {
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 9683747..1418414 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1314,6 +1314,7 @@ static const struct drm_crtc_helper_funcs mga_helper_funcs = {
 static void mga_crtc_init(struct mga_device *mdev)
 {
 	struct mga_crtc *mga_crtc;
+	struct drm_plane *primary;
 	int i;
 
 	mga_crtc = kzalloc(sizeof(struct mga_crtc) +
@@ -1323,7 +1324,8 @@ static void mga_crtc_init(struct mga_device *mdev)
 	if (mga_crtc == NULL)
 		return;
 
-	drm_crtc_init(mdev->dev, &mga_crtc->base, &mga_crtc_funcs);
+	primary = drm_primary_helper_create_plane(mdev->dev);
+	drm_crtc_init(mdev->dev, &mga_crtc->base, primary, &mga_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE);
 	mdev->mode_info.crtc = mga_crtc;
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 84c5b13..b10f681 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -740,6 +740,9 @@ void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
 
 void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
 {
+	/* don't actually detatch our primary plane: */
+	if (to_mdp4_crtc(crtc)->plane == plane)
+		return;
 	set_attach(crtc, mdp4_plane_pipe(plane), NULL);
 }
 
@@ -791,7 +794,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
 
 	INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb);
 
-	drm_crtc_init(dev, crtc, &mdp4_crtc_funcs);
+	drm_crtc_init(dev, crtc, plane, &mdp4_crtc_funcs);
 	drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
 
 	mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index f279402..7dc3d71 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -524,6 +524,9 @@ void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
 
 void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
 {
+	/* don't actually detatch our primary plane: */
+	if (to_mdp5_crtc(crtc)->plane == plane)
+		return;
 	set_attach(crtc, mdp5_plane_pipe(plane), NULL);
 }
 
@@ -559,7 +562,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
 
 	INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb);
 
-	drm_crtc_init(dev, crtc, &mdp5_crtc_funcs);
+	drm_crtc_init(dev, crtc, plane, &mdp5_crtc_funcs);
 	drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
 
 	mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 0e3270c..b55be84 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -1106,6 +1106,7 @@ int
 nv04_crtc_create(struct drm_device *dev, int crtc_num)
 {
 	struct nouveau_crtc *nv_crtc;
+	struct drm_plane *primary;
 	int ret, i;
 
 	nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
@@ -1122,7 +1123,8 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
 	nv_crtc->index = crtc_num;
 	nv_crtc->last_dpms = NV_DPMS_CLEARED;
 
-	drm_crtc_init(dev, &nv_crtc->base, &nv04_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &nv_crtc->base, primary, &nv04_crtc_funcs);
 	drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs);
 	drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
 
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 2dccafc..5706842 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1348,6 +1348,7 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
 	struct nv50_disp *disp = nv50_disp(dev);
 	struct nv50_head *head;
 	struct drm_crtc *crtc;
+	struct drm_plane *primary;
 	int ret, i;
 
 	head = kzalloc(sizeof(*head), GFP_KERNEL);
@@ -1369,7 +1370,8 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
 	}
 
 	crtc = &head->base.base;
-	drm_crtc_init(dev, crtc, &nv50_crtc_func);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, crtc, primary, &nv50_crtc_func);
 	drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 4313bb0..fdf9dc0 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -677,7 +677,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 	info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
 	info->trans_enabled = false;
 
-	drm_crtc_init(dev, crtc, &omap_crtc_funcs);
+	drm_crtc_init(dev, crtc, plane, &omap_crtc_funcs);
 	drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
 	omap_plane_install_properties(omap_crtc->plane, &crtc->base);
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 798bde2..24b6112 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -636,12 +636,14 @@ static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
 static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
 {
 	struct qxl_crtc *qxl_crtc;
+	struct drm_plane *primary;
 
 	qxl_crtc = kzalloc(sizeof(struct qxl_crtc), GFP_KERNEL);
 	if (!qxl_crtc)
 		return -ENOMEM;
 
-	drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &qxl_crtc->base, primary, &qxl_crtc_funcs);
 	qxl_crtc->index = crtc_id;
 	drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256);
 	drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index fbd8b93..a29d217 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -552,13 +552,15 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
 {
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_crtc *radeon_crtc;
+	struct drm_plane *primary;
 	int i;
 
 	radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
 	if (radeon_crtc == NULL)
 		return;
 
-	drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, &radeon_crtc->base, primary, &radeon_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
 	radeon_crtc->crtc_id = index;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index fbf4be3..151ffaa 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -540,6 +540,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
 	struct platform_device *pdev = to_platform_device(rcdu->dev);
 	struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
 	struct drm_crtc *crtc = &rcrtc->crtc;
+	struct drm_plane *primary;
 	unsigned int irqflags;
 	char clk_name[5];
 	char *name;
@@ -568,7 +569,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
 
 	rcrtc->plane->crtc = crtc;
 
-	ret = drm_crtc_init(rcdu->ddev, crtc, &crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	ret = drm_crtc_init(rcdu->ddev, crtc, primary, &crtc_funcs);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 0428076..e806553 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -512,11 +512,12 @@ static const struct drm_crtc_funcs crtc_funcs = {
 int shmob_drm_crtc_create(struct shmob_drm_device *sdev)
 {
 	struct drm_crtc *crtc = &sdev->crtc.crtc;
+	struct drm_plane *primary;
 	int ret;
 
 	sdev->crtc.dpms = DRM_MODE_DPMS_OFF;
 
-	ret = drm_crtc_init(sdev->ddev, crtc, &crtc_funcs);
+	ret = drm_crtc_init(sdev->ddev, crtc, primary, &crtc_funcs);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 76e5b22..5e2ee9d 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1099,9 +1099,11 @@ static int tegra_dc_init(struct host1x_client *client)
 {
 	struct tegra_drm *tegra = dev_get_drvdata(client->parent);
 	struct tegra_dc *dc = host1x_client_to_dc(client);
+	struct drm_plane *primary;
 	int err;
 
-	drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(tegra->drm, &dc->base, primary, &tegra_crtc_funcs);
 	drm_mode_crtc_set_gamma_size(&dc->base, 256);
 	drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index d36efc1..310314c 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -651,6 +651,7 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
 {
 	struct tilcdc_crtc *tilcdc_crtc;
 	struct drm_crtc *crtc;
+	struct drm_plane *primary;
 	int ret;
 
 	tilcdc_crtc = kzalloc(sizeof(*tilcdc_crtc), GFP_KERNEL);
@@ -671,7 +672,8 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
 		goto fail;
 	}
 
-	ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	ret = drm_crtc_init(dev, crtc, primary, &tilcdc_crtc_funcs);
 	if (ret < 0)
 		goto fail;
 
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 2ae1eb7..1255944 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -389,12 +389,14 @@ static const struct drm_crtc_funcs udl_crtc_funcs = {
 static int udl_crtc_init(struct drm_device *dev)
 {
 	struct drm_crtc *crtc;
+	struct drm_plane *primary;
 
 	crtc = kzalloc(sizeof(struct drm_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
 	if (crtc == NULL)
 		return -ENOMEM;
 
-	drm_crtc_init(dev, crtc, &udl_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, crtc, primary, &udl_crtc_funcs);
 	drm_crtc_helper_add(crtc, &udl_helper_funcs);
 
 	return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index a055a26..001ec81 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -343,6 +343,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 	struct drm_connector *connector;
 	struct drm_encoder *encoder;
 	struct drm_crtc *crtc;
+	struct drm_plane *primary;
 
 	ldu = kzalloc(sizeof(*ldu), GFP_KERNEL);
 	if (!ldu)
@@ -373,7 +374,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 
 	(void) drm_sysfs_connector_add(connector);
 
-	drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, crtc, primary, &vmw_legacy_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 22406c8..585da43 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -439,6 +439,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
 	struct drm_connector *connector;
 	struct drm_encoder *encoder;
 	struct drm_crtc *crtc;
+	struct drm_plane *primary;
 
 	sou = kzalloc(sizeof(*sou), GFP_KERNEL);
 	if (!sou)
@@ -469,7 +470,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
 
 	(void) drm_sysfs_connector_add(connector);
 
-	drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs);
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(dev, crtc, primary, &vmw_screen_object_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 236ed66..8c7b1d3 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -475,6 +475,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_crtc *imx_drm_crtc;
+	struct drm_plane *primary;
 	int ret;
 
 	mutex_lock(&imxdrm->mutex);
@@ -520,7 +521,8 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	drm_crtc_helper_add(crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
 
-	drm_crtc_init(imxdrm->drm, crtc,
+	primary = drm_primary_helper_create_plane(dev);
+	drm_crtc_init(imxdrm->drm, crtc, primary,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
 	drm_mode_group_reinit(imxdrm->drm);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 74f4943..4dc84f8 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -270,6 +270,7 @@ struct drm_crtc_funcs {
  * @dev: parent DRM device
  * @head: list management
  * @base: base KMS object for ID tracking etc.
+ * @primary: primary plane for this CRTC
  * @enabled: is this CRTC enabled?
  * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
@@ -305,6 +306,9 @@ struct drm_crtc {
 
 	struct drm_mode_object base;
 
+	/* primary plane for CRTC */
+	struct drm_plane *primary;
+
 	/* framebuffer the connector is currently bound to */
 	struct drm_framebuffer *fb;
 
@@ -907,6 +911,7 @@ extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
 
 extern int drm_crtc_init(struct drm_device *dev,
 			 struct drm_crtc *crtc,
+			 struct drm_plane *primary,
 			 const struct drm_crtc_funcs *funcs);
 extern void drm_crtc_cleanup(struct drm_crtc *crtc);
 extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2)
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (6 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2) Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 11:57   ` Daniel Vetter
  2014-03-19  0:22 ` [RFCv3 09/14] drm: Allow userspace to ask for full plane list (universal planes) Matt Roper
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

Now that CRTC's have a primary plane, there's no need to track the
framebuffer in the CRTC.  Replace all references to the CRTC fb
with the primary plane's fb.

Also note that this simplifies framebuffer removal slightly; we no
longer need to scan all CRTC's and disable the ones that were using the
framebuffer since the existing loop over all planes will take care
of disabling the primary plane (and on most hardware, the CRTC by
extension).

v2: Fixup several lingering crtc->fb instances that were missed in the
    first patch iteration.

Tested-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/ast/ast_mode.c               |  12 +--
 drivers/gpu/drm/bochs/bochs_kms.c            |   4 +-
 drivers/gpu/drm/cirrus/cirrus_mode.c         |  10 +-
 drivers/gpu/drm/drm_crtc.c                   |  56 ++++------
 drivers/gpu/drm/drm_crtc_helper.c            |  21 ++--
 drivers/gpu/drm/drm_fb_helper.c              |   6 +-
 drivers/gpu/drm/gma500/cdv_intel_display.c   |   2 +-
 drivers/gpu/drm/gma500/cdv_intel_dp.c        |   2 +-
 drivers/gpu/drm/gma500/cdv_intel_hdmi.c      |   3 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
 drivers/gpu/drm/gma500/gma_display.c         |  17 ++--
 drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
 drivers/gpu/drm/gma500/mdfld_intel_display.c |  17 ++--
 drivers/gpu/drm/gma500/oaktrail_crtc.c       |  13 +--
 drivers/gpu/drm/gma500/psb_intel_display.c   |   2 +-
 drivers/gpu/drm/gma500/psb_intel_lvds.c      |   2 +-
 drivers/gpu/drm/gma500/psb_intel_sdvo.c      |   2 +-
 drivers/gpu/drm/i915/i915_debugfs.c          |   4 +-
 drivers/gpu/drm/i915/i915_irq.c              |   4 +-
 drivers/gpu/drm/i915/intel_display.c         | 147 ++++++++++++++-------------
 drivers/gpu/drm/i915/intel_dp.c              |   5 +-
 drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
 drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
 drivers/gpu/drm/i915/intel_pm.c              |  36 +++----
 drivers/gpu/drm/mgag200/mgag200_mode.c       |  28 ++---
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  28 ++---
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  22 ++--
 drivers/gpu/drm/nouveau/dispnv04/crtc.c      |  20 ++--
 drivers/gpu/drm/nouveau/dispnv04/dfp.c       |   2 +-
 drivers/gpu/drm/nouveau/nouveau_display.c    |   8 +-
 drivers/gpu/drm/nouveau/nv50_display.c       |  17 ++--
 drivers/gpu/drm/qxl/qxl_display.c            |  11 +-
 drivers/gpu/drm/radeon/atombios_crtc.c       |  20 ++--
 drivers/gpu/drm/radeon/r100.c                |   4 +-
 drivers/gpu/drm/radeon/radeon_connectors.c   |   2 +-
 drivers/gpu/drm/radeon/radeon_device.c       |   3 +-
 drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
 drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +--
 drivers/gpu/drm/udl/udl_modeset.c            |   2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c          |  14 +--
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c          |   8 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c         |   8 +-
 include/drm/drm_crtc.h                       |   3 -
 43 files changed, 300 insertions(+), 299 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 44f0d32..bd1e156 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -81,7 +81,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
 	u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
 	u32 hborder, vborder;
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
 		color_index = VGAModeIndex - 1;
@@ -176,7 +176,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
 
 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
-		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
+		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
@@ -340,7 +340,7 @@ static void ast_set_offset_reg(struct drm_crtc *crtc)
 
 	u16 offset;
 
-	offset = crtc->fb->pitches[0] >> 3;
+	offset = crtc->primary->fb->pitches[0] >> 3;
 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
 	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
 }
@@ -365,7 +365,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
 	struct ast_private *ast = crtc->dev->dev_private;
 	u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		jregA0 = 0x70;
 		jregA3 = 0x01;
@@ -418,7 +418,7 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo
 static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		     struct ast_vbios_mode_info *vbios_mode)
 {
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		break;
 	default:
@@ -490,7 +490,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
 		ast_bo_unreserve(bo);
 	}
 
-	ast_fb = to_ast_framebuffer(crtc->fb);
+	ast_fb = to_ast_framebuffer(crtc->primary->fb);
 	obj = ast_fb->obj;
 	bo = gem_to_ast_bo(obj);
 
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 182f5c9..b67ad12 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -62,10 +62,10 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 		}
 	}
 
-	if (WARN_ON(crtc->fb == NULL))
+	if (WARN_ON(crtc->primary->fb == NULL))
 		return -EINVAL;
 
-	bochs_fb = to_bochs_framebuffer(crtc->fb);
+	bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
 	bo = gem_to_bochs_bo(bochs_fb->obj);
 	ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
 	if (ret)
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 449246f..5291d2f 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -149,7 +149,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
 		cirrus_bo_unreserve(bo);
 	}
 
-	cirrus_fb = to_cirrus_framebuffer(crtc->fb);
+	cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb);
 	obj = cirrus_fb->obj;
 	bo = gem_to_cirrus_bo(obj);
 
@@ -268,7 +268,7 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
 	sr07 = RREG8(SEQ_DATA);
 	sr07 &= 0xe0;
 	hdr = 0;
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		sr07 |= 0x11;
 		break;
@@ -291,13 +291,13 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
 	WREG_SEQ(0x7, sr07);
 
 	/* Program the pitch */
-	tmp = crtc->fb->pitches[0] / 8;
+	tmp = crtc->primary->fb->pitches[0] / 8;
 	WREG_CRT(VGA_CRTC_OFFSET, tmp);
 
 	/* Enable extended blanking and pitch bits, and enable full memory */
 	tmp = 0x22;
-	tmp |= (crtc->fb->pitches[0] >> 7) & 0x10;
-	tmp |= (crtc->fb->pitches[0] >> 6) & 0x40;
+	tmp |= (crtc->primary->fb->pitches[0] >> 7) & 0x10;
+	tmp |= (crtc->primary->fb->pitches[0] >> 6) & 0x40;
 	WREG_CRT(0x1b, tmp);
 
 	/* Enable high-colour modes */
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0feb66cc..0c395e8 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -634,7 +634,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
  * drm_framebuffer_remove - remove and unreference a framebuffer object
  * @fb: framebuffer to remove
  *
- * Scans all the CRTCs and planes in @dev's mode_config.  If they're
+ * Scans all the planes in @dev's mode_config.  If they're
  * using @fb, removes it, setting it to NULL. Then drops the reference to the
  * passed-in framebuffer. Might take the modeset locks.
  *
@@ -645,10 +645,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
 void drm_framebuffer_remove(struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = fb->dev;
-	struct drm_crtc *crtc;
 	struct drm_plane *plane;
-	struct drm_mode_set set;
-	int ret;
 
 	WARN_ON(!list_empty(&fb->filp_head));
 
@@ -669,19 +666,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	 */
 	if (atomic_read(&fb->refcount.refcount) > 1) {
 		drm_modeset_lock_all(dev);
-		/* remove from any CRTC */
-		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-			if (crtc->fb == fb) {
-				/* should turn off the crtc */
-				memset(&set, 0, sizeof(struct drm_mode_set));
-				set.crtc = crtc;
-				set.fb = NULL;
-				ret = drm_mode_set_config_internal(&set);
-				if (ret)
-					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
-			}
-		}
-
+		/* remove from any plane */
 		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
 			if (plane->fb == fb)
 				drm_plane_force_disable(plane);
@@ -1930,8 +1915,8 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	crtc_resp->x = crtc->x;
 	crtc_resp->y = crtc->y;
 	crtc_resp->gamma_size = crtc->gamma_size;
-	if (crtc->fb)
-		crtc_resp->fb_id = crtc->fb->base.id;
+	if (crtc->primary->fb)
+		crtc_resp->fb_id = crtc->primary->fb->base.id;
 	else
 		crtc_resp->fb_id = 0;
 
@@ -2438,7 +2423,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 	 * crtcs. Atomic modeset will have saner semantics ...
 	 */
 	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
-		tmp->old_fb = tmp->fb;
+		tmp->old_fb = tmp->primary->fb;
 
 	fb = set->fb;
 
@@ -2446,13 +2431,16 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 	if (ret == 0) {
 		crtc->primary->crtc = crtc;
 
-		/* crtc->fb must be updated by ->set_config, enforces this. */
-		WARN_ON(fb != crtc->fb);
+		/*
+		 * crtc->primary->fb must be updated by ->set_config,
+		 * enforces this.
+		 */
+		WARN_ON(fb != crtc->primary->fb);
 	}
 
 	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
-		if (tmp->fb)
-			drm_framebuffer_reference(tmp->fb);
+		if (tmp->primary->fb)
+			drm_framebuffer_reference(tmp->primary->fb);
 		if (tmp->old_fb)
 			drm_framebuffer_unreference(tmp->old_fb);
 	}
@@ -2511,12 +2499,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 		/* If we have a mode we need a framebuffer. */
 		/* If we pass -1, set the mode with the currently bound fb */
 		if (crtc_req->fb_id == -1) {
-			if (!crtc->fb) {
+			if (!crtc->primary->fb) {
 				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
 				ret = -EINVAL;
 				goto out;
 			}
-			fb = crtc->fb;
+			fb = crtc->primary->fb;
 			/* Make refcounting symmetric with the lookup path. */
 			drm_framebuffer_reference(fb);
 		} else {
@@ -4309,7 +4297,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	crtc = obj_to_crtc(obj);
 
 	mutex_lock(&crtc->mutex);
-	if (crtc->fb == NULL) {
+	if (crtc->primary->fb == NULL) {
 		/* The framebuffer is currently unbound, presumably
 		 * due to a hotplug event, that userspace has not
 		 * yet discovered.
@@ -4331,7 +4319,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if (ret)
 		goto out;
 
-	if (crtc->fb->pixel_format != fb->pixel_format) {
+	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
 		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
 		ret = -EINVAL;
 		goto out;
@@ -4364,7 +4352,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 			(void (*) (struct drm_pending_event *)) kfree;
 	}
 
-	old_fb = crtc->fb;
+	old_fb = crtc->primary->fb;
 	ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
 	if (ret) {
 		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
@@ -4377,12 +4365,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 		old_fb = NULL;
 	} else {
 		/*
-		 * Warn if the driver hasn't properly updated the crtc->fb
-		 * field to reflect that the new framebuffer is now used.
-		 * Failing to do so will screw with the reference counting
-		 * on framebuffers.
+		 * Warn if the driver hasn't properly updated the
+		 * crtc->primary->fb field to reflect that the new framebuffer
+		 * is now used.  Failing to do so will screw with the reference
+		 * counting on framebuffers.
 		 */
-		WARN_ON(crtc->fb != fb);
+		WARN_ON(crtc->primary->fb != fb);
 		/* Unref only the old framebuffer. */
 		fb = NULL;
 	}
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index a855178..8825afb 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -319,7 +319,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
 				(*crtc_funcs->disable)(crtc);
 			else
 				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
-			crtc->fb = NULL;
+			crtc->primary->fb = NULL;
 		}
 	}
 }
@@ -646,19 +646,19 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 	save_set.mode = &set->crtc->mode;
 	save_set.x = set->crtc->x;
 	save_set.y = set->crtc->y;
-	save_set.fb = set->crtc->fb;
+	save_set.fb = set->crtc->primary->fb;
 
 	/* We should be able to check here if the fb has the same properties
 	 * and then just flip_or_move it */
-	if (set->crtc->fb != set->fb) {
+	if (set->crtc->primary->fb != set->fb) {
 		/* If we have no fb then treat it as a full mode set */
-		if (set->crtc->fb == NULL) {
+		if (set->crtc->primary->fb == NULL) {
 			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
 			mode_changed = true;
 		} else if (set->fb == NULL) {
 			mode_changed = true;
 		} else if (set->fb->pixel_format !=
-			   set->crtc->fb->pixel_format) {
+			   set->crtc->primary->fb->pixel_format) {
 			mode_changed = true;
 		} else
 			fb_changed = true;
@@ -759,13 +759,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 			DRM_DEBUG_KMS("attempting to set mode from"
 					" userspace\n");
 			drm_mode_debug_printmodeline(set->mode);
-			set->crtc->fb = set->fb;
+			set->crtc->primary->fb = set->fb;
 			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
 						      set->x, set->y,
 						      save_set.fb)) {
 				DRM_ERROR("failed to set mode on [CRTC:%d]\n",
 					  set->crtc->base.id);
-				set->crtc->fb = save_set.fb;
+				set->crtc->primary->fb = save_set.fb;
 				ret = -EINVAL;
 				goto fail;
 			}
@@ -780,13 +780,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 	} else if (fb_changed) {
 		set->crtc->x = set->x;
 		set->crtc->y = set->y;
-		set->crtc->fb = set->fb;
+		set->crtc->primary->fb = set->fb;
 		ret = crtc_funcs->mode_set_base(set->crtc,
 						set->x, set->y, save_set.fb);
 		if (ret != 0) {
 			set->crtc->x = save_set.x;
 			set->crtc->y = save_set.y;
-			set->crtc->fb = save_set.fb;
+			set->crtc->primary->fb = save_set.fb;
 			goto fail;
 		}
 	}
@@ -982,7 +982,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
 			continue;
 
 		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
-					       crtc->x, crtc->y, crtc->fb);
+					       crtc->x, crtc->y,
+					       crtc->primary->fb);
 
 		/* Restoring the old config should never fail! */
 		if (ret == false)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 9c6251f..e8e2b41 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -232,7 +232,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
 
 	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
 		if (crtc->base.id == c->base.id)
-			return c->fb;
+			return c->primary->fb;
 	}
 
 	return NULL;
@@ -366,9 +366,9 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
 		return false;
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (crtc->fb)
+		if (crtc->primary->fb)
 			crtcs_bound++;
-		if (crtc->fb == fb_helper->fb)
+		if (crtc->primary->fb == fb_helper->fb)
 			bound++;
 	}
 
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 8fbfa06..1cddcf8 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -463,7 +463,7 @@ static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe)
 	crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 	gma_crtc = to_gma_crtc(crtc);
 
-	if (crtc->fb == NULL || !gma_crtc->active)
+	if (crtc->primary->fb == NULL || !gma_crtc->active)
 		return false;
 	return true;
 }
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index 0490ce3..9ff30c2 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -1693,7 +1693,7 @@ done:
 		struct drm_crtc *crtc = encoder->base.crtc;
 		drm_crtc_helper_set_mode(crtc, &crtc->mode,
 					 crtc->x, crtc->y,
-					 crtc->fb);
+					 crtc->primary->fb);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index 1c0d723..04956e6 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -199,7 +199,8 @@ static int cdv_hdmi_set_property(struct drm_connector *connector,
 		    crtc->saved_mode.vdisplay != 0) {
 			if (centre) {
 				if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
-					    encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb))
+					    encoder->crtc->x, encoder->crtc->y,
+					    encoder->crtc->primary->fb))
 					return -1;
 			} else {
 				struct drm_encoder_helper_funcs *helpers
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 20e08e6..58f11df 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -494,7 +494,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
 						      &crtc->saved_mode,
 						      encoder->crtc->x,
 						      encoder->crtc->y,
-						      encoder->crtc->fb))
+						      encoder->crtc->primary->fb))
 				return -1;
 		}
 	} else if (!strcmp(property->name, "backlight") && encoder) {
diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
index 386de2c..7b73dd1 100644
--- a/drivers/gpu/drm/gma500/gma_display.c
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -59,7 +59,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 	struct drm_device *dev = crtc->dev;
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
 	int pipe = gma_crtc->pipe;
 	const struct psb_offset *map = &dev_priv->regmap[pipe];
 	unsigned long start, offset;
@@ -70,7 +70,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 		return 0;
 
 	/* no fb bound */
-	if (!crtc->fb) {
+	if (!crtc->primary->fb) {
 		dev_err(dev->dev, "No FB bound\n");
 		goto gma_pipe_cleaner;
 	}
@@ -81,19 +81,20 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 	if (ret < 0)
 		goto gma_pipe_set_base_exit;
 	start = psbfb->gtt->offset;
-	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+	offset = y * crtc->primary->fb->pitches[0] +
+		x * (crtc->primary->fb->bits_per_pixel / 8);
 
-	REG_WRITE(map->stride, crtc->fb->pitches[0]);
+	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
 
 	dspcntr = REG_READ(map->cntr);
 	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		dspcntr |= DISPPLANE_8BPP;
 		break;
 	case 16:
-		if (crtc->fb->depth == 15)
+		if (crtc->primary->fb->depth == 15)
 			dspcntr |= DISPPLANE_15_16BPP;
 		else
 			dspcntr |= DISPPLANE_16BPP;
@@ -511,8 +512,8 @@ void gma_crtc_disable(struct drm_crtc *crtc)
 
 	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 
-	if (crtc->fb) {
-		gt = to_psb_fb(crtc->fb)->gtt;
+	if (crtc->primary->fb) {
+		gt = to_psb_fb(crtc->primary->fb)->gtt;
 		psb_gtt_unpin(gt);
 	}
 }
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 860a4ee..6e91b20 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -287,7 +287,7 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
 						&gma_crtc->saved_mode,
 						encoder->crtc->x,
 						encoder->crtc->y,
-						encoder->crtc->fb))
+						encoder->crtc->primary->fb))
 					goto set_prop_error;
 			} else {
 				struct drm_encoder_helper_funcs *funcs =
diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c
index 321c00a..c54386a 100644
--- a/drivers/gpu/drm/gma500/mdfld_intel_display.c
+++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c
@@ -166,7 +166,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 	struct drm_device *dev = crtc->dev;
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
 	int pipe = gma_crtc->pipe;
 	const struct psb_offset *map = &dev_priv->regmap[pipe];
 	unsigned long start, offset;
@@ -178,12 +178,12 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 	dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
 
 	/* no fb bound */
-	if (!crtc->fb) {
+	if (!crtc->primary->fb) {
 		dev_dbg(dev->dev, "No FB bound\n");
 		return 0;
 	}
 
-	ret = check_fb(crtc->fb);
+	ret = check_fb(crtc->primary->fb);
 	if (ret)
 		return ret;
 
@@ -196,18 +196,19 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 		return 0;
 
 	start = psbfb->gtt->offset;
-	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+	offset = y * crtc->primary->fb->pitches[0] +
+		x * (crtc->primary->fb->bits_per_pixel / 8);
 
-	REG_WRITE(map->stride, crtc->fb->pitches[0]);
+	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
 	dspcntr = REG_READ(map->cntr);
 	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		dspcntr |= DISPPLANE_8BPP;
 		break;
 	case 16:
-		if (crtc->fb->depth == 15)
+		if (crtc->primary->fb->depth == 15)
 			dspcntr |= DISPPLANE_15_16BPP;
 		else
 			dspcntr |= DISPPLANE_16BPP;
@@ -700,7 +701,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
 	}
 #endif
 
-	ret = check_fb(crtc->fb);
+	ret = check_fb(crtc->primary->fb);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index 8195e85..b0fb42a 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -599,7 +599,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
 	int pipe = gma_crtc->pipe;
 	const struct psb_offset *map = &dev_priv->regmap[pipe];
 	unsigned long start, offset;
@@ -608,7 +608,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
 	int ret = 0;
 
 	/* no fb bound */
-	if (!crtc->fb) {
+	if (!crtc->primary->fb) {
 		dev_dbg(dev->dev, "No FB bound\n");
 		return 0;
 	}
@@ -617,19 +617,20 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
 		return 0;
 
 	start = psbfb->gtt->offset;
-	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+	offset = y * crtc->primary->fb->pitches[0] +
+		x * (crtc->primary->fb->bits_per_pixel / 8);
 
-	REG_WRITE(map->stride, crtc->fb->pitches[0]);
+	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
 
 	dspcntr = REG_READ(map->cntr);
 	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		dspcntr |= DISPPLANE_8BPP;
 		break;
 	case 16:
-		if (crtc->fb->depth == 15)
+		if (crtc->primary->fb->depth == 15)
 			dspcntr |= DISPPLANE_15_16BPP;
 		else
 			dspcntr |= DISPPLANE_16BPP;
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index c8f833d..25c174c 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -120,7 +120,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
 	const struct gma_limit_t *limit;
 
 	/* No scan out no play */
-	if (crtc->fb == NULL) {
+	if (crtc->primary->fb == NULL) {
 		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
 		return 0;
 	}
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index 32342f6..dcdf70e 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -614,7 +614,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
 						      &crtc->saved_mode,
 						      encoder->crtc->x,
 						      encoder->crtc->y,
-						      encoder->crtc->fb))
+						      encoder->crtc->primary->fb))
 				goto set_prop_error;
 		}
 	} else if (!strcmp(property->name, "backlight")) {
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 07d3a9e..1c0a2fb 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1844,7 +1844,7 @@ done:
 	if (psb_intel_sdvo->base.base.crtc) {
 		struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc;
 		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
-					 crtc->y, crtc->fb);
+					 crtc->y, crtc->primary->fb);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index d83d643..f00ba43 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2172,8 +2172,8 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc)
 	struct intel_encoder *intel_encoder;
 
 	seq_printf(m, "\tfb: %d, pos: %dx%d, size: %dx%d\n",
-		   crtc->fb->base.id, crtc->x, crtc->y,
-		   crtc->fb->width, crtc->fb->height);
+		   crtc->primary->fb->base.id, crtc->x, crtc->y,
+		   crtc->primary->fb->width, crtc->primary->fb->height);
 	for_each_encoder_on_crtc(dev, crtc, intel_encoder)
 		intel_encoder_info(m, intel_crtc, intel_encoder);
 }
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 37f852d..e8b3f9f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2380,8 +2380,8 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in
 	} else {
 		int dspaddr = DSPADDR(intel_crtc->plane);
 		stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) +
-							crtc->y * crtc->fb->pitches[0] +
-							crtc->x * crtc->fb->bits_per_pixel/8);
+							crtc->y * crtc->primary->fb->pitches[0] +
+							crtc->x * crtc->primary->fb->bits_per_pixel/8);
 	}
 
 	spin_unlock_irqrestore(&dev->event_lock, flags);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 21d12a9..c2f3730 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -744,7 +744,7 @@ bool intel_crtc_active(struct drm_crtc *crtc)
 	 * We can ditch the crtc->fb check as soon as we can
 	 * properly reconstruct framebuffers.
 	 */
-	return intel_crtc->active && crtc->fb &&
+	return intel_crtc->active && crtc->primary->fb &&
 		intel_crtc->config.adjusted_mode.crtc_clock;
 }
 
@@ -2086,17 +2086,18 @@ static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
 
 	if (plane_config->tiled) {
 		obj->tiling_mode = I915_TILING_X;
-		obj->stride = crtc->base.fb->pitches[0];
+		obj->stride = crtc->base.primary->fb->pitches[0];
 	}
 
-	mode_cmd.pixel_format = crtc->base.fb->pixel_format;
-	mode_cmd.width = crtc->base.fb->width;
-	mode_cmd.height = crtc->base.fb->height;
-	mode_cmd.pitches[0] = crtc->base.fb->pitches[0];
+	mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
+	mode_cmd.width = crtc->base.primary->fb->width;
+	mode_cmd.height = crtc->base.primary->fb->height;
+	mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0];
 
 	mutex_lock(&dev->struct_mutex);
 
-	if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.fb),
+	if (intel_framebuffer_init(dev,
+				   to_intel_framebuffer(crtc->base.primary->fb),
 				   &mode_cmd, obj)) {
 		DRM_DEBUG_KMS("intel fb init failed\n");
 		goto out_unref_obj;
@@ -2121,14 +2122,14 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
 	struct intel_crtc *i;
 	struct intel_framebuffer *fb;
 
-	if (!intel_crtc->base.fb)
+	if (!intel_crtc->base.primary->fb)
 		return;
 
 	if (intel_alloc_plane_obj(intel_crtc, plane_config))
 		return;
 
-	kfree(intel_crtc->base.fb);
-	intel_crtc->base.fb = NULL;
+	kfree(intel_crtc->base.primary->fb);
+	intel_crtc->base.primary->fb = NULL;
 
 	/*
 	 * Failed to alloc the obj, check to see if we should share
@@ -2140,13 +2141,13 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
 		if (c == &intel_crtc->base)
 			continue;
 
-		if (!i->active || !c->fb)
+		if (!i->active || !c->primary->fb)
 			continue;
 
-		fb = to_intel_framebuffer(c->fb);
+		fb = to_intel_framebuffer(c->primary->fb);
 		if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) {
-			drm_framebuffer_reference(c->fb);
-			intel_crtc->base.fb = c->fb;
+			drm_framebuffer_reference(c->primary->fb);
+			intel_crtc->base.primary->fb = c->primary->fb;
 			break;
 		}
 	}
@@ -2394,11 +2395,13 @@ void intel_display_handle_reset(struct drm_device *dev)
 		/*
 		 * FIXME: Once we have proper support for primary planes (and
 		 * disabling them without disabling the entire crtc) allow again
-		 * a NULL crtc->fb.
+		 * a NULL crtc->primary->fb.
 		 */
-		if (intel_crtc->active && crtc->fb)
-			dev_priv->display.update_plane(crtc, crtc->fb,
-						       crtc->x, crtc->y);
+		if (intel_crtc->active && crtc->primary->fb)
+			dev_priv->display.update_plane(crtc,
+						       crtc->primary->fb,
+						       crtc->x,
+						       crtc->y);
 		mutex_unlock(&crtc->mutex);
 	}
 }
@@ -2523,8 +2526,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 		return ret;
 	}
 
-	old_fb = crtc->fb;
-	crtc->fb = fb;
+	old_fb = crtc->primary->fb;
+	crtc->primary->fb = fb;
 	crtc->x = x;
 	crtc->y = y;
 
@@ -3118,7 +3121,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (crtc->fb == NULL)
+	if (crtc->primary->fb == NULL)
 		return;
 
 	WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
@@ -3127,7 +3130,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 		   !intel_crtc_has_pending_flip(crtc));
 
 	mutex_lock(&dev->struct_mutex);
-	intel_finish_fb(crtc->fb);
+	intel_finish_fb(crtc->primary->fb);
 	mutex_unlock(&dev->struct_mutex);
 }
 
@@ -4583,11 +4586,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
 	assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe);
 	assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
 
-	if (crtc->fb) {
+	if (crtc->primary->fb) {
 		mutex_lock(&dev->struct_mutex);
-		intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
+		intel_unpin_fb_obj(to_intel_framebuffer(crtc->primary->fb)->obj);
 		mutex_unlock(&dev->struct_mutex);
-		crtc->fb = NULL;
+		crtc->primary->fb = NULL;
 	}
 
 	/* Update computed state. */
@@ -5738,8 +5741,9 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
 	int fourcc, pixel_format;
 	int aligned_height;
 
-	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
-	if (!crtc->base.fb) {
+	crtc->base.primary->fb =
+		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
+	if (!crtc->base.primary->fb) {
 		DRM_DEBUG_KMS("failed to alloc fb\n");
 		return;
 	}
@@ -5752,8 +5756,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
 
 	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
 	fourcc = intel_format_to_fourcc(pixel_format);
-	crtc->base.fb->pixel_format = fourcc;
-	crtc->base.fb->bits_per_pixel =
+	crtc->base.primary->fb->pixel_format = fourcc;
+	crtc->base.primary->fb->bits_per_pixel =
 		drm_format_plane_cpp(fourcc, 0) * 8;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
@@ -5768,23 +5772,23 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
 	plane_config->base = base;
 
 	val = I915_READ(PIPESRC(pipe));
-	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
-	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
+	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
+	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
 
 	val = I915_READ(DSPSTRIDE(pipe));
-	crtc->base.fb->pitches[0] = val & 0xffffff80;
+	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
 
-	aligned_height = intel_align_height(dev, crtc->base.fb->height,
+	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
 					    plane_config->tiled);
 
-	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
+	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
 				   aligned_height, PAGE_SIZE);
 
 	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
-		      pipe, plane, crtc->base.fb->width,
-		      crtc->base.fb->height,
-		      crtc->base.fb->bits_per_pixel, base,
-		      crtc->base.fb->pitches[0],
+		      pipe, plane, crtc->base.primary->fb->width,
+		      crtc->base.primary->fb->height,
+		      crtc->base.primary->fb->bits_per_pixel, base,
+		      crtc->base.primary->fb->pitches[0],
 		      plane_config->size);
 
 }
@@ -6746,8 +6750,9 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
 	int fourcc, pixel_format;
 	int aligned_height;
 
-	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
-	if (!crtc->base.fb) {
+	crtc->base.primary->fb =
+		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
+	if (!crtc->base.primary->fb) {
 		DRM_DEBUG_KMS("failed to alloc fb\n");
 		return;
 	}
@@ -6760,8 +6765,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
 
 	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
 	fourcc = intel_format_to_fourcc(pixel_format);
-	crtc->base.fb->pixel_format = fourcc;
-	crtc->base.fb->bits_per_pixel =
+	crtc->base.primary->fb->pixel_format = fourcc;
+	crtc->base.primary->fb->bits_per_pixel =
 		drm_format_plane_cpp(fourcc, 0) * 8;
 
 	base = I915_READ(DSPSURF(plane)) & 0xfffff000;
@@ -6776,23 +6781,23 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
 	plane_config->base = base;
 
 	val = I915_READ(PIPESRC(pipe));
-	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
-	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
+	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
+	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
 
 	val = I915_READ(DSPSTRIDE(pipe));
-	crtc->base.fb->pitches[0] = val & 0xffffff80;
+	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
 
-	aligned_height = intel_align_height(dev, crtc->base.fb->height,
+	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
 					    plane_config->tiled);
 
-	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
+	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
 				   aligned_height, PAGE_SIZE);
 
 	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
-		      pipe, plane, crtc->base.fb->width,
-		      crtc->base.fb->height,
-		      crtc->base.fb->bits_per_pixel, base,
-		      crtc->base.fb->pitches[0],
+		      pipe, plane, crtc->base.primary->fb->width,
+		      crtc->base.primary->fb->height,
+		      crtc->base.primary->fb->bits_per_pixel, base,
+		      crtc->base.primary->fb->pitches[0],
 		      plane_config->size);
 }
 
@@ -8482,7 +8487,7 @@ void intel_mark_idle(struct drm_device *dev)
 		goto out;
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (!crtc->fb)
+		if (!crtc->primary->fb)
 			continue;
 
 		intel_decrease_pllclock(crtc);
@@ -8505,10 +8510,10 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 		return;
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (!crtc->fb)
+		if (!crtc->primary->fb)
 			continue;
 
-		if (to_intel_framebuffer(crtc->fb)->obj != obj)
+		if (to_intel_framebuffer(crtc->primary->fb)->obj != obj)
 			continue;
 
 		intel_increase_pllclock(crtc);
@@ -8936,7 +8941,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *old_fb = crtc->fb;
+	struct drm_framebuffer *old_fb = crtc->primary->fb;
 	struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_unpin_work *work;
@@ -8944,7 +8949,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	int ret;
 
 	/* Can't change pixel format via MI display flips. */
-	if (fb->pixel_format != crtc->fb->pixel_format)
+	if (fb->pixel_format != crtc->primary->fb->pixel_format)
 		return -EINVAL;
 
 	/*
@@ -8952,8 +8957,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	 * Note that pitch changes could also affect these register.
 	 */
 	if (INTEL_INFO(dev)->gen > 3 &&
-	    (fb->offsets[0] != crtc->fb->offsets[0] ||
-	     fb->pitches[0] != crtc->fb->pitches[0]))
+	    (fb->offsets[0] != crtc->primary->fb->offsets[0] ||
+	     fb->pitches[0] != crtc->primary->fb->pitches[0]))
 		return -EINVAL;
 
 	if (i915_terminally_wedged(&dev_priv->gpu_error))
@@ -8996,7 +9001,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	drm_gem_object_reference(&work->old_fb_obj->base);
 	drm_gem_object_reference(&obj->base);
 
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 
 	work->pending_flip_obj = obj;
 
@@ -9019,7 +9024,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
 cleanup_pending:
 	atomic_dec(&intel_crtc->unpin_work_count);
-	crtc->fb = old_fb;
+	crtc->primary->fb = old_fb;
 	drm_gem_object_unreference(&work->old_fb_obj->base);
 	drm_gem_object_unreference(&obj->base);
 	mutex_unlock(&dev->struct_mutex);
@@ -10060,7 +10065,7 @@ static int intel_set_mode(struct drm_crtc *crtc,
 
 void intel_crtc_restore_mode(struct drm_crtc *crtc)
 {
-	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb);
+	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
 }
 
 #undef for_each_intel_crtc_masked
@@ -10184,9 +10189,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
 	 * and then just flip_or_move it */
 	if (is_crtc_connector_off(set)) {
 		config->mode_changed = true;
-	} else if (set->crtc->fb != set->fb) {
+	} else if (set->crtc->primary->fb != set->fb) {
 		/* If we have no fb then treat it as a full mode set */
-		if (set->crtc->fb == NULL) {
+		if (set->crtc->primary->fb == NULL) {
 			struct intel_crtc *intel_crtc =
 				to_intel_crtc(set->crtc);
 
@@ -10200,7 +10205,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
 		} else if (set->fb == NULL) {
 			config->mode_changed = true;
 		} else if (set->fb->pixel_format !=
-			   set->crtc->fb->pixel_format) {
+			   set->crtc->primary->fb->pixel_format) {
 			config->mode_changed = true;
 		} else {
 			config->fb_changed = true;
@@ -10413,7 +10418,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 	save_set.mode = &set->crtc->mode;
 	save_set.x = set->crtc->x;
 	save_set.y = set->crtc->y;
-	save_set.fb = set->crtc->fb;
+	save_set.fb = set->crtc->primary->fb;
 
 	/* Compute whether we need a full modeset, only an fb base update or no
 	 * change at all. In the future we might also check whether only the
@@ -11755,7 +11760,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 				dev_priv->pipe_to_crtc_mapping[pipe];
 
 			__intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
-					 crtc->fb);
+					 crtc->primary->fb);
 		}
 	} else {
 		intel_modeset_update_staged_output_state(dev);
@@ -11780,15 +11785,15 @@ void intel_modeset_gem_init(struct drm_device *dev)
 	 */
 	mutex_lock(&dev->struct_mutex);
 	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
-		if (!c->fb)
+		if (!c->primary->fb)
 			continue;
 
-		fb = to_intel_framebuffer(c->fb);
+		fb = to_intel_framebuffer(c->primary->fb);
 		if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) {
 			DRM_ERROR("failed to pin boot fb on pipe %d\n",
 				  to_intel_crtc(c)->pipe);
-			drm_framebuffer_unreference(c->fb);
-			c->fb = NULL;
+			drm_framebuffer_unreference(c->primary->fb);
+			c->primary->fb = NULL;
 		}
 	}
 	mutex_unlock(&dev->struct_mutex);
@@ -11827,7 +11832,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		/* Skip inactive CRTCs */
-		if (!crtc->fb)
+		if (!crtc->primary->fb)
 			continue;
 
 		intel_increase_pllclock(crtc);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 59ee4dc..05531bf 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1634,7 +1634,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc = dig_port->base.base.crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
+	struct drm_i915_gem_object *obj =
+		to_intel_framebuffer(crtc->primary->fb)->obj;
 	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
 
 	dev_priv->psr.source_ok = false;
@@ -1667,7 +1668,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	obj = to_intel_framebuffer(crtc->fb)->obj;
+	obj = to_intel_framebuffer(crtc->primary->fb)->obj;
 	if (obj->tiling_mode != I915_TILING_X ||
 	    obj->fence_reg == I915_FENCE_REG_NONE) {
 		DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index d6d78c8..2b1d42d 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -481,7 +481,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		intel_crtc = to_intel_crtc(crtc);
 
-		if (!intel_crtc->active || !crtc->fb) {
+		if (!intel_crtc->active || !crtc->primary->fb) {
 			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
 				      pipe_name(intel_crtc->pipe));
 			continue;
@@ -491,7 +491,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
 			DRM_DEBUG_KMS("found possible fb from plane %c\n",
 				      pipe_name(intel_crtc->pipe));
 			plane_config = &intel_crtc->plane_config;
-			fb = to_intel_framebuffer(crtc->fb);
+			fb = to_intel_framebuffer(crtc->primary->fb);
 			max_size = plane_config->size;
 		}
 	}
@@ -560,7 +560,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
 		if (!intel_crtc->active)
 			continue;
 
-		WARN(!crtc->fb,
+		WARN(!crtc->primary->fb,
 		     "re-used BIOS config but lost an fb on crtc %d\n",
 		     crtc->base.id);
 	}
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 312961a..623cd32 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -606,14 +606,14 @@ static void update_colorkey(struct intel_overlay *overlay,
 {
 	u32 key = overlay->color_key;
 
-	switch (overlay->crtc->base.fb->bits_per_pixel) {
+	switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
 	case 8:
 		iowrite32(0, &regs->DCLRKV);
 		iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
 		break;
 
 	case 16:
-		if (overlay->crtc->base.fb->depth == 15) {
+		if (overlay->crtc->base.primary->fb->depth == 15) {
 			iowrite32(RGB15_TO_COLORKEY(key), &regs->DCLRKV);
 			iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
 				  &regs->DCLRKM);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 3a1b569..e2d73f4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -92,7 +92,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -149,7 +149,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -221,7 +221,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -277,7 +277,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -336,11 +336,11 @@ static void intel_fbc_work_fn(struct work_struct *__work)
 		/* Double check that we haven't switched fb without cancelling
 		 * the prior work.
 		 */
-		if (work->crtc->fb == work->fb) {
+		if (work->crtc->primary->fb == work->fb) {
 			dev_priv->display.enable_fbc(work->crtc);
 
 			dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
-			dev_priv->fbc.fb_id = work->crtc->fb->base.id;
+			dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
 			dev_priv->fbc.y = work->crtc->y;
 		}
 
@@ -393,7 +393,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc)
 	}
 
 	work->crtc = crtc;
-	work->fb = crtc->fb;
+	work->fb = crtc->primary->fb;
 	INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
 
 	dev_priv->fbc.fbc_work = work;
@@ -499,14 +499,14 @@ void intel_update_fbc(struct drm_device *dev)
 		}
 	}
 
-	if (!crtc || crtc->fb == NULL) {
+	if (!crtc || crtc->primary->fb == NULL) {
 		if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
 			DRM_DEBUG_KMS("no output, disabling\n");
 		goto out_disable;
 	}
 
 	intel_crtc = to_intel_crtc(crtc);
-	fb = crtc->fb;
+	fb = crtc->primary->fb;
 	intel_fb = to_intel_framebuffer(fb);
 	obj = intel_fb->obj;
 	adjusted_mode = &intel_crtc->config.adjusted_mode;
@@ -1041,7 +1041,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
 	crtc = single_enabled_crtc(dev);
 	if (crtc) {
 		const struct drm_display_mode *adjusted_mode;
-		int pixel_size = crtc->fb->bits_per_pixel / 8;
+		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 		int clock;
 
 		adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
@@ -1121,7 +1121,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
 	clock = adjusted_mode->crtc_clock;
 	htotal = adjusted_mode->crtc_htotal;
 	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
-	pixel_size = crtc->fb->bits_per_pixel / 8;
+	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 
 	/* Use the small buffer method to calculate plane watermark */
 	entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
@@ -1208,7 +1208,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
 	clock = adjusted_mode->crtc_clock;
 	htotal = adjusted_mode->crtc_htotal;
 	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
-	pixel_size = crtc->fb->bits_per_pixel / 8;
+	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 
 	line_time_us = max(htotal * 1000 / clock, 1);
 	line_count = (latency_ns / line_time_us + 1000) / 1000;
@@ -1247,7 +1247,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,
 		return false;
 
 	clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
-	pixel_size = crtc->fb->bits_per_pixel / 8;	/* BPP */
+	pixel_size = crtc->primary->fb->bits_per_pixel / 8;	/* BPP */
 
 	entries = (clock / 1000) * pixel_size;
 	*plane_prec_mult = (entries > 256) ?
@@ -1439,7 +1439,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
 		int clock = adjusted_mode->crtc_clock;
 		int htotal = adjusted_mode->crtc_htotal;
 		int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
-		int pixel_size = crtc->fb->bits_per_pixel / 8;
+		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 		unsigned long line_time_us;
 		int entries;
 
@@ -1512,7 +1512,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
 	crtc = intel_get_crtc_for_plane(dev, 0);
 	if (intel_crtc_active(crtc)) {
 		const struct drm_display_mode *adjusted_mode;
-		int cpp = crtc->fb->bits_per_pixel / 8;
+		int cpp = crtc->primary->fb->bits_per_pixel / 8;
 		if (IS_GEN2(dev))
 			cpp = 4;
 
@@ -1528,7 +1528,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
 	crtc = intel_get_crtc_for_plane(dev, 1);
 	if (intel_crtc_active(crtc)) {
 		const struct drm_display_mode *adjusted_mode;
-		int cpp = crtc->fb->bits_per_pixel / 8;
+		int cpp = crtc->primary->fb->bits_per_pixel / 8;
 		if (IS_GEN2(dev))
 			cpp = 4;
 
@@ -1565,7 +1565,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
 		int clock = adjusted_mode->crtc_clock;
 		int htotal = adjusted_mode->crtc_htotal;
 		int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w;
-		int pixel_size = enabled->fb->bits_per_pixel / 8;
+		int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
 		unsigned long line_time_us;
 		int entries;
 
@@ -2117,7 +2117,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
 	if (p->active) {
 		p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
 		p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
-		p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
+		p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
 		p->cur.bytes_per_pixel = 4;
 		p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
 		p->cur.horiz_pixels = 64;
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 1418414..f8c42b1 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -29,7 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
 	struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct mga_device *mdev = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 	int i;
 
 	if (!crtc->enabled)
@@ -742,7 +742,7 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
 		mgag200_bo_unreserve(bo);
 	}
 
-	mga_fb = to_mga_framebuffer(crtc->fb);
+	mga_fb = to_mga_framebuffer(crtc->primary->fb);
 	obj = mga_fb->obj;
 	bo = gem_to_mga_bo(obj);
 
@@ -805,7 +805,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 		/* 0x48: */        0,    0,    0,    0,    0,    0,    0,    0
 	};
 
-	bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1];
+	bppshift = mdev->bpp_shifts[(crtc->primary->fb->bits_per_pixel >> 3) - 1];
 
 	switch (mdev->type) {
 	case G200_SE_A:
@@ -843,12 +843,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 		break;
 	}
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
 		break;
 	case 16:
-		if (crtc->fb->depth == 15)
+		if (crtc->primary->fb->depth == 15)
 			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
 		else
 			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
@@ -896,8 +896,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 	WREG_SEQ(3, 0);
 	WREG_SEQ(4, 0xe);
 
-	pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
-	if (crtc->fb->bits_per_pixel == 24)
+	pitch = crtc->primary->fb->pitches[0] /
+		(crtc->primary->fb->bits_per_pixel / 8);
+	if (crtc->primary->fb->bits_per_pixel == 24)
 		pitch = (pitch * 3) >> (4 - bppshift);
 	else
 		pitch = pitch >> (4 - bppshift);
@@ -974,7 +975,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 		((vdisplay & 0xc00) >> 7) |
 		((vsyncstart & 0xc00) >> 5) |
 		((vdisplay & 0x400) >> 3);
-	if (crtc->fb->bits_per_pixel == 24)
+	if (crtc->primary->fb->bits_per_pixel == 24)
 		ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
 	else
 		ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
@@ -1034,9 +1035,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 			u32 bpp;
 			u32 mb;
 
-			if (crtc->fb->bits_per_pixel > 16)
+			if (crtc->primary->fb->bits_per_pixel > 16)
 				bpp = 32;
-			else if (crtc->fb->bits_per_pixel > 8)
+			else if (crtc->primary->fb->bits_per_pixel > 8)
 				bpp = 16;
 			else
 				bpp = 8;
@@ -1277,8 +1278,9 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
 	int ret;
 	DRM_DEBUG_KMS("\n");
 	mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-	if (crtc->fb) {
-		struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
+	if (crtc->primary->fb) {
+		struct mga_framebuffer *mga_fb =
+			to_mga_framebuffer(crtc->primary->fb);
 		struct drm_gem_object *obj = mga_fb->obj;
 		struct mgag200_bo *bo = gem_to_mga_bo(obj);
 		ret = mgag200_bo_reserve(bo, false);
@@ -1287,7 +1289,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
 		mgag200_bo_push_sysram(bo);
 		mgag200_bo_unreserve(bo);
 	}
-	crtc->fb = NULL;
+	crtc->primary->fb = NULL;
 }
 
 /* These provide the minimum set of functions required to handle a CRTC */
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index b10f681..f96497b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -120,7 +120,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
 
 	/* grab reference to incoming scanout fb: */
 	drm_framebuffer_reference(new_fb);
-	mdp4_crtc->base.fb = new_fb;
+	mdp4_crtc->base.primary->fb = new_fb;
 	mdp4_crtc->fb = new_fb;
 
 	if (old_fb)
@@ -182,7 +182,7 @@ static void pageflip_cb(struct msm_fence_cb *cb)
 	struct mdp4_crtc *mdp4_crtc =
 		container_of(cb, struct mdp4_crtc, pageflip_cb);
 	struct drm_crtc *crtc = &mdp4_crtc->base;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 
 	if (!fb)
 		return;
@@ -348,14 +348,14 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
 			mode->type, mode->flags);
 
 	/* grab extra ref for update_scanout() */
-	drm_framebuffer_reference(crtc->fb);
+	drm_framebuffer_reference(crtc->primary->fb);
 
-	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
+	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16);
 	if (ret) {
-		drm_framebuffer_unreference(crtc->fb);
+		drm_framebuffer_unreference(crtc->primary->fb);
 		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
 				mdp4_crtc->name, ret);
 		return ret;
@@ -368,7 +368,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
 	/* take data from pipe: */
 	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
 	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma),
-			crtc->fb->pitches[0]);
+			crtc->primary->fb->pitches[0]);
 	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
 			MDP4_DMA_DST_SIZE_WIDTH(0) |
 			MDP4_DMA_DST_SIZE_HEIGHT(0));
@@ -378,7 +378,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
 			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
 			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
 	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp),
-			crtc->fb->pitches[0]);
+			crtc->primary->fb->pitches[0]);
 
 	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
 
@@ -388,8 +388,8 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
 		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
 	}
 
-	update_fb(crtc, crtc->fb);
-	update_scanout(crtc, crtc->fb);
+	update_fb(crtc, crtc->primary->fb);
+	update_scanout(crtc, crtc->primary->fb);
 
 	return 0;
 }
@@ -420,19 +420,19 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	int ret;
 
 	/* grab extra ref for update_scanout() */
-	drm_framebuffer_reference(crtc->fb);
+	drm_framebuffer_reference(crtc->primary->fb);
 
-	ret = mdp4_plane_mode_set(plane, crtc, crtc->fb,
+	ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16);
 	if (ret) {
-		drm_framebuffer_unreference(crtc->fb);
+		drm_framebuffer_unreference(crtc->primary->fb);
 		return ret;
 	}
 
-	update_fb(crtc, crtc->fb);
-	update_scanout(crtc, crtc->fb);
+	update_fb(crtc, crtc->primary->fb);
+	update_scanout(crtc, crtc->primary->fb);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 7dc3d71..f200048 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -102,7 +102,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
 
 	/* grab reference to incoming scanout fb: */
 	drm_framebuffer_reference(new_fb);
-	mdp5_crtc->base.fb = new_fb;
+	mdp5_crtc->base.primary->fb = new_fb;
 	mdp5_crtc->fb = new_fb;
 
 	if (old_fb)
@@ -289,14 +289,14 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
 			mode->type, mode->flags);
 
 	/* grab extra ref for update_scanout() */
-	drm_framebuffer_reference(crtc->fb);
+	drm_framebuffer_reference(crtc->primary->fb);
 
-	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb,
+	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16);
 	if (ret) {
-		drm_framebuffer_unreference(crtc->fb);
+		drm_framebuffer_unreference(crtc->primary->fb);
 		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
 				mdp5_crtc->name, ret);
 		return ret;
@@ -306,8 +306,8 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
 			MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
 			MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
 
-	update_fb(crtc, crtc->fb);
-	update_scanout(crtc, crtc->fb);
+	update_fb(crtc, crtc->primary->fb);
+	update_scanout(crtc, crtc->primary->fb);
 
 	return 0;
 }
@@ -338,19 +338,19 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	int ret;
 
 	/* grab extra ref for update_scanout() */
-	drm_framebuffer_reference(crtc->fb);
+	drm_framebuffer_reference(crtc->primary->fb);
 
-	ret = mdp5_plane_mode_set(plane, crtc, crtc->fb,
+	ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16);
 	if (ret) {
-		drm_framebuffer_unreference(crtc->fb);
+		drm_framebuffer_unreference(crtc->primary->fb);
 		return ret;
 	}
 
-	update_fb(crtc, crtc->fb);
-	update_scanout(crtc, crtc->fb);
+	update_fb(crtc, crtc->primary->fb);
+	update_scanout(crtc, crtc->primary->fb);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index b55be84..2a5e9db 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -239,7 +239,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
 	struct drm_device *dev = crtc->dev;
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 
 	/* Calculate our timings */
 	int horizDisplay	= (mode->crtc_hdisplay >> 3)		- 1;
@@ -574,7 +574,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
 		regp->CRTC[NV_CIO_CRE_86] = 0x1;
 	}
 
-	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->fb->depth + 1) / 8;
+	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->primary->fb->depth + 1) / 8;
 	/* Enable slaved mode (called MODE_TV in nv4ref.h) */
 	if (lvds_output || tmds_output || tv_output)
 		regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7);
@@ -588,7 +588,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
 	regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
 				NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL |
 				NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON;
-	if (crtc->fb->depth == 16)
+	if (crtc->primary->fb->depth == 16)
 		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
 	if (nv_device(drm->device)->chipset >= 0x11)
 		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG;
@@ -609,7 +609,7 @@ static int
 nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
 {
 	struct nv04_display *disp = nv04_display(crtc->dev);
-	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	int ret;
 
@@ -808,7 +808,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
 	 * mark the lut values as dirty by setting depth==0, and it'll be
 	 * uploaded on the first mode_set_base()
 	 */
-	if (!nv_crtc->base.fb) {
+	if (!nv_crtc->base.primary->fb) {
 		nv_crtc->lut.depth = 0;
 		return;
 	}
@@ -832,7 +832,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
 	NV_DEBUG(drm, "index %d\n", nv_crtc->index);
 
 	/* no fb bound */
-	if (!atomic && !crtc->fb) {
+	if (!atomic && !crtc->primary->fb) {
 		NV_DEBUG(drm, "No FB bound\n");
 		return 0;
 	}
@@ -844,8 +844,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
 		drm_fb = passed_fb;
 		fb = nouveau_framebuffer(passed_fb);
 	} else {
-		drm_fb = crtc->fb;
-		fb = nouveau_framebuffer(crtc->fb);
+		drm_fb = crtc->primary->fb;
+		fb = nouveau_framebuffer(crtc->primary->fb);
 	}
 
 	nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -857,9 +857,9 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
 
 	/* Update the framebuffer format. */
 	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3;
-	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8;
+	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->primary->fb->depth + 1) / 8;
 	regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
-	if (crtc->fb->depth == 16)
+	if (crtc->primary->fb->depth == 16)
 		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
 	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX);
 	NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
index 7fdc51e..a2d669b 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
@@ -415,7 +415,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
 	/* Output property. */
 	if ((nv_connector->dithering_mode == DITHERING_MODE_ON) ||
 	    (nv_connector->dithering_mode == DITHERING_MODE_AUTO &&
-	     encoder->crtc->fb->depth > connector->display_info.bpc * 3)) {
+	     encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) {
 		if (nv_device(drm->device)->chipset == 0x11)
 			regp->dither = savep->dither | 0x00010000;
 		else {
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 2401159..4e24c72 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -569,7 +569,7 @@ nouveau_display_suspend(struct drm_device *dev)
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_framebuffer *nouveau_fb;
 
-		nouveau_fb = nouveau_framebuffer(crtc->fb);
+		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
 		if (!nouveau_fb || !nouveau_fb->nvbo)
 			continue;
 
@@ -596,7 +596,7 @@ nouveau_display_repin(struct drm_device *dev)
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_framebuffer *nouveau_fb;
 
-		nouveau_fb = nouveau_framebuffer(crtc->fb);
+		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
 		if (!nouveau_fb || !nouveau_fb->nvbo)
 			continue;
 
@@ -693,7 +693,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
 	struct drm_device *dev = crtc->dev;
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
+	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo;
 	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
 	struct nouveau_page_flip_state *s;
 	struct nouveau_channel *chan = drm->channel;
@@ -767,7 +767,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 		goto fail_unreserve;
 
 	/* Update the crtc struct and cleanup */
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 
 	nouveau_bo_fence(old_bo, fence);
 	ttm_bo_unreserve(&old_bo->bo);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 5706842..c744bf6 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -651,7 +651,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
 	nv_connector = nouveau_crtc_connector_get(nv_crtc);
 	connector = &nv_connector->base;
 	if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
-		if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
+		if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3)
 			mode = DITHERING_MODE_DYNAMIC2X2;
 	} else {
 		mode = nv_connector->dithering_mode;
@@ -785,7 +785,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
 
 		if (update) {
 			nv50_display_flip_stop(crtc);
-			nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
+			nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
 		}
 	}
 
@@ -1028,7 +1028,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
 	}
 
 	nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
-	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
+	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
 }
 
 static bool
@@ -1042,7 +1042,8 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
 static int
 nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
 {
-	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+	struct nouveau_framebuffer *nvfb =
+		nouveau_framebuffer(crtc->primary->fb);
 	struct nv50_head *head = nv50_head(crtc);
 	int ret;
 
@@ -1139,7 +1140,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
 	nv50_crtc_set_dither(nv_crtc, false);
 	nv50_crtc_set_scale(nv_crtc, false);
 	nv50_crtc_set_color_vibrance(nv_crtc, false);
-	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
+	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
 	return 0;
 }
 
@@ -1151,7 +1152,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	int ret;
 
-	if (!crtc->fb) {
+	if (!crtc->primary->fb) {
 		NV_DEBUG(drm, "No FB bound\n");
 		return 0;
 	}
@@ -1161,8 +1162,8 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 		return ret;
 
 	nv50_display_flip_stop(crtc);
-	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
-	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
+	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
+	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 24b6112..5be0b87 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -527,7 +527,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
 	bool recreate_primary = false;
 	int ret;
 	int surf_id;
-	if (!crtc->fb) {
+	if (!crtc->primary->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
 	}
@@ -536,7 +536,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
 		qfb = to_qxl_framebuffer(old_fb);
 		old_bo = gem_to_qxl_bo(qfb->obj);
 	}
-	qfb = to_qxl_framebuffer(crtc->fb);
+	qfb = to_qxl_framebuffer(crtc->primary->fb);
 	bo = gem_to_qxl_bo(qfb->obj);
 	if (!m)
 		/* and do we care? */
@@ -609,14 +609,15 @@ static void qxl_crtc_disable(struct drm_crtc *crtc)
 	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct qxl_device *qdev = dev->dev_private;
-	if (crtc->fb) {
-		struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb);
+	if (crtc->primary->fb) {
+		struct qxl_framebuffer *qfb =
+			to_qxl_framebuffer(crtc->primary->fb);
 		struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
 		int ret;
 		ret = qxl_bo_reserve(bo, false);
 		qxl_bo_unpin(bo);
 		qxl_bo_unreserve(bo);
-		crtc->fb = NULL;
+		crtc->primary->fb = NULL;
 	}
 
 	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index daa4dd3..fb187c7 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1106,7 +1106,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 	int r;
 
 	/* no fb bound */
-	if (!atomic && !crtc->fb) {
+	if (!atomic && !crtc->primary->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
 	}
@@ -1116,8 +1116,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 		target_fb = fb;
 	}
 	else {
-		radeon_fb = to_radeon_framebuffer(crtc->fb);
-		target_fb = crtc->fb;
+		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
+		target_fb = crtc->primary->fb;
 	}
 
 	/* If atomic, assume fb object is pinned & idle & fenced and
@@ -1316,7 +1316,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 	/* set pageflip to happen anywhere in vblank interval */
 	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
 
-	if (!atomic && fb && fb != crtc->fb) {
+	if (!atomic && fb && fb != crtc->primary->fb) {
 		radeon_fb = to_radeon_framebuffer(fb);
 		rbo = gem_to_radeon_bo(radeon_fb->obj);
 		r = radeon_bo_reserve(rbo, false);
@@ -1350,7 +1350,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
 	int r;
 
 	/* no fb bound */
-	if (!atomic && !crtc->fb) {
+	if (!atomic && !crtc->primary->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
 	}
@@ -1360,8 +1360,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
 		target_fb = fb;
 	}
 	else {
-		radeon_fb = to_radeon_framebuffer(crtc->fb);
-		target_fb = crtc->fb;
+		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
+		target_fb = crtc->primary->fb;
 	}
 
 	obj = radeon_fb->obj;
@@ -1485,7 +1485,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
 	/* set pageflip to happen anywhere in vblank interval */
 	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
 
-	if (!atomic && fb && fb != crtc->fb) {
+	if (!atomic && fb && fb != crtc->primary->fb) {
 		radeon_fb = to_radeon_framebuffer(fb);
 		rbo = gem_to_radeon_bo(radeon_fb->obj);
 		r = radeon_bo_reserve(rbo, false);
@@ -1972,12 +1972,12 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
 	int i;
 
 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-	if (crtc->fb) {
+	if (crtc->primary->fb) {
 		int r;
 		struct radeon_framebuffer *radeon_fb;
 		struct radeon_bo *rbo;
 
-		radeon_fb = to_radeon_framebuffer(crtc->fb);
+		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
 		rbo = gem_to_radeon_bo(radeon_fb->obj);
 		r = radeon_bo_reserve(rbo, false);
 		if (unlikely(r))
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 030f8e4..b6c3264 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3220,12 +3220,12 @@ void r100_bandwidth_update(struct radeon_device *rdev)
 
 	if (rdev->mode_info.crtcs[0]->base.enabled) {
 		mode1 = &rdev->mode_info.crtcs[0]->base.mode;
-		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8;
+		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;
-			pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8;
+			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 82d4f86..33b482b 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -89,7 +89,7 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)
 
 	if (crtc && crtc->enabled) {
 		drm_crtc_helper_set_mode(crtc, &crtc->mode,
-					 crtc->x, crtc->y, crtc->fb);
+					 crtc->x, crtc->y, crtc->primary->fb);
 	}
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 2e72dcd..c524aba 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1424,7 +1424,8 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
 
 	/* unpin the front buffers */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
+		struct radeon_framebuffer *rfb =
+			to_radeon_framebuffer(crtc->primary->fb);
 		struct radeon_bo *robj;
 
 		if (rfb == NULL || rfb->obj == NULL) {
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index a29d217..4e90049 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -369,7 +369,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
 	work->event = event;
 	work->rdev = rdev;
 	work->crtc_id = radeon_crtc->crtc_id;
-	old_radeon_fb = to_radeon_framebuffer(crtc->fb);
+	old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
 	new_radeon_fb = to_radeon_framebuffer(fb);
 	/* schedule unpin of the old buffer */
 	obj = old_radeon_fb->obj;
@@ -460,7 +460,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 
 	/* update crtc fb */
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 
 	r = drm_vblank_get(dev, radeon_crtc->crtc_id);
 	if (r) {
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 0b158f9..cafb1cc 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -385,7 +385,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
 
 	DRM_DEBUG_KMS("\n");
 	/* no fb bound */
-	if (!atomic && !crtc->fb) {
+	if (!atomic && !crtc->primary->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
 	}
@@ -395,8 +395,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
 		target_fb = fb;
 	}
 	else {
-		radeon_fb = to_radeon_framebuffer(crtc->fb);
-		target_fb = crtc->fb;
+		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
+		target_fb = crtc->primary->fb;
 	}
 
 	switch (target_fb->bits_per_pixel) {
@@ -444,7 +444,7 @@ retry:
 		 * We don't shutdown the display controller because new buffer
 		 * will end up in same spot.
 		 */
-		if (!atomic && fb && fb != crtc->fb) {
+		if (!atomic && fb && fb != crtc->primary->fb) {
 			struct radeon_bo *old_rbo;
 			unsigned long nsize, osize;
 
@@ -555,7 +555,7 @@ retry:
 	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
 	WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
 
-	if (!atomic && fb && fb != crtc->fb) {
+	if (!atomic && fb && fb != crtc->primary->fb) {
 		radeon_fb = to_radeon_framebuffer(fb);
 		rbo = gem_to_radeon_bo(radeon_fb->obj);
 		r = radeon_bo_reserve(rbo, false);
@@ -599,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
 		}
 	}
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (crtc->primary->fb->bits_per_pixel) {
 	case 8:
 		format = 2;
 		break;
@@ -1087,12 +1087,12 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
 static void radeon_crtc_disable(struct drm_crtc *crtc)
 {
 	radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-	if (crtc->fb) {
+	if (crtc->primary->fb) {
 		int r;
 		struct radeon_framebuffer *radeon_fb;
 		struct radeon_bo *rbo;
 
-		radeon_fb = to_radeon_framebuffer(crtc->fb);
+		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
 		rbo = gem_to_radeon_bo(radeon_fb->obj);
 		r = radeon_bo_reserve(rbo, false);
 		if (unlikely(r))
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 1255944..c63b5e7 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -310,7 +310,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
 
 {
 	struct drm_device *dev = crtc->dev;
-	struct udl_framebuffer *ufb = to_udl_fb(crtc->fb);
+	struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb);
 	struct udl_device *udl = dev->dev_private;
 	char *buf;
 	char *wrptr;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 8a65041..1d59ed3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -468,7 +468,7 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
 	num_units = 0;
 	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
 			    head) {
-		if (crtc->fb != &framebuffer->base)
+		if (crtc->primary->fb != &framebuffer->base)
 			continue;
 		units[num_units++] = vmw_crtc_to_du(crtc);
 	}
@@ -883,7 +883,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
 
 	num_units = 0;
 	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
-		if (crtc->fb != &framebuffer->base)
+		if (crtc->primary->fb != &framebuffer->base)
 			continue;
 		units[num_units++] = vmw_crtc_to_du(crtc);
 	}
@@ -1245,7 +1245,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
 
 	num_units = 0;
 	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
-		if (crtc->fb != &vfb->base)
+		if (crtc->primary->fb != &vfb->base)
 			continue;
 		units[num_units++] = vmw_crtc_to_du(crtc);
 	}
@@ -1382,7 +1382,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
 
 	num_units = 0;
 	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
-		if (crtc->fb != &vfb->base)
+		if (crtc->primary->fb != &vfb->base)
 			continue;
 		units[num_units++] = vmw_crtc_to_du(crtc);
 	}
@@ -1725,7 +1725,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
 		     uint32_t page_flip_flags)
 {
 	struct vmw_private *dev_priv = vmw_priv(crtc->dev);
-	struct drm_framebuffer *old_fb = crtc->fb;
+	struct drm_framebuffer *old_fb = crtc->primary->fb;
 	struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
 	struct drm_file *file_priv ;
 	struct vmw_fence_obj *fence = NULL;
@@ -1743,7 +1743,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
 	if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
 		return -EINVAL;
 
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 
 	/* do a full screen dirty update */
 	clips.x1 = clips.y1 = 0;
@@ -1783,7 +1783,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
 	return ret;
 
 out_no_fence:
-	crtc->fb = old_fb;
+	crtc->primary->fb = old_fb;
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 001ec81..08fdd7f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -93,7 +93,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
 
 		if (crtc == NULL)
 			return 0;
-		fb = entry->base.crtc.fb;
+		fb = entry->base.crtc.primary->fb;
 
 		return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0],
 					  fb->bits_per_pixel, fb->depth);
@@ -101,7 +101,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
 
 	if (!list_empty(&lds->active)) {
 		entry = list_entry(lds->active.next, typeof(*entry), active);
-		fb = entry->base.crtc.fb;
+		fb = entry->base.crtc.primary->fb;
 
 		vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0],
 				   fb->bits_per_pixel, fb->depth);
@@ -259,7 +259,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
 
 		connector->encoder = NULL;
 		encoder->crtc = NULL;
-		crtc->fb = NULL;
+		crtc->primary->fb = NULL;
 		crtc->enabled = false;
 
 		vmw_ldu_del_active(dev_priv, ldu);
@@ -280,7 +280,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
 
 	vmw_fb_off(dev_priv);
 
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 	encoder->crtc = crtc;
 	connector->encoder = encoder;
 	crtc->x = set->x;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 585da43..46ea096 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -307,7 +307,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
 
 		connector->encoder = NULL;
 		encoder->crtc = NULL;
-		crtc->fb = NULL;
+		crtc->primary->fb = NULL;
 		crtc->x = 0;
 		crtc->y = 0;
 		crtc->enabled = false;
@@ -368,7 +368,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
 
 		connector->encoder = NULL;
 		encoder->crtc = NULL;
-		crtc->fb = NULL;
+		crtc->primary->fb = NULL;
 		crtc->x = 0;
 		crtc->y = 0;
 		crtc->enabled = false;
@@ -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;
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 	crtc->x = set->x;
 	crtc->y = set->y;
 	crtc->enabled = true;
@@ -574,5 +574,5 @@ void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
 	BUG_ON(!sou->base.is_implicit);
 
 	dev_priv->sou_priv->implicit_fb =
-		vmw_framebuffer_to_vfb(sou->base.crtc.fb);
+		vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
 }
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 4dc84f8..9f7824d 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -309,9 +309,6 @@ struct drm_crtc {
 	/* primary plane for CRTC */
 	struct drm_plane *primary;
 
-	/* framebuffer the connector is currently bound to */
-	struct drm_framebuffer *fb;
-
 	/* Temporary tracking of the old fb while a modeset is ongoing. Used
 	 * by drm_mode_set_config_internal to implement correct refcounting. */
 	struct drm_framebuffer *old_fb;
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 09/14] drm: Allow userspace to ask for full plane list (universal planes)
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (7 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2) Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 14:27   ` Daniel Vetter
  2014-03-19  0:22 ` [RFCv3 10/14] drm/i915: Rename similar plane functions to avoid confusion Matt Roper
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

Userspace clients which wish to receive all DRM planes (primary and
cursor planes in addition to the traditional overlay planes) may set the
DRM_CLIENT_CAP_UNIVERSAL_PLANES capability.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/drm_crtc.c  | 20 +++++++++++++++-----
 drivers/gpu/drm/drm_ioctl.c |  5 +++++
 include/drm/drmP.h          |  5 +++++
 include/uapi/drm/drm.h      |  8 ++++++++
 4 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0c395e8..fb8e493 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2160,6 +2160,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 	struct drm_plane *plane;
 	uint32_t __user *plane_ptr;
 	int copied = 0, ret = 0;
+	unsigned num_planes;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -2167,17 +2168,26 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 	drm_modeset_lock_all(dev);
 	config = &dev->mode_config;
 
+	if (file_priv->universal_planes)
+		num_planes = config->num_total_plane;
+	else
+		num_planes = config->num_overlay_plane;
+
 	/*
 	 * This ioctl is called twice, once to determine how much space is
 	 * needed, and the 2nd time to fill it.
 	 */
-	if (config->num_overlay_plane &&
-	    (plane_resp->count_planes >= config->num_overlay_plane)) {
+	if (num_planes &&
+	    (plane_resp->count_planes >= num_planes)) {
 		plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 
 		list_for_each_entry(plane, &config->plane_list, head) {
-			/* Only advertise overlays to userspace for now. */
-			if (plane->type != DRM_PLANE_TYPE_OVERLAY)
+			/*
+			 * Unless userspace set the 'universal planes'
+			 * capability bit, only advertise overlays.
+			 */
+			if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
+			    !file_priv->universal_planes)
 				continue;
 
 			if (put_user(plane->base.id, plane_ptr + copied)) {
@@ -2187,7 +2197,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 			copied++;
 		}
 	}
-	plane_resp->count_planes = config->num_overlay_plane;
+	plane_resp->count_planes = num_planes;
 
 out:
 	drm_modeset_unlock_all(dev);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index f4dc9b7..5eb92b6 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -328,6 +328,11 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 			return -EINVAL;
 		file_priv->stereo_allowed = req->value;
 		break;
+	case DRM_CLIENT_CAP_UNIVERSAL_PLANES:
+		if (req->value > 1)
+			return -EINVAL;
+		file_priv->universal_planes = req->value;
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 3857450..1106297 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -438,6 +438,11 @@ struct drm_file {
 	unsigned is_master :1; /* this file private is a master for a minor */
 	/* true when the client has asked us to expose stereo 3D mode flags */
 	unsigned stereo_allowed :1;
+	/*
+	 * true if client understands CRTC primary planes and cursor planes
+	 * in the plane list
+	 */
+	unsigned universal_planes:1;
 
 	struct pid *pid;
 	kuid_t uid;
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index b06c8ed..6e4952b 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -637,6 +637,14 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_STEREO_3D	1
 
+/**
+ * DRM_CLIENT_CAP_UNIVERSAL_PLANES
+ *
+ * If set to 1, the DRM core will expose all planes (overlay, primary, and
+ * cursor) to userspace.
+ */
+#define DRM_CLIENT_CAP_UNIVERSAL_PLANES  2
+
 /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
 	__u64 capability;
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 10/14] drm/i915: Rename similar plane functions to avoid confusion
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (8 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 09/14] drm: Allow userspace to ask for full plane list (universal planes) Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 12:05   ` Daniel Vetter
  2014-03-19  0:22 ` [RFCv3 11/14] drm/i915: Intel-specific primary plane handling Matt Roper
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

The name 'update_plane' was used both for the primary plane functions in
intel_display.c and the sprite/overlay functions in intel_sprite.c.
Rename the primary plane functions to 'update_primary_plane' to avoid
confusion.

On a similar note, intel_display.c already had a function called
intel_disable_primary_plane() that programs the hardware to disable a
pipe's primary plane.  When we hook up primary planes through the DRM
plane interface, one of the natural handler names will be
intel_primary_plane_disable(), which is very similar.  To avoid
confusion, rename the existing intel_disable_primary_plane() to
intel_disable_primary_hw_plane() to make the two names a little more
distinct.

Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |  5 +--
 drivers/gpu/drm/i915/intel_display.c | 60 ++++++++++++++++++++----------------
 2 files changed, 36 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 70fbe90..a937711 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -462,8 +462,9 @@ struct drm_i915_display_funcs {
 			  struct drm_framebuffer *fb,
 			  struct drm_i915_gem_object *obj,
 			  uint32_t flags);
-	int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-			    int x, int y);
+	int (*update_primary_plane)(struct drm_crtc *crtc,
+				    struct drm_framebuffer *fb,
+				    int x, int y);
 	void (*hpd_irq_setup)(struct drm_device *dev);
 	/* clock updates for mode set */
 	/* cursor updates */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c2f3730..849a241 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1872,15 +1872,15 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
 }
 
 /**
- * intel_enable_primary_plane - enable the primary plane on a given pipe
+ * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
  * @dev_priv: i915 private structure
  * @plane: plane to enable
  * @pipe: pipe being fed
  *
  * Enable @plane on @pipe, making sure that @pipe is running first.
  */
-static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
-				       enum plane plane, enum pipe pipe)
+static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
+					  enum plane plane, enum pipe pipe)
 {
 	struct intel_crtc *intel_crtc =
 		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
@@ -1905,15 +1905,15 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
 }
 
 /**
- * intel_disable_primary_plane - disable the primary plane
+ * intel_disable_primary_hw_plane - disable the primary hardware plane
  * @dev_priv: i915 private structure
  * @plane: plane to disable
  * @pipe: pipe consuming the data
  *
  * Disable @plane; should be an independent operation.
  */
-static void intel_disable_primary_plane(struct drm_i915_private *dev_priv,
-					enum plane plane, enum pipe pipe)
+static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
+					   enum plane plane, enum pipe pipe)
 {
 	struct intel_crtc *intel_crtc =
 		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
@@ -2153,8 +2153,9 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
 	}
 }
 
-static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-			     int x, int y)
+static int i9xx_update_primary_plane(struct drm_crtc *crtc,
+				     struct drm_framebuffer *fb,
+				     int x, int y)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2253,8 +2254,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	return 0;
 }
 
-static int ironlake_update_plane(struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb, int x, int y)
+static int ironlake_update_primary_plane(struct drm_crtc *crtc,
+					 struct drm_framebuffer *fb,
+					 int x, int y)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2358,7 +2360,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 		dev_priv->display.disable_fbc(dev);
 	intel_increase_pllclock(crtc);
 
-	return dev_priv->display.update_plane(crtc, fb, x, y);
+	return dev_priv->display.update_primary_plane(crtc, fb, x, y);
 }
 
 void intel_display_handle_reset(struct drm_device *dev)
@@ -2398,10 +2400,10 @@ void intel_display_handle_reset(struct drm_device *dev)
 		 * a NULL crtc->primary->fb.
 		 */
 		if (intel_crtc->active && crtc->primary->fb)
-			dev_priv->display.update_plane(crtc,
-						       crtc->primary->fb,
-						       crtc->x,
-						       crtc->y);
+			dev_priv->display.update_primary_plane(crtc,
+							       crtc->primary->fb,
+							       crtc->x,
+							       crtc->y);
 		mutex_unlock(&crtc->mutex);
 	}
 }
@@ -2517,7 +2519,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 		intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
 	}
 
-	ret = dev_priv->display.update_plane(crtc, fb, x, y);
+	ret = dev_priv->display.update_primary_plane(crtc, fb, x, y);
 	if (ret) {
 		mutex_lock(&dev->struct_mutex);
 		intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
@@ -3704,7 +3706,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
-	intel_enable_primary_plane(dev_priv, plane, pipe);
+	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
 	intel_crtc_update_cursor(crtc, true);
 
@@ -3748,7 +3750,7 @@ static void haswell_crtc_enable_planes(struct drm_crtc *crtc)
 	int pipe = intel_crtc->pipe;
 	int plane = intel_crtc->plane;
 
-	intel_enable_primary_plane(dev_priv, plane, pipe);
+	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
 	intel_crtc_update_cursor(crtc, true);
 
@@ -3780,7 +3782,7 @@ static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
 
 	intel_crtc_update_cursor(crtc, false);
 	intel_disable_planes(crtc);
-	intel_disable_primary_plane(dev_priv, plane, pipe);
+	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 }
 
 /*
@@ -3908,7 +3910,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
 	intel_crtc_update_cursor(crtc, false);
 	intel_disable_planes(crtc);
-	intel_disable_primary_plane(dev_priv, plane, pipe);
+	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 
 	if (intel_crtc->config.has_pch_encoder)
 		intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
@@ -4391,7 +4393,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
-	intel_enable_primary_plane(dev_priv, plane, pipe);
+	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
 	intel_crtc_update_cursor(crtc, true);
 
@@ -4432,7 +4434,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
-	intel_enable_primary_plane(dev_priv, plane, pipe);
+	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
 	/* The fixup needs to happen before cursor is enabled */
 	if (IS_G4X(dev))
@@ -4490,7 +4492,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 	intel_crtc_dpms_overlay(intel_crtc, false);
 	intel_crtc_update_cursor(crtc, false);
 	intel_disable_planes(crtc);
-	intel_disable_primary_plane(dev_priv, plane, pipe);
+	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 
 	intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
 	intel_disable_pipe(dev_priv, pipe);
@@ -11034,7 +11036,8 @@ static void intel_init_display(struct drm_device *dev)
 		dev_priv->display.crtc_enable = haswell_crtc_enable;
 		dev_priv->display.crtc_disable = haswell_crtc_disable;
 		dev_priv->display.off = haswell_crtc_off;
-		dev_priv->display.update_plane = ironlake_update_plane;
+		dev_priv->display.update_primary_plane =
+			ironlake_update_primary_plane;
 	} else if (HAS_PCH_SPLIT(dev)) {
 		dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
 		dev_priv->display.get_plane_config = ironlake_get_plane_config;
@@ -11042,7 +11045,8 @@ static void intel_init_display(struct drm_device *dev)
 		dev_priv->display.crtc_enable = ironlake_crtc_enable;
 		dev_priv->display.crtc_disable = ironlake_crtc_disable;
 		dev_priv->display.off = ironlake_crtc_off;
-		dev_priv->display.update_plane = ironlake_update_plane;
+		dev_priv->display.update_primary_plane =
+			ironlake_update_primary_plane;
 	} else if (IS_VALLEYVIEW(dev)) {
 		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
 		dev_priv->display.get_plane_config = i9xx_get_plane_config;
@@ -11050,7 +11054,8 @@ static void intel_init_display(struct drm_device *dev)
 		dev_priv->display.crtc_enable = valleyview_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
 		dev_priv->display.off = i9xx_crtc_off;
-		dev_priv->display.update_plane = i9xx_update_plane;
+		dev_priv->display.update_primary_plane =
+			i9xx_update_primary_plane;
 	} else {
 		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
 		dev_priv->display.get_plane_config = i9xx_get_plane_config;
@@ -11058,7 +11063,8 @@ static void intel_init_display(struct drm_device *dev)
 		dev_priv->display.crtc_enable = i9xx_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
 		dev_priv->display.off = i9xx_crtc_off;
-		dev_priv->display.update_plane = i9xx_update_plane;
+		dev_priv->display.update_primary_plane =
+			i9xx_update_primary_plane;
 	}
 
 	/* Returns the core display clock speed */
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 11/14] drm/i915: Intel-specific primary plane handling
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (9 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 10/14] drm/i915: Rename similar plane functions to avoid confusion Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19 12:11   ` [Intel-gfx] " Daniel Vetter
  2014-03-19  0:22 ` [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization Matt Roper
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

Intel hardware allows the primary plane to be disabled independently of
the CRTC.  Provide custom primary plane handling to allow this.

Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 132 ++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 2 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 849a241..7d6878b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -39,6 +39,7 @@
 #include "i915_trace.h"
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_rect.h>
 #include <linux/dma_remapping.h>
 
 static void intel_increase_pllclock(struct drm_crtc *crtc);
@@ -10589,19 +10590,144 @@ static void intel_shared_dpll_init(struct drm_device *dev)
 	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
 }
 
+static int
+intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
+			     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+			     unsigned int crtc_w, unsigned int crtc_h,
+			     uint32_t src_x, uint32_t src_y,
+			     uint32_t src_w, uint32_t src_h)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_framebuffer *tmpfb;
+	struct drm_rect dest = {
+		.x1 = crtc_x,
+		.y1 = crtc_y,
+		.x2 = crtc_x + crtc_w,
+		.y2 = crtc_y + crtc_h,
+	};
+	struct drm_rect clip = {
+		.x2 = crtc->mode.hdisplay,
+		.y2 = crtc->mode.vdisplay,
+	};
+	int ret;
+
+	/* setplane API takes shifted source rectangle values; unshift them */
+	src_x >>= 16;
+	src_y >>= 16;
+	src_w >>= 16;
+	src_h >>= 16;
+
+	/*
+	 * Current hardware can't reposition the primary plane or scale it
+	 * (although this could change in the future).
+	 */
+	drm_rect_intersect(&dest, &clip);
+	if (dest.x1 != 0 || dest.y1 != 0 ||
+	    dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) {
+		DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n");
+		return -EINVAL;
+	}
+
+	if (crtc_w != src_w || crtc_h != src_h) {
+		DRM_DEBUG_KMS("Can't scale primary plane\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * pipe_set_base() adjusts crtc->primary->fb; however the DRM setplane
+	 * code that called us expects to handle the framebuffer update and
+	 * reference counting; save and restore the current fb before
+	 * calling it.
+	 */
+	tmpfb = plane->fb;
+	ret = intel_pipe_set_base(crtc, src_x, src_y, fb);
+	if (ret)
+		return ret;
+	plane->fb = tmpfb;
+
+	if (!intel_crtc->primary_enabled)
+		intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
+					      intel_crtc->pipe);
+
+	return 0;
+}
+
+static int
+intel_primary_plane_disable(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_crtc *intel_crtc;
+
+	if (!plane->fb)
+		return 0;
+
+	if (WARN_ON(!plane->crtc))
+		return -EINVAL;
+
+	intel_crtc = to_intel_crtc(plane->crtc);
+	if (intel_crtc->primary_enabled)
+		intel_disable_primary_hw_plane(dev_priv, intel_plane->plane,
+					       intel_plane->pipe);
+
+	return 0;
+}
+
+static void intel_primary_plane_destroy(struct drm_plane *plane)
+{
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	intel_primary_plane_disable(plane);
+	drm_plane_cleanup(plane);
+	kfree(intel_plane);
+}
+
+static const struct drm_plane_funcs intel_primary_plane_funcs = {
+	.update_plane = intel_primary_plane_setplane,
+	.disable_plane = intel_primary_plane_disable,
+	.destroy = intel_primary_plane_destroy,
+};
+
+static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
+						    int pipe)
+{
+	struct intel_plane *primary;
+
+	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
+	if (primary == NULL)
+		return NULL;
+
+	primary->can_scale = false;
+	primary->pipe = pipe;
+	primary->plane = pipe;
+
+	drm_plane_init(dev, &primary->base, 0,
+		       &intel_primary_plane_funcs, legacy_modeset_formats,
+		       ARRAY_SIZE(legacy_modeset_formats),
+		       DRM_PLANE_TYPE_PRIMARY);
+	return &primary->base;
+}
+
 static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc;
 	struct drm_plane *primary;
-	int i;
+	int i, ret;
 
 	intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
 	if (intel_crtc == NULL)
 		return;
 
-	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
+	primary = intel_primary_plane_create(dev, pipe);
+	ret = drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
+	if (ret) {
+		drm_crtc_cleanup(&intel_crtc->base);
+		kfree(intel_crtc);
+		return;
+	}
 
 	drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
 	for (i = 0; i < 256; i++) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 890c5cd..770f80d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -351,6 +351,7 @@ struct intel_crtc {
 	bool active;
 	unsigned long enabled_power_domains;
 	bool eld_vld;
+	struct intel_plane *primary_plane;
 	bool primary_enabled; /* is the primary plane (partially) visible? */
 	bool lowfreq_avail;
 	struct intel_overlay *overlay;
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (10 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 11/14] drm/i915: Intel-specific primary plane handling Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-28 21:04   ` Daniel Vetter
  2014-03-19  0:22 ` [RFCv3 13/14] drm/i915: Split cursor update code from cursor ioctl handling Matt Roper
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel

Add cursor plane as a parameter to drm_crtc_init() and update all
existing DRM drivers to use a helper-provided primary plane.  Passing
NULL for this parameter indicates that there is no hardware cursor
supported by the driver and no cursor plane should be provided to
userspace.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/armada/armada_crtc.c       | 2 +-
 drivers/gpu/drm/ast/ast_mode.c             | 2 +-
 drivers/gpu/drm/bochs/bochs_kms.c          | 2 +-
 drivers/gpu/drm/cirrus/cirrus_mode.c       | 3 ++-
 drivers/gpu/drm/drm_crtc.c                 | 6 ++++++
 drivers/gpu/drm/exynos/exynos_drm_crtc.c   | 2 +-
 drivers/gpu/drm/gma500/psb_intel_display.c | 3 ++-
 drivers/gpu/drm/i915/intel_display.c       | 3 ++-
 drivers/gpu/drm/mgag200/mgag200_mode.c     | 3 ++-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c   | 2 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c   | 2 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    | 2 +-
 drivers/gpu/drm/nouveau/nv50_display.c     | 2 +-
 drivers/gpu/drm/omapdrm/omap_crtc.c        | 2 +-
 drivers/gpu/drm/qxl/qxl_display.c          | 2 +-
 drivers/gpu/drm/radeon/radeon_display.c    | 3 ++-
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c     | 2 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c  | 2 +-
 drivers/gpu/drm/tegra/dc.c                 | 2 +-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c       | 2 +-
 drivers/gpu/drm/udl/udl_modeset.c          | 2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        | 2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       | 2 +-
 drivers/staging/imx-drm/imx-drm-core.c     | 2 +-
 include/drm/drm_crtc.h                     | 6 ++++++
 25 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 0a14d24..a6eec51 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -1088,7 +1088,7 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
 	priv->dcrtc[dcrtc->num] = dcrtc;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &dcrtc->crtc, primary, &armada_crtc_funcs);
+	drm_crtc_init(dev, &dcrtc->crtc, primary, NULL, &armada_crtc_funcs);
 	drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
 
 	drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index bd1e156..52415ca 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -634,7 +634,7 @@ static int ast_crtc_init(struct drm_device *dev)
 		return -ENOMEM;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &crtc->base, primary, &ast_crtc_funcs);
+	drm_crtc_init(dev, &crtc->base, primary, NULL, &ast_crtc_funcs);
 	drm_mode_crtc_set_gamma_size(&crtc->base, 256);
 	drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs);
 
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index b67ad12..e88101a 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -132,7 +132,7 @@ static void bochs_crtc_init(struct drm_device *dev)
 	struct drm_plane *primary;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, crtc, primary, &bochs_crtc_funcs);
+	drm_crtc_init(dev, crtc, primary, NULL, &bochs_crtc_funcs);
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 	drm_crtc_helper_add(crtc, &bochs_helper_funcs);
 }
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 5291d2f..04a002b 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -392,7 +392,8 @@ static void cirrus_crtc_init(struct drm_device *dev)
 		return;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &cirrus_crtc->base, primary, &cirrus_crtc_funcs);
+	drm_crtc_init(dev, &cirrus_crtc->base, primary, NULL,
+		      &cirrus_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
 	cdev->mode_info.crtc = cirrus_crtc;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index fb8e493..e6e1f39 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -683,6 +683,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
  * @dev: DRM device
  * @crtc: CRTC object to init
  * @primary: Primary plane for CRTC
+ * @cursor: Cursor plane for CRTC; may be NULL if no hardware cursor exists
  * @funcs: callbacks for the new CRTC
  *
  * Inits a new object created as base part of a driver crtc object.
@@ -692,6 +693,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
  */
 int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 		  struct drm_plane *primary,
+		  struct drm_plane *cursor,
 		  const struct drm_crtc_funcs *funcs)
 {
 	int ret;
@@ -716,6 +718,10 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	crtc->primary = primary;
 	primary->possible_crtcs = 1 << drm_crtc_index(crtc);
 
+	crtc->cursor = cursor;
+	if (cursor)
+		cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
+
  out:
 	drm_modeset_unlock_all(dev);
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 507abd5..a17eb1d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -344,7 +344,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
 	private->crtc[nr] = crtc;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, crtc, primary, &exynos_crtc_funcs);
+	drm_crtc_init(dev, crtc, primary, NULL, &exynos_crtc_funcs);
 	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
 	exynos_drm_crtc_attach_mode_property(crtc);
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 25c174c..26a363e 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -513,7 +513,8 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
 
 	/* Set the CRTC operations from the chip specific data */
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &gma_crtc->base, primary, dev_priv->ops->crtc_funcs);
+	drm_crtc_init(dev, &gma_crtc->base, primary, NULL,
+		      dev_priv->ops->crtc_funcs);
 
 	/* Set the CRTC clock functions from chip specific data */
 	gma_crtc->clock_funcs = dev_priv->ops->clock_funcs;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 7d6878b..d43b31d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10722,7 +10722,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 		return;
 
 	primary = intel_primary_plane_create(dev, pipe);
-	ret = drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
+	ret = drm_crtc_init(dev, &intel_crtc->base, primary, NULL,
+			    &intel_crtc_funcs);
 	if (ret) {
 		drm_crtc_cleanup(&intel_crtc->base);
 		kfree(intel_crtc);
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index f8c42b1..befa249 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1327,7 +1327,8 @@ static void mga_crtc_init(struct mga_device *mdev)
 		return;
 
 	primary = drm_primary_helper_create_plane(mdev->dev);
-	drm_crtc_init(mdev->dev, &mga_crtc->base, primary, &mga_crtc_funcs);
+	drm_crtc_init(mdev->dev, &mga_crtc->base, primary, NULL,
+		      &mga_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE);
 	mdev->mode_info.crtc = mga_crtc;
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index f96497b..2dcd224 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -794,7 +794,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
 
 	INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb);
 
-	drm_crtc_init(dev, crtc, plane, &mdp4_crtc_funcs);
+	drm_crtc_init(dev, crtc, plane, NULL, &mdp4_crtc_funcs);
 	drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
 
 	mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index f200048..e74751f 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -562,7 +562,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
 
 	INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb);
 
-	drm_crtc_init(dev, crtc, plane, &mdp5_crtc_funcs);
+	drm_crtc_init(dev, crtc, plane, NULL, &mdp5_crtc_funcs);
 	drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
 
 	mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 2a5e9db..974babe 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -1124,7 +1124,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
 	nv_crtc->last_dpms = NV_DPMS_CLEARED;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &nv_crtc->base, primary, &nv04_crtc_funcs);
+	drm_crtc_init(dev, &nv_crtc->base, primary, NULL, &nv04_crtc_funcs);
 	drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs);
 	drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
 
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index c744bf6..b1cc440 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1372,7 +1372,7 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
 
 	crtc = &head->base.base;
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, crtc, primary, &nv50_crtc_func);
+	drm_crtc_init(dev, crtc, primary, NULL, &nv50_crtc_func);
 	drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index fdf9dc0..9623c6f 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -677,7 +677,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 	info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
 	info->trans_enabled = false;
 
-	drm_crtc_init(dev, crtc, plane, &omap_crtc_funcs);
+	drm_crtc_init(dev, crtc, plane, NULL, &omap_crtc_funcs);
 	drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
 	omap_plane_install_properties(omap_crtc->plane, &crtc->base);
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 5be0b87..50ad5fc 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -644,7 +644,7 @@ static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
 		return -ENOMEM;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &qxl_crtc->base, primary, &qxl_crtc_funcs);
+	drm_crtc_init(dev, &qxl_crtc->base, primary, NULL, &qxl_crtc_funcs);
 	qxl_crtc->index = crtc_id;
 	drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256);
 	drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 4e90049..1ef84c5 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -560,7 +560,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
 		return;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, &radeon_crtc->base, primary, &radeon_crtc_funcs);
+	drm_crtc_init(dev, &radeon_crtc->base, primary, NULL,
+		      &radeon_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
 	radeon_crtc->crtc_id = index;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 151ffaa..dca3c4c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -570,7 +570,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
 	rcrtc->plane->crtc = crtc;
 
 	primary = drm_primary_helper_create_plane(dev);
-	ret = drm_crtc_init(rcdu->ddev, crtc, primary, &crtc_funcs);
+	ret = drm_crtc_init(rcdu->ddev, crtc, primary, NULL, &crtc_funcs);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index e806553..dedbd33 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -517,7 +517,7 @@ int shmob_drm_crtc_create(struct shmob_drm_device *sdev)
 
 	sdev->crtc.dpms = DRM_MODE_DPMS_OFF;
 
-	ret = drm_crtc_init(sdev->ddev, crtc, primary, &crtc_funcs);
+	ret = drm_crtc_init(sdev->ddev, crtc, primary, NULL, &crtc_funcs);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 5e2ee9d..3b2e73f 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1103,7 +1103,7 @@ static int tegra_dc_init(struct host1x_client *client)
 	int err;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(tegra->drm, &dc->base, primary, &tegra_crtc_funcs);
+	drm_crtc_init(tegra->drm, &dc->base, primary, NULL, &tegra_crtc_funcs);
 	drm_mode_crtc_set_gamma_size(&dc->base, 256);
 	drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 310314c..002c88c 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -673,7 +673,7 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
 	}
 
 	primary = drm_primary_helper_create_plane(dev);
-	ret = drm_crtc_init(dev, crtc, primary, &tilcdc_crtc_funcs);
+	ret = drm_crtc_init(dev, crtc, primary, NULL, &tilcdc_crtc_funcs);
 	if (ret < 0)
 		goto fail;
 
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index c63b5e7..9490cf5 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -396,7 +396,7 @@ static int udl_crtc_init(struct drm_device *dev)
 		return -ENOMEM;
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, crtc, primary, &udl_crtc_funcs);
+	drm_crtc_init(dev, crtc, primary, NULL, &udl_crtc_funcs);
 	drm_crtc_helper_add(crtc, &udl_helper_funcs);
 
 	return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 08fdd7f..07888c5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -375,7 +375,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 	(void) drm_sysfs_connector_add(connector);
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, crtc, primary, &vmw_legacy_crtc_funcs);
+	drm_crtc_init(dev, crtc, primary, NULL, &vmw_legacy_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 46ea096..b1ad841 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -471,7 +471,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
 	(void) drm_sysfs_connector_add(connector);
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(dev, crtc, primary, &vmw_screen_object_crtc_funcs);
+	drm_crtc_init(dev, crtc, primary, NULL, &vmw_screen_object_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(crtc, 256);
 
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 8c7b1d3..0710196 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -522,7 +522,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
 
 	primary = drm_primary_helper_create_plane(dev);
-	drm_crtc_init(imxdrm->drm, crtc, primary,
+	drm_crtc_init(imxdrm->drm, crtc, primary, NULL,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
 	drm_mode_group_reinit(imxdrm->drm);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 9f7824d..1c9704b 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -271,6 +271,8 @@ struct drm_crtc_funcs {
  * @head: list management
  * @base: base KMS object for ID tracking etc.
  * @primary: primary plane for this CRTC
+ * @cursor: cursor plane for this CRTC; may be NULL if no cursor
+ *    is supported
  * @enabled: is this CRTC enabled?
  * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
@@ -309,6 +311,9 @@ struct drm_crtc {
 	/* primary plane for CRTC */
 	struct drm_plane *primary;
 
+	/* cursor plane for CRTC */
+	struct drm_plane *cursor;
+
 	/* Temporary tracking of the old fb while a modeset is ongoing. Used
 	 * by drm_mode_set_config_internal to implement correct refcounting. */
 	struct drm_framebuffer *old_fb;
@@ -909,6 +914,7 @@ extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
 extern int drm_crtc_init(struct drm_device *dev,
 			 struct drm_crtc *crtc,
 			 struct drm_plane *primary,
+			 struct drm_plane *cursor,
 			 const struct drm_crtc_funcs *funcs);
 extern void drm_crtc_cleanup(struct drm_crtc *crtc);
 extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 13/14] drm/i915: Split cursor update code from cursor ioctl handling
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (11 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19  8:03   ` Chris Wilson
  2014-03-19  0:22 ` [RFCv3 14/14] drm/i915: Add cursor handlers and create cursor at crtc init Matt Roper
  2014-03-19  0:37 ` [RFCv3 00/14] Unified plane support Rob Clark
  14 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

Legacy cursor ioctls took GEM buffer handles from userspace directly
whereas the new unified plane handling assigns drm_framebuffer's to
cursor planes.  Splitting the code that actually updates the cursor
plane from the code that handles object lookup and reference counting
allows us to share common code between both interfaces.

Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 197 ++++++++++++++++++++++++-----------
 drivers/gpu/drm/i915/intel_drv.h     |   2 -
 2 files changed, 134 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d43b31d..f661469 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -43,7 +43,8 @@
 #include <linux/dma_remapping.h>
 
 static void intel_increase_pllclock(struct drm_crtc *crtc);
-static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc,
+				     struct drm_framebuffer *fb);
 
 static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
 				struct intel_crtc_config *pipe_config);
@@ -56,6 +57,11 @@ static int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
 				  struct drm_mode_fb_cmd2 *mode_cmd,
 				  struct drm_i915_gem_object *obj);
+static struct drm_framebuffer *
+intel_user_framebuffer_create(struct drm_device *dev,
+			      struct drm_file *filp,
+			      struct drm_mode_fb_cmd2 *mode_cmd);
+static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb);
 
 typedef struct {
 	int	min, max;
@@ -3709,7 +3715,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 	intel_enable_pipe(intel_crtc);
 	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
-	intel_crtc_update_cursor(crtc, true);
+	intel_crtc_update_cursor(crtc, crtc->cursor->fb);
 
 	if (intel_crtc->config.has_pch_encoder)
 		ironlake_pch_enable(crtc);
@@ -3753,7 +3759,7 @@ static void haswell_crtc_enable_planes(struct drm_crtc *crtc)
 
 	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
-	intel_crtc_update_cursor(crtc, true);
+	intel_crtc_update_cursor(crtc, crtc->cursor->fb);
 
 	hsw_enable_ips(intel_crtc);
 
@@ -3781,7 +3787,7 @@ static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
 
 	hsw_disable_ips(intel_crtc);
 
-	intel_crtc_update_cursor(crtc, false);
+	intel_crtc_update_cursor(crtc, NULL);
 	intel_disable_planes(crtc);
 	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 }
@@ -3909,7 +3915,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 	if (dev_priv->fbc.plane == plane)
 		intel_disable_fbc(dev);
 
-	intel_crtc_update_cursor(crtc, false);
+	intel_crtc_update_cursor(crtc, NULL);
 	intel_disable_planes(crtc);
 	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 
@@ -4396,7 +4402,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
 	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
-	intel_crtc_update_cursor(crtc, true);
+	intel_crtc_update_cursor(crtc, crtc->cursor->fb);
 
 	intel_update_fbc(dev);
 
@@ -4440,7 +4446,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 	/* The fixup needs to happen before cursor is enabled */
 	if (IS_G4X(dev))
 		g4x_fixup_plane(dev_priv, pipe);
-	intel_crtc_update_cursor(crtc, true);
+	intel_crtc_update_cursor(crtc, crtc->cursor->fb);
 
 	/* Give the overlay scaler a chance to enable if it's on this pipe */
 	intel_crtc_dpms_overlay(intel_crtc, true);
@@ -4491,7 +4497,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 		intel_disable_fbc(dev);
 
 	intel_crtc_dpms_overlay(intel_crtc, false);
-	intel_crtc_update_cursor(crtc, false);
+	intel_crtc_update_cursor(crtc, NULL);
 	intel_disable_planes(crtc);
 	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 
@@ -7739,7 +7745,7 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
 
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
 static void intel_crtc_update_cursor(struct drm_crtc *crtc,
-				     bool on)
+				     struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7750,32 +7756,36 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
-	if (on)
-		base = intel_crtc->cursor_addr;
+	if (!intel_crtc->active)
+		return;
 
-	if (x >= intel_crtc->config.pipe_src_w)
-		base = 0;
+	if (fb != NULL) {
+		base = intel_crtc->cursor_addr;
 
-	if (y >= intel_crtc->config.pipe_src_h)
-		base = 0;
+		if (x >= intel_crtc->config.pipe_src_w)
+			base = 0;
 
-	if (x < 0) {
-		if (x + intel_crtc->cursor_width <= 0)
+		if (y >= intel_crtc->config.pipe_src_h)
 			base = 0;
 
-		pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
-		x = -x;
-	}
-	pos |= x << CURSOR_X_SHIFT;
+		if (x < 0) {
+			if (x + fb->width <= 0)
+				base = 0;
 
-	if (y < 0) {
-		if (y + intel_crtc->cursor_height <= 0)
-			base = 0;
+			pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+			x = -x;
+		}
+		pos |= x << CURSOR_X_SHIFT;
 
-		pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
-		y = -y;
+		if (y < 0) {
+			if (y + fb->height <= 0)
+				base = 0;
+
+			pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+			y = -y;
+		}
+		pos |= y << CURSOR_Y_SHIFT;
 	}
-	pos |= y << CURSOR_Y_SHIFT;
 
 	visible = base != 0;
 	if (!visible && !intel_crtc->cursor_visible)
@@ -7793,41 +7803,46 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	}
 }
 
-static int intel_crtc_cursor_set(struct drm_crtc *crtc,
-				 struct drm_file *file,
-				 uint32_t handle,
-				 uint32_t width, uint32_t height)
+/*
+ * Common cursor-setting code shared by both the legacy cursor ioctls (which
+ * take a GEM bo handle directly from userspace) and the new unified plane
+ * interface (which takes drm_framebuffer's).  By the time we get here, the
+ * desired new buffer will be in the form of a DRM framebuffer, regardless
+ * of which userspace API was used.
+ */
+static int cursor_set_common(struct drm_crtc *crtc,
+			     struct drm_plane *cursor,
+			     struct drm_framebuffer *fb)
 {
-	struct drm_device *dev = crtc->dev;
+	struct drm_device *dev = cursor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct drm_i915_gem_object *obj;
-	uint32_t addr;
+	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+	struct drm_i915_gem_object *obj = NULL;
+	struct drm_i915_gem_object *cursor_bo = NULL;
+	uint32_t addr = 0;
 	int ret;
 
-	/* if we want to turn off the cursor ignore width and height */
-	if (!handle) {
+	BUG_ON(cursor != crtc->cursor);
+	BUG_ON(cursor->possible_crtcs != drm_crtc_mask(crtc));
+
+	if (fb == NULL) {
 		DRM_DEBUG_KMS("cursor off\n");
-		addr = 0;
-		obj = NULL;
 		mutex_lock(&dev->struct_mutex);
 		goto finish;
 	}
 
+	obj = intel_fb->obj;
+
 	/* Currently we only support 64x64 cursors */
-	if (width != 64 || height != 64) {
+	if (fb->width != 64 || fb->height != 64) {
 		DRM_ERROR("we currently only support 64x64 cursors\n");
 		return -EINVAL;
 	}
 
-	obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle));
-	if (&obj->base == NULL)
-		return -ENOENT;
-
-	if (obj->base.size < width * height * 4) {
-		DRM_DEBUG_KMS("buffer is to small\n");
-		ret = -ENOMEM;
-		goto fail;
+	if (obj->base.size < fb->width * fb->height * 4) {
+		DRM_DEBUG_KMS("Cursor buffer is too small\n");
+		return -ENOMEM;
 	}
 
 	/* we only need to pin inside GTT if cursor is non-phy */
@@ -7876,35 +7891,87 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 	}
 
 	if (IS_GEN2(dev))
-		I915_WRITE(CURSIZE, (height << 12) | width);
+		I915_WRITE(CURSIZE, (fb->height << 12) | fb->width);
 
- finish:
-	if (intel_crtc->cursor_bo) {
+finish:
+	if (cursor->fb) {
+		cursor_bo = to_intel_framebuffer(cursor->fb)->obj;
 		if (INTEL_INFO(dev)->cursor_needs_physical) {
-			if (intel_crtc->cursor_bo != obj)
-				i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
+			if (cursor_bo != obj)
+				i915_gem_detach_phys_object(dev, cursor_bo);
 		} else
-			i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo);
-		drm_gem_object_unreference(&intel_crtc->cursor_bo->base);
+			i915_gem_object_unpin_from_display_plane(cursor_bo);
 	}
 
 	mutex_unlock(&dev->struct_mutex);
 
 	intel_crtc->cursor_addr = addr;
-	intel_crtc->cursor_bo = obj;
-	intel_crtc->cursor_width = width;
-	intel_crtc->cursor_height = height;
-
-	if (intel_crtc->active)
-		intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 
 	return 0;
+
 fail_unpin:
 	i915_gem_object_unpin_from_display_plane(obj);
 fail_locked:
 	mutex_unlock(&dev->struct_mutex);
-fail:
-	drm_gem_object_unreference_unlocked(&obj->base);
+	return ret;
+}
+
+static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+				 struct drm_file *file,
+				 uint32_t handle,
+				 uint32_t width, uint32_t height)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_plane *cursor = crtc->cursor;
+	struct drm_framebuffer *fb = NULL;
+	struct drm_framebuffer *old_fb = NULL;
+	struct drm_i915_gem_object *new_obj = NULL;
+	struct drm_i915_gem_object *old_obj = NULL;
+	struct drm_mode_fb_cmd2 cmd = {
+		.width = width,
+		.height = height,
+		.pixel_format = DRM_FORMAT_ARGB8888,
+	};
+	int ret = 0;
+
+	/* i915 cursor support may be disabled for debugging */
+	if (cursor == NULL)
+		return -ENXIO;
+
+	old_fb = cursor->fb;
+
+	/* Wrap the buffer handle we got in a drm framebuffer */
+	if (handle != 0) {
+		cmd.handles[0] = handle;
+		fb = intel_user_framebuffer_create(dev, file, &cmd);
+		if (IS_ERR(fb))
+			return PTR_ERR(fb);
+	}
+
+	new_obj = fb ? to_intel_framebuffer(fb)->obj : NULL;
+	old_obj = old_fb ? to_intel_framebuffer(old_fb)->obj : NULL;
+
+	/* If this buffer is already the cursor image, no work is needed */
+	if (new_obj == old_obj) {
+		DRM_DEBUG_KMS("Cursor is already set with this object\n");
+		old_fb = NULL;
+		goto done;
+	}
+
+	ret = cursor_set_common(crtc, cursor, fb);
+	if (ret != 0) {
+		old_fb = NULL;
+	} else {
+		intel_crtc_update_cursor(crtc, fb);
+		cursor->fb = fb;
+		fb = NULL;
+	}
+
+done:
+	if (fb)
+		intel_user_framebuffer_destroy(fb);
+	if (old_fb)
+		intel_user_framebuffer_destroy(old_fb);
 	return ret;
 }
 
@@ -7912,11 +7979,15 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
+	/* i915 cursor support may be disabled for debugging */
+	if (crtc->cursor == NULL)
+		return -ENXIO;
+
 	intel_crtc->cursor_x = clamp_t(int, x, SHRT_MIN, SHRT_MAX);
 	intel_crtc->cursor_y = clamp_t(int, y, SHRT_MIN, SHRT_MAX);
 
 	if (intel_crtc->active)
-		intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
+		intel_crtc_update_cursor(crtc, crtc->cursor->fb);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 770f80d..76950bb 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -364,10 +364,8 @@ struct intel_crtc {
 	 * handled in the hw itself (with the TILEOFF register). */
 	unsigned long dspaddr_offset;
 
-	struct drm_i915_gem_object *cursor_bo;
 	uint32_t cursor_addr;
 	int16_t cursor_x, cursor_y;
-	int16_t cursor_width, cursor_height;
 	bool cursor_visible;
 
 	struct intel_plane_config plane_config;
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFCv3 14/14] drm/i915: Add cursor handlers and create cursor at crtc init
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (12 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 13/14] drm/i915: Split cursor update code from cursor ioctl handling Matt Roper
@ 2014-03-19  0:22 ` Matt Roper
  2014-03-19  0:37 ` [RFCv3 00/14] Unified plane support Rob Clark
  14 siblings, 0 replies; 46+ messages in thread
From: Matt Roper @ 2014-03-19  0:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 90 +++++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f661469..36bee38 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10781,11 +10781,98 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
 	return &primary->base;
 }
 
+static int
+intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
+			  struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+			  unsigned int crtc_w, unsigned int crtc_h,
+			  uint32_t src_x, uint32_t src_y,
+			  uint32_t src_w, uint32_t src_h)
+{
+	int ret;
+
+	/* setplane API takes shifted source rectangle values; unshift them */
+	src_x >>= 16;
+	src_y >>= 16;
+	src_w >>= 16;
+	src_h >>= 16;
+
+	/* Cursor planes are locked to their owning CRTC */
+	if (plane->possible_crtcs != drm_crtc_mask(crtc)) {
+		DRM_DEBUG_KMS("Cannot change cursor plane CRTC\n");
+		return -EINVAL;
+	}
+
+	/* Current hardware can't scale the cursor plane. */
+	if (crtc_w != src_w || crtc_h != src_h) {
+		DRM_DEBUG_KMS("Can't scale cursor plane\n");
+		return -EINVAL;
+	}
+
+	ret = cursor_set_common(crtc, crtc->cursor, fb);
+	if (ret)
+		return ret;
+
+	intel_crtc_cursor_move(crtc, crtc_x, crtc_y);
+	intel_crtc_update_cursor(crtc, fb);
+
+	return 0;
+}
+
+static int
+intel_cursor_plane_disable(struct drm_plane *plane)
+{
+	if (!plane->fb)
+		return 0;
+
+	BUG_ON(!plane->crtc);
+
+	return cursor_set_common(plane->crtc, plane, NULL);
+}
+
+static void intel_cursor_plane_destroy(struct drm_plane *plane)
+{
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	intel_cursor_plane_disable(plane);
+	drm_plane_cleanup(plane);
+	kfree(intel_plane);
+}
+
+static const struct drm_plane_funcs intel_cursor_plane_funcs = {
+	.update_plane = intel_cursor_plane_update,
+	.disable_plane = intel_cursor_plane_disable,
+	.destroy = intel_cursor_plane_destroy,
+};
+
+static const uint32_t cursor_formats[] = {
+	DRM_FORMAT_ARGB8888,
+};
+
+static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
+						   int pipe)
+{
+	struct intel_plane *cursor;
+
+	cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
+	if (cursor == NULL)
+		return NULL;
+
+	cursor->can_scale = false;
+	cursor->pipe = pipe;
+	cursor->plane = pipe;
+
+	drm_plane_init(dev, &cursor->base, 0,
+		       &intel_cursor_plane_funcs, cursor_formats,
+		       ARRAY_SIZE(cursor_formats),
+		       DRM_PLANE_TYPE_CURSOR);
+	return &cursor->base;
+}
+
 static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc;
 	struct drm_plane *primary;
+	struct drm_plane *cursor;
 	int i, ret;
 
 	intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
@@ -10793,7 +10880,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 		return;
 
 	primary = intel_primary_plane_create(dev, pipe);
-	ret = drm_crtc_init(dev, &intel_crtc->base, primary, NULL,
+	cursor = intel_cursor_plane_create(dev, pipe);
+	ret = drm_crtc_init(dev, &intel_crtc->base, primary, cursor,
 			    &intel_crtc_funcs);
 	if (ret) {
 		drm_crtc_cleanup(&intel_crtc->base);
-- 
1.8.5.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [RFCv3 00/14] Unified plane support
  2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
                   ` (13 preceding siblings ...)
  2014-03-19  0:22 ` [RFCv3 14/14] drm/i915: Add cursor handlers and create cursor at crtc init Matt Roper
@ 2014-03-19  0:37 ` Rob Clark
  14 siblings, 0 replies; 46+ messages in thread
From: Rob Clark @ 2014-03-19  0:37 UTC (permalink / raw)
  To: Matt Roper; +Cc: Intel Graphics Development, dri-devel

On Tue, Mar 18, 2014 at 8:22 PM, Matt Roper <matthew.d.roper@intel.com> wrote:
> Previous revision and explanation of series:
>    http://lists.freedesktop.org/archives/dri-devel/2014-March/055222.html
>
> Main changes since last pass:
>  * Added cursor plane support on i915.  Unfortunately it isn't possible to
>    create nice generic helper functions that make use of the legacy API's for
>    cursor planes as was done for primary planes; the legacy cursor ioctl's take
>    a driver handle directly (e.g., from GEM) rather than a DRM framebuffer.
>    With the unified plane support, we receive a DRM framebuffer via the SetPlane
>    API, but have no way of turning that into a driver handle that can be passed
>    to the legacy interfaces.
>  * Updated msm and omapdrm to use their existing "private" planes as primary
>    rather than using the primary helper functions.  (thanks Rob Clark!)
>  * Fixed several s/crtc->fb/crtc->primary->fb/ conversions that were missed
>    on the first pass (or new instances that popped up due to rebasing to
>    the latest code).
>
> I believe some of the next steps are:
>  * Create some new read-only plane properties that describe in more detail the
>    capabilities & limitations of various planes (max/min size, scaling
>    capabilities, tiling restrictions, etc.) so that generic userspace
>    compositors can make intelligent decisions about how best to use the various
>    planes on the plane list.  If anyone has strong feelings on what these
>    properties should look like, this would be a good time to start the
>    discussion.
>  * Update cursor support for the rest of the non-i915 drivers.  I believe the
>    list of drivers that currently support cursors are: armada, ast, gma500,
>    mgag200, msm, nouveau, radeon, vmwgfx, and qxl.
>  * Update imx-drm's CRTC creation to use its existing private primary plane
>    rather than using the primary helper function to create one.
>  * Provide patches for weston & xf86-video-modesetting that make use of the
>    unified plane interface to make real-world testing of this patchset a
>    bit easier.

not sure other's opionions, but personally I wouldn't object to doing
some of this as follow-up patchsets.  Ofc my selfish motivation is
that basing atomic on top of primary plane really seems like the right
move, and so sooner we can get the initial parts of this patchset
merged, the sooner we can try to merge atomic ;-)

BR,
-R

>
> Note that the first patch here is simply a build fix for current breakage of
> the drm-intel-nightly branch of the drm-intel repo.
>
>
> Matt Roper (14):
>   SQUASH! drm/i915: Do not dereference pointers from ring buffer in
>     evict event
>   drm: Add support for multiple plane types
>   drm: Add primary plane helpers
>   drm/exynos: Restrict plane loops to only operate on overlay planes
>   drm/i915: Restrict plane loops to only operate on overlay planes
>   drm: Add plane type property
>   drm: Specify primary plane at CRTC initialization (v2)
>   drm: Replace crtc fb with primary plane fb (v2)
>   drm: Allow userspace to ask for full plane list (universal planes)
>   drm/i915: Rename similar plane functions to avoid confusion
>   drm/i915: Intel-specific primary plane handling
>   drm: Specify cursor plane at CRTC initialization
>   drm/i915: Split cursor update code from cursor ioctl handling
>   drm/i915: Add cursor handlers and create cursor at crtc init
>
>  drivers/gpu/drm/armada/armada_crtc.c         |   4 +-
>  drivers/gpu/drm/armada/armada_overlay.c      |   3 +-
>  drivers/gpu/drm/ast/ast_mode.c               |  16 +-
>  drivers/gpu/drm/bochs/bochs_kms.c            |   8 +-
>  drivers/gpu/drm/cirrus/cirrus_mode.c         |  15 +-
>  drivers/gpu/drm/drm_crtc.c                   | 441 +++++++++++++++----
>  drivers/gpu/drm/drm_crtc_helper.c            |  21 +-
>  drivers/gpu/drm/drm_fb_helper.c              |   9 +-
>  drivers/gpu/drm/drm_ioctl.c                  |   5 +
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c     |   4 +-
>  drivers/gpu/drm/exynos/exynos_drm_encoder.c  |   6 +
>  drivers/gpu/drm/exynos/exynos_drm_plane.c    |   4 +-
>  drivers/gpu/drm/gma500/cdv_intel_display.c   |   2 +-
>  drivers/gpu/drm/gma500/cdv_intel_dp.c        |   2 +-
>  drivers/gpu/drm/gma500/cdv_intel_hdmi.c      |   3 +-
>  drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
>  drivers/gpu/drm/gma500/gma_display.c         |  17 +-
>  drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
>  drivers/gpu/drm/gma500/mdfld_intel_display.c |  17 +-
>  drivers/gpu/drm/gma500/oaktrail_crtc.c       |  13 +-
>  drivers/gpu/drm/gma500/psb_intel_display.c   |   7 +-
>  drivers/gpu/drm/gma500/psb_intel_lvds.c      |   2 +-
>  drivers/gpu/drm/gma500/psb_intel_sdvo.c      |   2 +-
>  drivers/gpu/drm/i915/i915_debugfs.c          |   4 +-
>  drivers/gpu/drm/i915/i915_drv.h              |   5 +-
>  drivers/gpu/drm/i915/i915_irq.c              |   4 +-
>  drivers/gpu/drm/i915/i915_trace.h            |   2 +-
>  drivers/gpu/drm/i915/intel_display.c         | 623 ++++++++++++++++++++-------
>  drivers/gpu/drm/i915/intel_dp.c              |   5 +-
>  drivers/gpu/drm/i915/intel_drv.h             |   3 +-
>  drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
>  drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
>  drivers/gpu/drm/i915/intel_pm.c              |  39 +-
>  drivers/gpu/drm/i915/intel_sprite.c          |   2 +-
>  drivers/gpu/drm/mgag200/mgag200_mode.c       |  33 +-
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  33 +-
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c    |   4 +-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  27 +-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c    |   4 +-
>  drivers/gpu/drm/nouveau/dispnv04/crtc.c      |  24 +-
>  drivers/gpu/drm/nouveau/dispnv04/dfp.c       |   2 +-
>  drivers/gpu/drm/nouveau/dispnv04/overlay.c   |   4 +-
>  drivers/gpu/drm/nouveau/nouveau_display.c    |   8 +-
>  drivers/gpu/drm/nouveau/nv50_display.c       |  21 +-
>  drivers/gpu/drm/omapdrm/omap_crtc.c          |   2 +-
>  drivers/gpu/drm/omapdrm/omap_plane.c         |   4 +-
>  drivers/gpu/drm/qxl/qxl_display.c            |  15 +-
>  drivers/gpu/drm/radeon/atombios_crtc.c       |  20 +-
>  drivers/gpu/drm/radeon/r100.c                |   4 +-
>  drivers/gpu/drm/radeon/radeon_connectors.c   |   2 +-
>  drivers/gpu/drm/radeon/radeon_device.c       |   3 +-
>  drivers/gpu/drm/radeon/radeon_display.c      |   9 +-
>  drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +-
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c       |   4 +-
>  drivers/gpu/drm/rcar-du/rcar_du_plane.c      |   3 +-
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c    |   3 +-
>  drivers/gpu/drm/shmobile/shmob_drm_plane.c   |   2 +-
>  drivers/gpu/drm/tegra/dc.c                   |   7 +-
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c         |   4 +-
>  drivers/gpu/drm/udl/udl_modeset.c            |   6 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_kms.c          |  14 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c          |  12 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c         |  12 +-
>  drivers/staging/imx-drm/imx-drm-core.c       |   4 +-
>  drivers/staging/imx-drm/ipuv3-plane.c        |   4 +-
>  include/drm/drmP.h                           |   5 +
>  include/drm/drm_crtc.h                       | 115 ++++-
>  include/uapi/drm/drm.h                       |   8 +
>  68 files changed, 1252 insertions(+), 488 deletions(-)
>
> Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
> --
> 1.8.5.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 13/14] drm/i915: Split cursor update code from cursor ioctl handling
  2014-03-19  0:22 ` [RFCv3 13/14] drm/i915: Split cursor update code from cursor ioctl handling Matt Roper
@ 2014-03-19  8:03   ` Chris Wilson
  0 siblings, 0 replies; 46+ messages in thread
From: Chris Wilson @ 2014-03-19  8:03 UTC (permalink / raw)
  To: Matt Roper; +Cc: Intel Graphics Development, dri-devel

On Tue, Mar 18, 2014 at 05:22:58PM -0700, Matt Roper wrote:
> Legacy cursor ioctls took GEM buffer handles from userspace directly
> whereas the new unified plane handling assigns drm_framebuffer's to
> cursor planes.  Splitting the code that actually updates the cursor
> plane from the code that handles object lookup and reference counting
> allows us to share common code between both interfaces.

This exposes an internal fb, a bo that was private is now public.

So maybe drm_framebuffer_init_private() and
intel_private_framebuffer_create().
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19  0:22 ` [RFCv3 03/14] drm: Add primary plane helpers Matt Roper
@ 2014-03-19 11:28   ` Daniel Vetter
  2014-03-19 12:56     ` Rob Clark
  2014-03-19 18:15     ` Matt Roper
  2014-03-19 11:50   ` Daniel Vetter
  2014-03-19 12:24   ` Daniel Vetter
  2 siblings, 2 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 11:28 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:48PM -0700, Matt Roper wrote:
> When we expose non-overlay planes to userspace, they will become
> accessible via standard userspace plane API's.  We should be able to
> handle the standard plane operations against primary planes in a generic
> way via the page flip handler and modeset handler.
> 
> Drivers that can program primary planes more efficiently, that want to
> use their own primary plane structure to track additional information,
> or that don't have the limitations assumed by the helpers are free to
> provide their own implementation of some or all of these handlers.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/drm_crtc.c | 288 +++++++++++++++++++++++++++++++++++++++------

Given that this is helper code to transition from the current interfaces
to universal planes I think we should shovel this into a new
drm_planes_helper.c library or something.

drm_crtc.c is reserved for core interface code between drm ioctl and the
main driver entry points.

Note that the legacy ioctl -> new universal plane code should probably
live here since long-term we want to phase out the legacy drm core ->
driver interfaces for cursors and primary planes.

>  include/drm/drm_crtc.h     |  81 +++++++++++++
>  2 files changed, 330 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 0983996..db54ae9 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1118,6 +1118,255 @@ void drm_plane_force_disable(struct drm_plane *plane)
>  }
>  EXPORT_SYMBOL(drm_plane_force_disable);
>  
> +/*
> + * Checks that the framebuffer is big enough for the CRTC viewport
> + * (x, y, hdisplay, vdisplay)
> + */
> +static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> +				   int x, int y,
> +				   const struct drm_display_mode *mode,
> +				   const struct drm_framebuffer *fb)
> +
> +{
> +	int hdisplay, vdisplay;
> +
> +	hdisplay = mode->hdisplay;
> +	vdisplay = mode->vdisplay;
> +
> +	if (drm_mode_is_stereo(mode)) {
> +		struct drm_display_mode adjusted = *mode;
> +
> +		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
> +		hdisplay = adjusted.crtc_hdisplay;
> +		vdisplay = adjusted.crtc_vdisplay;
> +	}
> +
> +	if (crtc->invert_dimensions)
> +		swap(hdisplay, vdisplay);
> +
> +	if (hdisplay > fb->width ||
> +	    vdisplay > fb->height ||
> +	    x > fb->width - hdisplay ||
> +	    y > fb->height - vdisplay) {
> +		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> +			      fb->width, fb->height, hdisplay, vdisplay, x, y,
> +			      crtc->invert_dimensions ? " (inverted)" : "");
> +		return -ENOSPC;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Returns the connectors currently associated with a CRTC.  This function
> + * should be called twice:  once with a NULL connector list to retrieve
> + * the list size, and once with the properly allocated list to be filled in.
> + */
> +static int get_connectors_for_crtc(struct drm_crtc *crtc,
> +				   struct drm_connector **connector_list,
> +				   int num_connectors)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_connector *connector;
> +	int count = 0;
> +
> +	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
> +		if (connector->encoder && connector->encoder->crtc == crtc) {
> +			if (connector_list != NULL && count < num_connectors)
> +				*(connector_list++) = connector;
> +
> +			count++;
> +		}
> +
> +	return count;
> +}
> +
> +/**
> + * drm_primary_helper_update() - Helper for primary plane update
> + * @plane: plane object to update
> + * @crtc: owning CRTC of owning plane
> + * @fb: framebuffer to flip onto plane
> + * @crtc_x: x offset of primary plane on crtc
> + * @crtc_y: y offset of primary plane on crtc
> + * @crtc_w: width of primary plane rectangle on crtc
> + * @crtc_h: height of primary plane rectangle on crtc
> + * @src_x: x offset of @fb for panning
> + * @src_y: y offset of @fb for panning
> + * @src_w: width of source rectangle in @fb
> + * @src_h: height of source rectangle in @fb
> + *
> + * Provides a default plane update handler for primary planes.  This is handler
> + * is called in response to a userspace SetPlane operation on the plane with a
> + * non-NULL framebuffer.  We call the driver's pageflip handler to update the
> + * framebuffer.
> + *
> + * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
> + * return an error.
> + *
> + * Note that we assume most hardware can't reposition or scale the primary
> + * plane, so we require that crtc_x = crtc_y = 0 and that src_w/src_h match the
> + * current mode.  Drivers for hardware that don't have these restrictions can
> + * provide their own implementation rather than using this helper.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
> +			      struct drm_framebuffer *fb,
> +			      int crtc_x, int crtc_y,
> +			      unsigned int crtc_w, unsigned int crtc_h,
> +			      uint32_t src_x, uint32_t src_y,
> +			      uint32_t src_w, uint32_t src_h)
> +{
> +	struct drm_mode_set set = {
> +		.crtc = crtc,
> +		.fb = fb,
> +		.mode = &crtc->mode,
> +		.x = crtc_x,
> +		.y = crtc_y,
> +	};
> +	struct drm_connector **connector_list;
> +	struct drm_framebuffer *tmpfb;
> +	int num_connectors, ret;
> +
> +	/* setplane API takes shifted source rectangle values; unshift them */
> +	src_x >>= 16;
> +	src_y >>= 16;
> +	src_w >>= 16;
> +	src_h >>= 16;

I think you need to check for 0 in the lower bits since set_config doesn't
support sub-pixel positioning.

Also we need to check for scaling and reject it and we need to check that
crtc_w/crtc_h will fill the entire crtc (otherwise set_config won't do the
right thing).

> +
> +	/* Primary planes are locked to their owning CRTC */
> +	if (plane->possible_crtcs != drm_crtc_mask(crtc)) {
> +		DRM_DEBUG_KMS("Cannot change primary plane CRTC\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!crtc->enabled) {
> +		DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb);
> +	if (ret)
> +		return ret;
> +
> +	/* Find current connectors for CRTC */
> +	num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
> +	BUG_ON(num_connectors == 0);
> +	connector_list = kzalloc(num_connectors * sizeof(*connector_list),
> +				 GFP_KERNEL);
> +	if (!connector_list)
> +		return -ENOMEM;
> +	get_connectors_for_crtc(crtc, connector_list, num_connectors);
> +
> +	set.connectors = connector_list;
> +	set.num_connectors = num_connectors;
> +
> +	/*
> +	 * set_config() adjusts crtc->primary->fb; however the DRM setplane
> +	 * code that called us expects to handle the framebuffer update and
> +	 * reference counting; save and restore the current fb before
> +	 * calling it.
> +	 */
> +	tmpfb = plane->fb;
> +	ret = crtc->funcs->set_config(&set);

I wonder whether we should have an oppportunistic path using the page_flip
interface here. Otoh we must have a fallback to ->set_config anyway since
the drivers currently only allow pageflips on identical buffers. E.g. i915
rejects tiling changes and stride changes and position changes. So I think
having a pageflip fastpath isn't worth the trouble.

Also I think you need to use set_config_internal here to get the
refcounting right.

> +	plane->fb = tmpfb;
> +
> +	kfree(connector_list);
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_primary_helper_update);
> +
> +/**
> + * drm_primary_helper_disable() - Helper for primary plane disable
> + * @plane: plane to disable
> + *
> + * Provides a default plane disable handler for primary planes.  This is handler
> + * is called in response to a userspace SetPlane operation on the plane with a
> + * NULL framebuffer parameter.  We call the driver's modeset handler with a NULL
> + * framebuffer to disable the CRTC.
> + *
> + * Note that some hardware may be able to disable the primary plane without
> + * disabling the whole CRTC.  Drivers for such hardware should provide their
> + * own disable handler that disables just the primary plane (and they'll likely
> + * need to provide their own update handler as well to properly re-enable a
> + * disabled primary plane).
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_primary_helper_disable(struct drm_plane *plane)
> +{
> +	struct drm_mode_set set = {
> +		.crtc = plane->crtc,
> +		.fb = NULL,
> +	};
> +
> +	if (plane->crtc == NULL || plane->fb == NULL)
> +		/* Already disabled */
> +		return 0;
> +
> +	return plane->crtc->funcs->set_config(&set);
> +}
> +EXPORT_SYMBOL(drm_primary_helper_disable);
> +
> +/**
> + * drm_primary_helper_destroy() - Helper for primary plane destruction
> + * @plane: plane to destroy
> + *
> + * Provides a default plane destroy handler for primary planes.  This handler
> + * is called during CRTC destruction.  We disable the primary plane, remove
> + * it from the DRM plane list, and deallocate the plane structure.
> + */
> +void drm_primary_helper_destroy(struct drm_plane *plane)
> +{
> +	plane->funcs->disable_plane(plane);
> +	drm_plane_cleanup(plane);
> +	kfree(plane);
> +}
> +EXPORT_SYMBOL(drm_primary_helper_destroy);
> +
> +const struct drm_plane_funcs drm_primary_helper_funcs = {
> +	.update_plane = drm_primary_helper_update,
> +	.disable_plane = drm_primary_helper_disable,
> +	.destroy = drm_primary_helper_destroy,
> +};
> +EXPORT_SYMBOL(drm_primary_helper_funcs);
> +
> +/**
> + * drm_primary_helper_create_plane() - Create a generic primary plane
> + * @dev: drm device
> + *
> + * Allocates and initializes a primary plane that can be used with the primary
> + * plane helpers.  Drivers that wish to use driver-specific plane structures or
> + * provide custom handler functions may perform their own allocation and
> + * initialization rather than calling this function.
> + */
> +struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev)
> +{
> +	struct drm_plane *primary;
> +	int ret;
> +
> +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> +	if (primary == NULL) {
> +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
> +		return NULL;
> +	}
> +
> +	/* possible_crtc's will be filled in later by crtc_init */
> +	ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
> +			     legacy_modeset_formats,
> +			     ARRAY_SIZE(legacy_modeset_formats),
> +			     DRM_PLANE_TYPE_PRIMARY);
> +	if (ret) {
> +		kfree(primary);
> +		primary = NULL;
> +	}
> +
> +	return primary;
> +}
> +EXPORT_SYMBOL(drm_primary_helper_create_plane);
> +
>  static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
>  {
>  	struct drm_property *edid;
> @@ -2185,45 +2434,6 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>  }
>  EXPORT_SYMBOL(drm_mode_set_config_internal);
>  
> -/*
> - * Checks that the framebuffer is big enough for the CRTC viewport
> - * (x, y, hdisplay, vdisplay)
> - */
> -static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> -				   int x, int y,
> -				   const struct drm_display_mode *mode,
> -				   const struct drm_framebuffer *fb)
> -
> -{
> -	int hdisplay, vdisplay;
> -
> -	hdisplay = mode->hdisplay;
> -	vdisplay = mode->vdisplay;
> -
> -	if (drm_mode_is_stereo(mode)) {
> -		struct drm_display_mode adjusted = *mode;
> -
> -		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
> -		hdisplay = adjusted.crtc_hdisplay;
> -		vdisplay = adjusted.crtc_vdisplay;
> -	}
> -
> -	if (crtc->invert_dimensions)
> -		swap(hdisplay, vdisplay);
> -
> -	if (hdisplay > fb->width ||
> -	    vdisplay > fb->height ||
> -	    x > fb->width - hdisplay ||
> -	    y > fb->height - vdisplay) {
> -		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> -			      fb->width, fb->height, hdisplay, vdisplay, x, y,
> -			      crtc->invert_dimensions ? " (inverted)" : "");
> -		return -ENOSPC;
> -	}
> -
> -	return 0;
> -}
> -
>  /**
>   * drm_mode_setcrtc - set CRTC configuration
>   * @dev: drm device for the ioctl
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index e69ada8..f43fa92 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -581,6 +581,87 @@ struct drm_plane {
>  	enum drm_plane_type type;
>  };
>  
> +extern int drm_primary_helper_update(struct drm_plane *plane,
> +				     struct drm_crtc *crtc,
> +				     struct drm_framebuffer *fb,
> +				     int crtc_x, int crtc_y,
> +				     unsigned int crtc_w, unsigned int crtc_h,
> +				     uint32_t src_x, uint32_t src_y,
> +				     uint32_t src_w, uint32_t src_h);
> +extern int drm_primary_helper_disable(struct drm_plane *plane);
> +extern void drm_primary_helper_destroy(struct drm_plane *plane);
> +extern const struct drm_plane_funcs drm_primary_helper_funcs;
> +extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev);
> +
> +/*
> + * This is the list of formats that have historically been accepted by the
> + * modeset API.  The primary plane helpers use this list by default, but
> + * individual drivers may provide their own primary plane initialization
> + * that provides a more hw-specific format list.
> + */
> +const static uint32_t legacy_modeset_formats[] = {

What is this giant array doing in a header file?

> +       DRM_FORMAT_C8,
> +       DRM_FORMAT_RGB332,
> +       DRM_FORMAT_BGR233,
> +       DRM_FORMAT_XRGB4444,
> +       DRM_FORMAT_XBGR4444,
> +       DRM_FORMAT_RGBX4444,
> +       DRM_FORMAT_BGRX4444,
> +       DRM_FORMAT_ARGB4444,
> +       DRM_FORMAT_ABGR4444,
> +       DRM_FORMAT_RGBA4444,
> +       DRM_FORMAT_BGRA4444,
> +       DRM_FORMAT_XRGB1555,
> +       DRM_FORMAT_XBGR1555,
> +       DRM_FORMAT_RGBX5551,
> +       DRM_FORMAT_BGRX5551,
> +       DRM_FORMAT_ARGB1555,
> +       DRM_FORMAT_ABGR1555,
> +       DRM_FORMAT_RGBA5551,
> +       DRM_FORMAT_BGRA5551,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_BGR565,
> +       DRM_FORMAT_RGB888,
> +       DRM_FORMAT_BGR888,
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_RGBX8888,
> +       DRM_FORMAT_BGRX8888,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_ABGR8888,
> +       DRM_FORMAT_RGBA8888,
> +       DRM_FORMAT_BGRA8888,
> +       DRM_FORMAT_XRGB2101010,
> +       DRM_FORMAT_XBGR2101010,
> +       DRM_FORMAT_RGBX1010102,
> +       DRM_FORMAT_BGRX1010102,
> +       DRM_FORMAT_ARGB2101010,
> +       DRM_FORMAT_ABGR2101010,
> +       DRM_FORMAT_RGBA1010102,
> +       DRM_FORMAT_BGRA1010102,
> +       DRM_FORMAT_YUYV,
> +       DRM_FORMAT_YVYU,
> +       DRM_FORMAT_UYVY,
> +       DRM_FORMAT_VYUY,
> +       DRM_FORMAT_AYUV,
> +       DRM_FORMAT_NV12,
> +       DRM_FORMAT_NV21,
> +       DRM_FORMAT_NV16,
> +       DRM_FORMAT_NV61,
> +       DRM_FORMAT_NV24,
> +       DRM_FORMAT_NV42,
> +       DRM_FORMAT_YUV410,
> +       DRM_FORMAT_YVU410,
> +       DRM_FORMAT_YUV411,
> +       DRM_FORMAT_YVU411,
> +       DRM_FORMAT_YUV420,
> +       DRM_FORMAT_YVU420,
> +       DRM_FORMAT_YUV422,
> +       DRM_FORMAT_YVU422,
> +       DRM_FORMAT_YUV444,
> +       DRM_FORMAT_YVU444,

Hm, I'm not sure whether we have any driver or user actually
supporing/using yuv buffers on primary planes. It might be potentially
confusing for userspace if the format list for primary planes is nowhere
near the reality. Maybe we should give drivers the option to specify a
suitable one here?

> +};
> +
>  /**
>   * drm_bridge_funcs - drm_bridge control functions
>   * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
> -- 
> 1.8.5.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 06/14] drm: Add plane type property
  2014-03-19  0:22 ` [RFCv3 06/14] drm: Add plane type property Matt Roper
@ 2014-03-19 11:31   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 11:31 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:51PM -0700, Matt Roper wrote:
> Add a plane type property to allow userspace to distinguish plane types.
> The type of the plane will now be established at drm_plane_init() time
> (replacing the 'priv' parameter previously used).
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Lots of churn here over all drivers. Can't we just do a sane default
behaviour for drm_plane_init (i.e. overlay planes) and add a new
drm_universal_plane_init with the full powers?

That way the transition is easier to handle and drivers can opt-in at
their own pace and as needed.
-Daniel

> ---
>  drivers/gpu/drm/armada/armada_overlay.c    |  3 +-
>  drivers/gpu/drm/drm_crtc.c                 | 65 ++++++++++++++++++++----------
>  drivers/gpu/drm/exynos/exynos_drm_plane.c  |  4 +-
>  drivers/gpu/drm/i915/intel_sprite.c        |  2 +-
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c  |  4 +-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c  |  4 +-
>  drivers/gpu/drm/nouveau/dispnv04/overlay.c |  4 +-
>  drivers/gpu/drm/omapdrm/omap_plane.c       |  4 +-
>  drivers/gpu/drm/rcar-du/rcar_du_plane.c    |  3 +-
>  drivers/gpu/drm/shmobile/shmob_drm_plane.c |  2 +-
>  drivers/gpu/drm/tegra/dc.c                 |  3 +-
>  drivers/staging/imx-drm/ipuv3-plane.c      |  4 +-
>  include/drm/drm_crtc.h                     |  3 +-
>  13 files changed, 70 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
> index c5b06fd..ef68c42 100644
> --- a/drivers/gpu/drm/armada/armada_overlay.c
> +++ b/drivers/gpu/drm/armada/armada_overlay.c
> @@ -444,7 +444,8 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
>  				  dplane);
>  
>  	drm_plane_init(dev, &dplane->base, crtcs, &armada_plane_funcs,
> -		       armada_formats, ARRAY_SIZE(armada_formats), false);
> +		       armada_formats, ARRAY_SIZE(armada_formats),
> +		       DRM_PLANE_TYPE_OVERLAY);
>  
>  	dplane->prop.colorkey_yr = 0xfefefe00;
>  	dplane->prop.colorkey_ug = 0x01010100;
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index db54ae9..8e869d6 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -121,6 +121,15 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] =
>  
>  DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
>  
> +static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
> +{
> +	{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
> +	{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
> +	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
> +};
> +
> +DRM_ENUM_NAME_FN(drm_get_plane_type, drm_plane_type_enum_list)
> +
>  /*
>   * Optional properties
>   */
> @@ -1007,7 +1016,7 @@ EXPORT_SYMBOL(drm_encoder_cleanup);
>   * @funcs: callbacks for the new plane
>   * @formats: array of supported formats (%DRM_FORMAT_*)
>   * @format_count: number of elements in @formats
> - * @priv: plane is private (hidden from userspace)?
> + * @type: type of plane (overlay, primary, cursor)
>   *
>   * Inits a preallocate plane object created as base part of a driver plane
>   * object.
> @@ -1019,7 +1028,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
>  		   unsigned long possible_crtcs,
>  		   const struct drm_plane_funcs *funcs,
>  		   const uint32_t *formats, uint32_t format_count,
> -		   bool priv)
> +		   enum drm_plane_type type)
>  {
>  	int ret;
>  
> @@ -1044,20 +1053,16 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
>  	memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
>  	plane->format_count = format_count;
>  	plane->possible_crtcs = possible_crtcs;
> -	plane->type = DRM_PLANE_TYPE_OVERLAY;
> +	plane->type = type;
>  
> -	/* private planes are not exposed to userspace, but depending on
> -	 * display hardware, might be convenient to allow sharing programming
> -	 * for the scanout engine with the crtc implementation.
> -	 */
> -	if (!priv) {
> -		list_add_tail(&plane->head, &dev->mode_config.plane_list);
> -		dev->mode_config.num_total_plane++;
> -		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
> -			dev->mode_config.num_overlay_plane++;
> -	} else {
> -		INIT_LIST_HEAD(&plane->head);
> -	}
> +	list_add_tail(&plane->head, &dev->mode_config.plane_list);
> +	dev->mode_config.num_total_plane++;
> +	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
> +		dev->mode_config.num_overlay_plane++;
> +
> +	drm_object_attach_property(&plane->base,
> +				   dev->mode_config.plane_type_property,
> +				   plane->type);
>  
>   out:
>  	drm_modeset_unlock_all(dev);
> @@ -1081,13 +1086,13 @@ void drm_plane_cleanup(struct drm_plane *plane)
>  	drm_modeset_lock_all(dev);
>  	kfree(plane->format_types);
>  	drm_mode_object_put(dev, &plane->base);
> -	/* if not added to a list, it must be a private plane */
> -	if (!list_empty(&plane->head)) {
> -		list_del(&plane->head);
> -	        dev->mode_config.num_total_plane--;
> -		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
> -			dev->mode_config.num_overlay_plane--;
> -	}
> +
> +	BUG_ON(list_empty(&plane->head));
> +
> +	list_del(&plane->head);
> +	dev->mode_config.num_total_plane--;
> +	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
> +		dev->mode_config.num_overlay_plane--;
>  	drm_modeset_unlock_all(dev);
>  }
>  EXPORT_SYMBOL(drm_plane_cleanup);
> @@ -1388,6 +1393,21 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
>  	return 0;
>  }
>  
> +static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
> +{
> +	struct drm_property *type;
> +
> +	/*
> +	 * Standard properties (apply to all planes)
> +	 */
> +	type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
> +					"TYPE", drm_plane_type_enum_list,
> +					ARRAY_SIZE(drm_plane_type_enum_list));
> +	dev->mode_config.plane_type_property = type;
> +
> +	return 0;
> +}
> +
>  /**
>   * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
>   * @dev: DRM device
> @@ -4744,6 +4764,7 @@ void drm_mode_config_init(struct drm_device *dev)
>  
>  	drm_modeset_lock_all(dev);
>  	drm_mode_create_standard_connector_properties(dev);
> +	drm_mode_create_standard_plane_properties(dev);
>  	drm_modeset_unlock_all(dev);
>  
>  	/* Just to be sure */
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> index fcb0652..7943dd3 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> @@ -263,14 +263,16 @@ struct drm_plane *exynos_plane_init(struct drm_device *dev,
>  {
>  	struct exynos_plane *exynos_plane;
>  	int err;
> +	enum drm_plane_type type;
>  
>  	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
>  	if (!exynos_plane)
>  		return NULL;
>  
> +	type = priv ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
>  	err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
>  			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
> -			      priv);
> +			      type);
>  	if (err) {
>  		DRM_ERROR("failed to initialize plane\n");
>  		kfree(exynos_plane);
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 336ae6c..630485c 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -1145,7 +1145,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
>  	ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
>  			     &intel_plane_funcs,
>  			     plane_formats, num_plane_formats,
> -			     false);
> +			     DRM_PLANE_TYPE_OVERLAY);
>  	if (ret)
>  		kfree(intel_plane);
>  
> diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
> index 1e893dd..afa9c67 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
> @@ -222,6 +222,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
>  	struct drm_plane *plane = NULL;
>  	struct mdp4_plane *mdp4_plane;
>  	int ret;
> +	enum drm_plane_type type;
>  
>  	mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL);
>  	if (!mdp4_plane) {
> @@ -237,9 +238,10 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
>  	mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats,
>  			ARRAY_SIZE(mdp4_plane->formats));
>  
> +	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
>  	drm_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
>  			mdp4_plane->formats, mdp4_plane->nformats,
> -			private_plane);
> +			type);
>  
>  	mdp4_plane_install_properties(plane, &plane->base);
>  
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> index 0ac8bb5..651baac 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> @@ -357,6 +357,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
>  {
>  	struct drm_plane *plane = NULL;
>  	struct mdp5_plane *mdp5_plane;
> +	enum drm_plane_type type;
>  	int ret;
>  
>  	mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
> @@ -373,9 +374,10 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
>  	mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
>  			ARRAY_SIZE(mdp5_plane->formats));
>  
> +	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
>  	drm_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
>  			mdp5_plane->formats, mdp5_plane->nformats,
> -			private_plane);
> +			type);
>  
>  	mdp5_plane_install_properties(plane, &plane->base);
>  
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
> index ab03f77..0b4f35d 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
> @@ -276,7 +276,7 @@ nv10_overlay_init(struct drm_device *device)
>  
>  	ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */,
>  			     &nv10_plane_funcs,
> -			     formats, num_formats, false);
> +			     formats, num_formats, DRM_PLANE_TYPE_OVERLAY);
>  	if (ret)
>  		goto err;
>  
> @@ -456,7 +456,7 @@ nv04_overlay_init(struct drm_device *device)
>  
>  	ret = drm_plane_init(device, &plane->base, 1 /* single crtc */,
>  			     &nv04_plane_funcs,
> -			     formats, 2, false);
> +			     formats, 2, DRM_PLANE_TYPE_OVERLAY);
>  	if (ret)
>  		goto err;
>  
> diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
> index 046d5e6..d4179b2 100644
> --- a/drivers/gpu/drm/omapdrm/omap_plane.c
> +++ b/drivers/gpu/drm/omapdrm/omap_plane.c
> @@ -384,6 +384,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
>  	struct omap_plane *omap_plane;
>  	struct omap_overlay_info *info;
>  	int ret;
> +	enum drm_plane_type type;
>  
>  	DBG("%s: priv=%d", plane_names[id], private_plane);
>  
> @@ -413,8 +414,9 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
>  	omap_plane->error_irq.irq = omap_plane_error_irq;
>  	omap_irq_register(dev, &omap_plane->error_irq);
>  
> +	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
>  	drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs,
> -			omap_plane->formats, omap_plane->nformats, private_plane);
> +			omap_plane->formats, omap_plane->nformats, type);
>  
>  	omap_plane_install_properties(plane, &plane->base);
>  
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
> index 3fb69d9..27f1531 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
> @@ -499,7 +499,8 @@ int rcar_du_planes_register(struct rcar_du_group *rgrp)
>  
>  		ret = drm_plane_init(rcdu->ddev, &plane->plane, crtcs,
>  				     &rcar_du_plane_funcs, formats,
> -				     ARRAY_SIZE(formats), false);
> +				     ARRAY_SIZE(formats),
> +				     DRM_PLANE_TYPE_OVERLAY);
>  		if (ret < 0)
>  			return ret;
>  
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
> index 060ae03..2b03fff 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
> @@ -257,7 +257,7 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
>  
>  	ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
>  			     &shmob_drm_plane_funcs, formats,
> -			     ARRAY_SIZE(formats), false);
> +			     ARRAY_SIZE(formats), DRM_PLANE_TYPE_OVERLAY);
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
> index 9336006..76e5b22 100644
> --- a/drivers/gpu/drm/tegra/dc.c
> +++ b/drivers/gpu/drm/tegra/dc.c
> @@ -137,7 +137,8 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
>  
>  		err = drm_plane_init(drm, &plane->base, 1 << dc->pipe,
>  				     &tegra_plane_funcs, plane_formats,
> -				     ARRAY_SIZE(plane_formats), false);
> +				     ARRAY_SIZE(plane_formats),
> +				     DRM_PLANE_TYPE_OVERLAY);
>  		if (err < 0) {
>  			kfree(plane);
>  			return err;
> diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
> index 34b642a..7975369 100644
> --- a/drivers/staging/imx-drm/ipuv3-plane.c
> +++ b/drivers/staging/imx-drm/ipuv3-plane.c
> @@ -355,6 +355,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
>  {
>  	struct ipu_plane *ipu_plane;
>  	int ret;
> +	enum drm_plane_type type;
>  
>  	DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
>  		      dma, dp, possible_crtcs);
> @@ -369,10 +370,11 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
>  	ipu_plane->dma = dma;
>  	ipu_plane->dp_flow = dp;
>  
> +	type = priv ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
>  	ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
>  			     &ipu_plane_funcs, ipu_plane_formats,
>  			     ARRAY_SIZE(ipu_plane_formats),
> -			     priv);
> +			     type);
>  	if (ret) {
>  		DRM_ERROR("failed to initialize plane\n");
>  		kfree(ipu_plane);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index f43fa92..74f4943 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -852,6 +852,7 @@ struct drm_mode_config {
>  	struct list_head property_blob_list;
>  	struct drm_property *edid_property;
>  	struct drm_property *dpms_property;
> +	struct drm_property *plane_type_property;
>  
>  	/* DVI-I properties */
>  	struct drm_property *dvi_i_subconnector_property;
> @@ -960,7 +961,7 @@ extern int drm_plane_init(struct drm_device *dev,
>  			  unsigned long possible_crtcs,
>  			  const struct drm_plane_funcs *funcs,
>  			  const uint32_t *formats, uint32_t format_count,
> -			  bool priv);
> +			  enum drm_plane_type type);
>  extern void drm_plane_cleanup(struct drm_plane *plane);
>  extern void drm_plane_force_disable(struct drm_plane *plane);
>  
> -- 
> 1.8.5.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2)
  2014-03-19  0:22 ` [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2) Matt Roper
@ 2014-03-19 11:41   ` Daniel Vetter
  2014-03-20  5:43   ` Inki Dae
  1 sibling, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 11:41 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:52PM -0700, Matt Roper wrote:
> Add primary plane as a parameter to drm_crtc_init() and update all
> existing DRM drivers to use a helper-provided primary plane.
> 
> v2: Update msm & omap drivers to use existing "private" planes as primary
>     planes instead of helper  [Rob Clark]
> 
> Tested-by: Rob Clark <robdclark@gmail.com>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Again massive pile of changes all over drivers. I think we need to have
again two functions to pull this off and let drivers transition at their
own pace. For this I'd suggest

1) Do a s/drm_crtc_init/drm_legacy_crtc_init/ sed job over the entire
tree, get this patch merged into drm-next this week for 3.15. This will
cause some major havoc with the imx staging changes, so maybe do that
patch on top of linux-next and merge it shortly before -rc1. We need to
coordinate with Dave Airlie about this.

Plan be would be to add a new drm_brave_new_world_crtc_init, and I just
can't come up with a good name. Maybe drm_universal_planes_crtc_init or
something like that. Ugly in any case.

I think good naming suggestings here would be awesome, since it would
allow us to avoid the big flag-day patch above.

2) Add sensible default behaviour to drm_crtc_init/drm_legacy_crtc_init,
which allows drivers to transition to explicit primary planes at easy.

3) Transition drivers, but only where needed.

I didn't really spot anything in the patch itself.

Cheers, Daniel

> ---
>  drivers/gpu/drm/armada/armada_crtc.c       | 4 +++-
>  drivers/gpu/drm/ast/ast_mode.c             | 4 +++-
>  drivers/gpu/drm/bochs/bochs_kms.c          | 4 +++-
>  drivers/gpu/drm/cirrus/cirrus_mode.c       | 4 +++-
>  drivers/gpu/drm/drm_crtc.c                 | 9 ++++++++-
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c   | 4 +++-
>  drivers/gpu/drm/gma500/psb_intel_display.c | 4 +++-
>  drivers/gpu/drm/i915/intel_display.c       | 4 +++-
>  drivers/gpu/drm/mgag200/mgag200_mode.c     | 4 +++-
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c   | 5 ++++-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c   | 5 ++++-
>  drivers/gpu/drm/nouveau/dispnv04/crtc.c    | 4 +++-
>  drivers/gpu/drm/nouveau/nv50_display.c     | 4 +++-
>  drivers/gpu/drm/omapdrm/omap_crtc.c        | 2 +-
>  drivers/gpu/drm/qxl/qxl_display.c          | 4 +++-
>  drivers/gpu/drm/radeon/radeon_display.c    | 4 +++-
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c     | 4 +++-
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c  | 3 ++-
>  drivers/gpu/drm/tegra/dc.c                 | 4 +++-
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c       | 4 +++-
>  drivers/gpu/drm/udl/udl_modeset.c          | 4 +++-
>  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        | 4 +++-
>  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       | 4 +++-
>  drivers/staging/imx-drm/imx-drm-core.c     | 4 +++-
>  include/drm/drm_crtc.h                     | 5 +++++
>  25 files changed, 81 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
> index d8e3982..0a14d24 100644
> --- a/drivers/gpu/drm/armada/armada_crtc.c
> +++ b/drivers/gpu/drm/armada/armada_crtc.c
> @@ -1030,6 +1030,7 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
>  {
>  	struct armada_private *priv = dev->dev_private;
>  	struct armada_crtc *dcrtc;
> +	struct drm_plane *primary;
>  	void __iomem *base;
>  	int ret;
>  
> @@ -1086,7 +1087,8 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
>  
>  	priv->dcrtc[dcrtc->num] = dcrtc;
>  
> -	drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &dcrtc->crtc, primary, &armada_crtc_funcs);
>  	drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
>  
>  	drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> index cca063b..44f0d32 100644
> --- a/drivers/gpu/drm/ast/ast_mode.c
> +++ b/drivers/gpu/drm/ast/ast_mode.c
> @@ -626,13 +626,15 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
>  static int ast_crtc_init(struct drm_device *dev)
>  {
>  	struct ast_crtc *crtc;
> +	struct drm_plane *primary;
>  	int i;
>  
>  	crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
>  	if (!crtc)
>  		return -ENOMEM;
>  
> -	drm_crtc_init(dev, &crtc->base, &ast_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &crtc->base, primary, &ast_crtc_funcs);
>  	drm_mode_crtc_set_gamma_size(&crtc->base, 256);
>  	drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs);
>  
> diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
> index 62ec7d4..182f5c9 100644
> --- a/drivers/gpu/drm/bochs/bochs_kms.c
> +++ b/drivers/gpu/drm/bochs/bochs_kms.c
> @@ -129,8 +129,10 @@ static void bochs_crtc_init(struct drm_device *dev)
>  {
>  	struct bochs_device *bochs = dev->dev_private;
>  	struct drm_crtc *crtc = &bochs->crtc;
> +	struct drm_plane *primary;
>  
> -	drm_crtc_init(dev, crtc, &bochs_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, crtc, primary, &bochs_crtc_funcs);
>  	drm_mode_crtc_set_gamma_size(crtc, 256);
>  	drm_crtc_helper_add(crtc, &bochs_helper_funcs);
>  }
> diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> index 530f78f..449246f 100644
> --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
> @@ -381,6 +381,7 @@ static void cirrus_crtc_init(struct drm_device *dev)
>  {
>  	struct cirrus_device *cdev = dev->dev_private;
>  	struct cirrus_crtc *cirrus_crtc;
> +	struct drm_plane *primary;
>  	int i;
>  
>  	cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
> @@ -390,7 +391,8 @@ static void cirrus_crtc_init(struct drm_device *dev)
>  	if (cirrus_crtc == NULL)
>  		return;
>  
> -	drm_crtc_init(dev, &cirrus_crtc->base, &cirrus_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &cirrus_crtc->base, primary, &cirrus_crtc_funcs);
>  
>  	drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
>  	cdev->mode_info.crtc = cirrus_crtc;
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 8e869d6..0feb66cc 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -697,6 +697,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
>   * drm_crtc_init - Initialise a new CRTC object
>   * @dev: DRM device
>   * @crtc: CRTC object to init
> + * @primary: Primary plane for CRTC
>   * @funcs: callbacks for the new CRTC
>   *
>   * Inits a new object created as base part of a driver crtc object.
> @@ -705,7 +706,8 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
>   * Zero on success, error code on failure.
>   */
>  int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
> -		   const struct drm_crtc_funcs *funcs)
> +		  struct drm_plane *primary,
> +		  const struct drm_crtc_funcs *funcs)
>  {
>  	int ret;
>  
> @@ -726,6 +728,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
>  	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
>  	dev->mode_config.num_crtc++;
>  
> +	crtc->primary = primary;
> +	primary->possible_crtcs = 1 << drm_crtc_index(crtc);
> +
>   out:
>  	drm_modeset_unlock_all(dev);
>  
> @@ -2439,6 +2444,8 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>  
>  	ret = crtc->funcs->set_config(set);
>  	if (ret == 0) {
> +		crtc->primary->crtc = crtc;
> +
>  		/* crtc->fb must be updated by ->set_config, enforces this. */
>  		WARN_ON(fb != crtc->fb);
>  	}
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> index 6f3400f..507abd5 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> @@ -323,6 +323,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
>  	struct exynos_drm_crtc *exynos_crtc;
>  	struct exynos_drm_private *private = dev->dev_private;
>  	struct drm_crtc *crtc;
> +	struct drm_plane *primary;
>  
>  	exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
>  	if (!exynos_crtc)
> @@ -342,7 +343,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
>  
>  	private->crtc[nr] = crtc;
>  
> -	drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, crtc, primary, &exynos_crtc_funcs);
>  	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
>  
>  	exynos_drm_crtc_attach_mode_property(crtc);
> diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
> index c8841ac..c8f833d 100644
> --- a/drivers/gpu/drm/gma500/psb_intel_display.c
> +++ b/drivers/gpu/drm/gma500/psb_intel_display.c
> @@ -491,6 +491,7 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
>  {
>  	struct drm_psb_private *dev_priv = dev->dev_private;
>  	struct gma_crtc *gma_crtc;
> +	struct drm_plane *primary;
>  	int i;
>  	uint16_t *r_base, *g_base, *b_base;
>  
> @@ -511,7 +512,8 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
>  	}
>  
>  	/* Set the CRTC operations from the chip specific data */
> -	drm_crtc_init(dev, &gma_crtc->base, dev_priv->ops->crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &gma_crtc->base, primary, dev_priv->ops->crtc_funcs);
>  
>  	/* Set the CRTC clock functions from chip specific data */
>  	gma_crtc->clock_funcs = dev_priv->ops->clock_funcs;
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 048052a..21d12a9 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10586,13 +10586,15 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>  {
>  	drm_i915_private_t *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc;
> +	struct drm_plane *primary;
>  	int i;
>  
>  	intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
>  	if (intel_crtc == NULL)
>  		return;
>  
> -	drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
>  
>  	drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
>  	for (i = 0; i < 256; i++) {
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index 9683747..1418414 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> @@ -1314,6 +1314,7 @@ static const struct drm_crtc_helper_funcs mga_helper_funcs = {
>  static void mga_crtc_init(struct mga_device *mdev)
>  {
>  	struct mga_crtc *mga_crtc;
> +	struct drm_plane *primary;
>  	int i;
>  
>  	mga_crtc = kzalloc(sizeof(struct mga_crtc) +
> @@ -1323,7 +1324,8 @@ static void mga_crtc_init(struct mga_device *mdev)
>  	if (mga_crtc == NULL)
>  		return;
>  
> -	drm_crtc_init(mdev->dev, &mga_crtc->base, &mga_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(mdev->dev);
> +	drm_crtc_init(mdev->dev, &mga_crtc->base, primary, &mga_crtc_funcs);
>  
>  	drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE);
>  	mdev->mode_info.crtc = mga_crtc;
> diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> index 84c5b13..b10f681 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> @@ -740,6 +740,9 @@ void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
>  
>  void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
>  {
> +	/* don't actually detatch our primary plane: */
> +	if (to_mdp4_crtc(crtc)->plane == plane)
> +		return;
>  	set_attach(crtc, mdp4_plane_pipe(plane), NULL);
>  }
>  
> @@ -791,7 +794,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
>  
>  	INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb);
>  
> -	drm_crtc_init(dev, crtc, &mdp4_crtc_funcs);
> +	drm_crtc_init(dev, crtc, plane, &mdp4_crtc_funcs);
>  	drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
>  
>  	mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base);
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> index f279402..7dc3d71 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> @@ -524,6 +524,9 @@ void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
>  
>  void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
>  {
> +	/* don't actually detatch our primary plane: */
> +	if (to_mdp5_crtc(crtc)->plane == plane)
> +		return;
>  	set_attach(crtc, mdp5_plane_pipe(plane), NULL);
>  }
>  
> @@ -559,7 +562,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
>  
>  	INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb);
>  
> -	drm_crtc_init(dev, crtc, &mdp5_crtc_funcs);
> +	drm_crtc_init(dev, crtc, plane, &mdp5_crtc_funcs);
>  	drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
>  
>  	mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base);
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> index 0e3270c..b55be84 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> @@ -1106,6 +1106,7 @@ int
>  nv04_crtc_create(struct drm_device *dev, int crtc_num)
>  {
>  	struct nouveau_crtc *nv_crtc;
> +	struct drm_plane *primary;
>  	int ret, i;
>  
>  	nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
> @@ -1122,7 +1123,8 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
>  	nv_crtc->index = crtc_num;
>  	nv_crtc->last_dpms = NV_DPMS_CLEARED;
>  
> -	drm_crtc_init(dev, &nv_crtc->base, &nv04_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &nv_crtc->base, primary, &nv04_crtc_funcs);
>  	drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs);
>  	drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
>  
> diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> index 2dccafc..5706842 100644
> --- a/drivers/gpu/drm/nouveau/nv50_display.c
> +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> @@ -1348,6 +1348,7 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
>  	struct nv50_disp *disp = nv50_disp(dev);
>  	struct nv50_head *head;
>  	struct drm_crtc *crtc;
> +	struct drm_plane *primary;
>  	int ret, i;
>  
>  	head = kzalloc(sizeof(*head), GFP_KERNEL);
> @@ -1369,7 +1370,8 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
>  	}
>  
>  	crtc = &head->base.base;
> -	drm_crtc_init(dev, crtc, &nv50_crtc_func);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, crtc, primary, &nv50_crtc_func);
>  	drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
>  	drm_mode_crtc_set_gamma_size(crtc, 256);
>  
> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index 4313bb0..fdf9dc0 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -677,7 +677,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
>  	info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
>  	info->trans_enabled = false;
>  
> -	drm_crtc_init(dev, crtc, &omap_crtc_funcs);
> +	drm_crtc_init(dev, crtc, plane, &omap_crtc_funcs);
>  	drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
>  
>  	omap_plane_install_properties(omap_crtc->plane, &crtc->base);
> diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> index 798bde2..24b6112 100644
> --- a/drivers/gpu/drm/qxl/qxl_display.c
> +++ b/drivers/gpu/drm/qxl/qxl_display.c
> @@ -636,12 +636,14 @@ static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
>  static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
>  {
>  	struct qxl_crtc *qxl_crtc;
> +	struct drm_plane *primary;
>  
>  	qxl_crtc = kzalloc(sizeof(struct qxl_crtc), GFP_KERNEL);
>  	if (!qxl_crtc)
>  		return -ENOMEM;
>  
> -	drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &qxl_crtc->base, primary, &qxl_crtc_funcs);
>  	qxl_crtc->index = crtc_id;
>  	drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256);
>  	drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> index fbd8b93..a29d217 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -552,13 +552,15 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
>  {
>  	struct radeon_device *rdev = dev->dev_private;
>  	struct radeon_crtc *radeon_crtc;
> +	struct drm_plane *primary;
>  	int i;
>  
>  	radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
>  	if (radeon_crtc == NULL)
>  		return;
>  
> -	drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, &radeon_crtc->base, primary, &radeon_crtc_funcs);
>  
>  	drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
>  	radeon_crtc->crtc_id = index;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index fbf4be3..151ffaa 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -540,6 +540,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
>  	struct platform_device *pdev = to_platform_device(rcdu->dev);
>  	struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
>  	struct drm_crtc *crtc = &rcrtc->crtc;
> +	struct drm_plane *primary;
>  	unsigned int irqflags;
>  	char clk_name[5];
>  	char *name;
> @@ -568,7 +569,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
>  
>  	rcrtc->plane->crtc = crtc;
>  
> -	ret = drm_crtc_init(rcdu->ddev, crtc, &crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	ret = drm_crtc_init(rcdu->ddev, crtc, primary, &crtc_funcs);
>  	if (ret < 0)
>  		return ret;
>  
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> index 0428076..e806553 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -512,11 +512,12 @@ static const struct drm_crtc_funcs crtc_funcs = {
>  int shmob_drm_crtc_create(struct shmob_drm_device *sdev)
>  {
>  	struct drm_crtc *crtc = &sdev->crtc.crtc;
> +	struct drm_plane *primary;
>  	int ret;
>  
>  	sdev->crtc.dpms = DRM_MODE_DPMS_OFF;
>  
> -	ret = drm_crtc_init(sdev->ddev, crtc, &crtc_funcs);
> +	ret = drm_crtc_init(sdev->ddev, crtc, primary, &crtc_funcs);
>  	if (ret < 0)
>  		return ret;
>  
> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
> index 76e5b22..5e2ee9d 100644
> --- a/drivers/gpu/drm/tegra/dc.c
> +++ b/drivers/gpu/drm/tegra/dc.c
> @@ -1099,9 +1099,11 @@ static int tegra_dc_init(struct host1x_client *client)
>  {
>  	struct tegra_drm *tegra = dev_get_drvdata(client->parent);
>  	struct tegra_dc *dc = host1x_client_to_dc(client);
> +	struct drm_plane *primary;
>  	int err;
>  
> -	drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(tegra->drm, &dc->base, primary, &tegra_crtc_funcs);
>  	drm_mode_crtc_set_gamma_size(&dc->base, 256);
>  	drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
>  
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index d36efc1..310314c 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -651,6 +651,7 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
>  {
>  	struct tilcdc_crtc *tilcdc_crtc;
>  	struct drm_crtc *crtc;
> +	struct drm_plane *primary;
>  	int ret;
>  
>  	tilcdc_crtc = kzalloc(sizeof(*tilcdc_crtc), GFP_KERNEL);
> @@ -671,7 +672,8 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
>  		goto fail;
>  	}
>  
> -	ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	ret = drm_crtc_init(dev, crtc, primary, &tilcdc_crtc_funcs);
>  	if (ret < 0)
>  		goto fail;
>  
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index 2ae1eb7..1255944 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -389,12 +389,14 @@ static const struct drm_crtc_funcs udl_crtc_funcs = {
>  static int udl_crtc_init(struct drm_device *dev)
>  {
>  	struct drm_crtc *crtc;
> +	struct drm_plane *primary;
>  
>  	crtc = kzalloc(sizeof(struct drm_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
>  	if (crtc == NULL)
>  		return -ENOMEM;
>  
> -	drm_crtc_init(dev, crtc, &udl_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, crtc, primary, &udl_crtc_funcs);
>  	drm_crtc_helper_add(crtc, &udl_helper_funcs);
>  
>  	return 0;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> index a055a26..001ec81 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> @@ -343,6 +343,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
>  	struct drm_connector *connector;
>  	struct drm_encoder *encoder;
>  	struct drm_crtc *crtc;
> +	struct drm_plane *primary;
>  
>  	ldu = kzalloc(sizeof(*ldu), GFP_KERNEL);
>  	if (!ldu)
> @@ -373,7 +374,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
>  
>  	(void) drm_sysfs_connector_add(connector);
>  
> -	drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, crtc, primary, &vmw_legacy_crtc_funcs);
>  
>  	drm_mode_crtc_set_gamma_size(crtc, 256);
>  
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> index 22406c8..585da43 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> @@ -439,6 +439,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
>  	struct drm_connector *connector;
>  	struct drm_encoder *encoder;
>  	struct drm_crtc *crtc;
> +	struct drm_plane *primary;
>  
>  	sou = kzalloc(sizeof(*sou), GFP_KERNEL);
>  	if (!sou)
> @@ -469,7 +470,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
>  
>  	(void) drm_sysfs_connector_add(connector);
>  
> -	drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs);
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(dev, crtc, primary, &vmw_screen_object_crtc_funcs);
>  
>  	drm_mode_crtc_set_gamma_size(crtc, 256);
>  
> diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
> index 236ed66..8c7b1d3 100644
> --- a/drivers/staging/imx-drm/imx-drm-core.c
> +++ b/drivers/staging/imx-drm/imx-drm-core.c
> @@ -475,6 +475,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
>  {
>  	struct imx_drm_device *imxdrm = __imx_drm_device();
>  	struct imx_drm_crtc *imx_drm_crtc;
> +	struct drm_plane *primary;
>  	int ret;
>  
>  	mutex_lock(&imxdrm->mutex);
> @@ -520,7 +521,8 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
>  	drm_crtc_helper_add(crtc,
>  			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
>  
> -	drm_crtc_init(imxdrm->drm, crtc,
> +	primary = drm_primary_helper_create_plane(dev);
> +	drm_crtc_init(imxdrm->drm, crtc, primary,
>  			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
>  
>  	drm_mode_group_reinit(imxdrm->drm);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 74f4943..4dc84f8 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -270,6 +270,7 @@ struct drm_crtc_funcs {
>   * @dev: parent DRM device
>   * @head: list management
>   * @base: base KMS object for ID tracking etc.
> + * @primary: primary plane for this CRTC
>   * @enabled: is this CRTC enabled?
>   * @mode: current mode timings
>   * @hwmode: mode timings as programmed to hw regs
> @@ -305,6 +306,9 @@ struct drm_crtc {
>  
>  	struct drm_mode_object base;
>  
> +	/* primary plane for CRTC */
> +	struct drm_plane *primary;
> +
>  	/* framebuffer the connector is currently bound to */
>  	struct drm_framebuffer *fb;
>  
> @@ -907,6 +911,7 @@ extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
>  
>  extern int drm_crtc_init(struct drm_device *dev,
>  			 struct drm_crtc *crtc,
> +			 struct drm_plane *primary,
>  			 const struct drm_crtc_funcs *funcs);
>  extern void drm_crtc_cleanup(struct drm_crtc *crtc);
>  extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
> -- 
> 1.8.5.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19  0:22 ` [RFCv3 03/14] drm: Add primary plane helpers Matt Roper
  2014-03-19 11:28   ` Daniel Vetter
@ 2014-03-19 11:50   ` Daniel Vetter
  2014-03-19 12:24   ` Daniel Vetter
  2 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 11:50 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:48PM -0700, Matt Roper wrote:
> When we expose non-overlay planes to userspace, they will become
> accessible via standard userspace plane API's.  We should be able to
> handle the standard plane operations against primary planes in a generic
> way via the page flip handler and modeset handler.
> 
> Drivers that can program primary planes more efficiently, that want to
> use their own primary plane structure to track additional information,
> or that don't have the limitations assumed by the helpers are free to
> provide their own implementation of some or all of these handlers.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---

One more below ...

> +/**
> + * drm_primary_helper_disable() - Helper for primary plane disable
> + * @plane: plane to disable
> + *
> + * Provides a default plane disable handler for primary planes.  This is handler
> + * is called in response to a userspace SetPlane operation on the plane with a
> + * NULL framebuffer parameter.  We call the driver's modeset handler with a NULL
> + * framebuffer to disable the CRTC.
> + *
> + * Note that some hardware may be able to disable the primary plane without
> + * disabling the whole CRTC.  Drivers for such hardware should provide their
> + * own disable handler that disables just the primary plane (and they'll likely
> + * need to provide their own update handler as well to properly re-enable a
> + * disabled primary plane).
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_primary_helper_disable(struct drm_plane *plane)
> +{
> +	struct drm_mode_set set = {
> +		.crtc = plane->crtc,
> +		.fb = NULL,
> +	};
> +
> +	if (plane->crtc == NULL || plane->fb == NULL)
> +		/* Already disabled */
> +		return 0;

I think we should have a check here if any other plane is enabled
(including the cursor plane), and fail the plane disabling with -EBUSY.
Otherwise new userspace has no way to figure out whether the driver is
updated already or not.

> +
> +	return plane->crtc->funcs->set_config(&set);

Again I think you need to use set_config_internal to have correct fb
refcounting.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes
  2014-03-19  0:22 ` [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes Matt Roper
@ 2014-03-19 11:51   ` Daniel Vetter
  2014-03-19 14:26     ` Daniel Kurtz
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 11:51 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:49PM -0700, Matt Roper wrote:
> Before we add additional types of planes to the DRM plane list, ensure
> that existing loops over all planes continue to operate only on
> "overlay" planes and ignore primary & cursor planes.
> 
> Cc: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> index 06f1b2a..2fa2685 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> @@ -127,6 +127,9 @@ static void disable_plane_to_crtc(struct drm_device *dev,
>  	 * (encoder->crtc)
>  	 */
>  	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> +		if (plane->type != DRM_PLANE_TYPE_OVERLAY)

I think a drm_for_each_legacy_plane iteration helper would be neat for
this one and the following i915 patch.
-Daniel

> +			continue;
> +
>  		if (plane->crtc == old_crtc) {
>  			/*
>  			 * do not change below call order.
> @@ -247,6 +250,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
>  
>  	/* all planes connected to this encoder should be also disabled. */
>  	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> +		if (plane->type != DRM_PLANE_TYPE_OVERLAY)
> +			continue;
> +
>  		if (plane->crtc == encoder->crtc)
>  			plane->funcs->disable_plane(plane);
>  	}
> -- 
> 1.8.5.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2)
  2014-03-19  0:22 ` [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2) Matt Roper
@ 2014-03-19 11:57   ` Daniel Vetter
  2014-03-25  1:20     ` Matt Roper
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 11:57 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:53PM -0700, Matt Roper wrote:
> Now that CRTC's have a primary plane, there's no need to track the
> framebuffer in the CRTC.  Replace all references to the CRTC fb
> with the primary plane's fb.
> 
> Also note that this simplifies framebuffer removal slightly; we no
> longer need to scan all CRTC's and disable the ones that were using the
> framebuffer since the existing loop over all planes will take care
> of disabling the primary plane (and on most hardware, the CRTC by
> extension).
> 
> v2: Fixup several lingering crtc->fb instances that were missed in the
>     first patch iteration.
> 
> Tested-by: Rob Clark <robdclark@gmail.com>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Giant patch again, and I don't think there's any sane way we can avoid
this big sed job. Put I think we can make it less intrusive.

First: Have you looked into cocinelle to do this? I'm not sure whether
cocinelle is sufficiently type aware, but the upside of using it is that
it's much easier to regenerate the patch.

In any case I think we need to split this into the usual 3 phases to avoid
flag days:

1) Switch to crtc->primary->fb all over the core, but keep crtc->fb fully
functional. I.e. update it before calling into drivers and use that to
update crtc->primary->fb on return (e.g. in the pageflip ioctl).

2) Switch drivers over to look at crtc->primary->fb. This way we can even
split up the patch into per-driver patches which gives driver maintainers
more wiggle room.

3) Kill crtc->fb.

Steps 2&3 don't block merging of the universal planes support at all. So
we could get the core support in all early for 3.16, then let driver
maintainers pick up patche for 2 and shortly before the 3.16 merge window
opens send a pull request with all the stragglers and step 3.

No comments on the actual patch, the few functional changes hidden in the
massive diff looked ok. But hard to review properly ;-)

Cheers, Daniel

> ---
>  drivers/gpu/drm/ast/ast_mode.c               |  12 +--
>  drivers/gpu/drm/bochs/bochs_kms.c            |   4 +-
>  drivers/gpu/drm/cirrus/cirrus_mode.c         |  10 +-
>  drivers/gpu/drm/drm_crtc.c                   |  56 ++++------
>  drivers/gpu/drm/drm_crtc_helper.c            |  21 ++--
>  drivers/gpu/drm/drm_fb_helper.c              |   6 +-
>  drivers/gpu/drm/gma500/cdv_intel_display.c   |   2 +-
>  drivers/gpu/drm/gma500/cdv_intel_dp.c        |   2 +-
>  drivers/gpu/drm/gma500/cdv_intel_hdmi.c      |   3 +-
>  drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
>  drivers/gpu/drm/gma500/gma_display.c         |  17 ++--
>  drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
>  drivers/gpu/drm/gma500/mdfld_intel_display.c |  17 ++--
>  drivers/gpu/drm/gma500/oaktrail_crtc.c       |  13 +--
>  drivers/gpu/drm/gma500/psb_intel_display.c   |   2 +-
>  drivers/gpu/drm/gma500/psb_intel_lvds.c      |   2 +-
>  drivers/gpu/drm/gma500/psb_intel_sdvo.c      |   2 +-
>  drivers/gpu/drm/i915/i915_debugfs.c          |   4 +-
>  drivers/gpu/drm/i915/i915_irq.c              |   4 +-
>  drivers/gpu/drm/i915/intel_display.c         | 147 ++++++++++++++-------------
>  drivers/gpu/drm/i915/intel_dp.c              |   5 +-
>  drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
>  drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
>  drivers/gpu/drm/i915/intel_pm.c              |  36 +++----
>  drivers/gpu/drm/mgag200/mgag200_mode.c       |  28 ++---
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  28 ++---
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  22 ++--
>  drivers/gpu/drm/nouveau/dispnv04/crtc.c      |  20 ++--
>  drivers/gpu/drm/nouveau/dispnv04/dfp.c       |   2 +-
>  drivers/gpu/drm/nouveau/nouveau_display.c    |   8 +-
>  drivers/gpu/drm/nouveau/nv50_display.c       |  17 ++--
>  drivers/gpu/drm/qxl/qxl_display.c            |  11 +-
>  drivers/gpu/drm/radeon/atombios_crtc.c       |  20 ++--
>  drivers/gpu/drm/radeon/r100.c                |   4 +-
>  drivers/gpu/drm/radeon/radeon_connectors.c   |   2 +-
>  drivers/gpu/drm/radeon/radeon_device.c       |   3 +-
>  drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
>  drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +--
>  drivers/gpu/drm/udl/udl_modeset.c            |   2 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_kms.c          |  14 +--
>  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c          |   8 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c         |   8 +-
>  include/drm/drm_crtc.h                       |   3 -
>  43 files changed, 300 insertions(+), 299 deletions(-)
> 
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> index 44f0d32..bd1e156 100644
> --- a/drivers/gpu/drm/ast/ast_mode.c
> +++ b/drivers/gpu/drm/ast/ast_mode.c
> @@ -81,7 +81,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
>  	u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
>  	u32 hborder, vborder;
>  
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
>  		color_index = VGAModeIndex - 1;
> @@ -176,7 +176,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
>  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
>  
>  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
> -		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
> +		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
>  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
>  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
>  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
> @@ -340,7 +340,7 @@ static void ast_set_offset_reg(struct drm_crtc *crtc)
>  
>  	u16 offset;
>  
> -	offset = crtc->fb->pitches[0] >> 3;
> +	offset = crtc->primary->fb->pitches[0] >> 3;
>  	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
>  	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
>  }
> @@ -365,7 +365,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
>  	struct ast_private *ast = crtc->dev->dev_private;
>  	u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
>  
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		jregA0 = 0x70;
>  		jregA3 = 0x01;
> @@ -418,7 +418,7 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo
>  static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
>  		     struct ast_vbios_mode_info *vbios_mode)
>  {
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		break;
>  	default:
> @@ -490,7 +490,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
>  		ast_bo_unreserve(bo);
>  	}
>  
> -	ast_fb = to_ast_framebuffer(crtc->fb);
> +	ast_fb = to_ast_framebuffer(crtc->primary->fb);
>  	obj = ast_fb->obj;
>  	bo = gem_to_ast_bo(obj);
>  
> diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
> index 182f5c9..b67ad12 100644
> --- a/drivers/gpu/drm/bochs/bochs_kms.c
> +++ b/drivers/gpu/drm/bochs/bochs_kms.c
> @@ -62,10 +62,10 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  		}
>  	}
>  
> -	if (WARN_ON(crtc->fb == NULL))
> +	if (WARN_ON(crtc->primary->fb == NULL))
>  		return -EINVAL;
>  
> -	bochs_fb = to_bochs_framebuffer(crtc->fb);
> +	bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
>  	bo = gem_to_bochs_bo(bochs_fb->obj);
>  	ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
>  	if (ret)
> diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> index 449246f..5291d2f 100644
> --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
> @@ -149,7 +149,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
>  		cirrus_bo_unreserve(bo);
>  	}
>  
> -	cirrus_fb = to_cirrus_framebuffer(crtc->fb);
> +	cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb);
>  	obj = cirrus_fb->obj;
>  	bo = gem_to_cirrus_bo(obj);
>  
> @@ -268,7 +268,7 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
>  	sr07 = RREG8(SEQ_DATA);
>  	sr07 &= 0xe0;
>  	hdr = 0;
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		sr07 |= 0x11;
>  		break;
> @@ -291,13 +291,13 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
>  	WREG_SEQ(0x7, sr07);
>  
>  	/* Program the pitch */
> -	tmp = crtc->fb->pitches[0] / 8;
> +	tmp = crtc->primary->fb->pitches[0] / 8;
>  	WREG_CRT(VGA_CRTC_OFFSET, tmp);
>  
>  	/* Enable extended blanking and pitch bits, and enable full memory */
>  	tmp = 0x22;
> -	tmp |= (crtc->fb->pitches[0] >> 7) & 0x10;
> -	tmp |= (crtc->fb->pitches[0] >> 6) & 0x40;
> +	tmp |= (crtc->primary->fb->pitches[0] >> 7) & 0x10;
> +	tmp |= (crtc->primary->fb->pitches[0] >> 6) & 0x40;
>  	WREG_CRT(0x1b, tmp);
>  
>  	/* Enable high-colour modes */
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 0feb66cc..0c395e8 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -634,7 +634,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
>   * drm_framebuffer_remove - remove and unreference a framebuffer object
>   * @fb: framebuffer to remove
>   *
> - * Scans all the CRTCs and planes in @dev's mode_config.  If they're
> + * Scans all the planes in @dev's mode_config.  If they're
>   * using @fb, removes it, setting it to NULL. Then drops the reference to the
>   * passed-in framebuffer. Might take the modeset locks.
>   *
> @@ -645,10 +645,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
>  void drm_framebuffer_remove(struct drm_framebuffer *fb)
>  {
>  	struct drm_device *dev = fb->dev;
> -	struct drm_crtc *crtc;
>  	struct drm_plane *plane;
> -	struct drm_mode_set set;
> -	int ret;
>  
>  	WARN_ON(!list_empty(&fb->filp_head));
>  
> @@ -669,19 +666,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
>  	 */
>  	if (atomic_read(&fb->refcount.refcount) > 1) {
>  		drm_modeset_lock_all(dev);
> -		/* remove from any CRTC */
> -		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> -			if (crtc->fb == fb) {
> -				/* should turn off the crtc */
> -				memset(&set, 0, sizeof(struct drm_mode_set));
> -				set.crtc = crtc;
> -				set.fb = NULL;
> -				ret = drm_mode_set_config_internal(&set);
> -				if (ret)
> -					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
> -			}
> -		}
> -
> +		/* remove from any plane */
>  		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
>  			if (plane->fb == fb)
>  				drm_plane_force_disable(plane);
> @@ -1930,8 +1915,8 @@ int drm_mode_getcrtc(struct drm_device *dev,
>  	crtc_resp->x = crtc->x;
>  	crtc_resp->y = crtc->y;
>  	crtc_resp->gamma_size = crtc->gamma_size;
> -	if (crtc->fb)
> -		crtc_resp->fb_id = crtc->fb->base.id;
> +	if (crtc->primary->fb)
> +		crtc_resp->fb_id = crtc->primary->fb->base.id;
>  	else
>  		crtc_resp->fb_id = 0;
>  
> @@ -2438,7 +2423,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>  	 * crtcs. Atomic modeset will have saner semantics ...
>  	 */
>  	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
> -		tmp->old_fb = tmp->fb;
> +		tmp->old_fb = tmp->primary->fb;
>  
>  	fb = set->fb;
>  
> @@ -2446,13 +2431,16 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>  	if (ret == 0) {
>  		crtc->primary->crtc = crtc;
>  
> -		/* crtc->fb must be updated by ->set_config, enforces this. */
> -		WARN_ON(fb != crtc->fb);
> +		/*
> +		 * crtc->primary->fb must be updated by ->set_config,
> +		 * enforces this.
> +		 */
> +		WARN_ON(fb != crtc->primary->fb);
>  	}
>  
>  	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
> -		if (tmp->fb)
> -			drm_framebuffer_reference(tmp->fb);
> +		if (tmp->primary->fb)
> +			drm_framebuffer_reference(tmp->primary->fb);
>  		if (tmp->old_fb)
>  			drm_framebuffer_unreference(tmp->old_fb);
>  	}
> @@ -2511,12 +2499,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
>  		/* If we have a mode we need a framebuffer. */
>  		/* If we pass -1, set the mode with the currently bound fb */
>  		if (crtc_req->fb_id == -1) {
> -			if (!crtc->fb) {
> +			if (!crtc->primary->fb) {
>  				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
>  				ret = -EINVAL;
>  				goto out;
>  			}
> -			fb = crtc->fb;
> +			fb = crtc->primary->fb;
>  			/* Make refcounting symmetric with the lookup path. */
>  			drm_framebuffer_reference(fb);
>  		} else {
> @@ -4309,7 +4297,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  	crtc = obj_to_crtc(obj);
>  
>  	mutex_lock(&crtc->mutex);
> -	if (crtc->fb == NULL) {
> +	if (crtc->primary->fb == NULL) {
>  		/* The framebuffer is currently unbound, presumably
>  		 * due to a hotplug event, that userspace has not
>  		 * yet discovered.
> @@ -4331,7 +4319,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  	if (ret)
>  		goto out;
>  
> -	if (crtc->fb->pixel_format != fb->pixel_format) {
> +	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
>  		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
>  		ret = -EINVAL;
>  		goto out;
> @@ -4364,7 +4352,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  			(void (*) (struct drm_pending_event *)) kfree;
>  	}
>  
> -	old_fb = crtc->fb;
> +	old_fb = crtc->primary->fb;
>  	ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
>  	if (ret) {
>  		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
> @@ -4377,12 +4365,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  		old_fb = NULL;
>  	} else {
>  		/*
> -		 * Warn if the driver hasn't properly updated the crtc->fb
> -		 * field to reflect that the new framebuffer is now used.
> -		 * Failing to do so will screw with the reference counting
> -		 * on framebuffers.
> +		 * Warn if the driver hasn't properly updated the
> +		 * crtc->primary->fb field to reflect that the new framebuffer
> +		 * is now used.  Failing to do so will screw with the reference
> +		 * counting on framebuffers.
>  		 */
> -		WARN_ON(crtc->fb != fb);
> +		WARN_ON(crtc->primary->fb != fb);
>  		/* Unref only the old framebuffer. */
>  		fb = NULL;
>  	}
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index a855178..8825afb 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -319,7 +319,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
>  				(*crtc_funcs->disable)(crtc);
>  			else
>  				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
> -			crtc->fb = NULL;
> +			crtc->primary->fb = NULL;
>  		}
>  	}
>  }
> @@ -646,19 +646,19 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
>  	save_set.mode = &set->crtc->mode;
>  	save_set.x = set->crtc->x;
>  	save_set.y = set->crtc->y;
> -	save_set.fb = set->crtc->fb;
> +	save_set.fb = set->crtc->primary->fb;
>  
>  	/* We should be able to check here if the fb has the same properties
>  	 * and then just flip_or_move it */
> -	if (set->crtc->fb != set->fb) {
> +	if (set->crtc->primary->fb != set->fb) {
>  		/* If we have no fb then treat it as a full mode set */
> -		if (set->crtc->fb == NULL) {
> +		if (set->crtc->primary->fb == NULL) {
>  			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
>  			mode_changed = true;
>  		} else if (set->fb == NULL) {
>  			mode_changed = true;
>  		} else if (set->fb->pixel_format !=
> -			   set->crtc->fb->pixel_format) {
> +			   set->crtc->primary->fb->pixel_format) {
>  			mode_changed = true;
>  		} else
>  			fb_changed = true;
> @@ -759,13 +759,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
>  			DRM_DEBUG_KMS("attempting to set mode from"
>  					" userspace\n");
>  			drm_mode_debug_printmodeline(set->mode);
> -			set->crtc->fb = set->fb;
> +			set->crtc->primary->fb = set->fb;
>  			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
>  						      set->x, set->y,
>  						      save_set.fb)) {
>  				DRM_ERROR("failed to set mode on [CRTC:%d]\n",
>  					  set->crtc->base.id);
> -				set->crtc->fb = save_set.fb;
> +				set->crtc->primary->fb = save_set.fb;
>  				ret = -EINVAL;
>  				goto fail;
>  			}
> @@ -780,13 +780,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
>  	} else if (fb_changed) {
>  		set->crtc->x = set->x;
>  		set->crtc->y = set->y;
> -		set->crtc->fb = set->fb;
> +		set->crtc->primary->fb = set->fb;
>  		ret = crtc_funcs->mode_set_base(set->crtc,
>  						set->x, set->y, save_set.fb);
>  		if (ret != 0) {
>  			set->crtc->x = save_set.x;
>  			set->crtc->y = save_set.y;
> -			set->crtc->fb = save_set.fb;
> +			set->crtc->primary->fb = save_set.fb;
>  			goto fail;
>  		}
>  	}
> @@ -982,7 +982,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
>  			continue;
>  
>  		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
> -					       crtc->x, crtc->y, crtc->fb);
> +					       crtc->x, crtc->y,
> +					       crtc->primary->fb);
>  
>  		/* Restoring the old config should never fail! */
>  		if (ret == false)
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 9c6251f..e8e2b41 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -232,7 +232,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
>  
>  	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
>  		if (crtc->base.id == c->base.id)
> -			return c->fb;
> +			return c->primary->fb;
>  	}
>  
>  	return NULL;
> @@ -366,9 +366,9 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
>  		return false;
>  
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> -		if (crtc->fb)
> +		if (crtc->primary->fb)
>  			crtcs_bound++;
> -		if (crtc->fb == fb_helper->fb)
> +		if (crtc->primary->fb == fb_helper->fb)
>  			bound++;
>  	}
>  
> diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
> index 8fbfa06..1cddcf8 100644
> --- a/drivers/gpu/drm/gma500/cdv_intel_display.c
> +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
> @@ -463,7 +463,7 @@ static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe)
>  	crtc = dev_priv->pipe_to_crtc_mapping[pipe];
>  	gma_crtc = to_gma_crtc(crtc);
>  
> -	if (crtc->fb == NULL || !gma_crtc->active)
> +	if (crtc->primary->fb == NULL || !gma_crtc->active)
>  		return false;
>  	return true;
>  }
> diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
> index 0490ce3..9ff30c2 100644
> --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
> +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
> @@ -1693,7 +1693,7 @@ done:
>  		struct drm_crtc *crtc = encoder->base.crtc;
>  		drm_crtc_helper_set_mode(crtc, &crtc->mode,
>  					 crtc->x, crtc->y,
> -					 crtc->fb);
> +					 crtc->primary->fb);
>  	}
>  
>  	return 0;
> diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> index 1c0d723..04956e6 100644
> --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> @@ -199,7 +199,8 @@ static int cdv_hdmi_set_property(struct drm_connector *connector,
>  		    crtc->saved_mode.vdisplay != 0) {
>  			if (centre) {
>  				if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
> -					    encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb))
> +					    encoder->crtc->x, encoder->crtc->y,
> +					    encoder->crtc->primary->fb))
>  					return -1;
>  			} else {
>  				struct drm_encoder_helper_funcs *helpers
> diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> index 20e08e6..58f11df 100644
> --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> @@ -494,7 +494,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
>  						      &crtc->saved_mode,
>  						      encoder->crtc->x,
>  						      encoder->crtc->y,
> -						      encoder->crtc->fb))
> +						      encoder->crtc->primary->fb))
>  				return -1;
>  		}
>  	} else if (!strcmp(property->name, "backlight") && encoder) {
> diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
> index 386de2c..7b73dd1 100644
> --- a/drivers/gpu/drm/gma500/gma_display.c
> +++ b/drivers/gpu/drm/gma500/gma_display.c
> @@ -59,7 +59,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_psb_private *dev_priv = dev->dev_private;
>  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
>  	int pipe = gma_crtc->pipe;
>  	const struct psb_offset *map = &dev_priv->regmap[pipe];
>  	unsigned long start, offset;
> @@ -70,7 +70,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  		return 0;
>  
>  	/* no fb bound */
> -	if (!crtc->fb) {
> +	if (!crtc->primary->fb) {
>  		dev_err(dev->dev, "No FB bound\n");
>  		goto gma_pipe_cleaner;
>  	}
> @@ -81,19 +81,20 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  	if (ret < 0)
>  		goto gma_pipe_set_base_exit;
>  	start = psbfb->gtt->offset;
> -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> +	offset = y * crtc->primary->fb->pitches[0] +
> +		x * (crtc->primary->fb->bits_per_pixel / 8);
>  
> -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
>  
>  	dspcntr = REG_READ(map->cntr);
>  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
>  
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		dspcntr |= DISPPLANE_8BPP;
>  		break;
>  	case 16:
> -		if (crtc->fb->depth == 15)
> +		if (crtc->primary->fb->depth == 15)
>  			dspcntr |= DISPPLANE_15_16BPP;
>  		else
>  			dspcntr |= DISPPLANE_16BPP;
> @@ -511,8 +512,8 @@ void gma_crtc_disable(struct drm_crtc *crtc)
>  
>  	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
>  
> -	if (crtc->fb) {
> -		gt = to_psb_fb(crtc->fb)->gtt;
> +	if (crtc->primary->fb) {
> +		gt = to_psb_fb(crtc->primary->fb)->gtt;
>  		psb_gtt_unpin(gt);
>  	}
>  }
> diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> index 860a4ee..6e91b20 100644
> --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> @@ -287,7 +287,7 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
>  						&gma_crtc->saved_mode,
>  						encoder->crtc->x,
>  						encoder->crtc->y,
> -						encoder->crtc->fb))
> +						encoder->crtc->primary->fb))
>  					goto set_prop_error;
>  			} else {
>  				struct drm_encoder_helper_funcs *funcs =
> diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c
> index 321c00a..c54386a 100644
> --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c
> +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c
> @@ -166,7 +166,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_psb_private *dev_priv = dev->dev_private;
>  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
>  	int pipe = gma_crtc->pipe;
>  	const struct psb_offset *map = &dev_priv->regmap[pipe];
>  	unsigned long start, offset;
> @@ -178,12 +178,12 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  	dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
>  
>  	/* no fb bound */
> -	if (!crtc->fb) {
> +	if (!crtc->primary->fb) {
>  		dev_dbg(dev->dev, "No FB bound\n");
>  		return 0;
>  	}
>  
> -	ret = check_fb(crtc->fb);
> +	ret = check_fb(crtc->primary->fb);
>  	if (ret)
>  		return ret;
>  
> @@ -196,18 +196,19 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  		return 0;
>  
>  	start = psbfb->gtt->offset;
> -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> +	offset = y * crtc->primary->fb->pitches[0] +
> +		x * (crtc->primary->fb->bits_per_pixel / 8);
>  
> -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
>  	dspcntr = REG_READ(map->cntr);
>  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
>  
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		dspcntr |= DISPPLANE_8BPP;
>  		break;
>  	case 16:
> -		if (crtc->fb->depth == 15)
> +		if (crtc->primary->fb->depth == 15)
>  			dspcntr |= DISPPLANE_15_16BPP;
>  		else
>  			dspcntr |= DISPPLANE_16BPP;
> @@ -700,7 +701,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
>  	}
>  #endif
>  
> -	ret = check_fb(crtc->fb);
> +	ret = check_fb(crtc->primary->fb);
>  	if (ret)
>  		return ret;
>  
> diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
> index 8195e85..b0fb42a 100644
> --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
> +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
> @@ -599,7 +599,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_psb_private *dev_priv = dev->dev_private;
>  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
>  	int pipe = gma_crtc->pipe;
>  	const struct psb_offset *map = &dev_priv->regmap[pipe];
>  	unsigned long start, offset;
> @@ -608,7 +608,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
>  	int ret = 0;
>  
>  	/* no fb bound */
> -	if (!crtc->fb) {
> +	if (!crtc->primary->fb) {
>  		dev_dbg(dev->dev, "No FB bound\n");
>  		return 0;
>  	}
> @@ -617,19 +617,20 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
>  		return 0;
>  
>  	start = psbfb->gtt->offset;
> -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> +	offset = y * crtc->primary->fb->pitches[0] +
> +		x * (crtc->primary->fb->bits_per_pixel / 8);
>  
> -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
>  
>  	dspcntr = REG_READ(map->cntr);
>  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
>  
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		dspcntr |= DISPPLANE_8BPP;
>  		break;
>  	case 16:
> -		if (crtc->fb->depth == 15)
> +		if (crtc->primary->fb->depth == 15)
>  			dspcntr |= DISPPLANE_15_16BPP;
>  		else
>  			dspcntr |= DISPPLANE_16BPP;
> diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
> index c8f833d..25c174c 100644
> --- a/drivers/gpu/drm/gma500/psb_intel_display.c
> +++ b/drivers/gpu/drm/gma500/psb_intel_display.c
> @@ -120,7 +120,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
>  	const struct gma_limit_t *limit;
>  
>  	/* No scan out no play */
> -	if (crtc->fb == NULL) {
> +	if (crtc->primary->fb == NULL) {
>  		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
>  		return 0;
>  	}
> diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
> index 32342f6..dcdf70e 100644
> --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
> +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
> @@ -614,7 +614,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
>  						      &crtc->saved_mode,
>  						      encoder->crtc->x,
>  						      encoder->crtc->y,
> -						      encoder->crtc->fb))
> +						      encoder->crtc->primary->fb))
>  				goto set_prop_error;
>  		}
>  	} else if (!strcmp(property->name, "backlight")) {
> diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> index 07d3a9e..1c0a2fb 100644
> --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> @@ -1844,7 +1844,7 @@ done:
>  	if (psb_intel_sdvo->base.base.crtc) {
>  		struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc;
>  		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
> -					 crtc->y, crtc->fb);
> +					 crtc->y, crtc->primary->fb);
>  	}
>  
>  	return 0;
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index d83d643..f00ba43 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -2172,8 +2172,8 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc)
>  	struct intel_encoder *intel_encoder;
>  
>  	seq_printf(m, "\tfb: %d, pos: %dx%d, size: %dx%d\n",
> -		   crtc->fb->base.id, crtc->x, crtc->y,
> -		   crtc->fb->width, crtc->fb->height);
> +		   crtc->primary->fb->base.id, crtc->x, crtc->y,
> +		   crtc->primary->fb->width, crtc->primary->fb->height);
>  	for_each_encoder_on_crtc(dev, crtc, intel_encoder)
>  		intel_encoder_info(m, intel_crtc, intel_encoder);
>  }
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 37f852d..e8b3f9f 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2380,8 +2380,8 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in
>  	} else {
>  		int dspaddr = DSPADDR(intel_crtc->plane);
>  		stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) +
> -							crtc->y * crtc->fb->pitches[0] +
> -							crtc->x * crtc->fb->bits_per_pixel/8);
> +							crtc->y * crtc->primary->fb->pitches[0] +
> +							crtc->x * crtc->primary->fb->bits_per_pixel/8);
>  	}
>  
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 21d12a9..c2f3730 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -744,7 +744,7 @@ bool intel_crtc_active(struct drm_crtc *crtc)
>  	 * We can ditch the crtc->fb check as soon as we can
>  	 * properly reconstruct framebuffers.
>  	 */
> -	return intel_crtc->active && crtc->fb &&
> +	return intel_crtc->active && crtc->primary->fb &&
>  		intel_crtc->config.adjusted_mode.crtc_clock;
>  }
>  
> @@ -2086,17 +2086,18 @@ static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
>  
>  	if (plane_config->tiled) {
>  		obj->tiling_mode = I915_TILING_X;
> -		obj->stride = crtc->base.fb->pitches[0];
> +		obj->stride = crtc->base.primary->fb->pitches[0];
>  	}
>  
> -	mode_cmd.pixel_format = crtc->base.fb->pixel_format;
> -	mode_cmd.width = crtc->base.fb->width;
> -	mode_cmd.height = crtc->base.fb->height;
> -	mode_cmd.pitches[0] = crtc->base.fb->pitches[0];
> +	mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
> +	mode_cmd.width = crtc->base.primary->fb->width;
> +	mode_cmd.height = crtc->base.primary->fb->height;
> +	mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0];
>  
>  	mutex_lock(&dev->struct_mutex);
>  
> -	if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.fb),
> +	if (intel_framebuffer_init(dev,
> +				   to_intel_framebuffer(crtc->base.primary->fb),
>  				   &mode_cmd, obj)) {
>  		DRM_DEBUG_KMS("intel fb init failed\n");
>  		goto out_unref_obj;
> @@ -2121,14 +2122,14 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
>  	struct intel_crtc *i;
>  	struct intel_framebuffer *fb;
>  
> -	if (!intel_crtc->base.fb)
> +	if (!intel_crtc->base.primary->fb)
>  		return;
>  
>  	if (intel_alloc_plane_obj(intel_crtc, plane_config))
>  		return;
>  
> -	kfree(intel_crtc->base.fb);
> -	intel_crtc->base.fb = NULL;
> +	kfree(intel_crtc->base.primary->fb);
> +	intel_crtc->base.primary->fb = NULL;
>  
>  	/*
>  	 * Failed to alloc the obj, check to see if we should share
> @@ -2140,13 +2141,13 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
>  		if (c == &intel_crtc->base)
>  			continue;
>  
> -		if (!i->active || !c->fb)
> +		if (!i->active || !c->primary->fb)
>  			continue;
>  
> -		fb = to_intel_framebuffer(c->fb);
> +		fb = to_intel_framebuffer(c->primary->fb);
>  		if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) {
> -			drm_framebuffer_reference(c->fb);
> -			intel_crtc->base.fb = c->fb;
> +			drm_framebuffer_reference(c->primary->fb);
> +			intel_crtc->base.primary->fb = c->primary->fb;
>  			break;
>  		}
>  	}
> @@ -2394,11 +2395,13 @@ void intel_display_handle_reset(struct drm_device *dev)
>  		/*
>  		 * FIXME: Once we have proper support for primary planes (and
>  		 * disabling them without disabling the entire crtc) allow again
> -		 * a NULL crtc->fb.
> +		 * a NULL crtc->primary->fb.
>  		 */
> -		if (intel_crtc->active && crtc->fb)
> -			dev_priv->display.update_plane(crtc, crtc->fb,
> -						       crtc->x, crtc->y);
> +		if (intel_crtc->active && crtc->primary->fb)
> +			dev_priv->display.update_plane(crtc,
> +						       crtc->primary->fb,
> +						       crtc->x,
> +						       crtc->y);
>  		mutex_unlock(&crtc->mutex);
>  	}
>  }
> @@ -2523,8 +2526,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  		return ret;
>  	}
>  
> -	old_fb = crtc->fb;
> -	crtc->fb = fb;
> +	old_fb = crtc->primary->fb;
> +	crtc->primary->fb = fb;
>  	crtc->x = x;
>  	crtc->y = y;
>  
> @@ -3118,7 +3121,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  
> -	if (crtc->fb == NULL)
> +	if (crtc->primary->fb == NULL)
>  		return;
>  
>  	WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
> @@ -3127,7 +3130,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
>  		   !intel_crtc_has_pending_flip(crtc));
>  
>  	mutex_lock(&dev->struct_mutex);
> -	intel_finish_fb(crtc->fb);
> +	intel_finish_fb(crtc->primary->fb);
>  	mutex_unlock(&dev->struct_mutex);
>  }
>  
> @@ -4583,11 +4586,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
>  	assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe);
>  	assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
>  
> -	if (crtc->fb) {
> +	if (crtc->primary->fb) {
>  		mutex_lock(&dev->struct_mutex);
> -		intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
> +		intel_unpin_fb_obj(to_intel_framebuffer(crtc->primary->fb)->obj);
>  		mutex_unlock(&dev->struct_mutex);
> -		crtc->fb = NULL;
> +		crtc->primary->fb = NULL;
>  	}
>  
>  	/* Update computed state. */
> @@ -5738,8 +5741,9 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
>  	int fourcc, pixel_format;
>  	int aligned_height;
>  
> -	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> -	if (!crtc->base.fb) {
> +	crtc->base.primary->fb =
> +		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> +	if (!crtc->base.primary->fb) {
>  		DRM_DEBUG_KMS("failed to alloc fb\n");
>  		return;
>  	}
> @@ -5752,8 +5756,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
>  
>  	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
>  	fourcc = intel_format_to_fourcc(pixel_format);
> -	crtc->base.fb->pixel_format = fourcc;
> -	crtc->base.fb->bits_per_pixel =
> +	crtc->base.primary->fb->pixel_format = fourcc;
> +	crtc->base.primary->fb->bits_per_pixel =
>  		drm_format_plane_cpp(fourcc, 0) * 8;
>  
>  	if (INTEL_INFO(dev)->gen >= 4) {
> @@ -5768,23 +5772,23 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
>  	plane_config->base = base;
>  
>  	val = I915_READ(PIPESRC(pipe));
> -	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
> -	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
> +	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
> +	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
>  
>  	val = I915_READ(DSPSTRIDE(pipe));
> -	crtc->base.fb->pitches[0] = val & 0xffffff80;
> +	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
>  
> -	aligned_height = intel_align_height(dev, crtc->base.fb->height,
> +	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
>  					    plane_config->tiled);
>  
> -	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
> +	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
>  				   aligned_height, PAGE_SIZE);
>  
>  	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
> -		      pipe, plane, crtc->base.fb->width,
> -		      crtc->base.fb->height,
> -		      crtc->base.fb->bits_per_pixel, base,
> -		      crtc->base.fb->pitches[0],
> +		      pipe, plane, crtc->base.primary->fb->width,
> +		      crtc->base.primary->fb->height,
> +		      crtc->base.primary->fb->bits_per_pixel, base,
> +		      crtc->base.primary->fb->pitches[0],
>  		      plane_config->size);
>  
>  }
> @@ -6746,8 +6750,9 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
>  	int fourcc, pixel_format;
>  	int aligned_height;
>  
> -	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> -	if (!crtc->base.fb) {
> +	crtc->base.primary->fb =
> +		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> +	if (!crtc->base.primary->fb) {
>  		DRM_DEBUG_KMS("failed to alloc fb\n");
>  		return;
>  	}
> @@ -6760,8 +6765,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
>  
>  	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
>  	fourcc = intel_format_to_fourcc(pixel_format);
> -	crtc->base.fb->pixel_format = fourcc;
> -	crtc->base.fb->bits_per_pixel =
> +	crtc->base.primary->fb->pixel_format = fourcc;
> +	crtc->base.primary->fb->bits_per_pixel =
>  		drm_format_plane_cpp(fourcc, 0) * 8;
>  
>  	base = I915_READ(DSPSURF(plane)) & 0xfffff000;
> @@ -6776,23 +6781,23 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
>  	plane_config->base = base;
>  
>  	val = I915_READ(PIPESRC(pipe));
> -	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
> -	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
> +	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
> +	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
>  
>  	val = I915_READ(DSPSTRIDE(pipe));
> -	crtc->base.fb->pitches[0] = val & 0xffffff80;
> +	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
>  
> -	aligned_height = intel_align_height(dev, crtc->base.fb->height,
> +	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
>  					    plane_config->tiled);
>  
> -	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
> +	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
>  				   aligned_height, PAGE_SIZE);
>  
>  	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
> -		      pipe, plane, crtc->base.fb->width,
> -		      crtc->base.fb->height,
> -		      crtc->base.fb->bits_per_pixel, base,
> -		      crtc->base.fb->pitches[0],
> +		      pipe, plane, crtc->base.primary->fb->width,
> +		      crtc->base.primary->fb->height,
> +		      crtc->base.primary->fb->bits_per_pixel, base,
> +		      crtc->base.primary->fb->pitches[0],
>  		      plane_config->size);
>  }
>  
> @@ -8482,7 +8487,7 @@ void intel_mark_idle(struct drm_device *dev)
>  		goto out;
>  
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> -		if (!crtc->fb)
> +		if (!crtc->primary->fb)
>  			continue;
>  
>  		intel_decrease_pllclock(crtc);
> @@ -8505,10 +8510,10 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
>  		return;
>  
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> -		if (!crtc->fb)
> +		if (!crtc->primary->fb)
>  			continue;
>  
> -		if (to_intel_framebuffer(crtc->fb)->obj != obj)
> +		if (to_intel_framebuffer(crtc->primary->fb)->obj != obj)
>  			continue;
>  
>  		intel_increase_pllclock(crtc);
> @@ -8936,7 +8941,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_framebuffer *old_fb = crtc->fb;
> +	struct drm_framebuffer *old_fb = crtc->primary->fb;
>  	struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	struct intel_unpin_work *work;
> @@ -8944,7 +8949,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	int ret;
>  
>  	/* Can't change pixel format via MI display flips. */
> -	if (fb->pixel_format != crtc->fb->pixel_format)
> +	if (fb->pixel_format != crtc->primary->fb->pixel_format)
>  		return -EINVAL;
>  
>  	/*
> @@ -8952,8 +8957,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	 * Note that pitch changes could also affect these register.
>  	 */
>  	if (INTEL_INFO(dev)->gen > 3 &&
> -	    (fb->offsets[0] != crtc->fb->offsets[0] ||
> -	     fb->pitches[0] != crtc->fb->pitches[0]))
> +	    (fb->offsets[0] != crtc->primary->fb->offsets[0] ||
> +	     fb->pitches[0] != crtc->primary->fb->pitches[0]))
>  		return -EINVAL;
>  
>  	if (i915_terminally_wedged(&dev_priv->gpu_error))
> @@ -8996,7 +9001,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	drm_gem_object_reference(&work->old_fb_obj->base);
>  	drm_gem_object_reference(&obj->base);
>  
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  
>  	work->pending_flip_obj = obj;
>  
> @@ -9019,7 +9024,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  
>  cleanup_pending:
>  	atomic_dec(&intel_crtc->unpin_work_count);
> -	crtc->fb = old_fb;
> +	crtc->primary->fb = old_fb;
>  	drm_gem_object_unreference(&work->old_fb_obj->base);
>  	drm_gem_object_unreference(&obj->base);
>  	mutex_unlock(&dev->struct_mutex);
> @@ -10060,7 +10065,7 @@ static int intel_set_mode(struct drm_crtc *crtc,
>  
>  void intel_crtc_restore_mode(struct drm_crtc *crtc)
>  {
> -	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb);
> +	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
>  }
>  
>  #undef for_each_intel_crtc_masked
> @@ -10184,9 +10189,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
>  	 * and then just flip_or_move it */
>  	if (is_crtc_connector_off(set)) {
>  		config->mode_changed = true;
> -	} else if (set->crtc->fb != set->fb) {
> +	} else if (set->crtc->primary->fb != set->fb) {
>  		/* If we have no fb then treat it as a full mode set */
> -		if (set->crtc->fb == NULL) {
> +		if (set->crtc->primary->fb == NULL) {
>  			struct intel_crtc *intel_crtc =
>  				to_intel_crtc(set->crtc);
>  
> @@ -10200,7 +10205,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
>  		} else if (set->fb == NULL) {
>  			config->mode_changed = true;
>  		} else if (set->fb->pixel_format !=
> -			   set->crtc->fb->pixel_format) {
> +			   set->crtc->primary->fb->pixel_format) {
>  			config->mode_changed = true;
>  		} else {
>  			config->fb_changed = true;
> @@ -10413,7 +10418,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
>  	save_set.mode = &set->crtc->mode;
>  	save_set.x = set->crtc->x;
>  	save_set.y = set->crtc->y;
> -	save_set.fb = set->crtc->fb;
> +	save_set.fb = set->crtc->primary->fb;
>  
>  	/* Compute whether we need a full modeset, only an fb base update or no
>  	 * change at all. In the future we might also check whether only the
> @@ -11755,7 +11760,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
>  				dev_priv->pipe_to_crtc_mapping[pipe];
>  
>  			__intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
> -					 crtc->fb);
> +					 crtc->primary->fb);
>  		}
>  	} else {
>  		intel_modeset_update_staged_output_state(dev);
> @@ -11780,15 +11785,15 @@ void intel_modeset_gem_init(struct drm_device *dev)
>  	 */
>  	mutex_lock(&dev->struct_mutex);
>  	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
> -		if (!c->fb)
> +		if (!c->primary->fb)
>  			continue;
>  
> -		fb = to_intel_framebuffer(c->fb);
> +		fb = to_intel_framebuffer(c->primary->fb);
>  		if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) {
>  			DRM_ERROR("failed to pin boot fb on pipe %d\n",
>  				  to_intel_crtc(c)->pipe);
> -			drm_framebuffer_unreference(c->fb);
> -			c->fb = NULL;
> +			drm_framebuffer_unreference(c->primary->fb);
> +			c->primary->fb = NULL;
>  		}
>  	}
>  	mutex_unlock(&dev->struct_mutex);
> @@ -11827,7 +11832,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
>  
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>  		/* Skip inactive CRTCs */
> -		if (!crtc->fb)
> +		if (!crtc->primary->fb)
>  			continue;
>  
>  		intel_increase_pllclock(crtc);
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 59ee4dc..05531bf 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1634,7 +1634,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct drm_crtc *crtc = dig_port->base.base.crtc;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
> +	struct drm_i915_gem_object *obj =
> +		to_intel_framebuffer(crtc->primary->fb)->obj;
>  	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
>  
>  	dev_priv->psr.source_ok = false;
> @@ -1667,7 +1668,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>  		return false;
>  	}
>  
> -	obj = to_intel_framebuffer(crtc->fb)->obj;
> +	obj = to_intel_framebuffer(crtc->primary->fb)->obj;
>  	if (obj->tiling_mode != I915_TILING_X ||
>  	    obj->fence_reg == I915_FENCE_REG_NONE) {
>  		DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> index d6d78c8..2b1d42d 100644
> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> @@ -481,7 +481,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>  		intel_crtc = to_intel_crtc(crtc);
>  
> -		if (!intel_crtc->active || !crtc->fb) {
> +		if (!intel_crtc->active || !crtc->primary->fb) {
>  			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
>  				      pipe_name(intel_crtc->pipe));
>  			continue;
> @@ -491,7 +491,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
>  			DRM_DEBUG_KMS("found possible fb from plane %c\n",
>  				      pipe_name(intel_crtc->pipe));
>  			plane_config = &intel_crtc->plane_config;
> -			fb = to_intel_framebuffer(crtc->fb);
> +			fb = to_intel_framebuffer(crtc->primary->fb);
>  			max_size = plane_config->size;
>  		}
>  	}
> @@ -560,7 +560,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
>  		if (!intel_crtc->active)
>  			continue;
>  
> -		WARN(!crtc->fb,
> +		WARN(!crtc->primary->fb,
>  		     "re-used BIOS config but lost an fb on crtc %d\n",
>  		     crtc->base.id);
>  	}
> diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
> index 312961a..623cd32 100644
> --- a/drivers/gpu/drm/i915/intel_overlay.c
> +++ b/drivers/gpu/drm/i915/intel_overlay.c
> @@ -606,14 +606,14 @@ static void update_colorkey(struct intel_overlay *overlay,
>  {
>  	u32 key = overlay->color_key;
>  
> -	switch (overlay->crtc->base.fb->bits_per_pixel) {
> +	switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
>  	case 8:
>  		iowrite32(0, &regs->DCLRKV);
>  		iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
>  		break;
>  
>  	case 16:
> -		if (overlay->crtc->base.fb->depth == 15) {
> +		if (overlay->crtc->base.primary->fb->depth == 15) {
>  			iowrite32(RGB15_TO_COLORKEY(key), &regs->DCLRKV);
>  			iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
>  				  &regs->DCLRKM);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 3a1b569..e2d73f4 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -92,7 +92,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
>  	struct drm_i915_gem_object *obj = intel_fb->obj;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -149,7 +149,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
>  	struct drm_i915_gem_object *obj = intel_fb->obj;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -221,7 +221,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
>  	struct drm_i915_gem_object *obj = intel_fb->obj;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -277,7 +277,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
>  	struct drm_i915_gem_object *obj = intel_fb->obj;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -336,11 +336,11 @@ static void intel_fbc_work_fn(struct work_struct *__work)
>  		/* Double check that we haven't switched fb without cancelling
>  		 * the prior work.
>  		 */
> -		if (work->crtc->fb == work->fb) {
> +		if (work->crtc->primary->fb == work->fb) {
>  			dev_priv->display.enable_fbc(work->crtc);
>  
>  			dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
> -			dev_priv->fbc.fb_id = work->crtc->fb->base.id;
> +			dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
>  			dev_priv->fbc.y = work->crtc->y;
>  		}
>  
> @@ -393,7 +393,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc)
>  	}
>  
>  	work->crtc = crtc;
> -	work->fb = crtc->fb;
> +	work->fb = crtc->primary->fb;
>  	INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
>  
>  	dev_priv->fbc.fbc_work = work;
> @@ -499,14 +499,14 @@ void intel_update_fbc(struct drm_device *dev)
>  		}
>  	}
>  
> -	if (!crtc || crtc->fb == NULL) {
> +	if (!crtc || crtc->primary->fb == NULL) {
>  		if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
>  			DRM_DEBUG_KMS("no output, disabling\n");
>  		goto out_disable;
>  	}
>  
>  	intel_crtc = to_intel_crtc(crtc);
> -	fb = crtc->fb;
> +	fb = crtc->primary->fb;
>  	intel_fb = to_intel_framebuffer(fb);
>  	obj = intel_fb->obj;
>  	adjusted_mode = &intel_crtc->config.adjusted_mode;
> @@ -1041,7 +1041,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
>  	crtc = single_enabled_crtc(dev);
>  	if (crtc) {
>  		const struct drm_display_mode *adjusted_mode;
> -		int pixel_size = crtc->fb->bits_per_pixel / 8;
> +		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
>  		int clock;
>  
>  		adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
> @@ -1121,7 +1121,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
>  	clock = adjusted_mode->crtc_clock;
>  	htotal = adjusted_mode->crtc_htotal;
>  	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> -	pixel_size = crtc->fb->bits_per_pixel / 8;
> +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
>  
>  	/* Use the small buffer method to calculate plane watermark */
>  	entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
> @@ -1208,7 +1208,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
>  	clock = adjusted_mode->crtc_clock;
>  	htotal = adjusted_mode->crtc_htotal;
>  	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> -	pixel_size = crtc->fb->bits_per_pixel / 8;
> +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
>  
>  	line_time_us = max(htotal * 1000 / clock, 1);
>  	line_count = (latency_ns / line_time_us + 1000) / 1000;
> @@ -1247,7 +1247,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,
>  		return false;
>  
>  	clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
> -	pixel_size = crtc->fb->bits_per_pixel / 8;	/* BPP */
> +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;	/* BPP */
>  
>  	entries = (clock / 1000) * pixel_size;
>  	*plane_prec_mult = (entries > 256) ?
> @@ -1439,7 +1439,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
>  		int clock = adjusted_mode->crtc_clock;
>  		int htotal = adjusted_mode->crtc_htotal;
>  		int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> -		int pixel_size = crtc->fb->bits_per_pixel / 8;
> +		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
>  		unsigned long line_time_us;
>  		int entries;
>  
> @@ -1512,7 +1512,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
>  	crtc = intel_get_crtc_for_plane(dev, 0);
>  	if (intel_crtc_active(crtc)) {
>  		const struct drm_display_mode *adjusted_mode;
> -		int cpp = crtc->fb->bits_per_pixel / 8;
> +		int cpp = crtc->primary->fb->bits_per_pixel / 8;
>  		if (IS_GEN2(dev))
>  			cpp = 4;
>  
> @@ -1528,7 +1528,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
>  	crtc = intel_get_crtc_for_plane(dev, 1);
>  	if (intel_crtc_active(crtc)) {
>  		const struct drm_display_mode *adjusted_mode;
> -		int cpp = crtc->fb->bits_per_pixel / 8;
> +		int cpp = crtc->primary->fb->bits_per_pixel / 8;
>  		if (IS_GEN2(dev))
>  			cpp = 4;
>  
> @@ -1565,7 +1565,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
>  		int clock = adjusted_mode->crtc_clock;
>  		int htotal = adjusted_mode->crtc_htotal;
>  		int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w;
> -		int pixel_size = enabled->fb->bits_per_pixel / 8;
> +		int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
>  		unsigned long line_time_us;
>  		int entries;
>  
> @@ -2117,7 +2117,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
>  	if (p->active) {
>  		p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
>  		p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
> -		p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
> +		p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
>  		p->cur.bytes_per_pixel = 4;
>  		p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
>  		p->cur.horiz_pixels = 64;
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index 1418414..f8c42b1 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> @@ -29,7 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
>  	struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
>  	struct drm_device *dev = crtc->dev;
>  	struct mga_device *mdev = dev->dev_private;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  	int i;
>  
>  	if (!crtc->enabled)
> @@ -742,7 +742,7 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
>  		mgag200_bo_unreserve(bo);
>  	}
>  
> -	mga_fb = to_mga_framebuffer(crtc->fb);
> +	mga_fb = to_mga_framebuffer(crtc->primary->fb);
>  	obj = mga_fb->obj;
>  	bo = gem_to_mga_bo(obj);
>  
> @@ -805,7 +805,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
>  		/* 0x48: */        0,    0,    0,    0,    0,    0,    0,    0
>  	};
>  
> -	bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1];
> +	bppshift = mdev->bpp_shifts[(crtc->primary->fb->bits_per_pixel >> 3) - 1];
>  
>  	switch (mdev->type) {
>  	case G200_SE_A:
> @@ -843,12 +843,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
>  		break;
>  	}
>  
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
>  		break;
>  	case 16:
> -		if (crtc->fb->depth == 15)
> +		if (crtc->primary->fb->depth == 15)
>  			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
>  		else
>  			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
> @@ -896,8 +896,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
>  	WREG_SEQ(3, 0);
>  	WREG_SEQ(4, 0xe);
>  
> -	pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
> -	if (crtc->fb->bits_per_pixel == 24)
> +	pitch = crtc->primary->fb->pitches[0] /
> +		(crtc->primary->fb->bits_per_pixel / 8);
> +	if (crtc->primary->fb->bits_per_pixel == 24)
>  		pitch = (pitch * 3) >> (4 - bppshift);
>  	else
>  		pitch = pitch >> (4 - bppshift);
> @@ -974,7 +975,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
>  		((vdisplay & 0xc00) >> 7) |
>  		((vsyncstart & 0xc00) >> 5) |
>  		((vdisplay & 0x400) >> 3);
> -	if (crtc->fb->bits_per_pixel == 24)
> +	if (crtc->primary->fb->bits_per_pixel == 24)
>  		ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
>  	else
>  		ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
> @@ -1034,9 +1035,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
>  			u32 bpp;
>  			u32 mb;
>  
> -			if (crtc->fb->bits_per_pixel > 16)
> +			if (crtc->primary->fb->bits_per_pixel > 16)
>  				bpp = 32;
> -			else if (crtc->fb->bits_per_pixel > 8)
> +			else if (crtc->primary->fb->bits_per_pixel > 8)
>  				bpp = 16;
>  			else
>  				bpp = 8;
> @@ -1277,8 +1278,9 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
>  	int ret;
>  	DRM_DEBUG_KMS("\n");
>  	mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> -	if (crtc->fb) {
> -		struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
> +	if (crtc->primary->fb) {
> +		struct mga_framebuffer *mga_fb =
> +			to_mga_framebuffer(crtc->primary->fb);
>  		struct drm_gem_object *obj = mga_fb->obj;
>  		struct mgag200_bo *bo = gem_to_mga_bo(obj);
>  		ret = mgag200_bo_reserve(bo, false);
> @@ -1287,7 +1289,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
>  		mgag200_bo_push_sysram(bo);
>  		mgag200_bo_unreserve(bo);
>  	}
> -	crtc->fb = NULL;
> +	crtc->primary->fb = NULL;
>  }
>  
>  /* These provide the minimum set of functions required to handle a CRTC */
> diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> index b10f681..f96497b 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> @@ -120,7 +120,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
>  
>  	/* grab reference to incoming scanout fb: */
>  	drm_framebuffer_reference(new_fb);
> -	mdp4_crtc->base.fb = new_fb;
> +	mdp4_crtc->base.primary->fb = new_fb;
>  	mdp4_crtc->fb = new_fb;
>  
>  	if (old_fb)
> @@ -182,7 +182,7 @@ static void pageflip_cb(struct msm_fence_cb *cb)
>  	struct mdp4_crtc *mdp4_crtc =
>  		container_of(cb, struct mdp4_crtc, pageflip_cb);
>  	struct drm_crtc *crtc = &mdp4_crtc->base;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  
>  	if (!fb)
>  		return;
> @@ -348,14 +348,14 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
>  			mode->type, mode->flags);
>  
>  	/* grab extra ref for update_scanout() */
> -	drm_framebuffer_reference(crtc->fb);
> +	drm_framebuffer_reference(crtc->primary->fb);
>  
> -	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
> +	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb,
>  			0, 0, mode->hdisplay, mode->vdisplay,
>  			x << 16, y << 16,
>  			mode->hdisplay << 16, mode->vdisplay << 16);
>  	if (ret) {
> -		drm_framebuffer_unreference(crtc->fb);
> +		drm_framebuffer_unreference(crtc->primary->fb);
>  		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
>  				mdp4_crtc->name, ret);
>  		return ret;
> @@ -368,7 +368,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
>  	/* take data from pipe: */
>  	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
>  	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma),
> -			crtc->fb->pitches[0]);
> +			crtc->primary->fb->pitches[0]);
>  	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
>  			MDP4_DMA_DST_SIZE_WIDTH(0) |
>  			MDP4_DMA_DST_SIZE_HEIGHT(0));
> @@ -378,7 +378,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
>  			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
>  			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
>  	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp),
> -			crtc->fb->pitches[0]);
> +			crtc->primary->fb->pitches[0]);
>  
>  	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
>  
> @@ -388,8 +388,8 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
>  		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
>  	}
>  
> -	update_fb(crtc, crtc->fb);
> -	update_scanout(crtc, crtc->fb);
> +	update_fb(crtc, crtc->primary->fb);
> +	update_scanout(crtc, crtc->primary->fb);
>  
>  	return 0;
>  }
> @@ -420,19 +420,19 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  	int ret;
>  
>  	/* grab extra ref for update_scanout() */
> -	drm_framebuffer_reference(crtc->fb);
> +	drm_framebuffer_reference(crtc->primary->fb);
>  
> -	ret = mdp4_plane_mode_set(plane, crtc, crtc->fb,
> +	ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb,
>  			0, 0, mode->hdisplay, mode->vdisplay,
>  			x << 16, y << 16,
>  			mode->hdisplay << 16, mode->vdisplay << 16);
>  	if (ret) {
> -		drm_framebuffer_unreference(crtc->fb);
> +		drm_framebuffer_unreference(crtc->primary->fb);
>  		return ret;
>  	}
>  
> -	update_fb(crtc, crtc->fb);
> -	update_scanout(crtc, crtc->fb);
> +	update_fb(crtc, crtc->primary->fb);
> +	update_scanout(crtc, crtc->primary->fb);
>  
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> index 7dc3d71..f200048 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> @@ -102,7 +102,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
>  
>  	/* grab reference to incoming scanout fb: */
>  	drm_framebuffer_reference(new_fb);
> -	mdp5_crtc->base.fb = new_fb;
> +	mdp5_crtc->base.primary->fb = new_fb;
>  	mdp5_crtc->fb = new_fb;
>  
>  	if (old_fb)
> @@ -289,14 +289,14 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
>  			mode->type, mode->flags);
>  
>  	/* grab extra ref for update_scanout() */
> -	drm_framebuffer_reference(crtc->fb);
> +	drm_framebuffer_reference(crtc->primary->fb);
>  
> -	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb,
> +	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb,
>  			0, 0, mode->hdisplay, mode->vdisplay,
>  			x << 16, y << 16,
>  			mode->hdisplay << 16, mode->vdisplay << 16);
>  	if (ret) {
> -		drm_framebuffer_unreference(crtc->fb);
> +		drm_framebuffer_unreference(crtc->primary->fb);
>  		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
>  				mdp5_crtc->name, ret);
>  		return ret;
> @@ -306,8 +306,8 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
>  			MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
>  			MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
>  
> -	update_fb(crtc, crtc->fb);
> -	update_scanout(crtc, crtc->fb);
> +	update_fb(crtc, crtc->primary->fb);
> +	update_scanout(crtc, crtc->primary->fb);
>  
>  	return 0;
>  }
> @@ -338,19 +338,19 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  	int ret;
>  
>  	/* grab extra ref for update_scanout() */
> -	drm_framebuffer_reference(crtc->fb);
> +	drm_framebuffer_reference(crtc->primary->fb);
>  
> -	ret = mdp5_plane_mode_set(plane, crtc, crtc->fb,
> +	ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb,
>  			0, 0, mode->hdisplay, mode->vdisplay,
>  			x << 16, y << 16,
>  			mode->hdisplay << 16, mode->vdisplay << 16);
>  	if (ret) {
> -		drm_framebuffer_unreference(crtc->fb);
> +		drm_framebuffer_unreference(crtc->primary->fb);
>  		return ret;
>  	}
>  
> -	update_fb(crtc, crtc->fb);
> -	update_scanout(crtc, crtc->fb);
> +	update_fb(crtc, crtc->primary->fb);
> +	update_scanout(crtc, crtc->primary->fb);
>  
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> index b55be84..2a5e9db 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> @@ -239,7 +239,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
>  	struct drm_device *dev = crtc->dev;
>  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
>  	struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  
>  	/* Calculate our timings */
>  	int horizDisplay	= (mode->crtc_hdisplay >> 3)		- 1;
> @@ -574,7 +574,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
>  		regp->CRTC[NV_CIO_CRE_86] = 0x1;
>  	}
>  
> -	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->fb->depth + 1) / 8;
> +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->primary->fb->depth + 1) / 8;
>  	/* Enable slaved mode (called MODE_TV in nv4ref.h) */
>  	if (lvds_output || tmds_output || tv_output)
>  		regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7);
> @@ -588,7 +588,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
>  	regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
>  				NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL |
>  				NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON;
> -	if (crtc->fb->depth == 16)
> +	if (crtc->primary->fb->depth == 16)
>  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
>  	if (nv_device(drm->device)->chipset >= 0x11)
>  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG;
> @@ -609,7 +609,7 @@ static int
>  nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
>  {
>  	struct nv04_display *disp = nv04_display(crtc->dev);
> -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
> +	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
>  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
>  	int ret;
>  
> @@ -808,7 +808,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
>  	 * mark the lut values as dirty by setting depth==0, and it'll be
>  	 * uploaded on the first mode_set_base()
>  	 */
> -	if (!nv_crtc->base.fb) {
> +	if (!nv_crtc->base.primary->fb) {
>  		nv_crtc->lut.depth = 0;
>  		return;
>  	}
> @@ -832,7 +832,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
>  	NV_DEBUG(drm, "index %d\n", nv_crtc->index);
>  
>  	/* no fb bound */
> -	if (!atomic && !crtc->fb) {
> +	if (!atomic && !crtc->primary->fb) {
>  		NV_DEBUG(drm, "No FB bound\n");
>  		return 0;
>  	}
> @@ -844,8 +844,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
>  		drm_fb = passed_fb;
>  		fb = nouveau_framebuffer(passed_fb);
>  	} else {
> -		drm_fb = crtc->fb;
> -		fb = nouveau_framebuffer(crtc->fb);
> +		drm_fb = crtc->primary->fb;
> +		fb = nouveau_framebuffer(crtc->primary->fb);
>  	}
>  
>  	nv_crtc->fb.offset = fb->nvbo->bo.offset;
> @@ -857,9 +857,9 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
>  
>  	/* Update the framebuffer format. */
>  	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3;
> -	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8;
> +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->primary->fb->depth + 1) / 8;
>  	regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
> -	if (crtc->fb->depth == 16)
> +	if (crtc->primary->fb->depth == 16)
>  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
>  	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX);
>  	NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL,
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> index 7fdc51e..a2d669b 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> @@ -415,7 +415,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
>  	/* Output property. */
>  	if ((nv_connector->dithering_mode == DITHERING_MODE_ON) ||
>  	    (nv_connector->dithering_mode == DITHERING_MODE_AUTO &&
> -	     encoder->crtc->fb->depth > connector->display_info.bpc * 3)) {
> +	     encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) {
>  		if (nv_device(drm->device)->chipset == 0x11)
>  			regp->dither = savep->dither | 0x00010000;
>  		else {
> diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
> index 2401159..4e24c72 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_display.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_display.c
> @@ -569,7 +569,7 @@ nouveau_display_suspend(struct drm_device *dev)
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>  		struct nouveau_framebuffer *nouveau_fb;
>  
> -		nouveau_fb = nouveau_framebuffer(crtc->fb);
> +		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
>  		if (!nouveau_fb || !nouveau_fb->nvbo)
>  			continue;
>  
> @@ -596,7 +596,7 @@ nouveau_display_repin(struct drm_device *dev)
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>  		struct nouveau_framebuffer *nouveau_fb;
>  
> -		nouveau_fb = nouveau_framebuffer(crtc->fb);
> +		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
>  		if (!nouveau_fb || !nouveau_fb->nvbo)
>  			continue;
>  
> @@ -693,7 +693,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
>  	struct drm_device *dev = crtc->dev;
>  	struct nouveau_drm *drm = nouveau_drm(dev);
> -	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
> +	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo;
>  	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
>  	struct nouveau_page_flip_state *s;
>  	struct nouveau_channel *chan = drm->channel;
> @@ -767,7 +767,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  		goto fail_unreserve;
>  
>  	/* Update the crtc struct and cleanup */
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  
>  	nouveau_bo_fence(old_bo, fence);
>  	ttm_bo_unreserve(&old_bo->bo);
> diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> index 5706842..c744bf6 100644
> --- a/drivers/gpu/drm/nouveau/nv50_display.c
> +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> @@ -651,7 +651,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
>  	nv_connector = nouveau_crtc_connector_get(nv_crtc);
>  	connector = &nv_connector->base;
>  	if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
> -		if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
> +		if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3)
>  			mode = DITHERING_MODE_DYNAMIC2X2;
>  	} else {
>  		mode = nv_connector->dithering_mode;
> @@ -785,7 +785,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
>  
>  		if (update) {
>  			nv50_display_flip_stop(crtc);
> -			nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> +			nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
>  		}
>  	}
>  
> @@ -1028,7 +1028,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
>  	}
>  
>  	nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
> -	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> +	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
>  }
>  
>  static bool
> @@ -1042,7 +1042,8 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
>  static int
>  nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
>  {
> -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
> +	struct nouveau_framebuffer *nvfb =
> +		nouveau_framebuffer(crtc->primary->fb);
>  	struct nv50_head *head = nv50_head(crtc);
>  	int ret;
>  
> @@ -1139,7 +1140,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
>  	nv50_crtc_set_dither(nv_crtc, false);
>  	nv50_crtc_set_scale(nv_crtc, false);
>  	nv50_crtc_set_color_vibrance(nv_crtc, false);
> -	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
> +	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
>  	return 0;
>  }
>  
> @@ -1151,7 +1152,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
>  	int ret;
>  
> -	if (!crtc->fb) {
> +	if (!crtc->primary->fb) {
>  		NV_DEBUG(drm, "No FB bound\n");
>  		return 0;
>  	}
> @@ -1161,8 +1162,8 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  		return ret;
>  
>  	nv50_display_flip_stop(crtc);
> -	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
> -	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> +	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
> +	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> index 24b6112..5be0b87 100644
> --- a/drivers/gpu/drm/qxl/qxl_display.c
> +++ b/drivers/gpu/drm/qxl/qxl_display.c
> @@ -527,7 +527,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
>  	bool recreate_primary = false;
>  	int ret;
>  	int surf_id;
> -	if (!crtc->fb) {
> +	if (!crtc->primary->fb) {
>  		DRM_DEBUG_KMS("No FB bound\n");
>  		return 0;
>  	}
> @@ -536,7 +536,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
>  		qfb = to_qxl_framebuffer(old_fb);
>  		old_bo = gem_to_qxl_bo(qfb->obj);
>  	}
> -	qfb = to_qxl_framebuffer(crtc->fb);
> +	qfb = to_qxl_framebuffer(crtc->primary->fb);
>  	bo = gem_to_qxl_bo(qfb->obj);
>  	if (!m)
>  		/* and do we care? */
> @@ -609,14 +609,15 @@ static void qxl_crtc_disable(struct drm_crtc *crtc)
>  	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
>  	struct drm_device *dev = crtc->dev;
>  	struct qxl_device *qdev = dev->dev_private;
> -	if (crtc->fb) {
> -		struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb);
> +	if (crtc->primary->fb) {
> +		struct qxl_framebuffer *qfb =
> +			to_qxl_framebuffer(crtc->primary->fb);
>  		struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
>  		int ret;
>  		ret = qxl_bo_reserve(bo, false);
>  		qxl_bo_unpin(bo);
>  		qxl_bo_unreserve(bo);
> -		crtc->fb = NULL;
> +		crtc->primary->fb = NULL;
>  	}
>  
>  	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
> diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
> index daa4dd3..fb187c7 100644
> --- a/drivers/gpu/drm/radeon/atombios_crtc.c
> +++ b/drivers/gpu/drm/radeon/atombios_crtc.c
> @@ -1106,7 +1106,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
>  	int r;
>  
>  	/* no fb bound */
> -	if (!atomic && !crtc->fb) {
> +	if (!atomic && !crtc->primary->fb) {
>  		DRM_DEBUG_KMS("No FB bound\n");
>  		return 0;
>  	}
> @@ -1116,8 +1116,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
>  		target_fb = fb;
>  	}
>  	else {
> -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> -		target_fb = crtc->fb;
> +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> +		target_fb = crtc->primary->fb;
>  	}
>  
>  	/* If atomic, assume fb object is pinned & idle & fenced and
> @@ -1316,7 +1316,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
>  	/* set pageflip to happen anywhere in vblank interval */
>  	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
>  
> -	if (!atomic && fb && fb != crtc->fb) {
> +	if (!atomic && fb && fb != crtc->primary->fb) {
>  		radeon_fb = to_radeon_framebuffer(fb);
>  		rbo = gem_to_radeon_bo(radeon_fb->obj);
>  		r = radeon_bo_reserve(rbo, false);
> @@ -1350,7 +1350,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
>  	int r;
>  
>  	/* no fb bound */
> -	if (!atomic && !crtc->fb) {
> +	if (!atomic && !crtc->primary->fb) {
>  		DRM_DEBUG_KMS("No FB bound\n");
>  		return 0;
>  	}
> @@ -1360,8 +1360,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
>  		target_fb = fb;
>  	}
>  	else {
> -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> -		target_fb = crtc->fb;
> +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> +		target_fb = crtc->primary->fb;
>  	}
>  
>  	obj = radeon_fb->obj;
> @@ -1485,7 +1485,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
>  	/* set pageflip to happen anywhere in vblank interval */
>  	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
>  
> -	if (!atomic && fb && fb != crtc->fb) {
> +	if (!atomic && fb && fb != crtc->primary->fb) {
>  		radeon_fb = to_radeon_framebuffer(fb);
>  		rbo = gem_to_radeon_bo(radeon_fb->obj);
>  		r = radeon_bo_reserve(rbo, false);
> @@ -1972,12 +1972,12 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
>  	int i;
>  
>  	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> -	if (crtc->fb) {
> +	if (crtc->primary->fb) {
>  		int r;
>  		struct radeon_framebuffer *radeon_fb;
>  		struct radeon_bo *rbo;
>  
> -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
>  		rbo = gem_to_radeon_bo(radeon_fb->obj);
>  		r = radeon_bo_reserve(rbo, false);
>  		if (unlikely(r))
> diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
> index 030f8e4..b6c3264 100644
> --- a/drivers/gpu/drm/radeon/r100.c
> +++ b/drivers/gpu/drm/radeon/r100.c
> @@ -3220,12 +3220,12 @@ void r100_bandwidth_update(struct radeon_device *rdev)
>  
>  	if (rdev->mode_info.crtcs[0]->base.enabled) {
>  		mode1 = &rdev->mode_info.crtcs[0]->base.mode;
> -		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8;
> +		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;
> -			pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8;
> +			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 82d4f86..33b482b 100644
> --- a/drivers/gpu/drm/radeon/radeon_connectors.c
> +++ b/drivers/gpu/drm/radeon/radeon_connectors.c
> @@ -89,7 +89,7 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)
>  
>  	if (crtc && crtc->enabled) {
>  		drm_crtc_helper_set_mode(crtc, &crtc->mode,
> -					 crtc->x, crtc->y, crtc->fb);
> +					 crtc->x, crtc->y, crtc->primary->fb);
>  	}
>  }
>  
> diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
> index 2e72dcd..c524aba 100644
> --- a/drivers/gpu/drm/radeon/radeon_device.c
> +++ b/drivers/gpu/drm/radeon/radeon_device.c
> @@ -1424,7 +1424,8 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
>  
>  	/* unpin the front buffers */
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> -		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
> +		struct radeon_framebuffer *rfb =
> +			to_radeon_framebuffer(crtc->primary->fb);
>  		struct radeon_bo *robj;
>  
>  		if (rfb == NULL || rfb->obj == NULL) {
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> index a29d217..4e90049 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -369,7 +369,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
>  	work->event = event;
>  	work->rdev = rdev;
>  	work->crtc_id = radeon_crtc->crtc_id;
> -	old_radeon_fb = to_radeon_framebuffer(crtc->fb);
> +	old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
>  	new_radeon_fb = to_radeon_framebuffer(fb);
>  	/* schedule unpin of the old buffer */
>  	obj = old_radeon_fb->obj;
> @@ -460,7 +460,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  
>  	/* update crtc fb */
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  
>  	r = drm_vblank_get(dev, radeon_crtc->crtc_id);
>  	if (r) {
> diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> index 0b158f9..cafb1cc 100644
> --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> @@ -385,7 +385,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
>  
>  	DRM_DEBUG_KMS("\n");
>  	/* no fb bound */
> -	if (!atomic && !crtc->fb) {
> +	if (!atomic && !crtc->primary->fb) {
>  		DRM_DEBUG_KMS("No FB bound\n");
>  		return 0;
>  	}
> @@ -395,8 +395,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
>  		target_fb = fb;
>  	}
>  	else {
> -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> -		target_fb = crtc->fb;
> +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> +		target_fb = crtc->primary->fb;
>  	}
>  
>  	switch (target_fb->bits_per_pixel) {
> @@ -444,7 +444,7 @@ retry:
>  		 * We don't shutdown the display controller because new buffer
>  		 * will end up in same spot.
>  		 */
> -		if (!atomic && fb && fb != crtc->fb) {
> +		if (!atomic && fb && fb != crtc->primary->fb) {
>  			struct radeon_bo *old_rbo;
>  			unsigned long nsize, osize;
>  
> @@ -555,7 +555,7 @@ retry:
>  	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
>  	WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
>  
> -	if (!atomic && fb && fb != crtc->fb) {
> +	if (!atomic && fb && fb != crtc->primary->fb) {
>  		radeon_fb = to_radeon_framebuffer(fb);
>  		rbo = gem_to_radeon_bo(radeon_fb->obj);
>  		r = radeon_bo_reserve(rbo, false);
> @@ -599,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
>  		}
>  	}
>  
> -	switch (crtc->fb->bits_per_pixel) {
> +	switch (crtc->primary->fb->bits_per_pixel) {
>  	case 8:
>  		format = 2;
>  		break;
> @@ -1087,12 +1087,12 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
>  static void radeon_crtc_disable(struct drm_crtc *crtc)
>  {
>  	radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> -	if (crtc->fb) {
> +	if (crtc->primary->fb) {
>  		int r;
>  		struct radeon_framebuffer *radeon_fb;
>  		struct radeon_bo *rbo;
>  
> -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
>  		rbo = gem_to_radeon_bo(radeon_fb->obj);
>  		r = radeon_bo_reserve(rbo, false);
>  		if (unlikely(r))
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index 1255944..c63b5e7 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -310,7 +310,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
>  
>  {
>  	struct drm_device *dev = crtc->dev;
> -	struct udl_framebuffer *ufb = to_udl_fb(crtc->fb);
> +	struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb);
>  	struct udl_device *udl = dev->dev_private;
>  	char *buf;
>  	char *wrptr;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> index 8a65041..1d59ed3 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> @@ -468,7 +468,7 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
>  	num_units = 0;
>  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
>  			    head) {
> -		if (crtc->fb != &framebuffer->base)
> +		if (crtc->primary->fb != &framebuffer->base)
>  			continue;
>  		units[num_units++] = vmw_crtc_to_du(crtc);
>  	}
> @@ -883,7 +883,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
>  
>  	num_units = 0;
>  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> -		if (crtc->fb != &framebuffer->base)
> +		if (crtc->primary->fb != &framebuffer->base)
>  			continue;
>  		units[num_units++] = vmw_crtc_to_du(crtc);
>  	}
> @@ -1245,7 +1245,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
>  
>  	num_units = 0;
>  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> -		if (crtc->fb != &vfb->base)
> +		if (crtc->primary->fb != &vfb->base)
>  			continue;
>  		units[num_units++] = vmw_crtc_to_du(crtc);
>  	}
> @@ -1382,7 +1382,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
>  
>  	num_units = 0;
>  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> -		if (crtc->fb != &vfb->base)
> +		if (crtc->primary->fb != &vfb->base)
>  			continue;
>  		units[num_units++] = vmw_crtc_to_du(crtc);
>  	}
> @@ -1725,7 +1725,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
>  		     uint32_t page_flip_flags)
>  {
>  	struct vmw_private *dev_priv = vmw_priv(crtc->dev);
> -	struct drm_framebuffer *old_fb = crtc->fb;
> +	struct drm_framebuffer *old_fb = crtc->primary->fb;
>  	struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
>  	struct drm_file *file_priv ;
>  	struct vmw_fence_obj *fence = NULL;
> @@ -1743,7 +1743,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
>  	if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
>  		return -EINVAL;
>  
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  
>  	/* do a full screen dirty update */
>  	clips.x1 = clips.y1 = 0;
> @@ -1783,7 +1783,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
>  	return ret;
>  
>  out_no_fence:
> -	crtc->fb = old_fb;
> +	crtc->primary->fb = old_fb;
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> index 001ec81..08fdd7f 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> @@ -93,7 +93,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
>  
>  		if (crtc == NULL)
>  			return 0;
> -		fb = entry->base.crtc.fb;
> +		fb = entry->base.crtc.primary->fb;
>  
>  		return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0],
>  					  fb->bits_per_pixel, fb->depth);
> @@ -101,7 +101,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
>  
>  	if (!list_empty(&lds->active)) {
>  		entry = list_entry(lds->active.next, typeof(*entry), active);
> -		fb = entry->base.crtc.fb;
> +		fb = entry->base.crtc.primary->fb;
>  
>  		vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0],
>  				   fb->bits_per_pixel, fb->depth);
> @@ -259,7 +259,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
>  
>  		connector->encoder = NULL;
>  		encoder->crtc = NULL;
> -		crtc->fb = NULL;
> +		crtc->primary->fb = NULL;
>  		crtc->enabled = false;
>  
>  		vmw_ldu_del_active(dev_priv, ldu);
> @@ -280,7 +280,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
>  
>  	vmw_fb_off(dev_priv);
>  
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  	encoder->crtc = crtc;
>  	connector->encoder = encoder;
>  	crtc->x = set->x;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> index 585da43..46ea096 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> @@ -307,7 +307,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
>  
>  		connector->encoder = NULL;
>  		encoder->crtc = NULL;
> -		crtc->fb = NULL;
> +		crtc->primary->fb = NULL;
>  		crtc->x = 0;
>  		crtc->y = 0;
>  		crtc->enabled = false;
> @@ -368,7 +368,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
>  
>  		connector->encoder = NULL;
>  		encoder->crtc = NULL;
> -		crtc->fb = NULL;
> +		crtc->primary->fb = NULL;
>  		crtc->x = 0;
>  		crtc->y = 0;
>  		crtc->enabled = false;
> @@ -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;
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  	crtc->x = set->x;
>  	crtc->y = set->y;
>  	crtc->enabled = true;
> @@ -574,5 +574,5 @@ void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
>  	BUG_ON(!sou->base.is_implicit);
>  
>  	dev_priv->sou_priv->implicit_fb =
> -		vmw_framebuffer_to_vfb(sou->base.crtc.fb);
> +		vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
>  }
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 4dc84f8..9f7824d 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -309,9 +309,6 @@ struct drm_crtc {
>  	/* primary plane for CRTC */
>  	struct drm_plane *primary;
>  
> -	/* framebuffer the connector is currently bound to */
> -	struct drm_framebuffer *fb;
> -
>  	/* Temporary tracking of the old fb while a modeset is ongoing. Used
>  	 * by drm_mode_set_config_internal to implement correct refcounting. */
>  	struct drm_framebuffer *old_fb;
> -- 
> 1.8.5.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 10/14] drm/i915: Rename similar plane functions to avoid confusion
  2014-03-19  0:22 ` [RFCv3 10/14] drm/i915: Rename similar plane functions to avoid confusion Matt Roper
@ 2014-03-19 12:05   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 12:05 UTC (permalink / raw)
  To: Matt Roper; +Cc: Intel Graphics Development, dri-devel

On Tue, Mar 18, 2014 at 05:22:55PM -0700, Matt Roper wrote:
> The name 'update_plane' was used both for the primary plane functions in
> intel_display.c and the sprite/overlay functions in intel_sprite.c.
> Rename the primary plane functions to 'update_primary_plane' to avoid
> confusion.
> 
> On a similar note, intel_display.c already had a function called
> intel_disable_primary_plane() that programs the hardware to disable a
> pipe's primary plane.  When we hook up primary planes through the DRM
> plane interface, one of the natural handler names will be
> intel_primary_plane_disable(), which is very similar.  To avoid
> confusion, rename the existing intel_disable_primary_plane() to
> intel_disable_primary_hw_plane() to make the two names a little more
> distinct.
> 
> Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Hah, here's the reason why doing a crtc->fb -> crtc->primary->fb flagday
isn't good ;-) Wanted to pull this in since I like it, and it conflicted.

Fixed up and merged to dinq, thanks.
-Daniel
> ---
>  drivers/gpu/drm/i915/i915_drv.h      |  5 +--
>  drivers/gpu/drm/i915/intel_display.c | 60 ++++++++++++++++++++----------------
>  2 files changed, 36 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 70fbe90..a937711 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -462,8 +462,9 @@ struct drm_i915_display_funcs {
>  			  struct drm_framebuffer *fb,
>  			  struct drm_i915_gem_object *obj,
>  			  uint32_t flags);
> -	int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
> -			    int x, int y);
> +	int (*update_primary_plane)(struct drm_crtc *crtc,
> +				    struct drm_framebuffer *fb,
> +				    int x, int y);
>  	void (*hpd_irq_setup)(struct drm_device *dev);
>  	/* clock updates for mode set */
>  	/* cursor updates */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index c2f3730..849a241 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -1872,15 +1872,15 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
>  }
>  
>  /**
> - * intel_enable_primary_plane - enable the primary plane on a given pipe
> + * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
>   * @dev_priv: i915 private structure
>   * @plane: plane to enable
>   * @pipe: pipe being fed
>   *
>   * Enable @plane on @pipe, making sure that @pipe is running first.
>   */
> -static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
> -				       enum plane plane, enum pipe pipe)
> +static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
> +					  enum plane plane, enum pipe pipe)
>  {
>  	struct intel_crtc *intel_crtc =
>  		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> @@ -1905,15 +1905,15 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
>  }
>  
>  /**
> - * intel_disable_primary_plane - disable the primary plane
> + * intel_disable_primary_hw_plane - disable the primary hardware plane
>   * @dev_priv: i915 private structure
>   * @plane: plane to disable
>   * @pipe: pipe consuming the data
>   *
>   * Disable @plane; should be an independent operation.
>   */
> -static void intel_disable_primary_plane(struct drm_i915_private *dev_priv,
> -					enum plane plane, enum pipe pipe)
> +static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
> +					   enum plane plane, enum pipe pipe)
>  {
>  	struct intel_crtc *intel_crtc =
>  		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> @@ -2153,8 +2153,9 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
>  	}
>  }
>  
> -static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
> -			     int x, int y)
> +static int i9xx_update_primary_plane(struct drm_crtc *crtc,
> +				     struct drm_framebuffer *fb,
> +				     int x, int y)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -2253,8 +2254,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	return 0;
>  }
>  
> -static int ironlake_update_plane(struct drm_crtc *crtc,
> -				 struct drm_framebuffer *fb, int x, int y)
> +static int ironlake_update_primary_plane(struct drm_crtc *crtc,
> +					 struct drm_framebuffer *fb,
> +					 int x, int y)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -2358,7 +2360,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  		dev_priv->display.disable_fbc(dev);
>  	intel_increase_pllclock(crtc);
>  
> -	return dev_priv->display.update_plane(crtc, fb, x, y);
> +	return dev_priv->display.update_primary_plane(crtc, fb, x, y);
>  }
>  
>  void intel_display_handle_reset(struct drm_device *dev)
> @@ -2398,10 +2400,10 @@ void intel_display_handle_reset(struct drm_device *dev)
>  		 * a NULL crtc->primary->fb.
>  		 */
>  		if (intel_crtc->active && crtc->primary->fb)
> -			dev_priv->display.update_plane(crtc,
> -						       crtc->primary->fb,
> -						       crtc->x,
> -						       crtc->y);
> +			dev_priv->display.update_primary_plane(crtc,
> +							       crtc->primary->fb,
> +							       crtc->x,
> +							       crtc->y);
>  		mutex_unlock(&crtc->mutex);
>  	}
>  }
> @@ -2517,7 +2519,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
>  		intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
>  	}
>  
> -	ret = dev_priv->display.update_plane(crtc, fb, x, y);
> +	ret = dev_priv->display.update_primary_plane(crtc, fb, x, y);
>  	if (ret) {
>  		mutex_lock(&dev->struct_mutex);
>  		intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
> @@ -3704,7 +3706,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
>  
>  	intel_update_watermarks(crtc);
>  	intel_enable_pipe(intel_crtc);
> -	intel_enable_primary_plane(dev_priv, plane, pipe);
> +	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
>  	intel_enable_planes(crtc);
>  	intel_crtc_update_cursor(crtc, true);
>  
> @@ -3748,7 +3750,7 @@ static void haswell_crtc_enable_planes(struct drm_crtc *crtc)
>  	int pipe = intel_crtc->pipe;
>  	int plane = intel_crtc->plane;
>  
> -	intel_enable_primary_plane(dev_priv, plane, pipe);
> +	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
>  	intel_enable_planes(crtc);
>  	intel_crtc_update_cursor(crtc, true);
>  
> @@ -3780,7 +3782,7 @@ static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
>  
>  	intel_crtc_update_cursor(crtc, false);
>  	intel_disable_planes(crtc);
> -	intel_disable_primary_plane(dev_priv, plane, pipe);
> +	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
>  }
>  
>  /*
> @@ -3908,7 +3910,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>  
>  	intel_crtc_update_cursor(crtc, false);
>  	intel_disable_planes(crtc);
> -	intel_disable_primary_plane(dev_priv, plane, pipe);
> +	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
>  
>  	if (intel_crtc->config.has_pch_encoder)
>  		intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
> @@ -4391,7 +4393,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
>  	intel_update_watermarks(crtc);
>  	intel_enable_pipe(intel_crtc);
>  	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
> -	intel_enable_primary_plane(dev_priv, plane, pipe);
> +	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
>  	intel_enable_planes(crtc);
>  	intel_crtc_update_cursor(crtc, true);
>  
> @@ -4432,7 +4434,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
>  	intel_update_watermarks(crtc);
>  	intel_enable_pipe(intel_crtc);
>  	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
> -	intel_enable_primary_plane(dev_priv, plane, pipe);
> +	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
>  	intel_enable_planes(crtc);
>  	/* The fixup needs to happen before cursor is enabled */
>  	if (IS_G4X(dev))
> @@ -4490,7 +4492,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
>  	intel_crtc_dpms_overlay(intel_crtc, false);
>  	intel_crtc_update_cursor(crtc, false);
>  	intel_disable_planes(crtc);
> -	intel_disable_primary_plane(dev_priv, plane, pipe);
> +	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
>  
>  	intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
>  	intel_disable_pipe(dev_priv, pipe);
> @@ -11034,7 +11036,8 @@ static void intel_init_display(struct drm_device *dev)
>  		dev_priv->display.crtc_enable = haswell_crtc_enable;
>  		dev_priv->display.crtc_disable = haswell_crtc_disable;
>  		dev_priv->display.off = haswell_crtc_off;
> -		dev_priv->display.update_plane = ironlake_update_plane;
> +		dev_priv->display.update_primary_plane =
> +			ironlake_update_primary_plane;
>  	} else if (HAS_PCH_SPLIT(dev)) {
>  		dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
>  		dev_priv->display.get_plane_config = ironlake_get_plane_config;
> @@ -11042,7 +11045,8 @@ static void intel_init_display(struct drm_device *dev)
>  		dev_priv->display.crtc_enable = ironlake_crtc_enable;
>  		dev_priv->display.crtc_disable = ironlake_crtc_disable;
>  		dev_priv->display.off = ironlake_crtc_off;
> -		dev_priv->display.update_plane = ironlake_update_plane;
> +		dev_priv->display.update_primary_plane =
> +			ironlake_update_primary_plane;
>  	} else if (IS_VALLEYVIEW(dev)) {
>  		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
>  		dev_priv->display.get_plane_config = i9xx_get_plane_config;
> @@ -11050,7 +11054,8 @@ static void intel_init_display(struct drm_device *dev)
>  		dev_priv->display.crtc_enable = valleyview_crtc_enable;
>  		dev_priv->display.crtc_disable = i9xx_crtc_disable;
>  		dev_priv->display.off = i9xx_crtc_off;
> -		dev_priv->display.update_plane = i9xx_update_plane;
> +		dev_priv->display.update_primary_plane =
> +			i9xx_update_primary_plane;
>  	} else {
>  		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
>  		dev_priv->display.get_plane_config = i9xx_get_plane_config;
> @@ -11058,7 +11063,8 @@ static void intel_init_display(struct drm_device *dev)
>  		dev_priv->display.crtc_enable = i9xx_crtc_enable;
>  		dev_priv->display.crtc_disable = i9xx_crtc_disable;
>  		dev_priv->display.off = i9xx_crtc_off;
> -		dev_priv->display.update_plane = i9xx_update_plane;
> +		dev_priv->display.update_primary_plane =
> +			i9xx_update_primary_plane;
>  	}
>  
>  	/* Returns the core display clock speed */
> -- 
> 1.8.5.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Intel-gfx] [RFCv3 11/14] drm/i915: Intel-specific primary plane handling
  2014-03-19  0:22 ` [RFCv3 11/14] drm/i915: Intel-specific primary plane handling Matt Roper
@ 2014-03-19 12:11   ` Daniel Vetter
  2014-03-19 14:37     ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 12:11 UTC (permalink / raw)
  To: Matt Roper; +Cc: Intel Graphics Development, dri-devel

On Tue, Mar 18, 2014 at 05:22:56PM -0700, Matt Roper wrote:
> Intel hardware allows the primary plane to be disabled independently of
> the CRTC.  Provide custom primary plane handling to allow this.
> 
> Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Overall this is imo a new feature since it exposes primary plane disabling
to userspace. Which means I want a crc based igt for this. Two interesting
cases imo:

1) Partially visible primary plane behind an overlay plane. Disabling it
should change those areas from the primary plane to grey or something, so
easy to check with CRCs.

2) Primary plane + cursor, disable primary plane. Then check that the
cursor is still working. Same for overlay sprites.

At least on all currently supported platforms we don't have unified planes
in the hardware, so imo it's worth to check that this works properly.

> ---
>  drivers/gpu/drm/i915/intel_display.c | 132 ++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>  2 files changed, 130 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 849a241..7d6878b 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -39,6 +39,7 @@
>  #include "i915_trace.h"
>  #include <drm/drm_dp_helper.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_rect.h>
>  #include <linux/dma_remapping.h>
>  
>  static void intel_increase_pllclock(struct drm_crtc *crtc);
> @@ -10589,19 +10590,144 @@ static void intel_shared_dpll_init(struct drm_device *dev)
>  	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
>  }
>  
> +static int
> +intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
> +			     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
> +			     unsigned int crtc_w, unsigned int crtc_h,
> +			     uint32_t src_x, uint32_t src_y,
> +			     uint32_t src_w, uint32_t src_h)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +	struct drm_framebuffer *tmpfb;
> +	struct drm_rect dest = {
> +		.x1 = crtc_x,
> +		.y1 = crtc_y,
> +		.x2 = crtc_x + crtc_w,
> +		.y2 = crtc_y + crtc_h,
> +	};
> +	struct drm_rect clip = {
> +		.x2 = crtc->mode.hdisplay,
> +		.y2 = crtc->mode.vdisplay,
> +	};
> +	int ret;
> +
> +	/* setplane API takes shifted source rectangle values; unshift them */
> +	src_x >>= 16;
> +	src_y >>= 16;
> +	src_w >>= 16;
> +	src_h >>= 16;

Similar comments as with the generic helper: We need to check the scaling
constraints here better. Looks like a good opportunity to extract the
logic into some drm_rect helpers maybe?

> +
> +	/*
> +	 * Current hardware can't reposition the primary plane or scale it
> +	 * (although this could change in the future).
> +	 */
> +	drm_rect_intersect(&dest, &clip);
> +	if (dest.x1 != 0 || dest.y1 != 0 ||
> +	    dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) {
> +		DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n");
> +		return -EINVAL;
> +	}
> +
> +	if (crtc_w != src_w || crtc_h != src_h) {
> +		DRM_DEBUG_KMS("Can't scale primary plane\n");
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * pipe_set_base() adjusts crtc->primary->fb; however the DRM setplane
> +	 * code that called us expects to handle the framebuffer update and
> +	 * reference counting; save and restore the current fb before
> +	 * calling it.
> +	 */
> +	tmpfb = plane->fb;
> +	ret = intel_pipe_set_base(crtc, src_x, src_y, fb);
> +	if (ret)
> +		return ret;
> +	plane->fb = tmpfb;
> +
> +	if (!intel_crtc->primary_enabled)
> +		intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
> +					      intel_crtc->pipe);
> +
> +	return 0;
> +}
> +
> +static int
> +intel_primary_plane_disable(struct drm_plane *plane)
> +{
> +	struct drm_device *dev = plane->dev;
> +	drm_i915_private_t *dev_priv = dev->dev_private;
> +	struct intel_plane *intel_plane = to_intel_plane(plane);
> +	struct intel_crtc *intel_crtc;
> +
> +	if (!plane->fb)
> +		return 0;
> +
> +	if (WARN_ON(!plane->crtc))
> +		return -EINVAL;
> +
> +	intel_crtc = to_intel_crtc(plane->crtc);
> +	if (intel_crtc->primary_enabled)
> +		intel_disable_primary_hw_plane(dev_priv, intel_plane->plane,
> +					       intel_plane->pipe);
> +
> +	return 0;
> +}
> +
> +static void intel_primary_plane_destroy(struct drm_plane *plane)
> +{
> +	struct intel_plane *intel_plane = to_intel_plane(plane);
> +	intel_primary_plane_disable(plane);
> +	drm_plane_cleanup(plane);
> +	kfree(intel_plane);
> +}
> +
> +static const struct drm_plane_funcs intel_primary_plane_funcs = {
> +	.update_plane = intel_primary_plane_setplane,
> +	.disable_plane = intel_primary_plane_disable,
> +	.destroy = intel_primary_plane_destroy,
> +};
> +
> +static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
> +						    int pipe)
> +{
> +	struct intel_plane *primary;
> +
> +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> +	if (primary == NULL)
> +		return NULL;
> +
> +	primary->can_scale = false;
> +	primary->pipe = pipe;
> +	primary->plane = pipe;
> +
> +	drm_plane_init(dev, &primary->base, 0,
> +		       &intel_primary_plane_funcs, legacy_modeset_formats,
> +		       ARRAY_SIZE(legacy_modeset_formats),

We need our own proper format list for primary planes - we don't support
yuv and other crazy stuff like that on them. Also since we can now expose
this, I think we should have per-platform lists. E.g. only gen2/3 support
xrgb1555 and only gen4+ support xrgb2101010. Our framebuffer creation code
has all the limits properly encoded atm.

> +		       DRM_PLANE_TYPE_PRIMARY);
> +	return &primary->base;
> +}
> +
>  static void intel_crtc_init(struct drm_device *dev, int pipe)
>  {
>  	drm_i915_private_t *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc;
>  	struct drm_plane *primary;
> -	int i;
> +	int i, ret;
>  
>  	intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
>  	if (intel_crtc == NULL)
>  		return;
>  
> -	primary = drm_primary_helper_create_plane(dev);
> -	drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
> +	primary = intel_primary_plane_create(dev, pipe);
> +	ret = drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
> +	if (ret) {
> +		drm_crtc_cleanup(&intel_crtc->base);
> +		kfree(intel_crtc);
> +		return;
> +	}
>  
>  	drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
>  	for (i = 0; i < 256; i++) {
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 890c5cd..770f80d 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -351,6 +351,7 @@ struct intel_crtc {
>  	bool active;
>  	unsigned long enabled_power_domains;
>  	bool eld_vld;
> +	struct intel_plane *primary_plane;
>  	bool primary_enabled; /* is the primary plane (partially) visible? */
>  	bool lowfreq_avail;
>  	struct intel_overlay *overlay;
> -- 
> 1.8.5.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19  0:22 ` [RFCv3 03/14] drm: Add primary plane helpers Matt Roper
  2014-03-19 11:28   ` Daniel Vetter
  2014-03-19 11:50   ` Daniel Vetter
@ 2014-03-19 12:24   ` Daniel Vetter
  2014-03-19 23:01     ` Matt Roper
  2 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 12:24 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:48PM -0700, Matt Roper wrote:
> When we expose non-overlay planes to userspace, they will become
> accessible via standard userspace plane API's.  We should be able to
> handle the standard plane operations against primary planes in a generic
> way via the page flip handler and modeset handler.
> 
> Drivers that can program primary planes more efficiently, that want to
> use their own primary plane structure to track additional information,
> or that don't have the limitations assumed by the helpers are free to
> provide their own implementation of some or all of these handlers.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

One thing I've noticed with planes is that we don't have any per-plane
size limits. Which will be annoying for cursors at least, but looking at
intel's hw history there are other planes with limits smaller than
dev->mode_config.max_widht/height.

I think as part of the universal plane work here we should add this to the
getplane ioctl (we can extend at the end with full backwards compat) and
use the max_width/height as default for primary/overlay planes and
cursor_width/height for cursor planes.

Probably there's more stuff userspace might be interested in (like stride
limits and alignment maybe), but that'd be a start at least.
-Daniel

> ---
>  drivers/gpu/drm/drm_crtc.c | 288 +++++++++++++++++++++++++++++++++++++++------
>  include/drm/drm_crtc.h     |  81 +++++++++++++
>  2 files changed, 330 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 0983996..db54ae9 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1118,6 +1118,255 @@ void drm_plane_force_disable(struct drm_plane *plane)
>  }
>  EXPORT_SYMBOL(drm_plane_force_disable);
>  
> +/*
> + * Checks that the framebuffer is big enough for the CRTC viewport
> + * (x, y, hdisplay, vdisplay)
> + */
> +static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> +				   int x, int y,
> +				   const struct drm_display_mode *mode,
> +				   const struct drm_framebuffer *fb)
> +
> +{
> +	int hdisplay, vdisplay;
> +
> +	hdisplay = mode->hdisplay;
> +	vdisplay = mode->vdisplay;
> +
> +	if (drm_mode_is_stereo(mode)) {
> +		struct drm_display_mode adjusted = *mode;
> +
> +		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
> +		hdisplay = adjusted.crtc_hdisplay;
> +		vdisplay = adjusted.crtc_vdisplay;
> +	}
> +
> +	if (crtc->invert_dimensions)
> +		swap(hdisplay, vdisplay);
> +
> +	if (hdisplay > fb->width ||
> +	    vdisplay > fb->height ||
> +	    x > fb->width - hdisplay ||
> +	    y > fb->height - vdisplay) {
> +		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> +			      fb->width, fb->height, hdisplay, vdisplay, x, y,
> +			      crtc->invert_dimensions ? " (inverted)" : "");
> +		return -ENOSPC;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Returns the connectors currently associated with a CRTC.  This function
> + * should be called twice:  once with a NULL connector list to retrieve
> + * the list size, and once with the properly allocated list to be filled in.
> + */
> +static int get_connectors_for_crtc(struct drm_crtc *crtc,
> +				   struct drm_connector **connector_list,
> +				   int num_connectors)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_connector *connector;
> +	int count = 0;
> +
> +	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
> +		if (connector->encoder && connector->encoder->crtc == crtc) {
> +			if (connector_list != NULL && count < num_connectors)
> +				*(connector_list++) = connector;
> +
> +			count++;
> +		}
> +
> +	return count;
> +}
> +
> +/**
> + * drm_primary_helper_update() - Helper for primary plane update
> + * @plane: plane object to update
> + * @crtc: owning CRTC of owning plane
> + * @fb: framebuffer to flip onto plane
> + * @crtc_x: x offset of primary plane on crtc
> + * @crtc_y: y offset of primary plane on crtc
> + * @crtc_w: width of primary plane rectangle on crtc
> + * @crtc_h: height of primary plane rectangle on crtc
> + * @src_x: x offset of @fb for panning
> + * @src_y: y offset of @fb for panning
> + * @src_w: width of source rectangle in @fb
> + * @src_h: height of source rectangle in @fb
> + *
> + * Provides a default plane update handler for primary planes.  This is handler
> + * is called in response to a userspace SetPlane operation on the plane with a
> + * non-NULL framebuffer.  We call the driver's pageflip handler to update the
> + * framebuffer.
> + *
> + * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
> + * return an error.
> + *
> + * Note that we assume most hardware can't reposition or scale the primary
> + * plane, so we require that crtc_x = crtc_y = 0 and that src_w/src_h match the
> + * current mode.  Drivers for hardware that don't have these restrictions can
> + * provide their own implementation rather than using this helper.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
> +			      struct drm_framebuffer *fb,
> +			      int crtc_x, int crtc_y,
> +			      unsigned int crtc_w, unsigned int crtc_h,
> +			      uint32_t src_x, uint32_t src_y,
> +			      uint32_t src_w, uint32_t src_h)
> +{
> +	struct drm_mode_set set = {
> +		.crtc = crtc,
> +		.fb = fb,
> +		.mode = &crtc->mode,
> +		.x = crtc_x,
> +		.y = crtc_y,
> +	};
> +	struct drm_connector **connector_list;
> +	struct drm_framebuffer *tmpfb;
> +	int num_connectors, ret;
> +
> +	/* setplane API takes shifted source rectangle values; unshift them */
> +	src_x >>= 16;
> +	src_y >>= 16;
> +	src_w >>= 16;
> +	src_h >>= 16;
> +
> +	/* Primary planes are locked to their owning CRTC */
> +	if (plane->possible_crtcs != drm_crtc_mask(crtc)) {
> +		DRM_DEBUG_KMS("Cannot change primary plane CRTC\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!crtc->enabled) {
> +		DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb);
> +	if (ret)
> +		return ret;
> +
> +	/* Find current connectors for CRTC */
> +	num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
> +	BUG_ON(num_connectors == 0);
> +	connector_list = kzalloc(num_connectors * sizeof(*connector_list),
> +				 GFP_KERNEL);
> +	if (!connector_list)
> +		return -ENOMEM;
> +	get_connectors_for_crtc(crtc, connector_list, num_connectors);
> +
> +	set.connectors = connector_list;
> +	set.num_connectors = num_connectors;
> +
> +	/*
> +	 * set_config() adjusts crtc->primary->fb; however the DRM setplane
> +	 * code that called us expects to handle the framebuffer update and
> +	 * reference counting; save and restore the current fb before
> +	 * calling it.
> +	 */
> +	tmpfb = plane->fb;
> +	ret = crtc->funcs->set_config(&set);
> +	plane->fb = tmpfb;
> +
> +	kfree(connector_list);
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_primary_helper_update);
> +
> +/**
> + * drm_primary_helper_disable() - Helper for primary plane disable
> + * @plane: plane to disable
> + *
> + * Provides a default plane disable handler for primary planes.  This is handler
> + * is called in response to a userspace SetPlane operation on the plane with a
> + * NULL framebuffer parameter.  We call the driver's modeset handler with a NULL
> + * framebuffer to disable the CRTC.
> + *
> + * Note that some hardware may be able to disable the primary plane without
> + * disabling the whole CRTC.  Drivers for such hardware should provide their
> + * own disable handler that disables just the primary plane (and they'll likely
> + * need to provide their own update handler as well to properly re-enable a
> + * disabled primary plane).
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_primary_helper_disable(struct drm_plane *plane)
> +{
> +	struct drm_mode_set set = {
> +		.crtc = plane->crtc,
> +		.fb = NULL,
> +	};
> +
> +	if (plane->crtc == NULL || plane->fb == NULL)
> +		/* Already disabled */
> +		return 0;
> +
> +	return plane->crtc->funcs->set_config(&set);
> +}
> +EXPORT_SYMBOL(drm_primary_helper_disable);
> +
> +/**
> + * drm_primary_helper_destroy() - Helper for primary plane destruction
> + * @plane: plane to destroy
> + *
> + * Provides a default plane destroy handler for primary planes.  This handler
> + * is called during CRTC destruction.  We disable the primary plane, remove
> + * it from the DRM plane list, and deallocate the plane structure.
> + */
> +void drm_primary_helper_destroy(struct drm_plane *plane)
> +{
> +	plane->funcs->disable_plane(plane);
> +	drm_plane_cleanup(plane);
> +	kfree(plane);
> +}
> +EXPORT_SYMBOL(drm_primary_helper_destroy);
> +
> +const struct drm_plane_funcs drm_primary_helper_funcs = {
> +	.update_plane = drm_primary_helper_update,
> +	.disable_plane = drm_primary_helper_disable,
> +	.destroy = drm_primary_helper_destroy,
> +};
> +EXPORT_SYMBOL(drm_primary_helper_funcs);
> +
> +/**
> + * drm_primary_helper_create_plane() - Create a generic primary plane
> + * @dev: drm device
> + *
> + * Allocates and initializes a primary plane that can be used with the primary
> + * plane helpers.  Drivers that wish to use driver-specific plane structures or
> + * provide custom handler functions may perform their own allocation and
> + * initialization rather than calling this function.
> + */
> +struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev)
> +{
> +	struct drm_plane *primary;
> +	int ret;
> +
> +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> +	if (primary == NULL) {
> +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
> +		return NULL;
> +	}
> +
> +	/* possible_crtc's will be filled in later by crtc_init */
> +	ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
> +			     legacy_modeset_formats,
> +			     ARRAY_SIZE(legacy_modeset_formats),
> +			     DRM_PLANE_TYPE_PRIMARY);
> +	if (ret) {
> +		kfree(primary);
> +		primary = NULL;
> +	}
> +
> +	return primary;
> +}
> +EXPORT_SYMBOL(drm_primary_helper_create_plane);
> +
>  static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
>  {
>  	struct drm_property *edid;
> @@ -2185,45 +2434,6 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>  }
>  EXPORT_SYMBOL(drm_mode_set_config_internal);
>  
> -/*
> - * Checks that the framebuffer is big enough for the CRTC viewport
> - * (x, y, hdisplay, vdisplay)
> - */
> -static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> -				   int x, int y,
> -				   const struct drm_display_mode *mode,
> -				   const struct drm_framebuffer *fb)
> -
> -{
> -	int hdisplay, vdisplay;
> -
> -	hdisplay = mode->hdisplay;
> -	vdisplay = mode->vdisplay;
> -
> -	if (drm_mode_is_stereo(mode)) {
> -		struct drm_display_mode adjusted = *mode;
> -
> -		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
> -		hdisplay = adjusted.crtc_hdisplay;
> -		vdisplay = adjusted.crtc_vdisplay;
> -	}
> -
> -	if (crtc->invert_dimensions)
> -		swap(hdisplay, vdisplay);
> -
> -	if (hdisplay > fb->width ||
> -	    vdisplay > fb->height ||
> -	    x > fb->width - hdisplay ||
> -	    y > fb->height - vdisplay) {
> -		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> -			      fb->width, fb->height, hdisplay, vdisplay, x, y,
> -			      crtc->invert_dimensions ? " (inverted)" : "");
> -		return -ENOSPC;
> -	}
> -
> -	return 0;
> -}
> -
>  /**
>   * drm_mode_setcrtc - set CRTC configuration
>   * @dev: drm device for the ioctl
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index e69ada8..f43fa92 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -581,6 +581,87 @@ struct drm_plane {
>  	enum drm_plane_type type;
>  };
>  
> +extern int drm_primary_helper_update(struct drm_plane *plane,
> +				     struct drm_crtc *crtc,
> +				     struct drm_framebuffer *fb,
> +				     int crtc_x, int crtc_y,
> +				     unsigned int crtc_w, unsigned int crtc_h,
> +				     uint32_t src_x, uint32_t src_y,
> +				     uint32_t src_w, uint32_t src_h);
> +extern int drm_primary_helper_disable(struct drm_plane *plane);
> +extern void drm_primary_helper_destroy(struct drm_plane *plane);
> +extern const struct drm_plane_funcs drm_primary_helper_funcs;
> +extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev);
> +
> +/*
> + * This is the list of formats that have historically been accepted by the
> + * modeset API.  The primary plane helpers use this list by default, but
> + * individual drivers may provide their own primary plane initialization
> + * that provides a more hw-specific format list.
> + */
> +const static uint32_t legacy_modeset_formats[] = {
> +       DRM_FORMAT_C8,
> +       DRM_FORMAT_RGB332,
> +       DRM_FORMAT_BGR233,
> +       DRM_FORMAT_XRGB4444,
> +       DRM_FORMAT_XBGR4444,
> +       DRM_FORMAT_RGBX4444,
> +       DRM_FORMAT_BGRX4444,
> +       DRM_FORMAT_ARGB4444,
> +       DRM_FORMAT_ABGR4444,
> +       DRM_FORMAT_RGBA4444,
> +       DRM_FORMAT_BGRA4444,
> +       DRM_FORMAT_XRGB1555,
> +       DRM_FORMAT_XBGR1555,
> +       DRM_FORMAT_RGBX5551,
> +       DRM_FORMAT_BGRX5551,
> +       DRM_FORMAT_ARGB1555,
> +       DRM_FORMAT_ABGR1555,
> +       DRM_FORMAT_RGBA5551,
> +       DRM_FORMAT_BGRA5551,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_BGR565,
> +       DRM_FORMAT_RGB888,
> +       DRM_FORMAT_BGR888,
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_RGBX8888,
> +       DRM_FORMAT_BGRX8888,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_ABGR8888,
> +       DRM_FORMAT_RGBA8888,
> +       DRM_FORMAT_BGRA8888,
> +       DRM_FORMAT_XRGB2101010,
> +       DRM_FORMAT_XBGR2101010,
> +       DRM_FORMAT_RGBX1010102,
> +       DRM_FORMAT_BGRX1010102,
> +       DRM_FORMAT_ARGB2101010,
> +       DRM_FORMAT_ABGR2101010,
> +       DRM_FORMAT_RGBA1010102,
> +       DRM_FORMAT_BGRA1010102,
> +       DRM_FORMAT_YUYV,
> +       DRM_FORMAT_YVYU,
> +       DRM_FORMAT_UYVY,
> +       DRM_FORMAT_VYUY,
> +       DRM_FORMAT_AYUV,
> +       DRM_FORMAT_NV12,
> +       DRM_FORMAT_NV21,
> +       DRM_FORMAT_NV16,
> +       DRM_FORMAT_NV61,
> +       DRM_FORMAT_NV24,
> +       DRM_FORMAT_NV42,
> +       DRM_FORMAT_YUV410,
> +       DRM_FORMAT_YVU410,
> +       DRM_FORMAT_YUV411,
> +       DRM_FORMAT_YVU411,
> +       DRM_FORMAT_YUV420,
> +       DRM_FORMAT_YVU420,
> +       DRM_FORMAT_YUV422,
> +       DRM_FORMAT_YVU422,
> +       DRM_FORMAT_YUV444,
> +       DRM_FORMAT_YVU444,
> +};
> +
>  /**
>   * drm_bridge_funcs - drm_bridge control functions
>   * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
> -- 
> 1.8.5.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19 11:28   ` Daniel Vetter
@ 2014-03-19 12:56     ` Rob Clark
  2014-03-19 18:15     ` Matt Roper
  1 sibling, 0 replies; 46+ messages in thread
From: Rob Clark @ 2014-03-19 12:56 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Wed, Mar 19, 2014 at 7:28 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
>> +     /*
>> +      * set_config() adjusts crtc->primary->fb; however the DRM setplane
>> +      * code that called us expects to handle the framebuffer update and
>> +      * reference counting; save and restore the current fb before
>> +      * calling it.
>> +      */
>> +     tmpfb = plane->fb;
>> +     ret = crtc->funcs->set_config(&set);
>
> I wonder whether we should have an oppportunistic path using the page_flip
> interface here. Otoh we must have a fallback to ->set_config anyway since
> the drivers currently only allow pageflips on identical buffers. E.g. i915
> rejects tiling changes and stride changes and position changes. So I think
> having a pageflip fastpath isn't worth the trouble.


note that you'd get that opportunistic page_flip() path w/ the
addition of atomic series.  Although depending on when the two
different series are merged, the .page_flip() fast path might be a
good idea

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes
  2014-03-19 11:51   ` Daniel Vetter
@ 2014-03-19 14:26     ` Daniel Kurtz
  2014-03-19 19:31       ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Kurtz @ 2014-03-19 14:26 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Wed, Mar 19, 2014 at 7:51 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Tue, Mar 18, 2014 at 05:22:49PM -0700, Matt Roper wrote:
>> Before we add additional types of planes to the DRM plane list, ensure
>> that existing loops over all planes continue to operate only on
>> "overlay" planes and ignore primary & cursor planes.
>>
>> Cc: Inki Dae <inki.dae@samsung.com>
>> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
>> ---
>>  drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 ++++++
>>  1 file changed, 6 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> index 06f1b2a..2fa2685 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> @@ -127,6 +127,9 @@ static void disable_plane_to_crtc(struct drm_device *dev,
>>        * (encoder->crtc)
>>        */
>>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
>> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
>
> I think a drm_for_each_legacy_plane iteration helper would be neat for
> this one and the following i915 patch.
> -Daniel
>
>> +                     continue;
>> +
>>               if (plane->crtc == old_crtc) {
>>                       /*
>>                        * do not change below call order.
>> @@ -247,6 +250,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
>>
>>       /* all planes connected to this encoder should be also disabled. */
>>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
>> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
>> +                     continue;
>> +
>>               if (plane->crtc == encoder->crtc)
>>                       plane->funcs->disable_plane(plane);
>>       }

The original loop disables all planes attached to a crtc when
disabling an encoder attached to the same crtc.  It was added by:

commit bcf4cef94294992f7cd11d5a90fa58b0eae6c795
Author: Inki Dae <inki.dae@samsung.com>
Date:   Fri Aug 24 10:54:12 2012 -0700

    drm/exynos: Disable plane when released

    this patch ensures that each plane connected to encoder is disabled
    when released, by adding disable callback function of encoder helper

    we had faced with one issue that invalid memory is accessed by dma
    once drm is released and then the dma is turned on again. actually,
    in our case, page fault was incurred with iommu. the reason is that
    a gem buffer accessed by the dma is also released once drm is released.

    so this patch would fix this issue ensuring the dma is disabled
    when released.


An encoder receives and encodes the mixed output of all of the
planes/overlays.  It would seem that whether the individual planes
themselves are enabled or not should be completely independent of the
status any encoder.  However, I find the code in exynos_drm_encoder.c
very difficult to follow, so perhaps there is some extra linkage
between encoder/crtc/plane that is exynos specific.

In any case, judging from the commit message, this disable loop should
probably still iterate over all of the planes, not just the
"DRM_PLANE_TYPE_OVERLAY" ones.  So, I think this new patch is
incorrect.


>> --
>> 1.8.5.1
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 09/14] drm: Allow userspace to ask for full plane list (universal planes)
  2014-03-19  0:22 ` [RFCv3 09/14] drm: Allow userspace to ask for full plane list (universal planes) Matt Roper
@ 2014-03-19 14:27   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 14:27 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:54PM -0700, Matt Roper wrote:
> Userspace clients which wish to receive all DRM planes (primary and
> cursor planes in addition to the traditional overlay planes) may set the
> DRM_CLIENT_CAP_UNIVERSAL_PLANES capability.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

I don't see any issues with merging the primary plane stuff early, but I
think we should hold off a bit with exposing all this to userspace, at
least by default. I think we should have the cursor plane issues all
resolved and at least the userspace tests in decent shape before we throw
the big switch here.
-Daniel


> ---
>  drivers/gpu/drm/drm_crtc.c  | 20 +++++++++++++++-----
>  drivers/gpu/drm/drm_ioctl.c |  5 +++++
>  include/drm/drmP.h          |  5 +++++
>  include/uapi/drm/drm.h      |  8 ++++++++
>  4 files changed, 33 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 0c395e8..fb8e493 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -2160,6 +2160,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
>  	struct drm_plane *plane;
>  	uint32_t __user *plane_ptr;
>  	int copied = 0, ret = 0;
> +	unsigned num_planes;
>  
>  	if (!drm_core_check_feature(dev, DRIVER_MODESET))
>  		return -EINVAL;
> @@ -2167,17 +2168,26 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
>  	drm_modeset_lock_all(dev);
>  	config = &dev->mode_config;
>  
> +	if (file_priv->universal_planes)
> +		num_planes = config->num_total_plane;
> +	else
> +		num_planes = config->num_overlay_plane;
> +
>  	/*
>  	 * This ioctl is called twice, once to determine how much space is
>  	 * needed, and the 2nd time to fill it.
>  	 */
> -	if (config->num_overlay_plane &&
> -	    (plane_resp->count_planes >= config->num_overlay_plane)) {
> +	if (num_planes &&
> +	    (plane_resp->count_planes >= num_planes)) {
>  		plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
>  
>  		list_for_each_entry(plane, &config->plane_list, head) {
> -			/* Only advertise overlays to userspace for now. */
> -			if (plane->type != DRM_PLANE_TYPE_OVERLAY)
> +			/*
> +			 * Unless userspace set the 'universal planes'
> +			 * capability bit, only advertise overlays.
> +			 */
> +			if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
> +			    !file_priv->universal_planes)
>  				continue;
>  
>  			if (put_user(plane->base.id, plane_ptr + copied)) {
> @@ -2187,7 +2197,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
>  			copied++;
>  		}
>  	}
> -	plane_resp->count_planes = config->num_overlay_plane;
> +	plane_resp->count_planes = num_planes;
>  
>  out:
>  	drm_modeset_unlock_all(dev);
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index f4dc9b7..5eb92b6 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -328,6 +328,11 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
>  			return -EINVAL;
>  		file_priv->stereo_allowed = req->value;
>  		break;
> +	case DRM_CLIENT_CAP_UNIVERSAL_PLANES:
> +		if (req->value > 1)
> +			return -EINVAL;
> +		file_priv->universal_planes = req->value;
> +		break;
>  	default:
>  		return -EINVAL;
>  	}
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 3857450..1106297 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -438,6 +438,11 @@ struct drm_file {
>  	unsigned is_master :1; /* this file private is a master for a minor */
>  	/* true when the client has asked us to expose stereo 3D mode flags */
>  	unsigned stereo_allowed :1;
> +	/*
> +	 * true if client understands CRTC primary planes and cursor planes
> +	 * in the plane list
> +	 */
> +	unsigned universal_planes:1;
>  
>  	struct pid *pid;
>  	kuid_t uid;
> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> index b06c8ed..6e4952b 100644
> --- a/include/uapi/drm/drm.h
> +++ b/include/uapi/drm/drm.h
> @@ -637,6 +637,14 @@ struct drm_get_cap {
>   */
>  #define DRM_CLIENT_CAP_STEREO_3D	1
>  
> +/**
> + * DRM_CLIENT_CAP_UNIVERSAL_PLANES
> + *
> + * If set to 1, the DRM core will expose all planes (overlay, primary, and
> + * cursor) to userspace.
> + */
> +#define DRM_CLIENT_CAP_UNIVERSAL_PLANES  2
> +
>  /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
>  struct drm_set_client_cap {
>  	__u64 capability;
> -- 
> 1.8.5.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 11/14] drm/i915: Intel-specific primary plane handling
  2014-03-19 12:11   ` [Intel-gfx] " Daniel Vetter
@ 2014-03-19 14:37     ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 14:37 UTC (permalink / raw)
  To: Matt Roper; +Cc: Intel Graphics Development, dri-devel

On Wed, Mar 19, 2014 at 01:11:26PM +0100, Daniel Vetter wrote:
> On Tue, Mar 18, 2014 at 05:22:56PM -0700, Matt Roper wrote:
> > Intel hardware allows the primary plane to be disabled independently of
> > the CRTC.  Provide custom primary plane handling to allow this.
> > 
> > Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> 
> Overall this is imo a new feature since it exposes primary plane disabling
> to userspace. Which means I want a crc based igt for this. Two interesting
> cases imo:
> 
> 1) Partially visible primary plane behind an overlay plane. Disabling it
> should change those areas from the primary plane to grey or something, so
> easy to check with CRCs.
> 
> 2) Primary plane + cursor, disable primary plane. Then check that the
> cursor is still working. Same for overlay sprites.
> 
> At least on all currently supported platforms we don't have unified planes
> in the hardware, so imo it's worth to check that this works properly.

One big reason I've forgotten why I really want testcase for this is that
historically our code has fallen over in _really_ bad ways without a
primary fb. fastboot has brought a lot of these issues to light (since we
occasionally fail to wrap up the firmware's fb properly). So having a bit
of a baseline testcase so that we can easily add regression tests for
specific bugs once we inevitably run into them is good prep work, too.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19 11:28   ` Daniel Vetter
  2014-03-19 12:56     ` Rob Clark
@ 2014-03-19 18:15     ` Matt Roper
  2014-03-19 19:29       ` Daniel Vetter
  1 sibling, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19 18:15 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Wed, Mar 19, 2014 at 12:28:43PM +0100, Daniel Vetter wrote:
> On Tue, Mar 18, 2014 at 05:22:48PM -0700, Matt Roper wrote:
...
> > +
> > +	/*
> > +	 * set_config() adjusts crtc->primary->fb; however the DRM setplane
> > +	 * code that called us expects to handle the framebuffer update and
> > +	 * reference counting; save and restore the current fb before
> > +	 * calling it.
> > +	 */
> > +	tmpfb = plane->fb;
> > +	ret = crtc->funcs->set_config(&set);
> 
> I wonder whether we should have an oppportunistic path using the page_flip
> interface here. Otoh we must have a fallback to ->set_config anyway since
> the drivers currently only allow pageflips on identical buffers. E.g. i915
> rejects tiling changes and stride changes and position changes. So I think
> having a pageflip fastpath isn't worth the trouble.
> 
> Also I think you need to use set_config_internal here to get the
> refcounting right.

Hmm.  I specifically didn't use set_config_internal here because I
thought drm_mode_setplane() (and presumably the future atomic ioctl
which may also call into this) will already handle the refcounting for
us.  Am I overlooking something?


Matt

-- 
Matt Roper
Graphics Software Engineer
ISG Platform Enabling & Development
Intel Corporation
(916) 356-2795

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19 18:15     ` Matt Roper
@ 2014-03-19 19:29       ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 19:29 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Wed, Mar 19, 2014 at 11:15:36AM -0700, Matt Roper wrote:
> On Wed, Mar 19, 2014 at 12:28:43PM +0100, Daniel Vetter wrote:
> > On Tue, Mar 18, 2014 at 05:22:48PM -0700, Matt Roper wrote:
> ...
> > > +
> > > +	/*
> > > +	 * set_config() adjusts crtc->primary->fb; however the DRM setplane
> > > +	 * code that called us expects to handle the framebuffer update and
> > > +	 * reference counting; save and restore the current fb before
> > > +	 * calling it.
> > > +	 */
> > > +	tmpfb = plane->fb;
> > > +	ret = crtc->funcs->set_config(&set);
> > 
> > I wonder whether we should have an oppportunistic path using the page_flip
> > interface here. Otoh we must have a fallback to ->set_config anyway since
> > the drivers currently only allow pageflips on identical buffers. E.g. i915
> > rejects tiling changes and stride changes and position changes. So I think
> > having a pageflip fastpath isn't worth the trouble.
> > 
> > Also I think you need to use set_config_internal here to get the
> > refcounting right.
> 
> Hmm.  I specifically didn't use set_config_internal here because I
> thought drm_mode_setplane() (and presumably the future atomic ioctl
> which may also call into this) will already handle the refcounting for
> us.  Am I overlooking something?

Hm, I need to take a closer look again, but set_config has some really
funny rules about who updates which pointer and who grabs references for
which fb. Mostly since this has all grown rather add-hoc.

But you're right and the update_plane code already has some refcounting
and frobbing of its own, so I'm not sure what we really need to do here.
I think it at least needs a really big comment explaining what's going on.

Note that iirc the crtc helper code can still disable connectors in _any_
setcrtc call, so you might accidentally end up in a full modeset, with all
the fun this entails.

Definitely need to think more about this here. I hope we don't need to
rework the semantics of all drivers, since that would be major pain.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes
  2014-03-19 14:26     ` Daniel Kurtz
@ 2014-03-19 19:31       ` Daniel Vetter
  2014-03-20  1:56         ` Daniel Kurtz
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2014-03-19 19:31 UTC (permalink / raw)
  To: Daniel Kurtz; +Cc: dri-devel

On Wed, Mar 19, 2014 at 10:26:13PM +0800, Daniel Kurtz wrote:
> On Wed, Mar 19, 2014 at 7:51 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Tue, Mar 18, 2014 at 05:22:49PM -0700, Matt Roper wrote:
> >> Before we add additional types of planes to the DRM plane list, ensure
> >> that existing loops over all planes continue to operate only on
> >> "overlay" planes and ignore primary & cursor planes.
> >>
> >> Cc: Inki Dae <inki.dae@samsung.com>
> >> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> >> ---
> >>  drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 ++++++
> >>  1 file changed, 6 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> >> index 06f1b2a..2fa2685 100644
> >> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> >> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> >> @@ -127,6 +127,9 @@ static void disable_plane_to_crtc(struct drm_device *dev,
> >>        * (encoder->crtc)
> >>        */
> >>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> >> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
> >
> > I think a drm_for_each_legacy_plane iteration helper would be neat for
> > this one and the following i915 patch.
> > -Daniel
> >
> >> +                     continue;
> >> +
> >>               if (plane->crtc == old_crtc) {
> >>                       /*
> >>                        * do not change below call order.
> >> @@ -247,6 +250,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
> >>
> >>       /* all planes connected to this encoder should be also disabled. */
> >>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> >> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
> >> +                     continue;
> >> +
> >>               if (plane->crtc == encoder->crtc)
> >>                       plane->funcs->disable_plane(plane);
> >>       }
> 
> The original loop disables all planes attached to a crtc when
> disabling an encoder attached to the same crtc.  It was added by:
> 
> commit bcf4cef94294992f7cd11d5a90fa58b0eae6c795
> Author: Inki Dae <inki.dae@samsung.com>
> Date:   Fri Aug 24 10:54:12 2012 -0700
> 
>     drm/exynos: Disable plane when released
> 
>     this patch ensures that each plane connected to encoder is disabled
>     when released, by adding disable callback function of encoder helper
> 
>     we had faced with one issue that invalid memory is accessed by dma
>     once drm is released and then the dma is turned on again. actually,
>     in our case, page fault was incurred with iommu. the reason is that
>     a gem buffer accessed by the dma is also released once drm is released.
> 
>     so this patch would fix this issue ensuring the dma is disabled
>     when released.
> 
> 
> An encoder receives and encodes the mixed output of all of the
> planes/overlays.  It would seem that whether the individual planes
> themselves are enabled or not should be completely independent of the
> status any encoder.  However, I find the code in exynos_drm_encoder.c
> very difficult to follow, so perhaps there is some extra linkage
> between encoder/crtc/plane that is exynos specific.
> 
> In any case, judging from the commit message, this disable loop should
> probably still iterate over all of the planes, not just the
> "DRM_PLANE_TYPE_OVERLAY" ones.  So, I think this new patch is
> incorrect.

It keeps full backwars compatibility with existing semantics, which is the
right thing to do in such a case. It could be that exynos simply has a
bug, but imo that should be a separate patch outside of this series.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19 12:24   ` Daniel Vetter
@ 2014-03-19 23:01     ` Matt Roper
  2014-03-20 12:39       ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-19 23:01 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Wed, Mar 19, 2014 at 01:24:23PM +0100, Daniel Vetter wrote:
> On Tue, Mar 18, 2014 at 05:22:48PM -0700, Matt Roper wrote:
> > When we expose non-overlay planes to userspace, they will become
> > accessible via standard userspace plane API's.  We should be able to
> > handle the standard plane operations against primary planes in a generic
> > way via the page flip handler and modeset handler.
> > 
> > Drivers that can program primary planes more efficiently, that want to
> > use their own primary plane structure to track additional information,
> > or that don't have the limitations assumed by the helpers are free to
> > provide their own implementation of some or all of these handlers.
> > 
> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> 
> One thing I've noticed with planes is that we don't have any per-plane
> size limits. Which will be annoying for cursors at least, but looking at
> intel's hw history there are other planes with limits smaller than
> dev->mode_config.max_widht/height.
> 
> I think as part of the universal plane work here we should add this to the
> getplane ioctl (we can extend at the end with full backwards compat) and
> use the max_width/height as default for primary/overlay planes and
> cursor_width/height for cursor planes.

I'm not sure I understand how to (cleanly) extend the existing ioctl
safely.  Userspace (libdrm) allocates a drm_mode_get_plane structure on
the stack with a specific size.  If we try to extend this structure to
return more information, and have the kernel write into the new fields,
aren't we just going to be spilling over into other userspace stack
variables if we run an old libdrm on the new kernel?  The only
approaches I see that could make this work would be huge ugly hacks:
 * Reclaiming the top few bits of plane_id to use as "I sent you the
   new, larger structure" capability flags (which assumes plane ID's are
   always small enough to leave those bits 0 on current kernels; this
   would effectively reduce our plane ID address space).
 * Figure out a way to encode extra information as bogus pixel formats
   and shove it into the format list returned to userspace.  Presumably
   userspace would just ignore/skip the bogus formats.

I suppose we could add a new GetPlane2 ioctl or something that returned
more info, but I figured it was probably easier to just shove max plane
size (and a bunch of other plane capabilities / limitations) into some
new read-only plane properties.  Read-only properties are easy to extend
if we find other pieces of information we want to return in the future,
so that seems like the most natural interface to me.


Matt

> 
> Probably there's more stuff userspace might be interested in (like stride
> limits and alignment maybe), but that'd be a start at least.
> -Daniel
> 
> > ---
> >  drivers/gpu/drm/drm_crtc.c | 288 +++++++++++++++++++++++++++++++++++++++------
> >  include/drm/drm_crtc.h     |  81 +++++++++++++
> >  2 files changed, 330 insertions(+), 39 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> > index 0983996..db54ae9 100644
> > --- a/drivers/gpu/drm/drm_crtc.c
> > +++ b/drivers/gpu/drm/drm_crtc.c
> > @@ -1118,6 +1118,255 @@ void drm_plane_force_disable(struct drm_plane *plane)
> >  }
> >  EXPORT_SYMBOL(drm_plane_force_disable);
> >  
> > +/*
> > + * Checks that the framebuffer is big enough for the CRTC viewport
> > + * (x, y, hdisplay, vdisplay)
> > + */
> > +static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> > +				   int x, int y,
> > +				   const struct drm_display_mode *mode,
> > +				   const struct drm_framebuffer *fb)
> > +
> > +{
> > +	int hdisplay, vdisplay;
> > +
> > +	hdisplay = mode->hdisplay;
> > +	vdisplay = mode->vdisplay;
> > +
> > +	if (drm_mode_is_stereo(mode)) {
> > +		struct drm_display_mode adjusted = *mode;
> > +
> > +		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
> > +		hdisplay = adjusted.crtc_hdisplay;
> > +		vdisplay = adjusted.crtc_vdisplay;
> > +	}
> > +
> > +	if (crtc->invert_dimensions)
> > +		swap(hdisplay, vdisplay);
> > +
> > +	if (hdisplay > fb->width ||
> > +	    vdisplay > fb->height ||
> > +	    x > fb->width - hdisplay ||
> > +	    y > fb->height - vdisplay) {
> > +		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> > +			      fb->width, fb->height, hdisplay, vdisplay, x, y,
> > +			      crtc->invert_dimensions ? " (inverted)" : "");
> > +		return -ENOSPC;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * Returns the connectors currently associated with a CRTC.  This function
> > + * should be called twice:  once with a NULL connector list to retrieve
> > + * the list size, and once with the properly allocated list to be filled in.
> > + */
> > +static int get_connectors_for_crtc(struct drm_crtc *crtc,
> > +				   struct drm_connector **connector_list,
> > +				   int num_connectors)
> > +{
> > +	struct drm_device *dev = crtc->dev;
> > +	struct drm_connector *connector;
> > +	int count = 0;
> > +
> > +	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
> > +		if (connector->encoder && connector->encoder->crtc == crtc) {
> > +			if (connector_list != NULL && count < num_connectors)
> > +				*(connector_list++) = connector;
> > +
> > +			count++;
> > +		}
> > +
> > +	return count;
> > +}
> > +
> > +/**
> > + * drm_primary_helper_update() - Helper for primary plane update
> > + * @plane: plane object to update
> > + * @crtc: owning CRTC of owning plane
> > + * @fb: framebuffer to flip onto plane
> > + * @crtc_x: x offset of primary plane on crtc
> > + * @crtc_y: y offset of primary plane on crtc
> > + * @crtc_w: width of primary plane rectangle on crtc
> > + * @crtc_h: height of primary plane rectangle on crtc
> > + * @src_x: x offset of @fb for panning
> > + * @src_y: y offset of @fb for panning
> > + * @src_w: width of source rectangle in @fb
> > + * @src_h: height of source rectangle in @fb
> > + *
> > + * Provides a default plane update handler for primary planes.  This is handler
> > + * is called in response to a userspace SetPlane operation on the plane with a
> > + * non-NULL framebuffer.  We call the driver's pageflip handler to update the
> > + * framebuffer.
> > + *
> > + * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
> > + * return an error.
> > + *
> > + * Note that we assume most hardware can't reposition or scale the primary
> > + * plane, so we require that crtc_x = crtc_y = 0 and that src_w/src_h match the
> > + * current mode.  Drivers for hardware that don't have these restrictions can
> > + * provide their own implementation rather than using this helper.
> > + *
> > + * RETURNS:
> > + * Zero on success, error code on failure
> > + */
> > +int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
> > +			      struct drm_framebuffer *fb,
> > +			      int crtc_x, int crtc_y,
> > +			      unsigned int crtc_w, unsigned int crtc_h,
> > +			      uint32_t src_x, uint32_t src_y,
> > +			      uint32_t src_w, uint32_t src_h)
> > +{
> > +	struct drm_mode_set set = {
> > +		.crtc = crtc,
> > +		.fb = fb,
> > +		.mode = &crtc->mode,
> > +		.x = crtc_x,
> > +		.y = crtc_y,
> > +	};
> > +	struct drm_connector **connector_list;
> > +	struct drm_framebuffer *tmpfb;
> > +	int num_connectors, ret;
> > +
> > +	/* setplane API takes shifted source rectangle values; unshift them */
> > +	src_x >>= 16;
> > +	src_y >>= 16;
> > +	src_w >>= 16;
> > +	src_h >>= 16;
> > +
> > +	/* Primary planes are locked to their owning CRTC */
> > +	if (plane->possible_crtcs != drm_crtc_mask(crtc)) {
> > +		DRM_DEBUG_KMS("Cannot change primary plane CRTC\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (!crtc->enabled) {
> > +		DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Find current connectors for CRTC */
> > +	num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
> > +	BUG_ON(num_connectors == 0);
> > +	connector_list = kzalloc(num_connectors * sizeof(*connector_list),
> > +				 GFP_KERNEL);
> > +	if (!connector_list)
> > +		return -ENOMEM;
> > +	get_connectors_for_crtc(crtc, connector_list, num_connectors);
> > +
> > +	set.connectors = connector_list;
> > +	set.num_connectors = num_connectors;
> > +
> > +	/*
> > +	 * set_config() adjusts crtc->primary->fb; however the DRM setplane
> > +	 * code that called us expects to handle the framebuffer update and
> > +	 * reference counting; save and restore the current fb before
> > +	 * calling it.
> > +	 */
> > +	tmpfb = plane->fb;
> > +	ret = crtc->funcs->set_config(&set);
> > +	plane->fb = tmpfb;
> > +
> > +	kfree(connector_list);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL(drm_primary_helper_update);
> > +
> > +/**
> > + * drm_primary_helper_disable() - Helper for primary plane disable
> > + * @plane: plane to disable
> > + *
> > + * Provides a default plane disable handler for primary planes.  This is handler
> > + * is called in response to a userspace SetPlane operation on the plane with a
> > + * NULL framebuffer parameter.  We call the driver's modeset handler with a NULL
> > + * framebuffer to disable the CRTC.
> > + *
> > + * Note that some hardware may be able to disable the primary plane without
> > + * disabling the whole CRTC.  Drivers for such hardware should provide their
> > + * own disable handler that disables just the primary plane (and they'll likely
> > + * need to provide their own update handler as well to properly re-enable a
> > + * disabled primary plane).
> > + *
> > + * RETURNS:
> > + * Zero on success, error code on failure
> > + */
> > +int drm_primary_helper_disable(struct drm_plane *plane)
> > +{
> > +	struct drm_mode_set set = {
> > +		.crtc = plane->crtc,
> > +		.fb = NULL,
> > +	};
> > +
> > +	if (plane->crtc == NULL || plane->fb == NULL)
> > +		/* Already disabled */
> > +		return 0;
> > +
> > +	return plane->crtc->funcs->set_config(&set);
> > +}
> > +EXPORT_SYMBOL(drm_primary_helper_disable);
> > +
> > +/**
> > + * drm_primary_helper_destroy() - Helper for primary plane destruction
> > + * @plane: plane to destroy
> > + *
> > + * Provides a default plane destroy handler for primary planes.  This handler
> > + * is called during CRTC destruction.  We disable the primary plane, remove
> > + * it from the DRM plane list, and deallocate the plane structure.
> > + */
> > +void drm_primary_helper_destroy(struct drm_plane *plane)
> > +{
> > +	plane->funcs->disable_plane(plane);
> > +	drm_plane_cleanup(plane);
> > +	kfree(plane);
> > +}
> > +EXPORT_SYMBOL(drm_primary_helper_destroy);
> > +
> > +const struct drm_plane_funcs drm_primary_helper_funcs = {
> > +	.update_plane = drm_primary_helper_update,
> > +	.disable_plane = drm_primary_helper_disable,
> > +	.destroy = drm_primary_helper_destroy,
> > +};
> > +EXPORT_SYMBOL(drm_primary_helper_funcs);
> > +
> > +/**
> > + * drm_primary_helper_create_plane() - Create a generic primary plane
> > + * @dev: drm device
> > + *
> > + * Allocates and initializes a primary plane that can be used with the primary
> > + * plane helpers.  Drivers that wish to use driver-specific plane structures or
> > + * provide custom handler functions may perform their own allocation and
> > + * initialization rather than calling this function.
> > + */
> > +struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev)
> > +{
> > +	struct drm_plane *primary;
> > +	int ret;
> > +
> > +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> > +	if (primary == NULL) {
> > +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
> > +		return NULL;
> > +	}
> > +
> > +	/* possible_crtc's will be filled in later by crtc_init */
> > +	ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
> > +			     legacy_modeset_formats,
> > +			     ARRAY_SIZE(legacy_modeset_formats),
> > +			     DRM_PLANE_TYPE_PRIMARY);
> > +	if (ret) {
> > +		kfree(primary);
> > +		primary = NULL;
> > +	}
> > +
> > +	return primary;
> > +}
> > +EXPORT_SYMBOL(drm_primary_helper_create_plane);
> > +
> >  static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
> >  {
> >  	struct drm_property *edid;
> > @@ -2185,45 +2434,6 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
> >  }
> >  EXPORT_SYMBOL(drm_mode_set_config_internal);
> >  
> > -/*
> > - * Checks that the framebuffer is big enough for the CRTC viewport
> > - * (x, y, hdisplay, vdisplay)
> > - */
> > -static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> > -				   int x, int y,
> > -				   const struct drm_display_mode *mode,
> > -				   const struct drm_framebuffer *fb)
> > -
> > -{
> > -	int hdisplay, vdisplay;
> > -
> > -	hdisplay = mode->hdisplay;
> > -	vdisplay = mode->vdisplay;
> > -
> > -	if (drm_mode_is_stereo(mode)) {
> > -		struct drm_display_mode adjusted = *mode;
> > -
> > -		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
> > -		hdisplay = adjusted.crtc_hdisplay;
> > -		vdisplay = adjusted.crtc_vdisplay;
> > -	}
> > -
> > -	if (crtc->invert_dimensions)
> > -		swap(hdisplay, vdisplay);
> > -
> > -	if (hdisplay > fb->width ||
> > -	    vdisplay > fb->height ||
> > -	    x > fb->width - hdisplay ||
> > -	    y > fb->height - vdisplay) {
> > -		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> > -			      fb->width, fb->height, hdisplay, vdisplay, x, y,
> > -			      crtc->invert_dimensions ? " (inverted)" : "");
> > -		return -ENOSPC;
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> >  /**
> >   * drm_mode_setcrtc - set CRTC configuration
> >   * @dev: drm device for the ioctl
> > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> > index e69ada8..f43fa92 100644
> > --- a/include/drm/drm_crtc.h
> > +++ b/include/drm/drm_crtc.h
> > @@ -581,6 +581,87 @@ struct drm_plane {
> >  	enum drm_plane_type type;
> >  };
> >  
> > +extern int drm_primary_helper_update(struct drm_plane *plane,
> > +				     struct drm_crtc *crtc,
> > +				     struct drm_framebuffer *fb,
> > +				     int crtc_x, int crtc_y,
> > +				     unsigned int crtc_w, unsigned int crtc_h,
> > +				     uint32_t src_x, uint32_t src_y,
> > +				     uint32_t src_w, uint32_t src_h);
> > +extern int drm_primary_helper_disable(struct drm_plane *plane);
> > +extern void drm_primary_helper_destroy(struct drm_plane *plane);
> > +extern const struct drm_plane_funcs drm_primary_helper_funcs;
> > +extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev);
> > +
> > +/*
> > + * This is the list of formats that have historically been accepted by the
> > + * modeset API.  The primary plane helpers use this list by default, but
> > + * individual drivers may provide their own primary plane initialization
> > + * that provides a more hw-specific format list.
> > + */
> > +const static uint32_t legacy_modeset_formats[] = {
> > +       DRM_FORMAT_C8,
> > +       DRM_FORMAT_RGB332,
> > +       DRM_FORMAT_BGR233,
> > +       DRM_FORMAT_XRGB4444,
> > +       DRM_FORMAT_XBGR4444,
> > +       DRM_FORMAT_RGBX4444,
> > +       DRM_FORMAT_BGRX4444,
> > +       DRM_FORMAT_ARGB4444,
> > +       DRM_FORMAT_ABGR4444,
> > +       DRM_FORMAT_RGBA4444,
> > +       DRM_FORMAT_BGRA4444,
> > +       DRM_FORMAT_XRGB1555,
> > +       DRM_FORMAT_XBGR1555,
> > +       DRM_FORMAT_RGBX5551,
> > +       DRM_FORMAT_BGRX5551,
> > +       DRM_FORMAT_ARGB1555,
> > +       DRM_FORMAT_ABGR1555,
> > +       DRM_FORMAT_RGBA5551,
> > +       DRM_FORMAT_BGRA5551,
> > +       DRM_FORMAT_RGB565,
> > +       DRM_FORMAT_BGR565,
> > +       DRM_FORMAT_RGB888,
> > +       DRM_FORMAT_BGR888,
> > +       DRM_FORMAT_XRGB8888,
> > +       DRM_FORMAT_XBGR8888,
> > +       DRM_FORMAT_RGBX8888,
> > +       DRM_FORMAT_BGRX8888,
> > +       DRM_FORMAT_ARGB8888,
> > +       DRM_FORMAT_ABGR8888,
> > +       DRM_FORMAT_RGBA8888,
> > +       DRM_FORMAT_BGRA8888,
> > +       DRM_FORMAT_XRGB2101010,
> > +       DRM_FORMAT_XBGR2101010,
> > +       DRM_FORMAT_RGBX1010102,
> > +       DRM_FORMAT_BGRX1010102,
> > +       DRM_FORMAT_ARGB2101010,
> > +       DRM_FORMAT_ABGR2101010,
> > +       DRM_FORMAT_RGBA1010102,
> > +       DRM_FORMAT_BGRA1010102,
> > +       DRM_FORMAT_YUYV,
> > +       DRM_FORMAT_YVYU,
> > +       DRM_FORMAT_UYVY,
> > +       DRM_FORMAT_VYUY,
> > +       DRM_FORMAT_AYUV,
> > +       DRM_FORMAT_NV12,
> > +       DRM_FORMAT_NV21,
> > +       DRM_FORMAT_NV16,
> > +       DRM_FORMAT_NV61,
> > +       DRM_FORMAT_NV24,
> > +       DRM_FORMAT_NV42,
> > +       DRM_FORMAT_YUV410,
> > +       DRM_FORMAT_YVU410,
> > +       DRM_FORMAT_YUV411,
> > +       DRM_FORMAT_YVU411,
> > +       DRM_FORMAT_YUV420,
> > +       DRM_FORMAT_YVU420,
> > +       DRM_FORMAT_YUV422,
> > +       DRM_FORMAT_YVU422,
> > +       DRM_FORMAT_YUV444,
> > +       DRM_FORMAT_YVU444,
> > +};
> > +
> >  /**
> >   * drm_bridge_funcs - drm_bridge control functions
> >   * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
> > -- 
> > 1.8.5.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

-- 
Matt Roper
Graphics Software Engineer
ISG Platform Enabling & Development
Intel Corporation
(916) 356-2795

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes
  2014-03-19 19:31       ` Daniel Vetter
@ 2014-03-20  1:56         ` Daniel Kurtz
  2014-03-20 15:35           ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Kurtz @ 2014-03-20  1:56 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Thu, Mar 20, 2014 at 3:31 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Wed, Mar 19, 2014 at 10:26:13PM +0800, Daniel Kurtz wrote:
>> On Wed, Mar 19, 2014 at 7:51 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
>> > On Tue, Mar 18, 2014 at 05:22:49PM -0700, Matt Roper wrote:
>> >> Before we add additional types of planes to the DRM plane list, ensure
>> >> that existing loops over all planes continue to operate only on
>> >> "overlay" planes and ignore primary & cursor planes.
>> >>
>> >> Cc: Inki Dae <inki.dae@samsung.com>
>> >> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
>> >> ---
>> >>  drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 ++++++
>> >>  1 file changed, 6 insertions(+)
>> >>
>> >> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> >> index 06f1b2a..2fa2685 100644
>> >> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> >> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>> >> @@ -127,6 +127,9 @@ static void disable_plane_to_crtc(struct drm_device *dev,
>> >>        * (encoder->crtc)
>> >>        */
>> >>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
>> >> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
>> >
>> > I think a drm_for_each_legacy_plane iteration helper would be neat for
>> > this one and the following i915 patch.
>> > -Daniel
>> >
>> >> +                     continue;
>> >> +
>> >>               if (plane->crtc == old_crtc) {
>> >>                       /*
>> >>                        * do not change below call order.
>> >> @@ -247,6 +250,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
>> >>
>> >>       /* all planes connected to this encoder should be also disabled. */
>> >>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
>> >> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
>> >> +                     continue;
>> >> +
>> >>               if (plane->crtc == encoder->crtc)
>> >>                       plane->funcs->disable_plane(plane);
>> >>       }
>>
>> The original loop disables all planes attached to a crtc when
>> disabling an encoder attached to the same crtc.  It was added by:
>>
>> commit bcf4cef94294992f7cd11d5a90fa58b0eae6c795
>> Author: Inki Dae <inki.dae@samsung.com>
>> Date:   Fri Aug 24 10:54:12 2012 -0700
>>
>>     drm/exynos: Disable plane when released
>>
>>     this patch ensures that each plane connected to encoder is disabled
>>     when released, by adding disable callback function of encoder helper
>>
>>     we had faced with one issue that invalid memory is accessed by dma
>>     once drm is released and then the dma is turned on again. actually,
>>     in our case, page fault was incurred with iommu. the reason is that
>>     a gem buffer accessed by the dma is also released once drm is released.
>>
>>     so this patch would fix this issue ensuring the dma is disabled
>>     when released.
>>
>>
>> An encoder receives and encodes the mixed output of all of the
>> planes/overlays.  It would seem that whether the individual planes
>> themselves are enabled or not should be completely independent of the
>> status any encoder.  However, I find the code in exynos_drm_encoder.c
>> very difficult to follow, so perhaps there is some extra linkage
>> between encoder/crtc/plane that is exynos specific.
>>
>> In any case, judging from the commit message, this disable loop should
>> probably still iterate over all of the planes, not just the
>> "DRM_PLANE_TYPE_OVERLAY" ones.  So, I think this new patch is
>> incorrect.
>
> It keeps full backwars compatibility with existing semantics, which is the
> right thing to do in such a case. It could be that exynos simply has a
> bug, but imo that should be a separate patch outside of this series.

Indeed...  I missed the fact that in the existing code, the "priv"
(now primary) plane is not added to the plane_list, so it wouldn't
actually be disabled in this loop here anyway.

New question: are the planes that will become DRM_PLANE_TYPE_CURSOR
formerly "priv", or not?
If they were not, then I think the backwards- and forwards- compatible loop is:

  list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
    if (plane->type == DRM_PLANE_TYPE_PRIMARY)
      continue;
    /* do something with legacy planes */
  }


> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2)
  2014-03-19  0:22 ` [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2) Matt Roper
  2014-03-19 11:41   ` Daniel Vetter
@ 2014-03-20  5:43   ` Inki Dae
  2014-03-20 15:38     ` Daniel Vetter
  1 sibling, 1 reply; 46+ messages in thread
From: Inki Dae @ 2014-03-20  5:43 UTC (permalink / raw)
  To: Matt Roper; +Cc: DRI mailing list

Hi,

2014-03-19 9:22 GMT+09:00 Matt Roper <matthew.d.roper@intel.com>:
> Add primary plane as a parameter to drm_crtc_init() and update all
> existing DRM drivers to use a helper-provided primary plane.
>
> v2: Update msm & omap drivers to use existing "private" planes as primary
>     planes instead of helper  [Rob Clark]
>
> Tested-by: Rob Clark <robdclark@gmail.com>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/armada/armada_crtc.c       | 4 +++-
>  drivers/gpu/drm/ast/ast_mode.c             | 4 +++-
>  drivers/gpu/drm/bochs/bochs_kms.c          | 4 +++-
>  drivers/gpu/drm/cirrus/cirrus_mode.c       | 4 +++-
>  drivers/gpu/drm/drm_crtc.c                 | 9 ++++++++-
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c   | 4 +++-
>  drivers/gpu/drm/gma500/psb_intel_display.c | 4 +++-
>  drivers/gpu/drm/i915/intel_display.c       | 4 +++-
>  drivers/gpu/drm/mgag200/mgag200_mode.c     | 4 +++-
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c   | 5 ++++-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c   | 5 ++++-
>  drivers/gpu/drm/nouveau/dispnv04/crtc.c    | 4 +++-
>  drivers/gpu/drm/nouveau/nv50_display.c     | 4 +++-
>  drivers/gpu/drm/omapdrm/omap_crtc.c        | 2 +-
>  drivers/gpu/drm/qxl/qxl_display.c          | 4 +++-
>  drivers/gpu/drm/radeon/radeon_display.c    | 4 +++-
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c     | 4 +++-
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c  | 3 ++-
>  drivers/gpu/drm/tegra/dc.c                 | 4 +++-
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c       | 4 +++-
>  drivers/gpu/drm/udl/udl_modeset.c          | 4 +++-
>  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        | 4 +++-
>  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       | 4 +++-
>  drivers/staging/imx-drm/imx-drm-core.c     | 4 +++-
>  include/drm/drm_crtc.h                     | 5 +++++
>  25 files changed, 81 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
> index d8e3982..0a14d24 100644
> --- a/drivers/gpu/drm/armada/armada_crtc.c
> +++ b/drivers/gpu/drm/armada/armada_crtc.c
> @@ -1030,6 +1030,7 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
>  {
>         struct armada_private *priv = dev->dev_private;
>         struct armada_crtc *dcrtc;
> +       struct drm_plane *primary;
>         void __iomem *base;
>         int ret;
>
> @@ -1086,7 +1087,8 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
>
>         priv->dcrtc[dcrtc->num] = dcrtc;
>
> -       drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &dcrtc->crtc, primary, &armada_crtc_funcs);
>         drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
>
>         drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> index cca063b..44f0d32 100644
> --- a/drivers/gpu/drm/ast/ast_mode.c
> +++ b/drivers/gpu/drm/ast/ast_mode.c
> @@ -626,13 +626,15 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
>  static int ast_crtc_init(struct drm_device *dev)
>  {
>         struct ast_crtc *crtc;
> +       struct drm_plane *primary;
>         int i;
>
>         crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
>         if (!crtc)
>                 return -ENOMEM;
>
> -       drm_crtc_init(dev, &crtc->base, &ast_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &crtc->base, primary, &ast_crtc_funcs);
>         drm_mode_crtc_set_gamma_size(&crtc->base, 256);
>         drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs);
>
> diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
> index 62ec7d4..182f5c9 100644
> --- a/drivers/gpu/drm/bochs/bochs_kms.c
> +++ b/drivers/gpu/drm/bochs/bochs_kms.c
> @@ -129,8 +129,10 @@ static void bochs_crtc_init(struct drm_device *dev)
>  {
>         struct bochs_device *bochs = dev->dev_private;
>         struct drm_crtc *crtc = &bochs->crtc;
> +       struct drm_plane *primary;
>
> -       drm_crtc_init(dev, crtc, &bochs_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, crtc, primary, &bochs_crtc_funcs);
>         drm_mode_crtc_set_gamma_size(crtc, 256);
>         drm_crtc_helper_add(crtc, &bochs_helper_funcs);
>  }
> diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> index 530f78f..449246f 100644
> --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
> @@ -381,6 +381,7 @@ static void cirrus_crtc_init(struct drm_device *dev)
>  {
>         struct cirrus_device *cdev = dev->dev_private;
>         struct cirrus_crtc *cirrus_crtc;
> +       struct drm_plane *primary;
>         int i;
>
>         cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
> @@ -390,7 +391,8 @@ static void cirrus_crtc_init(struct drm_device *dev)
>         if (cirrus_crtc == NULL)
>                 return;
>
> -       drm_crtc_init(dev, &cirrus_crtc->base, &cirrus_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &cirrus_crtc->base, primary, &cirrus_crtc_funcs);
>
>         drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
>         cdev->mode_info.crtc = cirrus_crtc;
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 8e869d6..0feb66cc 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -697,6 +697,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
>   * drm_crtc_init - Initialise a new CRTC object
>   * @dev: DRM device
>   * @crtc: CRTC object to init
> + * @primary: Primary plane for CRTC
>   * @funcs: callbacks for the new CRTC
>   *
>   * Inits a new object created as base part of a driver crtc object.
> @@ -705,7 +706,8 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
>   * Zero on success, error code on failure.
>   */
>  int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
> -                  const struct drm_crtc_funcs *funcs)
> +                 struct drm_plane *primary,
> +                 const struct drm_crtc_funcs *funcs)
>  {
>         int ret;
>
> @@ -726,6 +728,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
>         list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
>         dev->mode_config.num_crtc++;
>
> +       crtc->primary = primary;
> +       primary->possible_crtcs = 1 << drm_crtc_index(crtc);
> +
>   out:
>         drm_modeset_unlock_all(dev);
>
> @@ -2439,6 +2444,8 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>
>         ret = crtc->funcs->set_config(set);
>         if (ret == 0) {
> +               crtc->primary->crtc = crtc;
> +
>                 /* crtc->fb must be updated by ->set_config, enforces this. */
>                 WARN_ON(fb != crtc->fb);
>         }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> index 6f3400f..507abd5 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> @@ -323,6 +323,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
>         struct exynos_drm_crtc *exynos_crtc;
>         struct exynos_drm_private *private = dev->dev_private;
>         struct drm_crtc *crtc;
> +       struct drm_plane *primary;
>
>         exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
>         if (!exynos_crtc)
> @@ -342,7 +343,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
>
>         private->crtc[nr] = crtc;
>
> -       drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, crtc, primary, &exynos_crtc_funcs);

Your patch would make kms requests to be broken. Exynos drm uses a
wrapper structure, exynos_plane, including original drm_plane, and
also a overlay object specific to exynos should be sent to crtc driver
through exynos_plane.

And re-factoring patch series for exynos drm framework will go to
-next soon. So how about that other maintainers can adopt your primary
plane feature individually later? For this, I guess you would need to
keep backward compatibility. We would really need the testing enough
for such feature and big changes.

Thanks,
Inki Dae

>         drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
>
>         exynos_drm_crtc_attach_mode_property(crtc);
> diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
> index c8841ac..c8f833d 100644
> --- a/drivers/gpu/drm/gma500/psb_intel_display.c
> +++ b/drivers/gpu/drm/gma500/psb_intel_display.c
> @@ -491,6 +491,7 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
>  {
>         struct drm_psb_private *dev_priv = dev->dev_private;
>         struct gma_crtc *gma_crtc;
> +       struct drm_plane *primary;
>         int i;
>         uint16_t *r_base, *g_base, *b_base;
>
> @@ -511,7 +512,8 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
>         }
>
>         /* Set the CRTC operations from the chip specific data */
> -       drm_crtc_init(dev, &gma_crtc->base, dev_priv->ops->crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &gma_crtc->base, primary, dev_priv->ops->crtc_funcs);
>
>         /* Set the CRTC clock functions from chip specific data */
>         gma_crtc->clock_funcs = dev_priv->ops->clock_funcs;
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 048052a..21d12a9 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10586,13 +10586,15 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>  {
>         drm_i915_private_t *dev_priv = dev->dev_private;
>         struct intel_crtc *intel_crtc;
> +       struct drm_plane *primary;
>         int i;
>
>         intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
>         if (intel_crtc == NULL)
>                 return;
>
> -       drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &intel_crtc->base, primary, &intel_crtc_funcs);
>
>         drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
>         for (i = 0; i < 256; i++) {
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index 9683747..1418414 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> @@ -1314,6 +1314,7 @@ static const struct drm_crtc_helper_funcs mga_helper_funcs = {
>  static void mga_crtc_init(struct mga_device *mdev)
>  {
>         struct mga_crtc *mga_crtc;
> +       struct drm_plane *primary;
>         int i;
>
>         mga_crtc = kzalloc(sizeof(struct mga_crtc) +
> @@ -1323,7 +1324,8 @@ static void mga_crtc_init(struct mga_device *mdev)
>         if (mga_crtc == NULL)
>                 return;
>
> -       drm_crtc_init(mdev->dev, &mga_crtc->base, &mga_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(mdev->dev);
> +       drm_crtc_init(mdev->dev, &mga_crtc->base, primary, &mga_crtc_funcs);
>
>         drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE);
>         mdev->mode_info.crtc = mga_crtc;
> diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> index 84c5b13..b10f681 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> @@ -740,6 +740,9 @@ void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
>
>  void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
>  {
> +       /* don't actually detatch our primary plane: */
> +       if (to_mdp4_crtc(crtc)->plane == plane)
> +               return;
>         set_attach(crtc, mdp4_plane_pipe(plane), NULL);
>  }
>
> @@ -791,7 +794,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
>
>         INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb);
>
> -       drm_crtc_init(dev, crtc, &mdp4_crtc_funcs);
> +       drm_crtc_init(dev, crtc, plane, &mdp4_crtc_funcs);
>         drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
>
>         mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base);
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> index f279402..7dc3d71 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> @@ -524,6 +524,9 @@ void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
>
>  void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
>  {
> +       /* don't actually detatch our primary plane: */
> +       if (to_mdp5_crtc(crtc)->plane == plane)
> +               return;
>         set_attach(crtc, mdp5_plane_pipe(plane), NULL);
>  }
>
> @@ -559,7 +562,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
>
>         INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb);
>
> -       drm_crtc_init(dev, crtc, &mdp5_crtc_funcs);
> +       drm_crtc_init(dev, crtc, plane, &mdp5_crtc_funcs);
>         drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
>
>         mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base);
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> index 0e3270c..b55be84 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> @@ -1106,6 +1106,7 @@ int
>  nv04_crtc_create(struct drm_device *dev, int crtc_num)
>  {
>         struct nouveau_crtc *nv_crtc;
> +       struct drm_plane *primary;
>         int ret, i;
>
>         nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
> @@ -1122,7 +1123,8 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
>         nv_crtc->index = crtc_num;
>         nv_crtc->last_dpms = NV_DPMS_CLEARED;
>
> -       drm_crtc_init(dev, &nv_crtc->base, &nv04_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &nv_crtc->base, primary, &nv04_crtc_funcs);
>         drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs);
>         drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
>
> diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> index 2dccafc..5706842 100644
> --- a/drivers/gpu/drm/nouveau/nv50_display.c
> +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> @@ -1348,6 +1348,7 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
>         struct nv50_disp *disp = nv50_disp(dev);
>         struct nv50_head *head;
>         struct drm_crtc *crtc;
> +       struct drm_plane *primary;
>         int ret, i;
>
>         head = kzalloc(sizeof(*head), GFP_KERNEL);
> @@ -1369,7 +1370,8 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
>         }
>
>         crtc = &head->base.base;
> -       drm_crtc_init(dev, crtc, &nv50_crtc_func);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, crtc, primary, &nv50_crtc_func);
>         drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
>         drm_mode_crtc_set_gamma_size(crtc, 256);
>
> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index 4313bb0..fdf9dc0 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -677,7 +677,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
>         info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
>         info->trans_enabled = false;
>
> -       drm_crtc_init(dev, crtc, &omap_crtc_funcs);
> +       drm_crtc_init(dev, crtc, plane, &omap_crtc_funcs);
>         drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
>
>         omap_plane_install_properties(omap_crtc->plane, &crtc->base);
> diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> index 798bde2..24b6112 100644
> --- a/drivers/gpu/drm/qxl/qxl_display.c
> +++ b/drivers/gpu/drm/qxl/qxl_display.c
> @@ -636,12 +636,14 @@ static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
>  static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
>  {
>         struct qxl_crtc *qxl_crtc;
> +       struct drm_plane *primary;
>
>         qxl_crtc = kzalloc(sizeof(struct qxl_crtc), GFP_KERNEL);
>         if (!qxl_crtc)
>                 return -ENOMEM;
>
> -       drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &qxl_crtc->base, primary, &qxl_crtc_funcs);
>         qxl_crtc->index = crtc_id;
>         drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256);
>         drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> index fbd8b93..a29d217 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -552,13 +552,15 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
>  {
>         struct radeon_device *rdev = dev->dev_private;
>         struct radeon_crtc *radeon_crtc;
> +       struct drm_plane *primary;
>         int i;
>
>         radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
>         if (radeon_crtc == NULL)
>                 return;
>
> -       drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, &radeon_crtc->base, primary, &radeon_crtc_funcs);
>
>         drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
>         radeon_crtc->crtc_id = index;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index fbf4be3..151ffaa 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -540,6 +540,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
>         struct platform_device *pdev = to_platform_device(rcdu->dev);
>         struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
>         struct drm_crtc *crtc = &rcrtc->crtc;
> +       struct drm_plane *primary;
>         unsigned int irqflags;
>         char clk_name[5];
>         char *name;
> @@ -568,7 +569,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
>
>         rcrtc->plane->crtc = crtc;
>
> -       ret = drm_crtc_init(rcdu->ddev, crtc, &crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       ret = drm_crtc_init(rcdu->ddev, crtc, primary, &crtc_funcs);
>         if (ret < 0)
>                 return ret;
>
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> index 0428076..e806553 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -512,11 +512,12 @@ static const struct drm_crtc_funcs crtc_funcs = {
>  int shmob_drm_crtc_create(struct shmob_drm_device *sdev)
>  {
>         struct drm_crtc *crtc = &sdev->crtc.crtc;
> +       struct drm_plane *primary;
>         int ret;
>
>         sdev->crtc.dpms = DRM_MODE_DPMS_OFF;
>
> -       ret = drm_crtc_init(sdev->ddev, crtc, &crtc_funcs);
> +       ret = drm_crtc_init(sdev->ddev, crtc, primary, &crtc_funcs);
>         if (ret < 0)
>                 return ret;
>
> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
> index 76e5b22..5e2ee9d 100644
> --- a/drivers/gpu/drm/tegra/dc.c
> +++ b/drivers/gpu/drm/tegra/dc.c
> @@ -1099,9 +1099,11 @@ static int tegra_dc_init(struct host1x_client *client)
>  {
>         struct tegra_drm *tegra = dev_get_drvdata(client->parent);
>         struct tegra_dc *dc = host1x_client_to_dc(client);
> +       struct drm_plane *primary;
>         int err;
>
> -       drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(tegra->drm, &dc->base, primary, &tegra_crtc_funcs);
>         drm_mode_crtc_set_gamma_size(&dc->base, 256);
>         drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
>
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index d36efc1..310314c 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -651,6 +651,7 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
>  {
>         struct tilcdc_crtc *tilcdc_crtc;
>         struct drm_crtc *crtc;
> +       struct drm_plane *primary;
>         int ret;
>
>         tilcdc_crtc = kzalloc(sizeof(*tilcdc_crtc), GFP_KERNEL);
> @@ -671,7 +672,8 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
>                 goto fail;
>         }
>
> -       ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       ret = drm_crtc_init(dev, crtc, primary, &tilcdc_crtc_funcs);
>         if (ret < 0)
>                 goto fail;
>
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index 2ae1eb7..1255944 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -389,12 +389,14 @@ static const struct drm_crtc_funcs udl_crtc_funcs = {
>  static int udl_crtc_init(struct drm_device *dev)
>  {
>         struct drm_crtc *crtc;
> +       struct drm_plane *primary;
>
>         crtc = kzalloc(sizeof(struct drm_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
>         if (crtc == NULL)
>                 return -ENOMEM;
>
> -       drm_crtc_init(dev, crtc, &udl_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, crtc, primary, &udl_crtc_funcs);
>         drm_crtc_helper_add(crtc, &udl_helper_funcs);
>
>         return 0;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> index a055a26..001ec81 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> @@ -343,6 +343,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
>         struct drm_connector *connector;
>         struct drm_encoder *encoder;
>         struct drm_crtc *crtc;
> +       struct drm_plane *primary;
>
>         ldu = kzalloc(sizeof(*ldu), GFP_KERNEL);
>         if (!ldu)
> @@ -373,7 +374,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
>
>         (void) drm_sysfs_connector_add(connector);
>
> -       drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, crtc, primary, &vmw_legacy_crtc_funcs);
>
>         drm_mode_crtc_set_gamma_size(crtc, 256);
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> index 22406c8..585da43 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> @@ -439,6 +439,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
>         struct drm_connector *connector;
>         struct drm_encoder *encoder;
>         struct drm_crtc *crtc;
> +       struct drm_plane *primary;
>
>         sou = kzalloc(sizeof(*sou), GFP_KERNEL);
>         if (!sou)
> @@ -469,7 +470,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
>
>         (void) drm_sysfs_connector_add(connector);
>
> -       drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs);
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(dev, crtc, primary, &vmw_screen_object_crtc_funcs);
>
>         drm_mode_crtc_set_gamma_size(crtc, 256);
>
> diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
> index 236ed66..8c7b1d3 100644
> --- a/drivers/staging/imx-drm/imx-drm-core.c
> +++ b/drivers/staging/imx-drm/imx-drm-core.c
> @@ -475,6 +475,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
>  {
>         struct imx_drm_device *imxdrm = __imx_drm_device();
>         struct imx_drm_crtc *imx_drm_crtc;
> +       struct drm_plane *primary;
>         int ret;
>
>         mutex_lock(&imxdrm->mutex);
> @@ -520,7 +521,8 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
>         drm_crtc_helper_add(crtc,
>                         imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
>
> -       drm_crtc_init(imxdrm->drm, crtc,
> +       primary = drm_primary_helper_create_plane(dev);
> +       drm_crtc_init(imxdrm->drm, crtc, primary,
>                         imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
>
>         drm_mode_group_reinit(imxdrm->drm);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 74f4943..4dc84f8 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -270,6 +270,7 @@ struct drm_crtc_funcs {
>   * @dev: parent DRM device
>   * @head: list management
>   * @base: base KMS object for ID tracking etc.
> + * @primary: primary plane for this CRTC
>   * @enabled: is this CRTC enabled?
>   * @mode: current mode timings
>   * @hwmode: mode timings as programmed to hw regs
> @@ -305,6 +306,9 @@ struct drm_crtc {
>
>         struct drm_mode_object base;
>
> +       /* primary plane for CRTC */
> +       struct drm_plane *primary;
> +
>         /* framebuffer the connector is currently bound to */
>         struct drm_framebuffer *fb;
>
> @@ -907,6 +911,7 @@ extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
>
>  extern int drm_crtc_init(struct drm_device *dev,
>                          struct drm_crtc *crtc,
> +                        struct drm_plane *primary,
>                          const struct drm_crtc_funcs *funcs);
>  extern void drm_crtc_cleanup(struct drm_crtc *crtc);
>  extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
> --
> 1.8.5.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 03/14] drm: Add primary plane helpers
  2014-03-19 23:01     ` Matt Roper
@ 2014-03-20 12:39       ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-20 12:39 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Thu, Mar 20, 2014 at 12:01 AM, Matt Roper <matthew.d.roper@intel.com> wrote:
> On Wed, Mar 19, 2014 at 01:24:23PM +0100, Daniel Vetter wrote:
>> On Tue, Mar 18, 2014 at 05:22:48PM -0700, Matt Roper wrote:
>> > When we expose non-overlay planes to userspace, they will become
>> > accessible via standard userspace plane API's.  We should be able to
>> > handle the standard plane operations against primary planes in a generic
>> > way via the page flip handler and modeset handler.
>> >
>> > Drivers that can program primary planes more efficiently, that want to
>> > use their own primary plane structure to track additional information,
>> > or that don't have the limitations assumed by the helpers are free to
>> > provide their own implementation of some or all of these handlers.
>> >
>> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
>>
>> One thing I've noticed with planes is that we don't have any per-plane
>> size limits. Which will be annoying for cursors at least, but looking at
>> intel's hw history there are other planes with limits smaller than
>> dev->mode_config.max_widht/height.
>>
>> I think as part of the universal plane work here we should add this to the
>> getplane ioctl (we can extend at the end with full backwards compat) and
>> use the max_width/height as default for primary/overlay planes and
>> cursor_width/height for cursor planes.
>
> I'm not sure I understand how to (cleanly) extend the existing ioctl
> safely.  Userspace (libdrm) allocates a drm_mode_get_plane structure on
> the stack with a specific size.  If we try to extend this structure to
> return more information, and have the kernel write into the new fields,
> aren't we just going to be spilling over into other userspace stack
> variables if we run an old libdrm on the new kernel?  The only
> approaches I see that could make this work would be huge ugly hacks:
>  * Reclaiming the top few bits of plane_id to use as "I sent you the
>    new, larger structure" capability flags (which assumes plane ID's are
>    always small enough to leave those bits 0 on current kernels; this
>    would effectively reduce our plane ID address space).
>  * Figure out a way to encode extra information as bogus pixel formats
>    and shove it into the format list returned to userspace.  Presumably
>    userspace would just ignore/skip the bogus formats.
>
> I suppose we could add a new GetPlane2 ioctl or something that returned
> more info, but I figured it was probably easier to just shove max plane
> size (and a bunch of other plane capabilities / limitations) into some
> new read-only plane properties.  Read-only properties are easy to extend
> if we find other pieces of information we want to return in the future,
> so that seems like the most natural interface to me.

The size userspace expects is passed in through the ioctl number. It
then zero-extends the structure correctly for both forward and
backwards compatibility. Which means that yeah, we can extend the
struct at the end, recompile libdrm and as long as the kernel treats 0
in the new fields sanely.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes
  2014-03-20  1:56         ` Daniel Kurtz
@ 2014-03-20 15:35           ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-20 15:35 UTC (permalink / raw)
  To: Daniel Kurtz; +Cc: dri-devel

On Thu, Mar 20, 2014 at 09:56:24AM +0800, Daniel Kurtz wrote:
> On Thu, Mar 20, 2014 at 3:31 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Wed, Mar 19, 2014 at 10:26:13PM +0800, Daniel Kurtz wrote:
> >> On Wed, Mar 19, 2014 at 7:51 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> >> > On Tue, Mar 18, 2014 at 05:22:49PM -0700, Matt Roper wrote:
> >> >> Before we add additional types of planes to the DRM plane list, ensure
> >> >> that existing loops over all planes continue to operate only on
> >> >> "overlay" planes and ignore primary & cursor planes.
> >> >>
> >> >> Cc: Inki Dae <inki.dae@samsung.com>
> >> >> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> >> >> ---
> >> >>  drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 ++++++
> >> >>  1 file changed, 6 insertions(+)
> >> >>
> >> >> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> >> >> index 06f1b2a..2fa2685 100644
> >> >> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> >> >> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> >> >> @@ -127,6 +127,9 @@ static void disable_plane_to_crtc(struct drm_device *dev,
> >> >>        * (encoder->crtc)
> >> >>        */
> >> >>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> >> >> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
> >> >
> >> > I think a drm_for_each_legacy_plane iteration helper would be neat for
> >> > this one and the following i915 patch.
> >> > -Daniel
> >> >
> >> >> +                     continue;
> >> >> +
> >> >>               if (plane->crtc == old_crtc) {
> >> >>                       /*
> >> >>                        * do not change below call order.
> >> >> @@ -247,6 +250,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
> >> >>
> >> >>       /* all planes connected to this encoder should be also disabled. */
> >> >>       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> >> >> +             if (plane->type != DRM_PLANE_TYPE_OVERLAY)
> >> >> +                     continue;
> >> >> +
> >> >>               if (plane->crtc == encoder->crtc)
> >> >>                       plane->funcs->disable_plane(plane);
> >> >>       }
> >>
> >> The original loop disables all planes attached to a crtc when
> >> disabling an encoder attached to the same crtc.  It was added by:
> >>
> >> commit bcf4cef94294992f7cd11d5a90fa58b0eae6c795
> >> Author: Inki Dae <inki.dae@samsung.com>
> >> Date:   Fri Aug 24 10:54:12 2012 -0700
> >>
> >>     drm/exynos: Disable plane when released
> >>
> >>     this patch ensures that each plane connected to encoder is disabled
> >>     when released, by adding disable callback function of encoder helper
> >>
> >>     we had faced with one issue that invalid memory is accessed by dma
> >>     once drm is released and then the dma is turned on again. actually,
> >>     in our case, page fault was incurred with iommu. the reason is that
> >>     a gem buffer accessed by the dma is also released once drm is released.
> >>
> >>     so this patch would fix this issue ensuring the dma is disabled
> >>     when released.
> >>
> >>
> >> An encoder receives and encodes the mixed output of all of the
> >> planes/overlays.  It would seem that whether the individual planes
> >> themselves are enabled or not should be completely independent of the
> >> status any encoder.  However, I find the code in exynos_drm_encoder.c
> >> very difficult to follow, so perhaps there is some extra linkage
> >> between encoder/crtc/plane that is exynos specific.
> >>
> >> In any case, judging from the commit message, this disable loop should
> >> probably still iterate over all of the planes, not just the
> >> "DRM_PLANE_TYPE_OVERLAY" ones.  So, I think this new patch is
> >> incorrect.
> >
> > It keeps full backwars compatibility with existing semantics, which is the
> > right thing to do in such a case. It could be that exynos simply has a
> > bug, but imo that should be a separate patch outside of this series.
> 
> Indeed...  I missed the fact that in the existing code, the "priv"
> (now primary) plane is not added to the plane_list, so it wouldn't
> actually be disabled in this loop here anyway.
> 
> New question: are the planes that will become DRM_PLANE_TYPE_CURSOR
> formerly "priv", or not?
> If they were not, then I think the backwards- and forwards- compatible loop is:
> 
>   list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
>     if (plane->type == DRM_PLANE_TYPE_PRIMARY)
>       continue;
>     /* do something with legacy planes */
>   }

Cursor planes haven't been exposed at all as plane objects before, not
even as private driver objects. So they'd need to be excluded here too.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2)
  2014-03-20  5:43   ` Inki Dae
@ 2014-03-20 15:38     ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-20 15:38 UTC (permalink / raw)
  To: Inki Dae; +Cc: DRI mailing list

On Thu, Mar 20, 2014 at 02:43:11PM +0900, Inki Dae wrote:
> Your patch would make kms requests to be broken. Exynos drm uses a
> wrapper structure, exynos_plane, including original drm_plane, and
> also a overlay object specific to exynos should be sent to crtc driver
> through exynos_plane.
> 
> And re-factoring patch series for exynos drm framework will go to
> -next soon. So how about that other maintainers can adopt your primary
> plane feature individually later? For this, I guess you would need to
> keep backward compatibility. We would really need the testing enough
> for such feature and big changes.

All my review thus far has been aimed at reducing subsystem-wide changes
to drivers. I think we can do the full primary plane conversion without
touching drivers at all. Of course there's a bit of cleanup, but driver
maintainers can merge that at their own pace (and so avoid ugly conflicts
with ongoing work).

I'm still working on how to reduce the impact for the cursor plane
conversion as much as possible, but that's going to be fairly hard
unfortunately.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2)
  2014-03-19 11:57   ` Daniel Vetter
@ 2014-03-25  1:20     ` Matt Roper
  2014-03-25 10:32       ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Matt Roper @ 2014-03-25  1:20 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Wed, Mar 19, 2014 at 12:57:21PM +0100, Daniel Vetter wrote:
> On Tue, Mar 18, 2014 at 05:22:53PM -0700, Matt Roper wrote:
> > Now that CRTC's have a primary plane, there's no need to track the
> > framebuffer in the CRTC.  Replace all references to the CRTC fb
> > with the primary plane's fb.
> > 
> > Also note that this simplifies framebuffer removal slightly; we no
> > longer need to scan all CRTC's and disable the ones that were using the
> > framebuffer since the existing loop over all planes will take care
> > of disabling the primary plane (and on most hardware, the CRTC by
> > extension).
> > 
> > v2: Fixup several lingering crtc->fb instances that were missed in the
> >     first patch iteration.
> > 
> > Tested-by: Rob Clark <robdclark@gmail.com>
> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> 
> Giant patch again, and I don't think there's any sane way we can avoid
> this big sed job. Put I think we can make it less intrusive.
> 
> First: Have you looked into cocinelle to do this? I'm not sure whether
> cocinelle is sufficiently type aware, but the upside of using it is that
> it's much easier to regenerate the patch.

Good idea!  Yeah, I think Coccinelle should do this pretty easily with
just:

        @@ struct drm_crtc *crtc; @@
        -   crtc->fb
        +   crtc->primary->fb

        @@ struct drm_crtc crtc; @@
        -   crtc.fb
        +   crtc.primary->fb

> In any case I think we need to split this into the usual 3 phases to avoid
> flag days:
> 
> 1) Switch to crtc->primary->fb all over the core, but keep crtc->fb fully
> functional. I.e. update it before calling into drivers and use that to
> update crtc->primary->fb on return (e.g. in the pageflip ioctl).

I'm starting to worry that this may be more tricky than it sounded when
I first read your email.  To be safe, it seems like we'll need to
sandwich all the various ->funcs-> driver calls in the core between
prepare_crtc_fbs() / finish_crtc_fbs() or similar since it's hard to
predict in a universal way when a driver might decide to go look at a
crtc's framebuffer (or even which crtcs it will decide to look at).
However even if we do that wrapping, there may be cases where the driver
calls back into a core helper function after modifying crtc->fb and the
core won't have that updated value unless we throw in extra sync-up
points.  

Is this pretty much what you had in mind or am I overlooking a much
simpler way to accomplish this?


Matt

> 
> 2) Switch drivers over to look at crtc->primary->fb. This way we can even
> split up the patch into per-driver patches which gives driver maintainers
> more wiggle room.
> 
> 3) Kill crtc->fb.
> 
> Steps 2&3 don't block merging of the universal planes support at all. So
> we could get the core support in all early for 3.16, then let driver
> maintainers pick up patche for 2 and shortly before the 3.16 merge window
> opens send a pull request with all the stragglers and step 3.
> 
> No comments on the actual patch, the few functional changes hidden in the
> massive diff looked ok. But hard to review properly ;-)
> 
> Cheers, Daniel
> 
> > ---
> >  drivers/gpu/drm/ast/ast_mode.c               |  12 +--
> >  drivers/gpu/drm/bochs/bochs_kms.c            |   4 +-
> >  drivers/gpu/drm/cirrus/cirrus_mode.c         |  10 +-
> >  drivers/gpu/drm/drm_crtc.c                   |  56 ++++------
> >  drivers/gpu/drm/drm_crtc_helper.c            |  21 ++--
> >  drivers/gpu/drm/drm_fb_helper.c              |   6 +-
> >  drivers/gpu/drm/gma500/cdv_intel_display.c   |   2 +-
> >  drivers/gpu/drm/gma500/cdv_intel_dp.c        |   2 +-
> >  drivers/gpu/drm/gma500/cdv_intel_hdmi.c      |   3 +-
> >  drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
> >  drivers/gpu/drm/gma500/gma_display.c         |  17 ++--
> >  drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
> >  drivers/gpu/drm/gma500/mdfld_intel_display.c |  17 ++--
> >  drivers/gpu/drm/gma500/oaktrail_crtc.c       |  13 +--
> >  drivers/gpu/drm/gma500/psb_intel_display.c   |   2 +-
> >  drivers/gpu/drm/gma500/psb_intel_lvds.c      |   2 +-
> >  drivers/gpu/drm/gma500/psb_intel_sdvo.c      |   2 +-
> >  drivers/gpu/drm/i915/i915_debugfs.c          |   4 +-
> >  drivers/gpu/drm/i915/i915_irq.c              |   4 +-
> >  drivers/gpu/drm/i915/intel_display.c         | 147 ++++++++++++++-------------
> >  drivers/gpu/drm/i915/intel_dp.c              |   5 +-
> >  drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
> >  drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
> >  drivers/gpu/drm/i915/intel_pm.c              |  36 +++----
> >  drivers/gpu/drm/mgag200/mgag200_mode.c       |  28 ++---
> >  drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  28 ++---
> >  drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  22 ++--
> >  drivers/gpu/drm/nouveau/dispnv04/crtc.c      |  20 ++--
> >  drivers/gpu/drm/nouveau/dispnv04/dfp.c       |   2 +-
> >  drivers/gpu/drm/nouveau/nouveau_display.c    |   8 +-
> >  drivers/gpu/drm/nouveau/nv50_display.c       |  17 ++--
> >  drivers/gpu/drm/qxl/qxl_display.c            |  11 +-
> >  drivers/gpu/drm/radeon/atombios_crtc.c       |  20 ++--
> >  drivers/gpu/drm/radeon/r100.c                |   4 +-
> >  drivers/gpu/drm/radeon/radeon_connectors.c   |   2 +-
> >  drivers/gpu/drm/radeon/radeon_device.c       |   3 +-
> >  drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
> >  drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +--
> >  drivers/gpu/drm/udl/udl_modeset.c            |   2 +-
> >  drivers/gpu/drm/vmwgfx/vmwgfx_kms.c          |  14 +--
> >  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c          |   8 +-
> >  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c         |   8 +-
> >  include/drm/drm_crtc.h                       |   3 -
> >  43 files changed, 300 insertions(+), 299 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> > index 44f0d32..bd1e156 100644
> > --- a/drivers/gpu/drm/ast/ast_mode.c
> > +++ b/drivers/gpu/drm/ast/ast_mode.c
> > @@ -81,7 +81,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
> >  	u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
> >  	u32 hborder, vborder;
> >  
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
> >  		color_index = VGAModeIndex - 1;
> > @@ -176,7 +176,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
> >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
> >  
> >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
> > -		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
> > +		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
> >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
> >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
> >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
> > @@ -340,7 +340,7 @@ static void ast_set_offset_reg(struct drm_crtc *crtc)
> >  
> >  	u16 offset;
> >  
> > -	offset = crtc->fb->pitches[0] >> 3;
> > +	offset = crtc->primary->fb->pitches[0] >> 3;
> >  	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
> >  	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
> >  }
> > @@ -365,7 +365,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
> >  	struct ast_private *ast = crtc->dev->dev_private;
> >  	u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
> >  
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		jregA0 = 0x70;
> >  		jregA3 = 0x01;
> > @@ -418,7 +418,7 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo
> >  static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
> >  		     struct ast_vbios_mode_info *vbios_mode)
> >  {
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		break;
> >  	default:
> > @@ -490,7 +490,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
> >  		ast_bo_unreserve(bo);
> >  	}
> >  
> > -	ast_fb = to_ast_framebuffer(crtc->fb);
> > +	ast_fb = to_ast_framebuffer(crtc->primary->fb);
> >  	obj = ast_fb->obj;
> >  	bo = gem_to_ast_bo(obj);
> >  
> > diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
> > index 182f5c9..b67ad12 100644
> > --- a/drivers/gpu/drm/bochs/bochs_kms.c
> > +++ b/drivers/gpu/drm/bochs/bochs_kms.c
> > @@ -62,10 +62,10 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> >  		}
> >  	}
> >  
> > -	if (WARN_ON(crtc->fb == NULL))
> > +	if (WARN_ON(crtc->primary->fb == NULL))
> >  		return -EINVAL;
> >  
> > -	bochs_fb = to_bochs_framebuffer(crtc->fb);
> > +	bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
> >  	bo = gem_to_bochs_bo(bochs_fb->obj);
> >  	ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
> >  	if (ret)
> > diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> > index 449246f..5291d2f 100644
> > --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> > +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
> > @@ -149,7 +149,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
> >  		cirrus_bo_unreserve(bo);
> >  	}
> >  
> > -	cirrus_fb = to_cirrus_framebuffer(crtc->fb);
> > +	cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb);
> >  	obj = cirrus_fb->obj;
> >  	bo = gem_to_cirrus_bo(obj);
> >  
> > @@ -268,7 +268,7 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
> >  	sr07 = RREG8(SEQ_DATA);
> >  	sr07 &= 0xe0;
> >  	hdr = 0;
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		sr07 |= 0x11;
> >  		break;
> > @@ -291,13 +291,13 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
> >  	WREG_SEQ(0x7, sr07);
> >  
> >  	/* Program the pitch */
> > -	tmp = crtc->fb->pitches[0] / 8;
> > +	tmp = crtc->primary->fb->pitches[0] / 8;
> >  	WREG_CRT(VGA_CRTC_OFFSET, tmp);
> >  
> >  	/* Enable extended blanking and pitch bits, and enable full memory */
> >  	tmp = 0x22;
> > -	tmp |= (crtc->fb->pitches[0] >> 7) & 0x10;
> > -	tmp |= (crtc->fb->pitches[0] >> 6) & 0x40;
> > +	tmp |= (crtc->primary->fb->pitches[0] >> 7) & 0x10;
> > +	tmp |= (crtc->primary->fb->pitches[0] >> 6) & 0x40;
> >  	WREG_CRT(0x1b, tmp);
> >  
> >  	/* Enable high-colour modes */
> > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> > index 0feb66cc..0c395e8 100644
> > --- a/drivers/gpu/drm/drm_crtc.c
> > +++ b/drivers/gpu/drm/drm_crtc.c
> > @@ -634,7 +634,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
> >   * drm_framebuffer_remove - remove and unreference a framebuffer object
> >   * @fb: framebuffer to remove
> >   *
> > - * Scans all the CRTCs and planes in @dev's mode_config.  If they're
> > + * Scans all the planes in @dev's mode_config.  If they're
> >   * using @fb, removes it, setting it to NULL. Then drops the reference to the
> >   * passed-in framebuffer. Might take the modeset locks.
> >   *
> > @@ -645,10 +645,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
> >  void drm_framebuffer_remove(struct drm_framebuffer *fb)
> >  {
> >  	struct drm_device *dev = fb->dev;
> > -	struct drm_crtc *crtc;
> >  	struct drm_plane *plane;
> > -	struct drm_mode_set set;
> > -	int ret;
> >  
> >  	WARN_ON(!list_empty(&fb->filp_head));
> >  
> > @@ -669,19 +666,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
> >  	 */
> >  	if (atomic_read(&fb->refcount.refcount) > 1) {
> >  		drm_modeset_lock_all(dev);
> > -		/* remove from any CRTC */
> > -		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > -			if (crtc->fb == fb) {
> > -				/* should turn off the crtc */
> > -				memset(&set, 0, sizeof(struct drm_mode_set));
> > -				set.crtc = crtc;
> > -				set.fb = NULL;
> > -				ret = drm_mode_set_config_internal(&set);
> > -				if (ret)
> > -					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
> > -			}
> > -		}
> > -
> > +		/* remove from any plane */
> >  		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> >  			if (plane->fb == fb)
> >  				drm_plane_force_disable(plane);
> > @@ -1930,8 +1915,8 @@ int drm_mode_getcrtc(struct drm_device *dev,
> >  	crtc_resp->x = crtc->x;
> >  	crtc_resp->y = crtc->y;
> >  	crtc_resp->gamma_size = crtc->gamma_size;
> > -	if (crtc->fb)
> > -		crtc_resp->fb_id = crtc->fb->base.id;
> > +	if (crtc->primary->fb)
> > +		crtc_resp->fb_id = crtc->primary->fb->base.id;
> >  	else
> >  		crtc_resp->fb_id = 0;
> >  
> > @@ -2438,7 +2423,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
> >  	 * crtcs. Atomic modeset will have saner semantics ...
> >  	 */
> >  	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
> > -		tmp->old_fb = tmp->fb;
> > +		tmp->old_fb = tmp->primary->fb;
> >  
> >  	fb = set->fb;
> >  
> > @@ -2446,13 +2431,16 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
> >  	if (ret == 0) {
> >  		crtc->primary->crtc = crtc;
> >  
> > -		/* crtc->fb must be updated by ->set_config, enforces this. */
> > -		WARN_ON(fb != crtc->fb);
> > +		/*
> > +		 * crtc->primary->fb must be updated by ->set_config,
> > +		 * enforces this.
> > +		 */
> > +		WARN_ON(fb != crtc->primary->fb);
> >  	}
> >  
> >  	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
> > -		if (tmp->fb)
> > -			drm_framebuffer_reference(tmp->fb);
> > +		if (tmp->primary->fb)
> > +			drm_framebuffer_reference(tmp->primary->fb);
> >  		if (tmp->old_fb)
> >  			drm_framebuffer_unreference(tmp->old_fb);
> >  	}
> > @@ -2511,12 +2499,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
> >  		/* If we have a mode we need a framebuffer. */
> >  		/* If we pass -1, set the mode with the currently bound fb */
> >  		if (crtc_req->fb_id == -1) {
> > -			if (!crtc->fb) {
> > +			if (!crtc->primary->fb) {
> >  				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
> >  				ret = -EINVAL;
> >  				goto out;
> >  			}
> > -			fb = crtc->fb;
> > +			fb = crtc->primary->fb;
> >  			/* Make refcounting symmetric with the lookup path. */
> >  			drm_framebuffer_reference(fb);
> >  		} else {
> > @@ -4309,7 +4297,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> >  	crtc = obj_to_crtc(obj);
> >  
> >  	mutex_lock(&crtc->mutex);
> > -	if (crtc->fb == NULL) {
> > +	if (crtc->primary->fb == NULL) {
> >  		/* The framebuffer is currently unbound, presumably
> >  		 * due to a hotplug event, that userspace has not
> >  		 * yet discovered.
> > @@ -4331,7 +4319,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> >  	if (ret)
> >  		goto out;
> >  
> > -	if (crtc->fb->pixel_format != fb->pixel_format) {
> > +	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
> >  		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
> >  		ret = -EINVAL;
> >  		goto out;
> > @@ -4364,7 +4352,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> >  			(void (*) (struct drm_pending_event *)) kfree;
> >  	}
> >  
> > -	old_fb = crtc->fb;
> > +	old_fb = crtc->primary->fb;
> >  	ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
> >  	if (ret) {
> >  		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
> > @@ -4377,12 +4365,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> >  		old_fb = NULL;
> >  	} else {
> >  		/*
> > -		 * Warn if the driver hasn't properly updated the crtc->fb
> > -		 * field to reflect that the new framebuffer is now used.
> > -		 * Failing to do so will screw with the reference counting
> > -		 * on framebuffers.
> > +		 * Warn if the driver hasn't properly updated the
> > +		 * crtc->primary->fb field to reflect that the new framebuffer
> > +		 * is now used.  Failing to do so will screw with the reference
> > +		 * counting on framebuffers.
> >  		 */
> > -		WARN_ON(crtc->fb != fb);
> > +		WARN_ON(crtc->primary->fb != fb);
> >  		/* Unref only the old framebuffer. */
> >  		fb = NULL;
> >  	}
> > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> > index a855178..8825afb 100644
> > --- a/drivers/gpu/drm/drm_crtc_helper.c
> > +++ b/drivers/gpu/drm/drm_crtc_helper.c
> > @@ -319,7 +319,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
> >  				(*crtc_funcs->disable)(crtc);
> >  			else
> >  				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
> > -			crtc->fb = NULL;
> > +			crtc->primary->fb = NULL;
> >  		}
> >  	}
> >  }
> > @@ -646,19 +646,19 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
> >  	save_set.mode = &set->crtc->mode;
> >  	save_set.x = set->crtc->x;
> >  	save_set.y = set->crtc->y;
> > -	save_set.fb = set->crtc->fb;
> > +	save_set.fb = set->crtc->primary->fb;
> >  
> >  	/* We should be able to check here if the fb has the same properties
> >  	 * and then just flip_or_move it */
> > -	if (set->crtc->fb != set->fb) {
> > +	if (set->crtc->primary->fb != set->fb) {
> >  		/* If we have no fb then treat it as a full mode set */
> > -		if (set->crtc->fb == NULL) {
> > +		if (set->crtc->primary->fb == NULL) {
> >  			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
> >  			mode_changed = true;
> >  		} else if (set->fb == NULL) {
> >  			mode_changed = true;
> >  		} else if (set->fb->pixel_format !=
> > -			   set->crtc->fb->pixel_format) {
> > +			   set->crtc->primary->fb->pixel_format) {
> >  			mode_changed = true;
> >  		} else
> >  			fb_changed = true;
> > @@ -759,13 +759,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
> >  			DRM_DEBUG_KMS("attempting to set mode from"
> >  					" userspace\n");
> >  			drm_mode_debug_printmodeline(set->mode);
> > -			set->crtc->fb = set->fb;
> > +			set->crtc->primary->fb = set->fb;
> >  			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
> >  						      set->x, set->y,
> >  						      save_set.fb)) {
> >  				DRM_ERROR("failed to set mode on [CRTC:%d]\n",
> >  					  set->crtc->base.id);
> > -				set->crtc->fb = save_set.fb;
> > +				set->crtc->primary->fb = save_set.fb;
> >  				ret = -EINVAL;
> >  				goto fail;
> >  			}
> > @@ -780,13 +780,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
> >  	} else if (fb_changed) {
> >  		set->crtc->x = set->x;
> >  		set->crtc->y = set->y;
> > -		set->crtc->fb = set->fb;
> > +		set->crtc->primary->fb = set->fb;
> >  		ret = crtc_funcs->mode_set_base(set->crtc,
> >  						set->x, set->y, save_set.fb);
> >  		if (ret != 0) {
> >  			set->crtc->x = save_set.x;
> >  			set->crtc->y = save_set.y;
> > -			set->crtc->fb = save_set.fb;
> > +			set->crtc->primary->fb = save_set.fb;
> >  			goto fail;
> >  		}
> >  	}
> > @@ -982,7 +982,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
> >  			continue;
> >  
> >  		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
> > -					       crtc->x, crtc->y, crtc->fb);
> > +					       crtc->x, crtc->y,
> > +					       crtc->primary->fb);
> >  
> >  		/* Restoring the old config should never fail! */
> >  		if (ret == false)
> > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > index 9c6251f..e8e2b41 100644
> > --- a/drivers/gpu/drm/drm_fb_helper.c
> > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > @@ -232,7 +232,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
> >  
> >  	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
> >  		if (crtc->base.id == c->base.id)
> > -			return c->fb;
> > +			return c->primary->fb;
> >  	}
> >  
> >  	return NULL;
> > @@ -366,9 +366,9 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
> >  		return false;
> >  
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > -		if (crtc->fb)
> > +		if (crtc->primary->fb)
> >  			crtcs_bound++;
> > -		if (crtc->fb == fb_helper->fb)
> > +		if (crtc->primary->fb == fb_helper->fb)
> >  			bound++;
> >  	}
> >  
> > diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
> > index 8fbfa06..1cddcf8 100644
> > --- a/drivers/gpu/drm/gma500/cdv_intel_display.c
> > +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
> > @@ -463,7 +463,7 @@ static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe)
> >  	crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> >  	gma_crtc = to_gma_crtc(crtc);
> >  
> > -	if (crtc->fb == NULL || !gma_crtc->active)
> > +	if (crtc->primary->fb == NULL || !gma_crtc->active)
> >  		return false;
> >  	return true;
> >  }
> > diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
> > index 0490ce3..9ff30c2 100644
> > --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
> > +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
> > @@ -1693,7 +1693,7 @@ done:
> >  		struct drm_crtc *crtc = encoder->base.crtc;
> >  		drm_crtc_helper_set_mode(crtc, &crtc->mode,
> >  					 crtc->x, crtc->y,
> > -					 crtc->fb);
> > +					 crtc->primary->fb);
> >  	}
> >  
> >  	return 0;
> > diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> > index 1c0d723..04956e6 100644
> > --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> > +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> > @@ -199,7 +199,8 @@ static int cdv_hdmi_set_property(struct drm_connector *connector,
> >  		    crtc->saved_mode.vdisplay != 0) {
> >  			if (centre) {
> >  				if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
> > -					    encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb))
> > +					    encoder->crtc->x, encoder->crtc->y,
> > +					    encoder->crtc->primary->fb))
> >  					return -1;
> >  			} else {
> >  				struct drm_encoder_helper_funcs *helpers
> > diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> > index 20e08e6..58f11df 100644
> > --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> > +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> > @@ -494,7 +494,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
> >  						      &crtc->saved_mode,
> >  						      encoder->crtc->x,
> >  						      encoder->crtc->y,
> > -						      encoder->crtc->fb))
> > +						      encoder->crtc->primary->fb))
> >  				return -1;
> >  		}
> >  	} else if (!strcmp(property->name, "backlight") && encoder) {
> > diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
> > index 386de2c..7b73dd1 100644
> > --- a/drivers/gpu/drm/gma500/gma_display.c
> > +++ b/drivers/gpu/drm/gma500/gma_display.c
> > @@ -59,7 +59,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_psb_private *dev_priv = dev->dev_private;
> >  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> > -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> > +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
> >  	int pipe = gma_crtc->pipe;
> >  	const struct psb_offset *map = &dev_priv->regmap[pipe];
> >  	unsigned long start, offset;
> > @@ -70,7 +70,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> >  		return 0;
> >  
> >  	/* no fb bound */
> > -	if (!crtc->fb) {
> > +	if (!crtc->primary->fb) {
> >  		dev_err(dev->dev, "No FB bound\n");
> >  		goto gma_pipe_cleaner;
> >  	}
> > @@ -81,19 +81,20 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> >  	if (ret < 0)
> >  		goto gma_pipe_set_base_exit;
> >  	start = psbfb->gtt->offset;
> > -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> > +	offset = y * crtc->primary->fb->pitches[0] +
> > +		x * (crtc->primary->fb->bits_per_pixel / 8);
> >  
> > -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> > +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
> >  
> >  	dspcntr = REG_READ(map->cntr);
> >  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
> >  
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		dspcntr |= DISPPLANE_8BPP;
> >  		break;
> >  	case 16:
> > -		if (crtc->fb->depth == 15)
> > +		if (crtc->primary->fb->depth == 15)
> >  			dspcntr |= DISPPLANE_15_16BPP;
> >  		else
> >  			dspcntr |= DISPPLANE_16BPP;
> > @@ -511,8 +512,8 @@ void gma_crtc_disable(struct drm_crtc *crtc)
> >  
> >  	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
> >  
> > -	if (crtc->fb) {
> > -		gt = to_psb_fb(crtc->fb)->gtt;
> > +	if (crtc->primary->fb) {
> > +		gt = to_psb_fb(crtc->primary->fb)->gtt;
> >  		psb_gtt_unpin(gt);
> >  	}
> >  }
> > diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> > index 860a4ee..6e91b20 100644
> > --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> > +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> > @@ -287,7 +287,7 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
> >  						&gma_crtc->saved_mode,
> >  						encoder->crtc->x,
> >  						encoder->crtc->y,
> > -						encoder->crtc->fb))
> > +						encoder->crtc->primary->fb))
> >  					goto set_prop_error;
> >  			} else {
> >  				struct drm_encoder_helper_funcs *funcs =
> > diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c
> > index 321c00a..c54386a 100644
> > --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c
> > +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c
> > @@ -166,7 +166,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_psb_private *dev_priv = dev->dev_private;
> >  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> > -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> > +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
> >  	int pipe = gma_crtc->pipe;
> >  	const struct psb_offset *map = &dev_priv->regmap[pipe];
> >  	unsigned long start, offset;
> > @@ -178,12 +178,12 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> >  	dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
> >  
> >  	/* no fb bound */
> > -	if (!crtc->fb) {
> > +	if (!crtc->primary->fb) {
> >  		dev_dbg(dev->dev, "No FB bound\n");
> >  		return 0;
> >  	}
> >  
> > -	ret = check_fb(crtc->fb);
> > +	ret = check_fb(crtc->primary->fb);
> >  	if (ret)
> >  		return ret;
> >  
> > @@ -196,18 +196,19 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> >  		return 0;
> >  
> >  	start = psbfb->gtt->offset;
> > -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> > +	offset = y * crtc->primary->fb->pitches[0] +
> > +		x * (crtc->primary->fb->bits_per_pixel / 8);
> >  
> > -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> > +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
> >  	dspcntr = REG_READ(map->cntr);
> >  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
> >  
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		dspcntr |= DISPPLANE_8BPP;
> >  		break;
> >  	case 16:
> > -		if (crtc->fb->depth == 15)
> > +		if (crtc->primary->fb->depth == 15)
> >  			dspcntr |= DISPPLANE_15_16BPP;
> >  		else
> >  			dspcntr |= DISPPLANE_16BPP;
> > @@ -700,7 +701,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
> >  	}
> >  #endif
> >  
> > -	ret = check_fb(crtc->fb);
> > +	ret = check_fb(crtc->primary->fb);
> >  	if (ret)
> >  		return ret;
> >  
> > diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
> > index 8195e85..b0fb42a 100644
> > --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
> > +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
> > @@ -599,7 +599,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_psb_private *dev_priv = dev->dev_private;
> >  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> > -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> > +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
> >  	int pipe = gma_crtc->pipe;
> >  	const struct psb_offset *map = &dev_priv->regmap[pipe];
> >  	unsigned long start, offset;
> > @@ -608,7 +608,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
> >  	int ret = 0;
> >  
> >  	/* no fb bound */
> > -	if (!crtc->fb) {
> > +	if (!crtc->primary->fb) {
> >  		dev_dbg(dev->dev, "No FB bound\n");
> >  		return 0;
> >  	}
> > @@ -617,19 +617,20 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
> >  		return 0;
> >  
> >  	start = psbfb->gtt->offset;
> > -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> > +	offset = y * crtc->primary->fb->pitches[0] +
> > +		x * (crtc->primary->fb->bits_per_pixel / 8);
> >  
> > -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> > +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
> >  
> >  	dspcntr = REG_READ(map->cntr);
> >  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
> >  
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		dspcntr |= DISPPLANE_8BPP;
> >  		break;
> >  	case 16:
> > -		if (crtc->fb->depth == 15)
> > +		if (crtc->primary->fb->depth == 15)
> >  			dspcntr |= DISPPLANE_15_16BPP;
> >  		else
> >  			dspcntr |= DISPPLANE_16BPP;
> > diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
> > index c8f833d..25c174c 100644
> > --- a/drivers/gpu/drm/gma500/psb_intel_display.c
> > +++ b/drivers/gpu/drm/gma500/psb_intel_display.c
> > @@ -120,7 +120,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
> >  	const struct gma_limit_t *limit;
> >  
> >  	/* No scan out no play */
> > -	if (crtc->fb == NULL) {
> > +	if (crtc->primary->fb == NULL) {
> >  		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
> >  		return 0;
> >  	}
> > diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
> > index 32342f6..dcdf70e 100644
> > --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
> > +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
> > @@ -614,7 +614,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
> >  						      &crtc->saved_mode,
> >  						      encoder->crtc->x,
> >  						      encoder->crtc->y,
> > -						      encoder->crtc->fb))
> > +						      encoder->crtc->primary->fb))
> >  				goto set_prop_error;
> >  		}
> >  	} else if (!strcmp(property->name, "backlight")) {
> > diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> > index 07d3a9e..1c0a2fb 100644
> > --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> > +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> > @@ -1844,7 +1844,7 @@ done:
> >  	if (psb_intel_sdvo->base.base.crtc) {
> >  		struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc;
> >  		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
> > -					 crtc->y, crtc->fb);
> > +					 crtc->y, crtc->primary->fb);
> >  	}
> >  
> >  	return 0;
> > diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> > index d83d643..f00ba43 100644
> > --- a/drivers/gpu/drm/i915/i915_debugfs.c
> > +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> > @@ -2172,8 +2172,8 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc)
> >  	struct intel_encoder *intel_encoder;
> >  
> >  	seq_printf(m, "\tfb: %d, pos: %dx%d, size: %dx%d\n",
> > -		   crtc->fb->base.id, crtc->x, crtc->y,
> > -		   crtc->fb->width, crtc->fb->height);
> > +		   crtc->primary->fb->base.id, crtc->x, crtc->y,
> > +		   crtc->primary->fb->width, crtc->primary->fb->height);
> >  	for_each_encoder_on_crtc(dev, crtc, intel_encoder)
> >  		intel_encoder_info(m, intel_crtc, intel_encoder);
> >  }
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 37f852d..e8b3f9f 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -2380,8 +2380,8 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in
> >  	} else {
> >  		int dspaddr = DSPADDR(intel_crtc->plane);
> >  		stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) +
> > -							crtc->y * crtc->fb->pitches[0] +
> > -							crtc->x * crtc->fb->bits_per_pixel/8);
> > +							crtc->y * crtc->primary->fb->pitches[0] +
> > +							crtc->x * crtc->primary->fb->bits_per_pixel/8);
> >  	}
> >  
> >  	spin_unlock_irqrestore(&dev->event_lock, flags);
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 21d12a9..c2f3730 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -744,7 +744,7 @@ bool intel_crtc_active(struct drm_crtc *crtc)
> >  	 * We can ditch the crtc->fb check as soon as we can
> >  	 * properly reconstruct framebuffers.
> >  	 */
> > -	return intel_crtc->active && crtc->fb &&
> > +	return intel_crtc->active && crtc->primary->fb &&
> >  		intel_crtc->config.adjusted_mode.crtc_clock;
> >  }
> >  
> > @@ -2086,17 +2086,18 @@ static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
> >  
> >  	if (plane_config->tiled) {
> >  		obj->tiling_mode = I915_TILING_X;
> > -		obj->stride = crtc->base.fb->pitches[0];
> > +		obj->stride = crtc->base.primary->fb->pitches[0];
> >  	}
> >  
> > -	mode_cmd.pixel_format = crtc->base.fb->pixel_format;
> > -	mode_cmd.width = crtc->base.fb->width;
> > -	mode_cmd.height = crtc->base.fb->height;
> > -	mode_cmd.pitches[0] = crtc->base.fb->pitches[0];
> > +	mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
> > +	mode_cmd.width = crtc->base.primary->fb->width;
> > +	mode_cmd.height = crtc->base.primary->fb->height;
> > +	mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0];
> >  
> >  	mutex_lock(&dev->struct_mutex);
> >  
> > -	if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.fb),
> > +	if (intel_framebuffer_init(dev,
> > +				   to_intel_framebuffer(crtc->base.primary->fb),
> >  				   &mode_cmd, obj)) {
> >  		DRM_DEBUG_KMS("intel fb init failed\n");
> >  		goto out_unref_obj;
> > @@ -2121,14 +2122,14 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
> >  	struct intel_crtc *i;
> >  	struct intel_framebuffer *fb;
> >  
> > -	if (!intel_crtc->base.fb)
> > +	if (!intel_crtc->base.primary->fb)
> >  		return;
> >  
> >  	if (intel_alloc_plane_obj(intel_crtc, plane_config))
> >  		return;
> >  
> > -	kfree(intel_crtc->base.fb);
> > -	intel_crtc->base.fb = NULL;
> > +	kfree(intel_crtc->base.primary->fb);
> > +	intel_crtc->base.primary->fb = NULL;
> >  
> >  	/*
> >  	 * Failed to alloc the obj, check to see if we should share
> > @@ -2140,13 +2141,13 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
> >  		if (c == &intel_crtc->base)
> >  			continue;
> >  
> > -		if (!i->active || !c->fb)
> > +		if (!i->active || !c->primary->fb)
> >  			continue;
> >  
> > -		fb = to_intel_framebuffer(c->fb);
> > +		fb = to_intel_framebuffer(c->primary->fb);
> >  		if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) {
> > -			drm_framebuffer_reference(c->fb);
> > -			intel_crtc->base.fb = c->fb;
> > +			drm_framebuffer_reference(c->primary->fb);
> > +			intel_crtc->base.primary->fb = c->primary->fb;
> >  			break;
> >  		}
> >  	}
> > @@ -2394,11 +2395,13 @@ void intel_display_handle_reset(struct drm_device *dev)
> >  		/*
> >  		 * FIXME: Once we have proper support for primary planes (and
> >  		 * disabling them without disabling the entire crtc) allow again
> > -		 * a NULL crtc->fb.
> > +		 * a NULL crtc->primary->fb.
> >  		 */
> > -		if (intel_crtc->active && crtc->fb)
> > -			dev_priv->display.update_plane(crtc, crtc->fb,
> > -						       crtc->x, crtc->y);
> > +		if (intel_crtc->active && crtc->primary->fb)
> > +			dev_priv->display.update_plane(crtc,
> > +						       crtc->primary->fb,
> > +						       crtc->x,
> > +						       crtc->y);
> >  		mutex_unlock(&crtc->mutex);
> >  	}
> >  }
> > @@ -2523,8 +2526,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> >  		return ret;
> >  	}
> >  
> > -	old_fb = crtc->fb;
> > -	crtc->fb = fb;
> > +	old_fb = crtc->primary->fb;
> > +	crtc->primary->fb = fb;
> >  	crtc->x = x;
> >  	crtc->y = y;
> >  
> > @@ -3118,7 +3121,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> >  
> > -	if (crtc->fb == NULL)
> > +	if (crtc->primary->fb == NULL)
> >  		return;
> >  
> >  	WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
> > @@ -3127,7 +3130,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
> >  		   !intel_crtc_has_pending_flip(crtc));
> >  
> >  	mutex_lock(&dev->struct_mutex);
> > -	intel_finish_fb(crtc->fb);
> > +	intel_finish_fb(crtc->primary->fb);
> >  	mutex_unlock(&dev->struct_mutex);
> >  }
> >  
> > @@ -4583,11 +4586,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
> >  	assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe);
> >  	assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
> >  
> > -	if (crtc->fb) {
> > +	if (crtc->primary->fb) {
> >  		mutex_lock(&dev->struct_mutex);
> > -		intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
> > +		intel_unpin_fb_obj(to_intel_framebuffer(crtc->primary->fb)->obj);
> >  		mutex_unlock(&dev->struct_mutex);
> > -		crtc->fb = NULL;
> > +		crtc->primary->fb = NULL;
> >  	}
> >  
> >  	/* Update computed state. */
> > @@ -5738,8 +5741,9 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
> >  	int fourcc, pixel_format;
> >  	int aligned_height;
> >  
> > -	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > -	if (!crtc->base.fb) {
> > +	crtc->base.primary->fb =
> > +		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > +	if (!crtc->base.primary->fb) {
> >  		DRM_DEBUG_KMS("failed to alloc fb\n");
> >  		return;
> >  	}
> > @@ -5752,8 +5756,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
> >  
> >  	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
> >  	fourcc = intel_format_to_fourcc(pixel_format);
> > -	crtc->base.fb->pixel_format = fourcc;
> > -	crtc->base.fb->bits_per_pixel =
> > +	crtc->base.primary->fb->pixel_format = fourcc;
> > +	crtc->base.primary->fb->bits_per_pixel =
> >  		drm_format_plane_cpp(fourcc, 0) * 8;
> >  
> >  	if (INTEL_INFO(dev)->gen >= 4) {
> > @@ -5768,23 +5772,23 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
> >  	plane_config->base = base;
> >  
> >  	val = I915_READ(PIPESRC(pipe));
> > -	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
> > -	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
> > +	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
> > +	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
> >  
> >  	val = I915_READ(DSPSTRIDE(pipe));
> > -	crtc->base.fb->pitches[0] = val & 0xffffff80;
> > +	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
> >  
> > -	aligned_height = intel_align_height(dev, crtc->base.fb->height,
> > +	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
> >  					    plane_config->tiled);
> >  
> > -	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
> > +	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
> >  				   aligned_height, PAGE_SIZE);
> >  
> >  	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
> > -		      pipe, plane, crtc->base.fb->width,
> > -		      crtc->base.fb->height,
> > -		      crtc->base.fb->bits_per_pixel, base,
> > -		      crtc->base.fb->pitches[0],
> > +		      pipe, plane, crtc->base.primary->fb->width,
> > +		      crtc->base.primary->fb->height,
> > +		      crtc->base.primary->fb->bits_per_pixel, base,
> > +		      crtc->base.primary->fb->pitches[0],
> >  		      plane_config->size);
> >  
> >  }
> > @@ -6746,8 +6750,9 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
> >  	int fourcc, pixel_format;
> >  	int aligned_height;
> >  
> > -	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > -	if (!crtc->base.fb) {
> > +	crtc->base.primary->fb =
> > +		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > +	if (!crtc->base.primary->fb) {
> >  		DRM_DEBUG_KMS("failed to alloc fb\n");
> >  		return;
> >  	}
> > @@ -6760,8 +6765,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
> >  
> >  	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
> >  	fourcc = intel_format_to_fourcc(pixel_format);
> > -	crtc->base.fb->pixel_format = fourcc;
> > -	crtc->base.fb->bits_per_pixel =
> > +	crtc->base.primary->fb->pixel_format = fourcc;
> > +	crtc->base.primary->fb->bits_per_pixel =
> >  		drm_format_plane_cpp(fourcc, 0) * 8;
> >  
> >  	base = I915_READ(DSPSURF(plane)) & 0xfffff000;
> > @@ -6776,23 +6781,23 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
> >  	plane_config->base = base;
> >  
> >  	val = I915_READ(PIPESRC(pipe));
> > -	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
> > -	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
> > +	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
> > +	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
> >  
> >  	val = I915_READ(DSPSTRIDE(pipe));
> > -	crtc->base.fb->pitches[0] = val & 0xffffff80;
> > +	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
> >  
> > -	aligned_height = intel_align_height(dev, crtc->base.fb->height,
> > +	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
> >  					    plane_config->tiled);
> >  
> > -	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
> > +	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
> >  				   aligned_height, PAGE_SIZE);
> >  
> >  	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
> > -		      pipe, plane, crtc->base.fb->width,
> > -		      crtc->base.fb->height,
> > -		      crtc->base.fb->bits_per_pixel, base,
> > -		      crtc->base.fb->pitches[0],
> > +		      pipe, plane, crtc->base.primary->fb->width,
> > +		      crtc->base.primary->fb->height,
> > +		      crtc->base.primary->fb->bits_per_pixel, base,
> > +		      crtc->base.primary->fb->pitches[0],
> >  		      plane_config->size);
> >  }
> >  
> > @@ -8482,7 +8487,7 @@ void intel_mark_idle(struct drm_device *dev)
> >  		goto out;
> >  
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > -		if (!crtc->fb)
> > +		if (!crtc->primary->fb)
> >  			continue;
> >  
> >  		intel_decrease_pllclock(crtc);
> > @@ -8505,10 +8510,10 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
> >  		return;
> >  
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > -		if (!crtc->fb)
> > +		if (!crtc->primary->fb)
> >  			continue;
> >  
> > -		if (to_intel_framebuffer(crtc->fb)->obj != obj)
> > +		if (to_intel_framebuffer(crtc->primary->fb)->obj != obj)
> >  			continue;
> >  
> >  		intel_increase_pllclock(crtc);
> > @@ -8936,7 +8941,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> >  {
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > -	struct drm_framebuffer *old_fb = crtc->fb;
> > +	struct drm_framebuffer *old_fb = crtc->primary->fb;
> >  	struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> >  	struct intel_unpin_work *work;
> > @@ -8944,7 +8949,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> >  	int ret;
> >  
> >  	/* Can't change pixel format via MI display flips. */
> > -	if (fb->pixel_format != crtc->fb->pixel_format)
> > +	if (fb->pixel_format != crtc->primary->fb->pixel_format)
> >  		return -EINVAL;
> >  
> >  	/*
> > @@ -8952,8 +8957,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> >  	 * Note that pitch changes could also affect these register.
> >  	 */
> >  	if (INTEL_INFO(dev)->gen > 3 &&
> > -	    (fb->offsets[0] != crtc->fb->offsets[0] ||
> > -	     fb->pitches[0] != crtc->fb->pitches[0]))
> > +	    (fb->offsets[0] != crtc->primary->fb->offsets[0] ||
> > +	     fb->pitches[0] != crtc->primary->fb->pitches[0]))
> >  		return -EINVAL;
> >  
> >  	if (i915_terminally_wedged(&dev_priv->gpu_error))
> > @@ -8996,7 +9001,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> >  	drm_gem_object_reference(&work->old_fb_obj->base);
> >  	drm_gem_object_reference(&obj->base);
> >  
> > -	crtc->fb = fb;
> > +	crtc->primary->fb = fb;
> >  
> >  	work->pending_flip_obj = obj;
> >  
> > @@ -9019,7 +9024,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> >  
> >  cleanup_pending:
> >  	atomic_dec(&intel_crtc->unpin_work_count);
> > -	crtc->fb = old_fb;
> > +	crtc->primary->fb = old_fb;
> >  	drm_gem_object_unreference(&work->old_fb_obj->base);
> >  	drm_gem_object_unreference(&obj->base);
> >  	mutex_unlock(&dev->struct_mutex);
> > @@ -10060,7 +10065,7 @@ static int intel_set_mode(struct drm_crtc *crtc,
> >  
> >  void intel_crtc_restore_mode(struct drm_crtc *crtc)
> >  {
> > -	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb);
> > +	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
> >  }
> >  
> >  #undef for_each_intel_crtc_masked
> > @@ -10184,9 +10189,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
> >  	 * and then just flip_or_move it */
> >  	if (is_crtc_connector_off(set)) {
> >  		config->mode_changed = true;
> > -	} else if (set->crtc->fb != set->fb) {
> > +	} else if (set->crtc->primary->fb != set->fb) {
> >  		/* If we have no fb then treat it as a full mode set */
> > -		if (set->crtc->fb == NULL) {
> > +		if (set->crtc->primary->fb == NULL) {
> >  			struct intel_crtc *intel_crtc =
> >  				to_intel_crtc(set->crtc);
> >  
> > @@ -10200,7 +10205,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
> >  		} else if (set->fb == NULL) {
> >  			config->mode_changed = true;
> >  		} else if (set->fb->pixel_format !=
> > -			   set->crtc->fb->pixel_format) {
> > +			   set->crtc->primary->fb->pixel_format) {
> >  			config->mode_changed = true;
> >  		} else {
> >  			config->fb_changed = true;
> > @@ -10413,7 +10418,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
> >  	save_set.mode = &set->crtc->mode;
> >  	save_set.x = set->crtc->x;
> >  	save_set.y = set->crtc->y;
> > -	save_set.fb = set->crtc->fb;
> > +	save_set.fb = set->crtc->primary->fb;
> >  
> >  	/* Compute whether we need a full modeset, only an fb base update or no
> >  	 * change at all. In the future we might also check whether only the
> > @@ -11755,7 +11760,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
> >  				dev_priv->pipe_to_crtc_mapping[pipe];
> >  
> >  			__intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
> > -					 crtc->fb);
> > +					 crtc->primary->fb);
> >  		}
> >  	} else {
> >  		intel_modeset_update_staged_output_state(dev);
> > @@ -11780,15 +11785,15 @@ void intel_modeset_gem_init(struct drm_device *dev)
> >  	 */
> >  	mutex_lock(&dev->struct_mutex);
> >  	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
> > -		if (!c->fb)
> > +		if (!c->primary->fb)
> >  			continue;
> >  
> > -		fb = to_intel_framebuffer(c->fb);
> > +		fb = to_intel_framebuffer(c->primary->fb);
> >  		if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) {
> >  			DRM_ERROR("failed to pin boot fb on pipe %d\n",
> >  				  to_intel_crtc(c)->pipe);
> > -			drm_framebuffer_unreference(c->fb);
> > -			c->fb = NULL;
> > +			drm_framebuffer_unreference(c->primary->fb);
> > +			c->primary->fb = NULL;
> >  		}
> >  	}
> >  	mutex_unlock(&dev->struct_mutex);
> > @@ -11827,7 +11832,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
> >  
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> >  		/* Skip inactive CRTCs */
> > -		if (!crtc->fb)
> > +		if (!crtc->primary->fb)
> >  			continue;
> >  
> >  		intel_increase_pllclock(crtc);
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > index 59ee4dc..05531bf 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -1634,7 +1634,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> >  	struct drm_crtc *crtc = dig_port->base.base.crtc;
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > -	struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
> > +	struct drm_i915_gem_object *obj =
> > +		to_intel_framebuffer(crtc->primary->fb)->obj;
> >  	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
> >  
> >  	dev_priv->psr.source_ok = false;
> > @@ -1667,7 +1668,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> >  		return false;
> >  	}
> >  
> > -	obj = to_intel_framebuffer(crtc->fb)->obj;
> > +	obj = to_intel_framebuffer(crtc->primary->fb)->obj;
> >  	if (obj->tiling_mode != I915_TILING_X ||
> >  	    obj->fence_reg == I915_FENCE_REG_NONE) {
> >  		DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
> > diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> > index d6d78c8..2b1d42d 100644
> > --- a/drivers/gpu/drm/i915/intel_fbdev.c
> > +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> > @@ -481,7 +481,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> >  		intel_crtc = to_intel_crtc(crtc);
> >  
> > -		if (!intel_crtc->active || !crtc->fb) {
> > +		if (!intel_crtc->active || !crtc->primary->fb) {
> >  			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
> >  				      pipe_name(intel_crtc->pipe));
> >  			continue;
> > @@ -491,7 +491,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
> >  			DRM_DEBUG_KMS("found possible fb from plane %c\n",
> >  				      pipe_name(intel_crtc->pipe));
> >  			plane_config = &intel_crtc->plane_config;
> > -			fb = to_intel_framebuffer(crtc->fb);
> > +			fb = to_intel_framebuffer(crtc->primary->fb);
> >  			max_size = plane_config->size;
> >  		}
> >  	}
> > @@ -560,7 +560,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
> >  		if (!intel_crtc->active)
> >  			continue;
> >  
> > -		WARN(!crtc->fb,
> > +		WARN(!crtc->primary->fb,
> >  		     "re-used BIOS config but lost an fb on crtc %d\n",
> >  		     crtc->base.id);
> >  	}
> > diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
> > index 312961a..623cd32 100644
> > --- a/drivers/gpu/drm/i915/intel_overlay.c
> > +++ b/drivers/gpu/drm/i915/intel_overlay.c
> > @@ -606,14 +606,14 @@ static void update_colorkey(struct intel_overlay *overlay,
> >  {
> >  	u32 key = overlay->color_key;
> >  
> > -	switch (overlay->crtc->base.fb->bits_per_pixel) {
> > +	switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		iowrite32(0, &regs->DCLRKV);
> >  		iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
> >  		break;
> >  
> >  	case 16:
> > -		if (overlay->crtc->base.fb->depth == 15) {
> > +		if (overlay->crtc->base.primary->fb->depth == 15) {
> >  			iowrite32(RGB15_TO_COLORKEY(key), &regs->DCLRKV);
> >  			iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
> >  				  &regs->DCLRKM);
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 3a1b569..e2d73f4 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -92,7 +92,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
> >  {
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > -	struct drm_framebuffer *fb = crtc->fb;
> > +	struct drm_framebuffer *fb = crtc->primary->fb;
> >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > @@ -149,7 +149,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc)
> >  {
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > -	struct drm_framebuffer *fb = crtc->fb;
> > +	struct drm_framebuffer *fb = crtc->primary->fb;
> >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > @@ -221,7 +221,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc)
> >  {
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > -	struct drm_framebuffer *fb = crtc->fb;
> > +	struct drm_framebuffer *fb = crtc->primary->fb;
> >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > @@ -277,7 +277,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc)
> >  {
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > -	struct drm_framebuffer *fb = crtc->fb;
> > +	struct drm_framebuffer *fb = crtc->primary->fb;
> >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > @@ -336,11 +336,11 @@ static void intel_fbc_work_fn(struct work_struct *__work)
> >  		/* Double check that we haven't switched fb without cancelling
> >  		 * the prior work.
> >  		 */
> > -		if (work->crtc->fb == work->fb) {
> > +		if (work->crtc->primary->fb == work->fb) {
> >  			dev_priv->display.enable_fbc(work->crtc);
> >  
> >  			dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
> > -			dev_priv->fbc.fb_id = work->crtc->fb->base.id;
> > +			dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
> >  			dev_priv->fbc.y = work->crtc->y;
> >  		}
> >  
> > @@ -393,7 +393,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc)
> >  	}
> >  
> >  	work->crtc = crtc;
> > -	work->fb = crtc->fb;
> > +	work->fb = crtc->primary->fb;
> >  	INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
> >  
> >  	dev_priv->fbc.fbc_work = work;
> > @@ -499,14 +499,14 @@ void intel_update_fbc(struct drm_device *dev)
> >  		}
> >  	}
> >  
> > -	if (!crtc || crtc->fb == NULL) {
> > +	if (!crtc || crtc->primary->fb == NULL) {
> >  		if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
> >  			DRM_DEBUG_KMS("no output, disabling\n");
> >  		goto out_disable;
> >  	}
> >  
> >  	intel_crtc = to_intel_crtc(crtc);
> > -	fb = crtc->fb;
> > +	fb = crtc->primary->fb;
> >  	intel_fb = to_intel_framebuffer(fb);
> >  	obj = intel_fb->obj;
> >  	adjusted_mode = &intel_crtc->config.adjusted_mode;
> > @@ -1041,7 +1041,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
> >  	crtc = single_enabled_crtc(dev);
> >  	if (crtc) {
> >  		const struct drm_display_mode *adjusted_mode;
> > -		int pixel_size = crtc->fb->bits_per_pixel / 8;
> > +		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> >  		int clock;
> >  
> >  		adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
> > @@ -1121,7 +1121,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
> >  	clock = adjusted_mode->crtc_clock;
> >  	htotal = adjusted_mode->crtc_htotal;
> >  	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> > -	pixel_size = crtc->fb->bits_per_pixel / 8;
> > +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> >  
> >  	/* Use the small buffer method to calculate plane watermark */
> >  	entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
> > @@ -1208,7 +1208,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
> >  	clock = adjusted_mode->crtc_clock;
> >  	htotal = adjusted_mode->crtc_htotal;
> >  	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> > -	pixel_size = crtc->fb->bits_per_pixel / 8;
> > +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> >  
> >  	line_time_us = max(htotal * 1000 / clock, 1);
> >  	line_count = (latency_ns / line_time_us + 1000) / 1000;
> > @@ -1247,7 +1247,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,
> >  		return false;
> >  
> >  	clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
> > -	pixel_size = crtc->fb->bits_per_pixel / 8;	/* BPP */
> > +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;	/* BPP */
> >  
> >  	entries = (clock / 1000) * pixel_size;
> >  	*plane_prec_mult = (entries > 256) ?
> > @@ -1439,7 +1439,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
> >  		int clock = adjusted_mode->crtc_clock;
> >  		int htotal = adjusted_mode->crtc_htotal;
> >  		int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> > -		int pixel_size = crtc->fb->bits_per_pixel / 8;
> > +		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> >  		unsigned long line_time_us;
> >  		int entries;
> >  
> > @@ -1512,7 +1512,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
> >  	crtc = intel_get_crtc_for_plane(dev, 0);
> >  	if (intel_crtc_active(crtc)) {
> >  		const struct drm_display_mode *adjusted_mode;
> > -		int cpp = crtc->fb->bits_per_pixel / 8;
> > +		int cpp = crtc->primary->fb->bits_per_pixel / 8;
> >  		if (IS_GEN2(dev))
> >  			cpp = 4;
> >  
> > @@ -1528,7 +1528,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
> >  	crtc = intel_get_crtc_for_plane(dev, 1);
> >  	if (intel_crtc_active(crtc)) {
> >  		const struct drm_display_mode *adjusted_mode;
> > -		int cpp = crtc->fb->bits_per_pixel / 8;
> > +		int cpp = crtc->primary->fb->bits_per_pixel / 8;
> >  		if (IS_GEN2(dev))
> >  			cpp = 4;
> >  
> > @@ -1565,7 +1565,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
> >  		int clock = adjusted_mode->crtc_clock;
> >  		int htotal = adjusted_mode->crtc_htotal;
> >  		int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w;
> > -		int pixel_size = enabled->fb->bits_per_pixel / 8;
> > +		int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
> >  		unsigned long line_time_us;
> >  		int entries;
> >  
> > @@ -2117,7 +2117,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
> >  	if (p->active) {
> >  		p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
> >  		p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
> > -		p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
> > +		p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
> >  		p->cur.bytes_per_pixel = 4;
> >  		p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
> >  		p->cur.horiz_pixels = 64;
> > diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> > index 1418414..f8c42b1 100644
> > --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> > +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> > @@ -29,7 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
> >  	struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
> >  	struct drm_device *dev = crtc->dev;
> >  	struct mga_device *mdev = dev->dev_private;
> > -	struct drm_framebuffer *fb = crtc->fb;
> > +	struct drm_framebuffer *fb = crtc->primary->fb;
> >  	int i;
> >  
> >  	if (!crtc->enabled)
> > @@ -742,7 +742,7 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
> >  		mgag200_bo_unreserve(bo);
> >  	}
> >  
> > -	mga_fb = to_mga_framebuffer(crtc->fb);
> > +	mga_fb = to_mga_framebuffer(crtc->primary->fb);
> >  	obj = mga_fb->obj;
> >  	bo = gem_to_mga_bo(obj);
> >  
> > @@ -805,7 +805,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> >  		/* 0x48: */        0,    0,    0,    0,    0,    0,    0,    0
> >  	};
> >  
> > -	bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1];
> > +	bppshift = mdev->bpp_shifts[(crtc->primary->fb->bits_per_pixel >> 3) - 1];
> >  
> >  	switch (mdev->type) {
> >  	case G200_SE_A:
> > @@ -843,12 +843,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> >  		break;
> >  	}
> >  
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
> >  		break;
> >  	case 16:
> > -		if (crtc->fb->depth == 15)
> > +		if (crtc->primary->fb->depth == 15)
> >  			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
> >  		else
> >  			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
> > @@ -896,8 +896,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> >  	WREG_SEQ(3, 0);
> >  	WREG_SEQ(4, 0xe);
> >  
> > -	pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
> > -	if (crtc->fb->bits_per_pixel == 24)
> > +	pitch = crtc->primary->fb->pitches[0] /
> > +		(crtc->primary->fb->bits_per_pixel / 8);
> > +	if (crtc->primary->fb->bits_per_pixel == 24)
> >  		pitch = (pitch * 3) >> (4 - bppshift);
> >  	else
> >  		pitch = pitch >> (4 - bppshift);
> > @@ -974,7 +975,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> >  		((vdisplay & 0xc00) >> 7) |
> >  		((vsyncstart & 0xc00) >> 5) |
> >  		((vdisplay & 0x400) >> 3);
> > -	if (crtc->fb->bits_per_pixel == 24)
> > +	if (crtc->primary->fb->bits_per_pixel == 24)
> >  		ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
> >  	else
> >  		ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
> > @@ -1034,9 +1035,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> >  			u32 bpp;
> >  			u32 mb;
> >  
> > -			if (crtc->fb->bits_per_pixel > 16)
> > +			if (crtc->primary->fb->bits_per_pixel > 16)
> >  				bpp = 32;
> > -			else if (crtc->fb->bits_per_pixel > 8)
> > +			else if (crtc->primary->fb->bits_per_pixel > 8)
> >  				bpp = 16;
> >  			else
> >  				bpp = 8;
> > @@ -1277,8 +1278,9 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
> >  	int ret;
> >  	DRM_DEBUG_KMS("\n");
> >  	mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> > -	if (crtc->fb) {
> > -		struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
> > +	if (crtc->primary->fb) {
> > +		struct mga_framebuffer *mga_fb =
> > +			to_mga_framebuffer(crtc->primary->fb);
> >  		struct drm_gem_object *obj = mga_fb->obj;
> >  		struct mgag200_bo *bo = gem_to_mga_bo(obj);
> >  		ret = mgag200_bo_reserve(bo, false);
> > @@ -1287,7 +1289,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
> >  		mgag200_bo_push_sysram(bo);
> >  		mgag200_bo_unreserve(bo);
> >  	}
> > -	crtc->fb = NULL;
> > +	crtc->primary->fb = NULL;
> >  }
> >  
> >  /* These provide the minimum set of functions required to handle a CRTC */
> > diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> > index b10f681..f96497b 100644
> > --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> > +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> > @@ -120,7 +120,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
> >  
> >  	/* grab reference to incoming scanout fb: */
> >  	drm_framebuffer_reference(new_fb);
> > -	mdp4_crtc->base.fb = new_fb;
> > +	mdp4_crtc->base.primary->fb = new_fb;
> >  	mdp4_crtc->fb = new_fb;
> >  
> >  	if (old_fb)
> > @@ -182,7 +182,7 @@ static void pageflip_cb(struct msm_fence_cb *cb)
> >  	struct mdp4_crtc *mdp4_crtc =
> >  		container_of(cb, struct mdp4_crtc, pageflip_cb);
> >  	struct drm_crtc *crtc = &mdp4_crtc->base;
> > -	struct drm_framebuffer *fb = crtc->fb;
> > +	struct drm_framebuffer *fb = crtc->primary->fb;
> >  
> >  	if (!fb)
> >  		return;
> > @@ -348,14 +348,14 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> >  			mode->type, mode->flags);
> >  
> >  	/* grab extra ref for update_scanout() */
> > -	drm_framebuffer_reference(crtc->fb);
> > +	drm_framebuffer_reference(crtc->primary->fb);
> >  
> > -	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
> > +	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb,
> >  			0, 0, mode->hdisplay, mode->vdisplay,
> >  			x << 16, y << 16,
> >  			mode->hdisplay << 16, mode->vdisplay << 16);
> >  	if (ret) {
> > -		drm_framebuffer_unreference(crtc->fb);
> > +		drm_framebuffer_unreference(crtc->primary->fb);
> >  		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
> >  				mdp4_crtc->name, ret);
> >  		return ret;
> > @@ -368,7 +368,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> >  	/* take data from pipe: */
> >  	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
> >  	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma),
> > -			crtc->fb->pitches[0]);
> > +			crtc->primary->fb->pitches[0]);
> >  	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
> >  			MDP4_DMA_DST_SIZE_WIDTH(0) |
> >  			MDP4_DMA_DST_SIZE_HEIGHT(0));
> > @@ -378,7 +378,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> >  			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
> >  			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
> >  	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp),
> > -			crtc->fb->pitches[0]);
> > +			crtc->primary->fb->pitches[0]);
> >  
> >  	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
> >  
> > @@ -388,8 +388,8 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> >  		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
> >  	}
> >  
> > -	update_fb(crtc, crtc->fb);
> > -	update_scanout(crtc, crtc->fb);
> > +	update_fb(crtc, crtc->primary->fb);
> > +	update_scanout(crtc, crtc->primary->fb);
> >  
> >  	return 0;
> >  }
> > @@ -420,19 +420,19 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> >  	int ret;
> >  
> >  	/* grab extra ref for update_scanout() */
> > -	drm_framebuffer_reference(crtc->fb);
> > +	drm_framebuffer_reference(crtc->primary->fb);
> >  
> > -	ret = mdp4_plane_mode_set(plane, crtc, crtc->fb,
> > +	ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb,
> >  			0, 0, mode->hdisplay, mode->vdisplay,
> >  			x << 16, y << 16,
> >  			mode->hdisplay << 16, mode->vdisplay << 16);
> >  	if (ret) {
> > -		drm_framebuffer_unreference(crtc->fb);
> > +		drm_framebuffer_unreference(crtc->primary->fb);
> >  		return ret;
> >  	}
> >  
> > -	update_fb(crtc, crtc->fb);
> > -	update_scanout(crtc, crtc->fb);
> > +	update_fb(crtc, crtc->primary->fb);
> > +	update_scanout(crtc, crtc->primary->fb);
> >  
> >  	return 0;
> >  }
> > diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> > index 7dc3d71..f200048 100644
> > --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> > +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> > @@ -102,7 +102,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
> >  
> >  	/* grab reference to incoming scanout fb: */
> >  	drm_framebuffer_reference(new_fb);
> > -	mdp5_crtc->base.fb = new_fb;
> > +	mdp5_crtc->base.primary->fb = new_fb;
> >  	mdp5_crtc->fb = new_fb;
> >  
> >  	if (old_fb)
> > @@ -289,14 +289,14 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
> >  			mode->type, mode->flags);
> >  
> >  	/* grab extra ref for update_scanout() */
> > -	drm_framebuffer_reference(crtc->fb);
> > +	drm_framebuffer_reference(crtc->primary->fb);
> >  
> > -	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb,
> > +	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb,
> >  			0, 0, mode->hdisplay, mode->vdisplay,
> >  			x << 16, y << 16,
> >  			mode->hdisplay << 16, mode->vdisplay << 16);
> >  	if (ret) {
> > -		drm_framebuffer_unreference(crtc->fb);
> > +		drm_framebuffer_unreference(crtc->primary->fb);
> >  		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
> >  				mdp5_crtc->name, ret);
> >  		return ret;
> > @@ -306,8 +306,8 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
> >  			MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
> >  			MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
> >  
> > -	update_fb(crtc, crtc->fb);
> > -	update_scanout(crtc, crtc->fb);
> > +	update_fb(crtc, crtc->primary->fb);
> > +	update_scanout(crtc, crtc->primary->fb);
> >  
> >  	return 0;
> >  }
> > @@ -338,19 +338,19 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> >  	int ret;
> >  
> >  	/* grab extra ref for update_scanout() */
> > -	drm_framebuffer_reference(crtc->fb);
> > +	drm_framebuffer_reference(crtc->primary->fb);
> >  
> > -	ret = mdp5_plane_mode_set(plane, crtc, crtc->fb,
> > +	ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb,
> >  			0, 0, mode->hdisplay, mode->vdisplay,
> >  			x << 16, y << 16,
> >  			mode->hdisplay << 16, mode->vdisplay << 16);
> >  	if (ret) {
> > -		drm_framebuffer_unreference(crtc->fb);
> > +		drm_framebuffer_unreference(crtc->primary->fb);
> >  		return ret;
> >  	}
> >  
> > -	update_fb(crtc, crtc->fb);
> > -	update_scanout(crtc, crtc->fb);
> > +	update_fb(crtc, crtc->primary->fb);
> > +	update_scanout(crtc, crtc->primary->fb);
> >  
> >  	return 0;
> >  }
> > diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> > index b55be84..2a5e9db 100644
> > --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> > +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> > @@ -239,7 +239,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
> >  	struct drm_device *dev = crtc->dev;
> >  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
> >  	struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
> > -	struct drm_framebuffer *fb = crtc->fb;
> > +	struct drm_framebuffer *fb = crtc->primary->fb;
> >  
> >  	/* Calculate our timings */
> >  	int horizDisplay	= (mode->crtc_hdisplay >> 3)		- 1;
> > @@ -574,7 +574,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
> >  		regp->CRTC[NV_CIO_CRE_86] = 0x1;
> >  	}
> >  
> > -	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->fb->depth + 1) / 8;
> > +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->primary->fb->depth + 1) / 8;
> >  	/* Enable slaved mode (called MODE_TV in nv4ref.h) */
> >  	if (lvds_output || tmds_output || tv_output)
> >  		regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7);
> > @@ -588,7 +588,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
> >  	regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
> >  				NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL |
> >  				NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON;
> > -	if (crtc->fb->depth == 16)
> > +	if (crtc->primary->fb->depth == 16)
> >  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
> >  	if (nv_device(drm->device)->chipset >= 0x11)
> >  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG;
> > @@ -609,7 +609,7 @@ static int
> >  nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
> >  {
> >  	struct nv04_display *disp = nv04_display(crtc->dev);
> > -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
> > +	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
> >  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
> >  	int ret;
> >  
> > @@ -808,7 +808,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
> >  	 * mark the lut values as dirty by setting depth==0, and it'll be
> >  	 * uploaded on the first mode_set_base()
> >  	 */
> > -	if (!nv_crtc->base.fb) {
> > +	if (!nv_crtc->base.primary->fb) {
> >  		nv_crtc->lut.depth = 0;
> >  		return;
> >  	}
> > @@ -832,7 +832,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
> >  	NV_DEBUG(drm, "index %d\n", nv_crtc->index);
> >  
> >  	/* no fb bound */
> > -	if (!atomic && !crtc->fb) {
> > +	if (!atomic && !crtc->primary->fb) {
> >  		NV_DEBUG(drm, "No FB bound\n");
> >  		return 0;
> >  	}
> > @@ -844,8 +844,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
> >  		drm_fb = passed_fb;
> >  		fb = nouveau_framebuffer(passed_fb);
> >  	} else {
> > -		drm_fb = crtc->fb;
> > -		fb = nouveau_framebuffer(crtc->fb);
> > +		drm_fb = crtc->primary->fb;
> > +		fb = nouveau_framebuffer(crtc->primary->fb);
> >  	}
> >  
> >  	nv_crtc->fb.offset = fb->nvbo->bo.offset;
> > @@ -857,9 +857,9 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
> >  
> >  	/* Update the framebuffer format. */
> >  	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3;
> > -	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8;
> > +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->primary->fb->depth + 1) / 8;
> >  	regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
> > -	if (crtc->fb->depth == 16)
> > +	if (crtc->primary->fb->depth == 16)
> >  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
> >  	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX);
> >  	NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL,
> > diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> > index 7fdc51e..a2d669b 100644
> > --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> > +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> > @@ -415,7 +415,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
> >  	/* Output property. */
> >  	if ((nv_connector->dithering_mode == DITHERING_MODE_ON) ||
> >  	    (nv_connector->dithering_mode == DITHERING_MODE_AUTO &&
> > -	     encoder->crtc->fb->depth > connector->display_info.bpc * 3)) {
> > +	     encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) {
> >  		if (nv_device(drm->device)->chipset == 0x11)
> >  			regp->dither = savep->dither | 0x00010000;
> >  		else {
> > diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
> > index 2401159..4e24c72 100644
> > --- a/drivers/gpu/drm/nouveau/nouveau_display.c
> > +++ b/drivers/gpu/drm/nouveau/nouveau_display.c
> > @@ -569,7 +569,7 @@ nouveau_display_suspend(struct drm_device *dev)
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> >  		struct nouveau_framebuffer *nouveau_fb;
> >  
> > -		nouveau_fb = nouveau_framebuffer(crtc->fb);
> > +		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
> >  		if (!nouveau_fb || !nouveau_fb->nvbo)
> >  			continue;
> >  
> > @@ -596,7 +596,7 @@ nouveau_display_repin(struct drm_device *dev)
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> >  		struct nouveau_framebuffer *nouveau_fb;
> >  
> > -		nouveau_fb = nouveau_framebuffer(crtc->fb);
> > +		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
> >  		if (!nouveau_fb || !nouveau_fb->nvbo)
> >  			continue;
> >  
> > @@ -693,7 +693,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
> >  	const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
> >  	struct drm_device *dev = crtc->dev;
> >  	struct nouveau_drm *drm = nouveau_drm(dev);
> > -	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
> > +	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo;
> >  	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
> >  	struct nouveau_page_flip_state *s;
> >  	struct nouveau_channel *chan = drm->channel;
> > @@ -767,7 +767,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
> >  		goto fail_unreserve;
> >  
> >  	/* Update the crtc struct and cleanup */
> > -	crtc->fb = fb;
> > +	crtc->primary->fb = fb;
> >  
> >  	nouveau_bo_fence(old_bo, fence);
> >  	ttm_bo_unreserve(&old_bo->bo);
> > diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> > index 5706842..c744bf6 100644
> > --- a/drivers/gpu/drm/nouveau/nv50_display.c
> > +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> > @@ -651,7 +651,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
> >  	nv_connector = nouveau_crtc_connector_get(nv_crtc);
> >  	connector = &nv_connector->base;
> >  	if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
> > -		if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
> > +		if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3)
> >  			mode = DITHERING_MODE_DYNAMIC2X2;
> >  	} else {
> >  		mode = nv_connector->dithering_mode;
> > @@ -785,7 +785,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
> >  
> >  		if (update) {
> >  			nv50_display_flip_stop(crtc);
> > -			nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> > +			nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
> >  		}
> >  	}
> >  
> > @@ -1028,7 +1028,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
> >  	}
> >  
> >  	nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
> > -	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> > +	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
> >  }
> >  
> >  static bool
> > @@ -1042,7 +1042,8 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
> >  static int
> >  nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
> >  {
> > -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
> > +	struct nouveau_framebuffer *nvfb =
> > +		nouveau_framebuffer(crtc->primary->fb);
> >  	struct nv50_head *head = nv50_head(crtc);
> >  	int ret;
> >  
> > @@ -1139,7 +1140,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
> >  	nv50_crtc_set_dither(nv_crtc, false);
> >  	nv50_crtc_set_scale(nv_crtc, false);
> >  	nv50_crtc_set_color_vibrance(nv_crtc, false);
> > -	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
> > +	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
> >  	return 0;
> >  }
> >  
> > @@ -1151,7 +1152,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> >  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
> >  	int ret;
> >  
> > -	if (!crtc->fb) {
> > +	if (!crtc->primary->fb) {
> >  		NV_DEBUG(drm, "No FB bound\n");
> >  		return 0;
> >  	}
> > @@ -1161,8 +1162,8 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> >  		return ret;
> >  
> >  	nv50_display_flip_stop(crtc);
> > -	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
> > -	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> > +	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
> > +	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
> >  	return 0;
> >  }
> >  
> > diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> > index 24b6112..5be0b87 100644
> > --- a/drivers/gpu/drm/qxl/qxl_display.c
> > +++ b/drivers/gpu/drm/qxl/qxl_display.c
> > @@ -527,7 +527,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
> >  	bool recreate_primary = false;
> >  	int ret;
> >  	int surf_id;
> > -	if (!crtc->fb) {
> > +	if (!crtc->primary->fb) {
> >  		DRM_DEBUG_KMS("No FB bound\n");
> >  		return 0;
> >  	}
> > @@ -536,7 +536,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
> >  		qfb = to_qxl_framebuffer(old_fb);
> >  		old_bo = gem_to_qxl_bo(qfb->obj);
> >  	}
> > -	qfb = to_qxl_framebuffer(crtc->fb);
> > +	qfb = to_qxl_framebuffer(crtc->primary->fb);
> >  	bo = gem_to_qxl_bo(qfb->obj);
> >  	if (!m)
> >  		/* and do we care? */
> > @@ -609,14 +609,15 @@ static void qxl_crtc_disable(struct drm_crtc *crtc)
> >  	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
> >  	struct drm_device *dev = crtc->dev;
> >  	struct qxl_device *qdev = dev->dev_private;
> > -	if (crtc->fb) {
> > -		struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb);
> > +	if (crtc->primary->fb) {
> > +		struct qxl_framebuffer *qfb =
> > +			to_qxl_framebuffer(crtc->primary->fb);
> >  		struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
> >  		int ret;
> >  		ret = qxl_bo_reserve(bo, false);
> >  		qxl_bo_unpin(bo);
> >  		qxl_bo_unreserve(bo);
> > -		crtc->fb = NULL;
> > +		crtc->primary->fb = NULL;
> >  	}
> >  
> >  	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
> > diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
> > index daa4dd3..fb187c7 100644
> > --- a/drivers/gpu/drm/radeon/atombios_crtc.c
> > +++ b/drivers/gpu/drm/radeon/atombios_crtc.c
> > @@ -1106,7 +1106,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
> >  	int r;
> >  
> >  	/* no fb bound */
> > -	if (!atomic && !crtc->fb) {
> > +	if (!atomic && !crtc->primary->fb) {
> >  		DRM_DEBUG_KMS("No FB bound\n");
> >  		return 0;
> >  	}
> > @@ -1116,8 +1116,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
> >  		target_fb = fb;
> >  	}
> >  	else {
> > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > -		target_fb = crtc->fb;
> > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > +		target_fb = crtc->primary->fb;
> >  	}
> >  
> >  	/* If atomic, assume fb object is pinned & idle & fenced and
> > @@ -1316,7 +1316,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
> >  	/* set pageflip to happen anywhere in vblank interval */
> >  	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
> >  
> > -	if (!atomic && fb && fb != crtc->fb) {
> > +	if (!atomic && fb && fb != crtc->primary->fb) {
> >  		radeon_fb = to_radeon_framebuffer(fb);
> >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> >  		r = radeon_bo_reserve(rbo, false);
> > @@ -1350,7 +1350,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
> >  	int r;
> >  
> >  	/* no fb bound */
> > -	if (!atomic && !crtc->fb) {
> > +	if (!atomic && !crtc->primary->fb) {
> >  		DRM_DEBUG_KMS("No FB bound\n");
> >  		return 0;
> >  	}
> > @@ -1360,8 +1360,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
> >  		target_fb = fb;
> >  	}
> >  	else {
> > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > -		target_fb = crtc->fb;
> > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > +		target_fb = crtc->primary->fb;
> >  	}
> >  
> >  	obj = radeon_fb->obj;
> > @@ -1485,7 +1485,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
> >  	/* set pageflip to happen anywhere in vblank interval */
> >  	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
> >  
> > -	if (!atomic && fb && fb != crtc->fb) {
> > +	if (!atomic && fb && fb != crtc->primary->fb) {
> >  		radeon_fb = to_radeon_framebuffer(fb);
> >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> >  		r = radeon_bo_reserve(rbo, false);
> > @@ -1972,12 +1972,12 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
> >  	int i;
> >  
> >  	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> > -	if (crtc->fb) {
> > +	if (crtc->primary->fb) {
> >  		int r;
> >  		struct radeon_framebuffer *radeon_fb;
> >  		struct radeon_bo *rbo;
> >  
> > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> >  		r = radeon_bo_reserve(rbo, false);
> >  		if (unlikely(r))
> > diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
> > index 030f8e4..b6c3264 100644
> > --- a/drivers/gpu/drm/radeon/r100.c
> > +++ b/drivers/gpu/drm/radeon/r100.c
> > @@ -3220,12 +3220,12 @@ void r100_bandwidth_update(struct radeon_device *rdev)
> >  
> >  	if (rdev->mode_info.crtcs[0]->base.enabled) {
> >  		mode1 = &rdev->mode_info.crtcs[0]->base.mode;
> > -		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8;
> > +		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;
> > -			pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8;
> > +			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 82d4f86..33b482b 100644
> > --- a/drivers/gpu/drm/radeon/radeon_connectors.c
> > +++ b/drivers/gpu/drm/radeon/radeon_connectors.c
> > @@ -89,7 +89,7 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)
> >  
> >  	if (crtc && crtc->enabled) {
> >  		drm_crtc_helper_set_mode(crtc, &crtc->mode,
> > -					 crtc->x, crtc->y, crtc->fb);
> > +					 crtc->x, crtc->y, crtc->primary->fb);
> >  	}
> >  }
> >  
> > diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
> > index 2e72dcd..c524aba 100644
> > --- a/drivers/gpu/drm/radeon/radeon_device.c
> > +++ b/drivers/gpu/drm/radeon/radeon_device.c
> > @@ -1424,7 +1424,8 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
> >  
> >  	/* unpin the front buffers */
> >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > -		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
> > +		struct radeon_framebuffer *rfb =
> > +			to_radeon_framebuffer(crtc->primary->fb);
> >  		struct radeon_bo *robj;
> >  
> >  		if (rfb == NULL || rfb->obj == NULL) {
> > diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> > index a29d217..4e90049 100644
> > --- a/drivers/gpu/drm/radeon/radeon_display.c
> > +++ b/drivers/gpu/drm/radeon/radeon_display.c
> > @@ -369,7 +369,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
> >  	work->event = event;
> >  	work->rdev = rdev;
> >  	work->crtc_id = radeon_crtc->crtc_id;
> > -	old_radeon_fb = to_radeon_framebuffer(crtc->fb);
> > +	old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> >  	new_radeon_fb = to_radeon_framebuffer(fb);
> >  	/* schedule unpin of the old buffer */
> >  	obj = old_radeon_fb->obj;
> > @@ -460,7 +460,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
> >  	spin_unlock_irqrestore(&dev->event_lock, flags);
> >  
> >  	/* update crtc fb */
> > -	crtc->fb = fb;
> > +	crtc->primary->fb = fb;
> >  
> >  	r = drm_vblank_get(dev, radeon_crtc->crtc_id);
> >  	if (r) {
> > diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> > index 0b158f9..cafb1cc 100644
> > --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> > +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> > @@ -385,7 +385,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
> >  
> >  	DRM_DEBUG_KMS("\n");
> >  	/* no fb bound */
> > -	if (!atomic && !crtc->fb) {
> > +	if (!atomic && !crtc->primary->fb) {
> >  		DRM_DEBUG_KMS("No FB bound\n");
> >  		return 0;
> >  	}
> > @@ -395,8 +395,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
> >  		target_fb = fb;
> >  	}
> >  	else {
> > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > -		target_fb = crtc->fb;
> > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > +		target_fb = crtc->primary->fb;
> >  	}
> >  
> >  	switch (target_fb->bits_per_pixel) {
> > @@ -444,7 +444,7 @@ retry:
> >  		 * We don't shutdown the display controller because new buffer
> >  		 * will end up in same spot.
> >  		 */
> > -		if (!atomic && fb && fb != crtc->fb) {
> > +		if (!atomic && fb && fb != crtc->primary->fb) {
> >  			struct radeon_bo *old_rbo;
> >  			unsigned long nsize, osize;
> >  
> > @@ -555,7 +555,7 @@ retry:
> >  	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
> >  	WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
> >  
> > -	if (!atomic && fb && fb != crtc->fb) {
> > +	if (!atomic && fb && fb != crtc->primary->fb) {
> >  		radeon_fb = to_radeon_framebuffer(fb);
> >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> >  		r = radeon_bo_reserve(rbo, false);
> > @@ -599,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
> >  		}
> >  	}
> >  
> > -	switch (crtc->fb->bits_per_pixel) {
> > +	switch (crtc->primary->fb->bits_per_pixel) {
> >  	case 8:
> >  		format = 2;
> >  		break;
> > @@ -1087,12 +1087,12 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
> >  static void radeon_crtc_disable(struct drm_crtc *crtc)
> >  {
> >  	radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> > -	if (crtc->fb) {
> > +	if (crtc->primary->fb) {
> >  		int r;
> >  		struct radeon_framebuffer *radeon_fb;
> >  		struct radeon_bo *rbo;
> >  
> > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> >  		r = radeon_bo_reserve(rbo, false);
> >  		if (unlikely(r))
> > diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> > index 1255944..c63b5e7 100644
> > --- a/drivers/gpu/drm/udl/udl_modeset.c
> > +++ b/drivers/gpu/drm/udl/udl_modeset.c
> > @@ -310,7 +310,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
> >  
> >  {
> >  	struct drm_device *dev = crtc->dev;
> > -	struct udl_framebuffer *ufb = to_udl_fb(crtc->fb);
> > +	struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb);
> >  	struct udl_device *udl = dev->dev_private;
> >  	char *buf;
> >  	char *wrptr;
> > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> > index 8a65041..1d59ed3 100644
> > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> > @@ -468,7 +468,7 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
> >  	num_units = 0;
> >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
> >  			    head) {
> > -		if (crtc->fb != &framebuffer->base)
> > +		if (crtc->primary->fb != &framebuffer->base)
> >  			continue;
> >  		units[num_units++] = vmw_crtc_to_du(crtc);
> >  	}
> > @@ -883,7 +883,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
> >  
> >  	num_units = 0;
> >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> > -		if (crtc->fb != &framebuffer->base)
> > +		if (crtc->primary->fb != &framebuffer->base)
> >  			continue;
> >  		units[num_units++] = vmw_crtc_to_du(crtc);
> >  	}
> > @@ -1245,7 +1245,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
> >  
> >  	num_units = 0;
> >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> > -		if (crtc->fb != &vfb->base)
> > +		if (crtc->primary->fb != &vfb->base)
> >  			continue;
> >  		units[num_units++] = vmw_crtc_to_du(crtc);
> >  	}
> > @@ -1382,7 +1382,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
> >  
> >  	num_units = 0;
> >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> > -		if (crtc->fb != &vfb->base)
> > +		if (crtc->primary->fb != &vfb->base)
> >  			continue;
> >  		units[num_units++] = vmw_crtc_to_du(crtc);
> >  	}
> > @@ -1725,7 +1725,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
> >  		     uint32_t page_flip_flags)
> >  {
> >  	struct vmw_private *dev_priv = vmw_priv(crtc->dev);
> > -	struct drm_framebuffer *old_fb = crtc->fb;
> > +	struct drm_framebuffer *old_fb = crtc->primary->fb;
> >  	struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
> >  	struct drm_file *file_priv ;
> >  	struct vmw_fence_obj *fence = NULL;
> > @@ -1743,7 +1743,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
> >  	if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
> >  		return -EINVAL;
> >  
> > -	crtc->fb = fb;
> > +	crtc->primary->fb = fb;
> >  
> >  	/* do a full screen dirty update */
> >  	clips.x1 = clips.y1 = 0;
> > @@ -1783,7 +1783,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
> >  	return ret;
> >  
> >  out_no_fence:
> > -	crtc->fb = old_fb;
> > +	crtc->primary->fb = old_fb;
> >  	return ret;
> >  }
> >  
> > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> > index 001ec81..08fdd7f 100644
> > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> > @@ -93,7 +93,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
> >  
> >  		if (crtc == NULL)
> >  			return 0;
> > -		fb = entry->base.crtc.fb;
> > +		fb = entry->base.crtc.primary->fb;
> >  
> >  		return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0],
> >  					  fb->bits_per_pixel, fb->depth);
> > @@ -101,7 +101,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
> >  
> >  	if (!list_empty(&lds->active)) {
> >  		entry = list_entry(lds->active.next, typeof(*entry), active);
> > -		fb = entry->base.crtc.fb;
> > +		fb = entry->base.crtc.primary->fb;
> >  
> >  		vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0],
> >  				   fb->bits_per_pixel, fb->depth);
> > @@ -259,7 +259,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
> >  
> >  		connector->encoder = NULL;
> >  		encoder->crtc = NULL;
> > -		crtc->fb = NULL;
> > +		crtc->primary->fb = NULL;
> >  		crtc->enabled = false;
> >  
> >  		vmw_ldu_del_active(dev_priv, ldu);
> > @@ -280,7 +280,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
> >  
> >  	vmw_fb_off(dev_priv);
> >  
> > -	crtc->fb = fb;
> > +	crtc->primary->fb = fb;
> >  	encoder->crtc = crtc;
> >  	connector->encoder = encoder;
> >  	crtc->x = set->x;
> > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> > index 585da43..46ea096 100644
> > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> > @@ -307,7 +307,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
> >  
> >  		connector->encoder = NULL;
> >  		encoder->crtc = NULL;
> > -		crtc->fb = NULL;
> > +		crtc->primary->fb = NULL;
> >  		crtc->x = 0;
> >  		crtc->y = 0;
> >  		crtc->enabled = false;
> > @@ -368,7 +368,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
> >  
> >  		connector->encoder = NULL;
> >  		encoder->crtc = NULL;
> > -		crtc->fb = NULL;
> > +		crtc->primary->fb = NULL;
> >  		crtc->x = 0;
> >  		crtc->y = 0;
> >  		crtc->enabled = false;
> > @@ -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;
> > -	crtc->fb = fb;
> > +	crtc->primary->fb = fb;
> >  	crtc->x = set->x;
> >  	crtc->y = set->y;
> >  	crtc->enabled = true;
> > @@ -574,5 +574,5 @@ void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
> >  	BUG_ON(!sou->base.is_implicit);
> >  
> >  	dev_priv->sou_priv->implicit_fb =
> > -		vmw_framebuffer_to_vfb(sou->base.crtc.fb);
> > +		vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
> >  }
> > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> > index 4dc84f8..9f7824d 100644
> > --- a/include/drm/drm_crtc.h
> > +++ b/include/drm/drm_crtc.h
> > @@ -309,9 +309,6 @@ struct drm_crtc {
> >  	/* primary plane for CRTC */
> >  	struct drm_plane *primary;
> >  
> > -	/* framebuffer the connector is currently bound to */
> > -	struct drm_framebuffer *fb;
> > -
> >  	/* Temporary tracking of the old fb while a modeset is ongoing. Used
> >  	 * by drm_mode_set_config_internal to implement correct refcounting. */
> >  	struct drm_framebuffer *old_fb;
> > -- 
> > 1.8.5.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

-- 
Matt Roper
Graphics Software Engineer
ISG Platform Enabling & Development
Intel Corporation
(916) 356-2795

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2)
  2014-03-25  1:20     ` Matt Roper
@ 2014-03-25 10:32       ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2014-03-25 10:32 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Mon, Mar 24, 2014 at 06:20:35PM -0700, Matt Roper wrote:
> On Wed, Mar 19, 2014 at 12:57:21PM +0100, Daniel Vetter wrote:
> > On Tue, Mar 18, 2014 at 05:22:53PM -0700, Matt Roper wrote:
> > > Now that CRTC's have a primary plane, there's no need to track the
> > > framebuffer in the CRTC.  Replace all references to the CRTC fb
> > > with the primary plane's fb.
> > > 
> > > Also note that this simplifies framebuffer removal slightly; we no
> > > longer need to scan all CRTC's and disable the ones that were using the
> > > framebuffer since the existing loop over all planes will take care
> > > of disabling the primary plane (and on most hardware, the CRTC by
> > > extension).
> > > 
> > > v2: Fixup several lingering crtc->fb instances that were missed in the
> > >     first patch iteration.
> > > 
> > > Tested-by: Rob Clark <robdclark@gmail.com>
> > > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> > 
> > Giant patch again, and I don't think there's any sane way we can avoid
> > this big sed job. Put I think we can make it less intrusive.
> > 
> > First: Have you looked into cocinelle to do this? I'm not sure whether
> > cocinelle is sufficiently type aware, but the upside of using it is that
> > it's much easier to regenerate the patch.
> 
> Good idea!  Yeah, I think Coccinelle should do this pretty easily with
> just:
> 
>         @@ struct drm_crtc *crtc; @@
>         -   crtc->fb
>         +   crtc->primary->fb
> 
>         @@ struct drm_crtc crtc; @@
>         -   crtc.fb
>         +   crtc.primary->fb
> 
> > In any case I think we need to split this into the usual 3 phases to avoid
> > flag days:
> > 
> > 1) Switch to crtc->primary->fb all over the core, but keep crtc->fb fully
> > functional. I.e. update it before calling into drivers and use that to
> > update crtc->primary->fb on return (e.g. in the pageflip ioctl).
> 
> I'm starting to worry that this may be more tricky than it sounded when
> I first read your email.  To be safe, it seems like we'll need to
> sandwich all the various ->funcs-> driver calls in the core between
> prepare_crtc_fbs() / finish_crtc_fbs() or similar since it's hard to
> predict in a universal way when a driver might decide to go look at a
> crtc's framebuffer (or even which crtcs it will decide to look at).
> However even if we do that wrapping, there may be cases where the driver
> calls back into a core helper function after modifying crtc->fb and the
> core won't have that updated value unless we throw in extra sync-up
> points.  
> 
> Is this pretty much what you had in mind or am I overlooking a much
> simpler way to accomplish this?

Hm, you're right that drivers can call back into crtc helpers (not the
core itself), which means doing that in stages is tricky. Which still
covers all the drivers except i915, so doesn't really buy us much. New
transition idea, unfortunately a bit longer.

1) Add crtc->primary and everywhere where we set (i.e. core, crtc helpers,
drivers) crtc->fb also add an assignement for crtc->primary->fb. No
transition assignment like crtc->primary->fb = crtc->fb and the other way
round in the core.

This should help a lot since we have about 300 places which look at
crtc->fb, but only 30 which change crtc->fb. Most of them in the core +
crct helpers, i915 (our own modeset infrastructure) and vmwgfx. So this
should be much simpler to get in without a giant mess.

2) Transition all parts to look at crtc->primary->fb at least, but keep
assigning to both.

3) Once 2) is complete, rip out the crtc->fb assignments and remove
crtc->fb.

Does this one here sound more workable? It's still a bit a flag day thing
but easier to manage than one massive subsystem wide sed job touching 300
places ...

One downside is that we can't enlist the compilers help for 1), but if you
have the entire patch-series ready (with the patches in 2) generated with
cocinelle) we can still compile-check the end-result, which should be good
enough to catch everything.

Cheers, Daniel
> 
> 
> Matt
> 
> > 
> > 2) Switch drivers over to look at crtc->primary->fb. This way we can even
> > split up the patch into per-driver patches which gives driver maintainers
> > more wiggle room.
> > 
> > 3) Kill crtc->fb.
> > 
> > Steps 2&3 don't block merging of the universal planes support at all. So
> > we could get the core support in all early for 3.16, then let driver
> > maintainers pick up patche for 2 and shortly before the 3.16 merge window
> > opens send a pull request with all the stragglers and step 3.
> > 
> > No comments on the actual patch, the few functional changes hidden in the
> > massive diff looked ok. But hard to review properly ;-)
> > 
> > Cheers, Daniel
> > 
> > > ---
> > >  drivers/gpu/drm/ast/ast_mode.c               |  12 +--
> > >  drivers/gpu/drm/bochs/bochs_kms.c            |   4 +-
> > >  drivers/gpu/drm/cirrus/cirrus_mode.c         |  10 +-
> > >  drivers/gpu/drm/drm_crtc.c                   |  56 ++++------
> > >  drivers/gpu/drm/drm_crtc_helper.c            |  21 ++--
> > >  drivers/gpu/drm/drm_fb_helper.c              |   6 +-
> > >  drivers/gpu/drm/gma500/cdv_intel_display.c   |   2 +-
> > >  drivers/gpu/drm/gma500/cdv_intel_dp.c        |   2 +-
> > >  drivers/gpu/drm/gma500/cdv_intel_hdmi.c      |   3 +-
> > >  drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
> > >  drivers/gpu/drm/gma500/gma_display.c         |  17 ++--
> > >  drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
> > >  drivers/gpu/drm/gma500/mdfld_intel_display.c |  17 ++--
> > >  drivers/gpu/drm/gma500/oaktrail_crtc.c       |  13 +--
> > >  drivers/gpu/drm/gma500/psb_intel_display.c   |   2 +-
> > >  drivers/gpu/drm/gma500/psb_intel_lvds.c      |   2 +-
> > >  drivers/gpu/drm/gma500/psb_intel_sdvo.c      |   2 +-
> > >  drivers/gpu/drm/i915/i915_debugfs.c          |   4 +-
> > >  drivers/gpu/drm/i915/i915_irq.c              |   4 +-
> > >  drivers/gpu/drm/i915/intel_display.c         | 147 ++++++++++++++-------------
> > >  drivers/gpu/drm/i915/intel_dp.c              |   5 +-
> > >  drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
> > >  drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
> > >  drivers/gpu/drm/i915/intel_pm.c              |  36 +++----
> > >  drivers/gpu/drm/mgag200/mgag200_mode.c       |  28 ++---
> > >  drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  28 ++---
> > >  drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  22 ++--
> > >  drivers/gpu/drm/nouveau/dispnv04/crtc.c      |  20 ++--
> > >  drivers/gpu/drm/nouveau/dispnv04/dfp.c       |   2 +-
> > >  drivers/gpu/drm/nouveau/nouveau_display.c    |   8 +-
> > >  drivers/gpu/drm/nouveau/nv50_display.c       |  17 ++--
> > >  drivers/gpu/drm/qxl/qxl_display.c            |  11 +-
> > >  drivers/gpu/drm/radeon/atombios_crtc.c       |  20 ++--
> > >  drivers/gpu/drm/radeon/r100.c                |   4 +-
> > >  drivers/gpu/drm/radeon/radeon_connectors.c   |   2 +-
> > >  drivers/gpu/drm/radeon/radeon_device.c       |   3 +-
> > >  drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
> > >  drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +--
> > >  drivers/gpu/drm/udl/udl_modeset.c            |   2 +-
> > >  drivers/gpu/drm/vmwgfx/vmwgfx_kms.c          |  14 +--
> > >  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c          |   8 +-
> > >  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c         |   8 +-
> > >  include/drm/drm_crtc.h                       |   3 -
> > >  43 files changed, 300 insertions(+), 299 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> > > index 44f0d32..bd1e156 100644
> > > --- a/drivers/gpu/drm/ast/ast_mode.c
> > > +++ b/drivers/gpu/drm/ast/ast_mode.c
> > > @@ -81,7 +81,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
> > >  	u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
> > >  	u32 hborder, vborder;
> > >  
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
> > >  		color_index = VGAModeIndex - 1;
> > > @@ -176,7 +176,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
> > >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
> > >  
> > >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
> > > -		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
> > > +		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
> > >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
> > >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
> > >  		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
> > > @@ -340,7 +340,7 @@ static void ast_set_offset_reg(struct drm_crtc *crtc)
> > >  
> > >  	u16 offset;
> > >  
> > > -	offset = crtc->fb->pitches[0] >> 3;
> > > +	offset = crtc->primary->fb->pitches[0] >> 3;
> > >  	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
> > >  	ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
> > >  }
> > > @@ -365,7 +365,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
> > >  	struct ast_private *ast = crtc->dev->dev_private;
> > >  	u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
> > >  
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		jregA0 = 0x70;
> > >  		jregA3 = 0x01;
> > > @@ -418,7 +418,7 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo
> > >  static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
> > >  		     struct ast_vbios_mode_info *vbios_mode)
> > >  {
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		break;
> > >  	default:
> > > @@ -490,7 +490,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
> > >  		ast_bo_unreserve(bo);
> > >  	}
> > >  
> > > -	ast_fb = to_ast_framebuffer(crtc->fb);
> > > +	ast_fb = to_ast_framebuffer(crtc->primary->fb);
> > >  	obj = ast_fb->obj;
> > >  	bo = gem_to_ast_bo(obj);
> > >  
> > > diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
> > > index 182f5c9..b67ad12 100644
> > > --- a/drivers/gpu/drm/bochs/bochs_kms.c
> > > +++ b/drivers/gpu/drm/bochs/bochs_kms.c
> > > @@ -62,10 +62,10 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> > >  		}
> > >  	}
> > >  
> > > -	if (WARN_ON(crtc->fb == NULL))
> > > +	if (WARN_ON(crtc->primary->fb == NULL))
> > >  		return -EINVAL;
> > >  
> > > -	bochs_fb = to_bochs_framebuffer(crtc->fb);
> > > +	bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
> > >  	bo = gem_to_bochs_bo(bochs_fb->obj);
> > >  	ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
> > >  	if (ret)
> > > diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> > > index 449246f..5291d2f 100644
> > > --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> > > +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
> > > @@ -149,7 +149,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
> > >  		cirrus_bo_unreserve(bo);
> > >  	}
> > >  
> > > -	cirrus_fb = to_cirrus_framebuffer(crtc->fb);
> > > +	cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb);
> > >  	obj = cirrus_fb->obj;
> > >  	bo = gem_to_cirrus_bo(obj);
> > >  
> > > @@ -268,7 +268,7 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
> > >  	sr07 = RREG8(SEQ_DATA);
> > >  	sr07 &= 0xe0;
> > >  	hdr = 0;
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		sr07 |= 0x11;
> > >  		break;
> > > @@ -291,13 +291,13 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
> > >  	WREG_SEQ(0x7, sr07);
> > >  
> > >  	/* Program the pitch */
> > > -	tmp = crtc->fb->pitches[0] / 8;
> > > +	tmp = crtc->primary->fb->pitches[0] / 8;
> > >  	WREG_CRT(VGA_CRTC_OFFSET, tmp);
> > >  
> > >  	/* Enable extended blanking and pitch bits, and enable full memory */
> > >  	tmp = 0x22;
> > > -	tmp |= (crtc->fb->pitches[0] >> 7) & 0x10;
> > > -	tmp |= (crtc->fb->pitches[0] >> 6) & 0x40;
> > > +	tmp |= (crtc->primary->fb->pitches[0] >> 7) & 0x10;
> > > +	tmp |= (crtc->primary->fb->pitches[0] >> 6) & 0x40;
> > >  	WREG_CRT(0x1b, tmp);
> > >  
> > >  	/* Enable high-colour modes */
> > > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> > > index 0feb66cc..0c395e8 100644
> > > --- a/drivers/gpu/drm/drm_crtc.c
> > > +++ b/drivers/gpu/drm/drm_crtc.c
> > > @@ -634,7 +634,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
> > >   * drm_framebuffer_remove - remove and unreference a framebuffer object
> > >   * @fb: framebuffer to remove
> > >   *
> > > - * Scans all the CRTCs and planes in @dev's mode_config.  If they're
> > > + * Scans all the planes in @dev's mode_config.  If they're
> > >   * using @fb, removes it, setting it to NULL. Then drops the reference to the
> > >   * passed-in framebuffer. Might take the modeset locks.
> > >   *
> > > @@ -645,10 +645,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
> > >  void drm_framebuffer_remove(struct drm_framebuffer *fb)
> > >  {
> > >  	struct drm_device *dev = fb->dev;
> > > -	struct drm_crtc *crtc;
> > >  	struct drm_plane *plane;
> > > -	struct drm_mode_set set;
> > > -	int ret;
> > >  
> > >  	WARN_ON(!list_empty(&fb->filp_head));
> > >  
> > > @@ -669,19 +666,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
> > >  	 */
> > >  	if (atomic_read(&fb->refcount.refcount) > 1) {
> > >  		drm_modeset_lock_all(dev);
> > > -		/* remove from any CRTC */
> > > -		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > > -			if (crtc->fb == fb) {
> > > -				/* should turn off the crtc */
> > > -				memset(&set, 0, sizeof(struct drm_mode_set));
> > > -				set.crtc = crtc;
> > > -				set.fb = NULL;
> > > -				ret = drm_mode_set_config_internal(&set);
> > > -				if (ret)
> > > -					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
> > > -			}
> > > -		}
> > > -
> > > +		/* remove from any plane */
> > >  		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> > >  			if (plane->fb == fb)
> > >  				drm_plane_force_disable(plane);
> > > @@ -1930,8 +1915,8 @@ int drm_mode_getcrtc(struct drm_device *dev,
> > >  	crtc_resp->x = crtc->x;
> > >  	crtc_resp->y = crtc->y;
> > >  	crtc_resp->gamma_size = crtc->gamma_size;
> > > -	if (crtc->fb)
> > > -		crtc_resp->fb_id = crtc->fb->base.id;
> > > +	if (crtc->primary->fb)
> > > +		crtc_resp->fb_id = crtc->primary->fb->base.id;
> > >  	else
> > >  		crtc_resp->fb_id = 0;
> > >  
> > > @@ -2438,7 +2423,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
> > >  	 * crtcs. Atomic modeset will have saner semantics ...
> > >  	 */
> > >  	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
> > > -		tmp->old_fb = tmp->fb;
> > > +		tmp->old_fb = tmp->primary->fb;
> > >  
> > >  	fb = set->fb;
> > >  
> > > @@ -2446,13 +2431,16 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
> > >  	if (ret == 0) {
> > >  		crtc->primary->crtc = crtc;
> > >  
> > > -		/* crtc->fb must be updated by ->set_config, enforces this. */
> > > -		WARN_ON(fb != crtc->fb);
> > > +		/*
> > > +		 * crtc->primary->fb must be updated by ->set_config,
> > > +		 * enforces this.
> > > +		 */
> > > +		WARN_ON(fb != crtc->primary->fb);
> > >  	}
> > >  
> > >  	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
> > > -		if (tmp->fb)
> > > -			drm_framebuffer_reference(tmp->fb);
> > > +		if (tmp->primary->fb)
> > > +			drm_framebuffer_reference(tmp->primary->fb);
> > >  		if (tmp->old_fb)
> > >  			drm_framebuffer_unreference(tmp->old_fb);
> > >  	}
> > > @@ -2511,12 +2499,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
> > >  		/* If we have a mode we need a framebuffer. */
> > >  		/* If we pass -1, set the mode with the currently bound fb */
> > >  		if (crtc_req->fb_id == -1) {
> > > -			if (!crtc->fb) {
> > > +			if (!crtc->primary->fb) {
> > >  				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
> > >  				ret = -EINVAL;
> > >  				goto out;
> > >  			}
> > > -			fb = crtc->fb;
> > > +			fb = crtc->primary->fb;
> > >  			/* Make refcounting symmetric with the lookup path. */
> > >  			drm_framebuffer_reference(fb);
> > >  		} else {
> > > @@ -4309,7 +4297,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> > >  	crtc = obj_to_crtc(obj);
> > >  
> > >  	mutex_lock(&crtc->mutex);
> > > -	if (crtc->fb == NULL) {
> > > +	if (crtc->primary->fb == NULL) {
> > >  		/* The framebuffer is currently unbound, presumably
> > >  		 * due to a hotplug event, that userspace has not
> > >  		 * yet discovered.
> > > @@ -4331,7 +4319,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> > >  	if (ret)
> > >  		goto out;
> > >  
> > > -	if (crtc->fb->pixel_format != fb->pixel_format) {
> > > +	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
> > >  		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
> > >  		ret = -EINVAL;
> > >  		goto out;
> > > @@ -4364,7 +4352,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> > >  			(void (*) (struct drm_pending_event *)) kfree;
> > >  	}
> > >  
> > > -	old_fb = crtc->fb;
> > > +	old_fb = crtc->primary->fb;
> > >  	ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
> > >  	if (ret) {
> > >  		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
> > > @@ -4377,12 +4365,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> > >  		old_fb = NULL;
> > >  	} else {
> > >  		/*
> > > -		 * Warn if the driver hasn't properly updated the crtc->fb
> > > -		 * field to reflect that the new framebuffer is now used.
> > > -		 * Failing to do so will screw with the reference counting
> > > -		 * on framebuffers.
> > > +		 * Warn if the driver hasn't properly updated the
> > > +		 * crtc->primary->fb field to reflect that the new framebuffer
> > > +		 * is now used.  Failing to do so will screw with the reference
> > > +		 * counting on framebuffers.
> > >  		 */
> > > -		WARN_ON(crtc->fb != fb);
> > > +		WARN_ON(crtc->primary->fb != fb);
> > >  		/* Unref only the old framebuffer. */
> > >  		fb = NULL;
> > >  	}
> > > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> > > index a855178..8825afb 100644
> > > --- a/drivers/gpu/drm/drm_crtc_helper.c
> > > +++ b/drivers/gpu/drm/drm_crtc_helper.c
> > > @@ -319,7 +319,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
> > >  				(*crtc_funcs->disable)(crtc);
> > >  			else
> > >  				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
> > > -			crtc->fb = NULL;
> > > +			crtc->primary->fb = NULL;
> > >  		}
> > >  	}
> > >  }
> > > @@ -646,19 +646,19 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
> > >  	save_set.mode = &set->crtc->mode;
> > >  	save_set.x = set->crtc->x;
> > >  	save_set.y = set->crtc->y;
> > > -	save_set.fb = set->crtc->fb;
> > > +	save_set.fb = set->crtc->primary->fb;
> > >  
> > >  	/* We should be able to check here if the fb has the same properties
> > >  	 * and then just flip_or_move it */
> > > -	if (set->crtc->fb != set->fb) {
> > > +	if (set->crtc->primary->fb != set->fb) {
> > >  		/* If we have no fb then treat it as a full mode set */
> > > -		if (set->crtc->fb == NULL) {
> > > +		if (set->crtc->primary->fb == NULL) {
> > >  			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
> > >  			mode_changed = true;
> > >  		} else if (set->fb == NULL) {
> > >  			mode_changed = true;
> > >  		} else if (set->fb->pixel_format !=
> > > -			   set->crtc->fb->pixel_format) {
> > > +			   set->crtc->primary->fb->pixel_format) {
> > >  			mode_changed = true;
> > >  		} else
> > >  			fb_changed = true;
> > > @@ -759,13 +759,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
> > >  			DRM_DEBUG_KMS("attempting to set mode from"
> > >  					" userspace\n");
> > >  			drm_mode_debug_printmodeline(set->mode);
> > > -			set->crtc->fb = set->fb;
> > > +			set->crtc->primary->fb = set->fb;
> > >  			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
> > >  						      set->x, set->y,
> > >  						      save_set.fb)) {
> > >  				DRM_ERROR("failed to set mode on [CRTC:%d]\n",
> > >  					  set->crtc->base.id);
> > > -				set->crtc->fb = save_set.fb;
> > > +				set->crtc->primary->fb = save_set.fb;
> > >  				ret = -EINVAL;
> > >  				goto fail;
> > >  			}
> > > @@ -780,13 +780,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
> > >  	} else if (fb_changed) {
> > >  		set->crtc->x = set->x;
> > >  		set->crtc->y = set->y;
> > > -		set->crtc->fb = set->fb;
> > > +		set->crtc->primary->fb = set->fb;
> > >  		ret = crtc_funcs->mode_set_base(set->crtc,
> > >  						set->x, set->y, save_set.fb);
> > >  		if (ret != 0) {
> > >  			set->crtc->x = save_set.x;
> > >  			set->crtc->y = save_set.y;
> > > -			set->crtc->fb = save_set.fb;
> > > +			set->crtc->primary->fb = save_set.fb;
> > >  			goto fail;
> > >  		}
> > >  	}
> > > @@ -982,7 +982,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
> > >  			continue;
> > >  
> > >  		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
> > > -					       crtc->x, crtc->y, crtc->fb);
> > > +					       crtc->x, crtc->y,
> > > +					       crtc->primary->fb);
> > >  
> > >  		/* Restoring the old config should never fail! */
> > >  		if (ret == false)
> > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > index 9c6251f..e8e2b41 100644
> > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > @@ -232,7 +232,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
> > >  
> > >  	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
> > >  		if (crtc->base.id == c->base.id)
> > > -			return c->fb;
> > > +			return c->primary->fb;
> > >  	}
> > >  
> > >  	return NULL;
> > > @@ -366,9 +366,9 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
> > >  		return false;
> > >  
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > > -		if (crtc->fb)
> > > +		if (crtc->primary->fb)
> > >  			crtcs_bound++;
> > > -		if (crtc->fb == fb_helper->fb)
> > > +		if (crtc->primary->fb == fb_helper->fb)
> > >  			bound++;
> > >  	}
> > >  
> > > diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
> > > index 8fbfa06..1cddcf8 100644
> > > --- a/drivers/gpu/drm/gma500/cdv_intel_display.c
> > > +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
> > > @@ -463,7 +463,7 @@ static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe)
> > >  	crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> > >  	gma_crtc = to_gma_crtc(crtc);
> > >  
> > > -	if (crtc->fb == NULL || !gma_crtc->active)
> > > +	if (crtc->primary->fb == NULL || !gma_crtc->active)
> > >  		return false;
> > >  	return true;
> > >  }
> > > diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
> > > index 0490ce3..9ff30c2 100644
> > > --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
> > > +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
> > > @@ -1693,7 +1693,7 @@ done:
> > >  		struct drm_crtc *crtc = encoder->base.crtc;
> > >  		drm_crtc_helper_set_mode(crtc, &crtc->mode,
> > >  					 crtc->x, crtc->y,
> > > -					 crtc->fb);
> > > +					 crtc->primary->fb);
> > >  	}
> > >  
> > >  	return 0;
> > > diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> > > index 1c0d723..04956e6 100644
> > > --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> > > +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> > > @@ -199,7 +199,8 @@ static int cdv_hdmi_set_property(struct drm_connector *connector,
> > >  		    crtc->saved_mode.vdisplay != 0) {
> > >  			if (centre) {
> > >  				if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
> > > -					    encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb))
> > > +					    encoder->crtc->x, encoder->crtc->y,
> > > +					    encoder->crtc->primary->fb))
> > >  					return -1;
> > >  			} else {
> > >  				struct drm_encoder_helper_funcs *helpers
> > > diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> > > index 20e08e6..58f11df 100644
> > > --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> > > +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
> > > @@ -494,7 +494,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
> > >  						      &crtc->saved_mode,
> > >  						      encoder->crtc->x,
> > >  						      encoder->crtc->y,
> > > -						      encoder->crtc->fb))
> > > +						      encoder->crtc->primary->fb))
> > >  				return -1;
> > >  		}
> > >  	} else if (!strcmp(property->name, "backlight") && encoder) {
> > > diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
> > > index 386de2c..7b73dd1 100644
> > > --- a/drivers/gpu/drm/gma500/gma_display.c
> > > +++ b/drivers/gpu/drm/gma500/gma_display.c
> > > @@ -59,7 +59,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_psb_private *dev_priv = dev->dev_private;
> > >  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> > > -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> > > +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
> > >  	int pipe = gma_crtc->pipe;
> > >  	const struct psb_offset *map = &dev_priv->regmap[pipe];
> > >  	unsigned long start, offset;
> > > @@ -70,7 +70,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> > >  		return 0;
> > >  
> > >  	/* no fb bound */
> > > -	if (!crtc->fb) {
> > > +	if (!crtc->primary->fb) {
> > >  		dev_err(dev->dev, "No FB bound\n");
> > >  		goto gma_pipe_cleaner;
> > >  	}
> > > @@ -81,19 +81,20 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> > >  	if (ret < 0)
> > >  		goto gma_pipe_set_base_exit;
> > >  	start = psbfb->gtt->offset;
> > > -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> > > +	offset = y * crtc->primary->fb->pitches[0] +
> > > +		x * (crtc->primary->fb->bits_per_pixel / 8);
> > >  
> > > -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> > > +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
> > >  
> > >  	dspcntr = REG_READ(map->cntr);
> > >  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
> > >  
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		dspcntr |= DISPPLANE_8BPP;
> > >  		break;
> > >  	case 16:
> > > -		if (crtc->fb->depth == 15)
> > > +		if (crtc->primary->fb->depth == 15)
> > >  			dspcntr |= DISPPLANE_15_16BPP;
> > >  		else
> > >  			dspcntr |= DISPPLANE_16BPP;
> > > @@ -511,8 +512,8 @@ void gma_crtc_disable(struct drm_crtc *crtc)
> > >  
> > >  	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
> > >  
> > > -	if (crtc->fb) {
> > > -		gt = to_psb_fb(crtc->fb)->gtt;
> > > +	if (crtc->primary->fb) {
> > > +		gt = to_psb_fb(crtc->primary->fb)->gtt;
> > >  		psb_gtt_unpin(gt);
> > >  	}
> > >  }
> > > diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> > > index 860a4ee..6e91b20 100644
> > > --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> > > +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
> > > @@ -287,7 +287,7 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
> > >  						&gma_crtc->saved_mode,
> > >  						encoder->crtc->x,
> > >  						encoder->crtc->y,
> > > -						encoder->crtc->fb))
> > > +						encoder->crtc->primary->fb))
> > >  					goto set_prop_error;
> > >  			} else {
> > >  				struct drm_encoder_helper_funcs *funcs =
> > > diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c
> > > index 321c00a..c54386a 100644
> > > --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c
> > > +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c
> > > @@ -166,7 +166,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_psb_private *dev_priv = dev->dev_private;
> > >  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> > > -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> > > +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
> > >  	int pipe = gma_crtc->pipe;
> > >  	const struct psb_offset *map = &dev_priv->regmap[pipe];
> > >  	unsigned long start, offset;
> > > @@ -178,12 +178,12 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> > >  	dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
> > >  
> > >  	/* no fb bound */
> > > -	if (!crtc->fb) {
> > > +	if (!crtc->primary->fb) {
> > >  		dev_dbg(dev->dev, "No FB bound\n");
> > >  		return 0;
> > >  	}
> > >  
> > > -	ret = check_fb(crtc->fb);
> > > +	ret = check_fb(crtc->primary->fb);
> > >  	if (ret)
> > >  		return ret;
> > >  
> > > @@ -196,18 +196,19 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> > >  		return 0;
> > >  
> > >  	start = psbfb->gtt->offset;
> > > -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> > > +	offset = y * crtc->primary->fb->pitches[0] +
> > > +		x * (crtc->primary->fb->bits_per_pixel / 8);
> > >  
> > > -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> > > +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
> > >  	dspcntr = REG_READ(map->cntr);
> > >  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
> > >  
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		dspcntr |= DISPPLANE_8BPP;
> > >  		break;
> > >  	case 16:
> > > -		if (crtc->fb->depth == 15)
> > > +		if (crtc->primary->fb->depth == 15)
> > >  			dspcntr |= DISPPLANE_15_16BPP;
> > >  		else
> > >  			dspcntr |= DISPPLANE_16BPP;
> > > @@ -700,7 +701,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
> > >  	}
> > >  #endif
> > >  
> > > -	ret = check_fb(crtc->fb);
> > > +	ret = check_fb(crtc->primary->fb);
> > >  	if (ret)
> > >  		return ret;
> > >  
> > > diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
> > > index 8195e85..b0fb42a 100644
> > > --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
> > > +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
> > > @@ -599,7 +599,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_psb_private *dev_priv = dev->dev_private;
> > >  	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
> > > -	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
> > > +	struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
> > >  	int pipe = gma_crtc->pipe;
> > >  	const struct psb_offset *map = &dev_priv->regmap[pipe];
> > >  	unsigned long start, offset;
> > > @@ -608,7 +608,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
> > >  	int ret = 0;
> > >  
> > >  	/* no fb bound */
> > > -	if (!crtc->fb) {
> > > +	if (!crtc->primary->fb) {
> > >  		dev_dbg(dev->dev, "No FB bound\n");
> > >  		return 0;
> > >  	}
> > > @@ -617,19 +617,20 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
> > >  		return 0;
> > >  
> > >  	start = psbfb->gtt->offset;
> > > -	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
> > > +	offset = y * crtc->primary->fb->pitches[0] +
> > > +		x * (crtc->primary->fb->bits_per_pixel / 8);
> > >  
> > > -	REG_WRITE(map->stride, crtc->fb->pitches[0]);
> > > +	REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
> > >  
> > >  	dspcntr = REG_READ(map->cntr);
> > >  	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
> > >  
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		dspcntr |= DISPPLANE_8BPP;
> > >  		break;
> > >  	case 16:
> > > -		if (crtc->fb->depth == 15)
> > > +		if (crtc->primary->fb->depth == 15)
> > >  			dspcntr |= DISPPLANE_15_16BPP;
> > >  		else
> > >  			dspcntr |= DISPPLANE_16BPP;
> > > diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
> > > index c8f833d..25c174c 100644
> > > --- a/drivers/gpu/drm/gma500/psb_intel_display.c
> > > +++ b/drivers/gpu/drm/gma500/psb_intel_display.c
> > > @@ -120,7 +120,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
> > >  	const struct gma_limit_t *limit;
> > >  
> > >  	/* No scan out no play */
> > > -	if (crtc->fb == NULL) {
> > > +	if (crtc->primary->fb == NULL) {
> > >  		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
> > >  		return 0;
> > >  	}
> > > diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
> > > index 32342f6..dcdf70e 100644
> > > --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
> > > +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
> > > @@ -614,7 +614,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
> > >  						      &crtc->saved_mode,
> > >  						      encoder->crtc->x,
> > >  						      encoder->crtc->y,
> > > -						      encoder->crtc->fb))
> > > +						      encoder->crtc->primary->fb))
> > >  				goto set_prop_error;
> > >  		}
> > >  	} else if (!strcmp(property->name, "backlight")) {
> > > diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> > > index 07d3a9e..1c0a2fb 100644
> > > --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> > > +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
> > > @@ -1844,7 +1844,7 @@ done:
> > >  	if (psb_intel_sdvo->base.base.crtc) {
> > >  		struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc;
> > >  		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
> > > -					 crtc->y, crtc->fb);
> > > +					 crtc->y, crtc->primary->fb);
> > >  	}
> > >  
> > >  	return 0;
> > > diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> > > index d83d643..f00ba43 100644
> > > --- a/drivers/gpu/drm/i915/i915_debugfs.c
> > > +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> > > @@ -2172,8 +2172,8 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc)
> > >  	struct intel_encoder *intel_encoder;
> > >  
> > >  	seq_printf(m, "\tfb: %d, pos: %dx%d, size: %dx%d\n",
> > > -		   crtc->fb->base.id, crtc->x, crtc->y,
> > > -		   crtc->fb->width, crtc->fb->height);
> > > +		   crtc->primary->fb->base.id, crtc->x, crtc->y,
> > > +		   crtc->primary->fb->width, crtc->primary->fb->height);
> > >  	for_each_encoder_on_crtc(dev, crtc, intel_encoder)
> > >  		intel_encoder_info(m, intel_crtc, intel_encoder);
> > >  }
> > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > > index 37f852d..e8b3f9f 100644
> > > --- a/drivers/gpu/drm/i915/i915_irq.c
> > > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > > @@ -2380,8 +2380,8 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in
> > >  	} else {
> > >  		int dspaddr = DSPADDR(intel_crtc->plane);
> > >  		stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) +
> > > -							crtc->y * crtc->fb->pitches[0] +
> > > -							crtc->x * crtc->fb->bits_per_pixel/8);
> > > +							crtc->y * crtc->primary->fb->pitches[0] +
> > > +							crtc->x * crtc->primary->fb->bits_per_pixel/8);
> > >  	}
> > >  
> > >  	spin_unlock_irqrestore(&dev->event_lock, flags);
> > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > > index 21d12a9..c2f3730 100644
> > > --- a/drivers/gpu/drm/i915/intel_display.c
> > > +++ b/drivers/gpu/drm/i915/intel_display.c
> > > @@ -744,7 +744,7 @@ bool intel_crtc_active(struct drm_crtc *crtc)
> > >  	 * We can ditch the crtc->fb check as soon as we can
> > >  	 * properly reconstruct framebuffers.
> > >  	 */
> > > -	return intel_crtc->active && crtc->fb &&
> > > +	return intel_crtc->active && crtc->primary->fb &&
> > >  		intel_crtc->config.adjusted_mode.crtc_clock;
> > >  }
> > >  
> > > @@ -2086,17 +2086,18 @@ static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
> > >  
> > >  	if (plane_config->tiled) {
> > >  		obj->tiling_mode = I915_TILING_X;
> > > -		obj->stride = crtc->base.fb->pitches[0];
> > > +		obj->stride = crtc->base.primary->fb->pitches[0];
> > >  	}
> > >  
> > > -	mode_cmd.pixel_format = crtc->base.fb->pixel_format;
> > > -	mode_cmd.width = crtc->base.fb->width;
> > > -	mode_cmd.height = crtc->base.fb->height;
> > > -	mode_cmd.pitches[0] = crtc->base.fb->pitches[0];
> > > +	mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
> > > +	mode_cmd.width = crtc->base.primary->fb->width;
> > > +	mode_cmd.height = crtc->base.primary->fb->height;
> > > +	mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0];
> > >  
> > >  	mutex_lock(&dev->struct_mutex);
> > >  
> > > -	if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.fb),
> > > +	if (intel_framebuffer_init(dev,
> > > +				   to_intel_framebuffer(crtc->base.primary->fb),
> > >  				   &mode_cmd, obj)) {
> > >  		DRM_DEBUG_KMS("intel fb init failed\n");
> > >  		goto out_unref_obj;
> > > @@ -2121,14 +2122,14 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
> > >  	struct intel_crtc *i;
> > >  	struct intel_framebuffer *fb;
> > >  
> > > -	if (!intel_crtc->base.fb)
> > > +	if (!intel_crtc->base.primary->fb)
> > >  		return;
> > >  
> > >  	if (intel_alloc_plane_obj(intel_crtc, plane_config))
> > >  		return;
> > >  
> > > -	kfree(intel_crtc->base.fb);
> > > -	intel_crtc->base.fb = NULL;
> > > +	kfree(intel_crtc->base.primary->fb);
> > > +	intel_crtc->base.primary->fb = NULL;
> > >  
> > >  	/*
> > >  	 * Failed to alloc the obj, check to see if we should share
> > > @@ -2140,13 +2141,13 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
> > >  		if (c == &intel_crtc->base)
> > >  			continue;
> > >  
> > > -		if (!i->active || !c->fb)
> > > +		if (!i->active || !c->primary->fb)
> > >  			continue;
> > >  
> > > -		fb = to_intel_framebuffer(c->fb);
> > > +		fb = to_intel_framebuffer(c->primary->fb);
> > >  		if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) {
> > > -			drm_framebuffer_reference(c->fb);
> > > -			intel_crtc->base.fb = c->fb;
> > > +			drm_framebuffer_reference(c->primary->fb);
> > > +			intel_crtc->base.primary->fb = c->primary->fb;
> > >  			break;
> > >  		}
> > >  	}
> > > @@ -2394,11 +2395,13 @@ void intel_display_handle_reset(struct drm_device *dev)
> > >  		/*
> > >  		 * FIXME: Once we have proper support for primary planes (and
> > >  		 * disabling them without disabling the entire crtc) allow again
> > > -		 * a NULL crtc->fb.
> > > +		 * a NULL crtc->primary->fb.
> > >  		 */
> > > -		if (intel_crtc->active && crtc->fb)
> > > -			dev_priv->display.update_plane(crtc, crtc->fb,
> > > -						       crtc->x, crtc->y);
> > > +		if (intel_crtc->active && crtc->primary->fb)
> > > +			dev_priv->display.update_plane(crtc,
> > > +						       crtc->primary->fb,
> > > +						       crtc->x,
> > > +						       crtc->y);
> > >  		mutex_unlock(&crtc->mutex);
> > >  	}
> > >  }
> > > @@ -2523,8 +2526,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
> > >  		return ret;
> > >  	}
> > >  
> > > -	old_fb = crtc->fb;
> > > -	crtc->fb = fb;
> > > +	old_fb = crtc->primary->fb;
> > > +	crtc->primary->fb = fb;
> > >  	crtc->x = x;
> > >  	crtc->y = y;
> > >  
> > > @@ -3118,7 +3121,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > >  
> > > -	if (crtc->fb == NULL)
> > > +	if (crtc->primary->fb == NULL)
> > >  		return;
> > >  
> > >  	WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
> > > @@ -3127,7 +3130,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
> > >  		   !intel_crtc_has_pending_flip(crtc));
> > >  
> > >  	mutex_lock(&dev->struct_mutex);
> > > -	intel_finish_fb(crtc->fb);
> > > +	intel_finish_fb(crtc->primary->fb);
> > >  	mutex_unlock(&dev->struct_mutex);
> > >  }
> > >  
> > > @@ -4583,11 +4586,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
> > >  	assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe);
> > >  	assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
> > >  
> > > -	if (crtc->fb) {
> > > +	if (crtc->primary->fb) {
> > >  		mutex_lock(&dev->struct_mutex);
> > > -		intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
> > > +		intel_unpin_fb_obj(to_intel_framebuffer(crtc->primary->fb)->obj);
> > >  		mutex_unlock(&dev->struct_mutex);
> > > -		crtc->fb = NULL;
> > > +		crtc->primary->fb = NULL;
> > >  	}
> > >  
> > >  	/* Update computed state. */
> > > @@ -5738,8 +5741,9 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
> > >  	int fourcc, pixel_format;
> > >  	int aligned_height;
> > >  
> > > -	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > > -	if (!crtc->base.fb) {
> > > +	crtc->base.primary->fb =
> > > +		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > > +	if (!crtc->base.primary->fb) {
> > >  		DRM_DEBUG_KMS("failed to alloc fb\n");
> > >  		return;
> > >  	}
> > > @@ -5752,8 +5756,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
> > >  
> > >  	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
> > >  	fourcc = intel_format_to_fourcc(pixel_format);
> > > -	crtc->base.fb->pixel_format = fourcc;
> > > -	crtc->base.fb->bits_per_pixel =
> > > +	crtc->base.primary->fb->pixel_format = fourcc;
> > > +	crtc->base.primary->fb->bits_per_pixel =
> > >  		drm_format_plane_cpp(fourcc, 0) * 8;
> > >  
> > >  	if (INTEL_INFO(dev)->gen >= 4) {
> > > @@ -5768,23 +5772,23 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
> > >  	plane_config->base = base;
> > >  
> > >  	val = I915_READ(PIPESRC(pipe));
> > > -	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
> > > -	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
> > > +	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
> > > +	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
> > >  
> > >  	val = I915_READ(DSPSTRIDE(pipe));
> > > -	crtc->base.fb->pitches[0] = val & 0xffffff80;
> > > +	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
> > >  
> > > -	aligned_height = intel_align_height(dev, crtc->base.fb->height,
> > > +	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
> > >  					    plane_config->tiled);
> > >  
> > > -	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
> > > +	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
> > >  				   aligned_height, PAGE_SIZE);
> > >  
> > >  	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
> > > -		      pipe, plane, crtc->base.fb->width,
> > > -		      crtc->base.fb->height,
> > > -		      crtc->base.fb->bits_per_pixel, base,
> > > -		      crtc->base.fb->pitches[0],
> > > +		      pipe, plane, crtc->base.primary->fb->width,
> > > +		      crtc->base.primary->fb->height,
> > > +		      crtc->base.primary->fb->bits_per_pixel, base,
> > > +		      crtc->base.primary->fb->pitches[0],
> > >  		      plane_config->size);
> > >  
> > >  }
> > > @@ -6746,8 +6750,9 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
> > >  	int fourcc, pixel_format;
> > >  	int aligned_height;
> > >  
> > > -	crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > > -	if (!crtc->base.fb) {
> > > +	crtc->base.primary->fb =
> > > +		kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
> > > +	if (!crtc->base.primary->fb) {
> > >  		DRM_DEBUG_KMS("failed to alloc fb\n");
> > >  		return;
> > >  	}
> > > @@ -6760,8 +6765,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
> > >  
> > >  	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
> > >  	fourcc = intel_format_to_fourcc(pixel_format);
> > > -	crtc->base.fb->pixel_format = fourcc;
> > > -	crtc->base.fb->bits_per_pixel =
> > > +	crtc->base.primary->fb->pixel_format = fourcc;
> > > +	crtc->base.primary->fb->bits_per_pixel =
> > >  		drm_format_plane_cpp(fourcc, 0) * 8;
> > >  
> > >  	base = I915_READ(DSPSURF(plane)) & 0xfffff000;
> > > @@ -6776,23 +6781,23 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
> > >  	plane_config->base = base;
> > >  
> > >  	val = I915_READ(PIPESRC(pipe));
> > > -	crtc->base.fb->width = ((val >> 16) & 0xfff) + 1;
> > > -	crtc->base.fb->height = ((val >> 0) & 0xfff) + 1;
> > > +	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
> > > +	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
> > >  
> > >  	val = I915_READ(DSPSTRIDE(pipe));
> > > -	crtc->base.fb->pitches[0] = val & 0xffffff80;
> > > +	crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
> > >  
> > > -	aligned_height = intel_align_height(dev, crtc->base.fb->height,
> > > +	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
> > >  					    plane_config->tiled);
> > >  
> > > -	plane_config->size = ALIGN(crtc->base.fb->pitches[0] *
> > > +	plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
> > >  				   aligned_height, PAGE_SIZE);
> > >  
> > >  	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
> > > -		      pipe, plane, crtc->base.fb->width,
> > > -		      crtc->base.fb->height,
> > > -		      crtc->base.fb->bits_per_pixel, base,
> > > -		      crtc->base.fb->pitches[0],
> > > +		      pipe, plane, crtc->base.primary->fb->width,
> > > +		      crtc->base.primary->fb->height,
> > > +		      crtc->base.primary->fb->bits_per_pixel, base,
> > > +		      crtc->base.primary->fb->pitches[0],
> > >  		      plane_config->size);
> > >  }
> > >  
> > > @@ -8482,7 +8487,7 @@ void intel_mark_idle(struct drm_device *dev)
> > >  		goto out;
> > >  
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > > -		if (!crtc->fb)
> > > +		if (!crtc->primary->fb)
> > >  			continue;
> > >  
> > >  		intel_decrease_pllclock(crtc);
> > > @@ -8505,10 +8510,10 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
> > >  		return;
> > >  
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > > -		if (!crtc->fb)
> > > +		if (!crtc->primary->fb)
> > >  			continue;
> > >  
> > > -		if (to_intel_framebuffer(crtc->fb)->obj != obj)
> > > +		if (to_intel_framebuffer(crtc->primary->fb)->obj != obj)
> > >  			continue;
> > >  
> > >  		intel_increase_pllclock(crtc);
> > > @@ -8936,7 +8941,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> > >  {
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > -	struct drm_framebuffer *old_fb = crtc->fb;
> > > +	struct drm_framebuffer *old_fb = crtc->primary->fb;
> > >  	struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
> > >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > >  	struct intel_unpin_work *work;
> > > @@ -8944,7 +8949,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> > >  	int ret;
> > >  
> > >  	/* Can't change pixel format via MI display flips. */
> > > -	if (fb->pixel_format != crtc->fb->pixel_format)
> > > +	if (fb->pixel_format != crtc->primary->fb->pixel_format)
> > >  		return -EINVAL;
> > >  
> > >  	/*
> > > @@ -8952,8 +8957,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> > >  	 * Note that pitch changes could also affect these register.
> > >  	 */
> > >  	if (INTEL_INFO(dev)->gen > 3 &&
> > > -	    (fb->offsets[0] != crtc->fb->offsets[0] ||
> > > -	     fb->pitches[0] != crtc->fb->pitches[0]))
> > > +	    (fb->offsets[0] != crtc->primary->fb->offsets[0] ||
> > > +	     fb->pitches[0] != crtc->primary->fb->pitches[0]))
> > >  		return -EINVAL;
> > >  
> > >  	if (i915_terminally_wedged(&dev_priv->gpu_error))
> > > @@ -8996,7 +9001,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> > >  	drm_gem_object_reference(&work->old_fb_obj->base);
> > >  	drm_gem_object_reference(&obj->base);
> > >  
> > > -	crtc->fb = fb;
> > > +	crtc->primary->fb = fb;
> > >  
> > >  	work->pending_flip_obj = obj;
> > >  
> > > @@ -9019,7 +9024,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> > >  
> > >  cleanup_pending:
> > >  	atomic_dec(&intel_crtc->unpin_work_count);
> > > -	crtc->fb = old_fb;
> > > +	crtc->primary->fb = old_fb;
> > >  	drm_gem_object_unreference(&work->old_fb_obj->base);
> > >  	drm_gem_object_unreference(&obj->base);
> > >  	mutex_unlock(&dev->struct_mutex);
> > > @@ -10060,7 +10065,7 @@ static int intel_set_mode(struct drm_crtc *crtc,
> > >  
> > >  void intel_crtc_restore_mode(struct drm_crtc *crtc)
> > >  {
> > > -	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb);
> > > +	intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
> > >  }
> > >  
> > >  #undef for_each_intel_crtc_masked
> > > @@ -10184,9 +10189,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
> > >  	 * and then just flip_or_move it */
> > >  	if (is_crtc_connector_off(set)) {
> > >  		config->mode_changed = true;
> > > -	} else if (set->crtc->fb != set->fb) {
> > > +	} else if (set->crtc->primary->fb != set->fb) {
> > >  		/* If we have no fb then treat it as a full mode set */
> > > -		if (set->crtc->fb == NULL) {
> > > +		if (set->crtc->primary->fb == NULL) {
> > >  			struct intel_crtc *intel_crtc =
> > >  				to_intel_crtc(set->crtc);
> > >  
> > > @@ -10200,7 +10205,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
> > >  		} else if (set->fb == NULL) {
> > >  			config->mode_changed = true;
> > >  		} else if (set->fb->pixel_format !=
> > > -			   set->crtc->fb->pixel_format) {
> > > +			   set->crtc->primary->fb->pixel_format) {
> > >  			config->mode_changed = true;
> > >  		} else {
> > >  			config->fb_changed = true;
> > > @@ -10413,7 +10418,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
> > >  	save_set.mode = &set->crtc->mode;
> > >  	save_set.x = set->crtc->x;
> > >  	save_set.y = set->crtc->y;
> > > -	save_set.fb = set->crtc->fb;
> > > +	save_set.fb = set->crtc->primary->fb;
> > >  
> > >  	/* Compute whether we need a full modeset, only an fb base update or no
> > >  	 * change at all. In the future we might also check whether only the
> > > @@ -11755,7 +11760,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
> > >  				dev_priv->pipe_to_crtc_mapping[pipe];
> > >  
> > >  			__intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
> > > -					 crtc->fb);
> > > +					 crtc->primary->fb);
> > >  		}
> > >  	} else {
> > >  		intel_modeset_update_staged_output_state(dev);
> > > @@ -11780,15 +11785,15 @@ void intel_modeset_gem_init(struct drm_device *dev)
> > >  	 */
> > >  	mutex_lock(&dev->struct_mutex);
> > >  	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
> > > -		if (!c->fb)
> > > +		if (!c->primary->fb)
> > >  			continue;
> > >  
> > > -		fb = to_intel_framebuffer(c->fb);
> > > +		fb = to_intel_framebuffer(c->primary->fb);
> > >  		if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) {
> > >  			DRM_ERROR("failed to pin boot fb on pipe %d\n",
> > >  				  to_intel_crtc(c)->pipe);
> > > -			drm_framebuffer_unreference(c->fb);
> > > -			c->fb = NULL;
> > > +			drm_framebuffer_unreference(c->primary->fb);
> > > +			c->primary->fb = NULL;
> > >  		}
> > >  	}
> > >  	mutex_unlock(&dev->struct_mutex);
> > > @@ -11827,7 +11832,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
> > >  
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > >  		/* Skip inactive CRTCs */
> > > -		if (!crtc->fb)
> > > +		if (!crtc->primary->fb)
> > >  			continue;
> > >  
> > >  		intel_increase_pllclock(crtc);
> > > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > > index 59ee4dc..05531bf 100644
> > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > @@ -1634,7 +1634,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > >  	struct drm_crtc *crtc = dig_port->base.base.crtc;
> > >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > > -	struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
> > > +	struct drm_i915_gem_object *obj =
> > > +		to_intel_framebuffer(crtc->primary->fb)->obj;
> > >  	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
> > >  
> > >  	dev_priv->psr.source_ok = false;
> > > @@ -1667,7 +1668,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> > >  		return false;
> > >  	}
> > >  
> > > -	obj = to_intel_framebuffer(crtc->fb)->obj;
> > > +	obj = to_intel_framebuffer(crtc->primary->fb)->obj;
> > >  	if (obj->tiling_mode != I915_TILING_X ||
> > >  	    obj->fence_reg == I915_FENCE_REG_NONE) {
> > >  		DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
> > > diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> > > index d6d78c8..2b1d42d 100644
> > > --- a/drivers/gpu/drm/i915/intel_fbdev.c
> > > +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> > > @@ -481,7 +481,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > >  		intel_crtc = to_intel_crtc(crtc);
> > >  
> > > -		if (!intel_crtc->active || !crtc->fb) {
> > > +		if (!intel_crtc->active || !crtc->primary->fb) {
> > >  			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
> > >  				      pipe_name(intel_crtc->pipe));
> > >  			continue;
> > > @@ -491,7 +491,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
> > >  			DRM_DEBUG_KMS("found possible fb from plane %c\n",
> > >  				      pipe_name(intel_crtc->pipe));
> > >  			plane_config = &intel_crtc->plane_config;
> > > -			fb = to_intel_framebuffer(crtc->fb);
> > > +			fb = to_intel_framebuffer(crtc->primary->fb);
> > >  			max_size = plane_config->size;
> > >  		}
> > >  	}
> > > @@ -560,7 +560,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
> > >  		if (!intel_crtc->active)
> > >  			continue;
> > >  
> > > -		WARN(!crtc->fb,
> > > +		WARN(!crtc->primary->fb,
> > >  		     "re-used BIOS config but lost an fb on crtc %d\n",
> > >  		     crtc->base.id);
> > >  	}
> > > diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
> > > index 312961a..623cd32 100644
> > > --- a/drivers/gpu/drm/i915/intel_overlay.c
> > > +++ b/drivers/gpu/drm/i915/intel_overlay.c
> > > @@ -606,14 +606,14 @@ static void update_colorkey(struct intel_overlay *overlay,
> > >  {
> > >  	u32 key = overlay->color_key;
> > >  
> > > -	switch (overlay->crtc->base.fb->bits_per_pixel) {
> > > +	switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		iowrite32(0, &regs->DCLRKV);
> > >  		iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
> > >  		break;
> > >  
> > >  	case 16:
> > > -		if (overlay->crtc->base.fb->depth == 15) {
> > > +		if (overlay->crtc->base.primary->fb->depth == 15) {
> > >  			iowrite32(RGB15_TO_COLORKEY(key), &regs->DCLRKV);
> > >  			iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
> > >  				  &regs->DCLRKM);
> > > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > > index 3a1b569..e2d73f4 100644
> > > --- a/drivers/gpu/drm/i915/intel_pm.c
> > > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > > @@ -92,7 +92,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
> > >  {
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > -	struct drm_framebuffer *fb = crtc->fb;
> > > +	struct drm_framebuffer *fb = crtc->primary->fb;
> > >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> > >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> > >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > > @@ -149,7 +149,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc)
> > >  {
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > -	struct drm_framebuffer *fb = crtc->fb;
> > > +	struct drm_framebuffer *fb = crtc->primary->fb;
> > >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> > >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> > >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > > @@ -221,7 +221,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc)
> > >  {
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > -	struct drm_framebuffer *fb = crtc->fb;
> > > +	struct drm_framebuffer *fb = crtc->primary->fb;
> > >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> > >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> > >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > > @@ -277,7 +277,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc)
> > >  {
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > -	struct drm_framebuffer *fb = crtc->fb;
> > > +	struct drm_framebuffer *fb = crtc->primary->fb;
> > >  	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> > >  	struct drm_i915_gem_object *obj = intel_fb->obj;
> > >  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > > @@ -336,11 +336,11 @@ static void intel_fbc_work_fn(struct work_struct *__work)
> > >  		/* Double check that we haven't switched fb without cancelling
> > >  		 * the prior work.
> > >  		 */
> > > -		if (work->crtc->fb == work->fb) {
> > > +		if (work->crtc->primary->fb == work->fb) {
> > >  			dev_priv->display.enable_fbc(work->crtc);
> > >  
> > >  			dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
> > > -			dev_priv->fbc.fb_id = work->crtc->fb->base.id;
> > > +			dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
> > >  			dev_priv->fbc.y = work->crtc->y;
> > >  		}
> > >  
> > > @@ -393,7 +393,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc)
> > >  	}
> > >  
> > >  	work->crtc = crtc;
> > > -	work->fb = crtc->fb;
> > > +	work->fb = crtc->primary->fb;
> > >  	INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
> > >  
> > >  	dev_priv->fbc.fbc_work = work;
> > > @@ -499,14 +499,14 @@ void intel_update_fbc(struct drm_device *dev)
> > >  		}
> > >  	}
> > >  
> > > -	if (!crtc || crtc->fb == NULL) {
> > > +	if (!crtc || crtc->primary->fb == NULL) {
> > >  		if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
> > >  			DRM_DEBUG_KMS("no output, disabling\n");
> > >  		goto out_disable;
> > >  	}
> > >  
> > >  	intel_crtc = to_intel_crtc(crtc);
> > > -	fb = crtc->fb;
> > > +	fb = crtc->primary->fb;
> > >  	intel_fb = to_intel_framebuffer(fb);
> > >  	obj = intel_fb->obj;
> > >  	adjusted_mode = &intel_crtc->config.adjusted_mode;
> > > @@ -1041,7 +1041,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
> > >  	crtc = single_enabled_crtc(dev);
> > >  	if (crtc) {
> > >  		const struct drm_display_mode *adjusted_mode;
> > > -		int pixel_size = crtc->fb->bits_per_pixel / 8;
> > > +		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> > >  		int clock;
> > >  
> > >  		adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
> > > @@ -1121,7 +1121,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
> > >  	clock = adjusted_mode->crtc_clock;
> > >  	htotal = adjusted_mode->crtc_htotal;
> > >  	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> > > -	pixel_size = crtc->fb->bits_per_pixel / 8;
> > > +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> > >  
> > >  	/* Use the small buffer method to calculate plane watermark */
> > >  	entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
> > > @@ -1208,7 +1208,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
> > >  	clock = adjusted_mode->crtc_clock;
> > >  	htotal = adjusted_mode->crtc_htotal;
> > >  	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> > > -	pixel_size = crtc->fb->bits_per_pixel / 8;
> > > +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> > >  
> > >  	line_time_us = max(htotal * 1000 / clock, 1);
> > >  	line_count = (latency_ns / line_time_us + 1000) / 1000;
> > > @@ -1247,7 +1247,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,
> > >  		return false;
> > >  
> > >  	clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
> > > -	pixel_size = crtc->fb->bits_per_pixel / 8;	/* BPP */
> > > +	pixel_size = crtc->primary->fb->bits_per_pixel / 8;	/* BPP */
> > >  
> > >  	entries = (clock / 1000) * pixel_size;
> > >  	*plane_prec_mult = (entries > 256) ?
> > > @@ -1439,7 +1439,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
> > >  		int clock = adjusted_mode->crtc_clock;
> > >  		int htotal = adjusted_mode->crtc_htotal;
> > >  		int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
> > > -		int pixel_size = crtc->fb->bits_per_pixel / 8;
> > > +		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
> > >  		unsigned long line_time_us;
> > >  		int entries;
> > >  
> > > @@ -1512,7 +1512,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
> > >  	crtc = intel_get_crtc_for_plane(dev, 0);
> > >  	if (intel_crtc_active(crtc)) {
> > >  		const struct drm_display_mode *adjusted_mode;
> > > -		int cpp = crtc->fb->bits_per_pixel / 8;
> > > +		int cpp = crtc->primary->fb->bits_per_pixel / 8;
> > >  		if (IS_GEN2(dev))
> > >  			cpp = 4;
> > >  
> > > @@ -1528,7 +1528,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
> > >  	crtc = intel_get_crtc_for_plane(dev, 1);
> > >  	if (intel_crtc_active(crtc)) {
> > >  		const struct drm_display_mode *adjusted_mode;
> > > -		int cpp = crtc->fb->bits_per_pixel / 8;
> > > +		int cpp = crtc->primary->fb->bits_per_pixel / 8;
> > >  		if (IS_GEN2(dev))
> > >  			cpp = 4;
> > >  
> > > @@ -1565,7 +1565,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
> > >  		int clock = adjusted_mode->crtc_clock;
> > >  		int htotal = adjusted_mode->crtc_htotal;
> > >  		int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w;
> > > -		int pixel_size = enabled->fb->bits_per_pixel / 8;
> > > +		int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
> > >  		unsigned long line_time_us;
> > >  		int entries;
> > >  
> > > @@ -2117,7 +2117,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
> > >  	if (p->active) {
> > >  		p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
> > >  		p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
> > > -		p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
> > > +		p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
> > >  		p->cur.bytes_per_pixel = 4;
> > >  		p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
> > >  		p->cur.horiz_pixels = 64;
> > > diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> > > index 1418414..f8c42b1 100644
> > > --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> > > +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> > > @@ -29,7 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
> > >  	struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct mga_device *mdev = dev->dev_private;
> > > -	struct drm_framebuffer *fb = crtc->fb;
> > > +	struct drm_framebuffer *fb = crtc->primary->fb;
> > >  	int i;
> > >  
> > >  	if (!crtc->enabled)
> > > @@ -742,7 +742,7 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
> > >  		mgag200_bo_unreserve(bo);
> > >  	}
> > >  
> > > -	mga_fb = to_mga_framebuffer(crtc->fb);
> > > +	mga_fb = to_mga_framebuffer(crtc->primary->fb);
> > >  	obj = mga_fb->obj;
> > >  	bo = gem_to_mga_bo(obj);
> > >  
> > > @@ -805,7 +805,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> > >  		/* 0x48: */        0,    0,    0,    0,    0,    0,    0,    0
> > >  	};
> > >  
> > > -	bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1];
> > > +	bppshift = mdev->bpp_shifts[(crtc->primary->fb->bits_per_pixel >> 3) - 1];
> > >  
> > >  	switch (mdev->type) {
> > >  	case G200_SE_A:
> > > @@ -843,12 +843,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> > >  		break;
> > >  	}
> > >  
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
> > >  		break;
> > >  	case 16:
> > > -		if (crtc->fb->depth == 15)
> > > +		if (crtc->primary->fb->depth == 15)
> > >  			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
> > >  		else
> > >  			dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
> > > @@ -896,8 +896,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> > >  	WREG_SEQ(3, 0);
> > >  	WREG_SEQ(4, 0xe);
> > >  
> > > -	pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
> > > -	if (crtc->fb->bits_per_pixel == 24)
> > > +	pitch = crtc->primary->fb->pitches[0] /
> > > +		(crtc->primary->fb->bits_per_pixel / 8);
> > > +	if (crtc->primary->fb->bits_per_pixel == 24)
> > >  		pitch = (pitch * 3) >> (4 - bppshift);
> > >  	else
> > >  		pitch = pitch >> (4 - bppshift);
> > > @@ -974,7 +975,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> > >  		((vdisplay & 0xc00) >> 7) |
> > >  		((vsyncstart & 0xc00) >> 5) |
> > >  		((vdisplay & 0x400) >> 3);
> > > -	if (crtc->fb->bits_per_pixel == 24)
> > > +	if (crtc->primary->fb->bits_per_pixel == 24)
> > >  		ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
> > >  	else
> > >  		ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
> > > @@ -1034,9 +1035,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
> > >  			u32 bpp;
> > >  			u32 mb;
> > >  
> > > -			if (crtc->fb->bits_per_pixel > 16)
> > > +			if (crtc->primary->fb->bits_per_pixel > 16)
> > >  				bpp = 32;
> > > -			else if (crtc->fb->bits_per_pixel > 8)
> > > +			else if (crtc->primary->fb->bits_per_pixel > 8)
> > >  				bpp = 16;
> > >  			else
> > >  				bpp = 8;
> > > @@ -1277,8 +1278,9 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
> > >  	int ret;
> > >  	DRM_DEBUG_KMS("\n");
> > >  	mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> > > -	if (crtc->fb) {
> > > -		struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
> > > +	if (crtc->primary->fb) {
> > > +		struct mga_framebuffer *mga_fb =
> > > +			to_mga_framebuffer(crtc->primary->fb);
> > >  		struct drm_gem_object *obj = mga_fb->obj;
> > >  		struct mgag200_bo *bo = gem_to_mga_bo(obj);
> > >  		ret = mgag200_bo_reserve(bo, false);
> > > @@ -1287,7 +1289,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
> > >  		mgag200_bo_push_sysram(bo);
> > >  		mgag200_bo_unreserve(bo);
> > >  	}
> > > -	crtc->fb = NULL;
> > > +	crtc->primary->fb = NULL;
> > >  }
> > >  
> > >  /* These provide the minimum set of functions required to handle a CRTC */
> > > diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> > > index b10f681..f96497b 100644
> > > --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> > > +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> > > @@ -120,7 +120,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
> > >  
> > >  	/* grab reference to incoming scanout fb: */
> > >  	drm_framebuffer_reference(new_fb);
> > > -	mdp4_crtc->base.fb = new_fb;
> > > +	mdp4_crtc->base.primary->fb = new_fb;
> > >  	mdp4_crtc->fb = new_fb;
> > >  
> > >  	if (old_fb)
> > > @@ -182,7 +182,7 @@ static void pageflip_cb(struct msm_fence_cb *cb)
> > >  	struct mdp4_crtc *mdp4_crtc =
> > >  		container_of(cb, struct mdp4_crtc, pageflip_cb);
> > >  	struct drm_crtc *crtc = &mdp4_crtc->base;
> > > -	struct drm_framebuffer *fb = crtc->fb;
> > > +	struct drm_framebuffer *fb = crtc->primary->fb;
> > >  
> > >  	if (!fb)
> > >  		return;
> > > @@ -348,14 +348,14 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> > >  			mode->type, mode->flags);
> > >  
> > >  	/* grab extra ref for update_scanout() */
> > > -	drm_framebuffer_reference(crtc->fb);
> > > +	drm_framebuffer_reference(crtc->primary->fb);
> > >  
> > > -	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
> > > +	ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb,
> > >  			0, 0, mode->hdisplay, mode->vdisplay,
> > >  			x << 16, y << 16,
> > >  			mode->hdisplay << 16, mode->vdisplay << 16);
> > >  	if (ret) {
> > > -		drm_framebuffer_unreference(crtc->fb);
> > > +		drm_framebuffer_unreference(crtc->primary->fb);
> > >  		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
> > >  				mdp4_crtc->name, ret);
> > >  		return ret;
> > > @@ -368,7 +368,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> > >  	/* take data from pipe: */
> > >  	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
> > >  	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma),
> > > -			crtc->fb->pitches[0]);
> > > +			crtc->primary->fb->pitches[0]);
> > >  	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
> > >  			MDP4_DMA_DST_SIZE_WIDTH(0) |
> > >  			MDP4_DMA_DST_SIZE_HEIGHT(0));
> > > @@ -378,7 +378,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> > >  			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
> > >  			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
> > >  	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp),
> > > -			crtc->fb->pitches[0]);
> > > +			crtc->primary->fb->pitches[0]);
> > >  
> > >  	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
> > >  
> > > @@ -388,8 +388,8 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
> > >  		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
> > >  	}
> > >  
> > > -	update_fb(crtc, crtc->fb);
> > > -	update_scanout(crtc, crtc->fb);
> > > +	update_fb(crtc, crtc->primary->fb);
> > > +	update_scanout(crtc, crtc->primary->fb);
> > >  
> > >  	return 0;
> > >  }
> > > @@ -420,19 +420,19 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> > >  	int ret;
> > >  
> > >  	/* grab extra ref for update_scanout() */
> > > -	drm_framebuffer_reference(crtc->fb);
> > > +	drm_framebuffer_reference(crtc->primary->fb);
> > >  
> > > -	ret = mdp4_plane_mode_set(plane, crtc, crtc->fb,
> > > +	ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb,
> > >  			0, 0, mode->hdisplay, mode->vdisplay,
> > >  			x << 16, y << 16,
> > >  			mode->hdisplay << 16, mode->vdisplay << 16);
> > >  	if (ret) {
> > > -		drm_framebuffer_unreference(crtc->fb);
> > > +		drm_framebuffer_unreference(crtc->primary->fb);
> > >  		return ret;
> > >  	}
> > >  
> > > -	update_fb(crtc, crtc->fb);
> > > -	update_scanout(crtc, crtc->fb);
> > > +	update_fb(crtc, crtc->primary->fb);
> > > +	update_scanout(crtc, crtc->primary->fb);
> > >  
> > >  	return 0;
> > >  }
> > > diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> > > index 7dc3d71..f200048 100644
> > > --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> > > +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> > > @@ -102,7 +102,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
> > >  
> > >  	/* grab reference to incoming scanout fb: */
> > >  	drm_framebuffer_reference(new_fb);
> > > -	mdp5_crtc->base.fb = new_fb;
> > > +	mdp5_crtc->base.primary->fb = new_fb;
> > >  	mdp5_crtc->fb = new_fb;
> > >  
> > >  	if (old_fb)
> > > @@ -289,14 +289,14 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
> > >  			mode->type, mode->flags);
> > >  
> > >  	/* grab extra ref for update_scanout() */
> > > -	drm_framebuffer_reference(crtc->fb);
> > > +	drm_framebuffer_reference(crtc->primary->fb);
> > >  
> > > -	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb,
> > > +	ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb,
> > >  			0, 0, mode->hdisplay, mode->vdisplay,
> > >  			x << 16, y << 16,
> > >  			mode->hdisplay << 16, mode->vdisplay << 16);
> > >  	if (ret) {
> > > -		drm_framebuffer_unreference(crtc->fb);
> > > +		drm_framebuffer_unreference(crtc->primary->fb);
> > >  		dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
> > >  				mdp5_crtc->name, ret);
> > >  		return ret;
> > > @@ -306,8 +306,8 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
> > >  			MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
> > >  			MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
> > >  
> > > -	update_fb(crtc, crtc->fb);
> > > -	update_scanout(crtc, crtc->fb);
> > > +	update_fb(crtc, crtc->primary->fb);
> > > +	update_scanout(crtc, crtc->primary->fb);
> > >  
> > >  	return 0;
> > >  }
> > > @@ -338,19 +338,19 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> > >  	int ret;
> > >  
> > >  	/* grab extra ref for update_scanout() */
> > > -	drm_framebuffer_reference(crtc->fb);
> > > +	drm_framebuffer_reference(crtc->primary->fb);
> > >  
> > > -	ret = mdp5_plane_mode_set(plane, crtc, crtc->fb,
> > > +	ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb,
> > >  			0, 0, mode->hdisplay, mode->vdisplay,
> > >  			x << 16, y << 16,
> > >  			mode->hdisplay << 16, mode->vdisplay << 16);
> > >  	if (ret) {
> > > -		drm_framebuffer_unreference(crtc->fb);
> > > +		drm_framebuffer_unreference(crtc->primary->fb);
> > >  		return ret;
> > >  	}
> > >  
> > > -	update_fb(crtc, crtc->fb);
> > > -	update_scanout(crtc, crtc->fb);
> > > +	update_fb(crtc, crtc->primary->fb);
> > > +	update_scanout(crtc, crtc->primary->fb);
> > >  
> > >  	return 0;
> > >  }
> > > diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> > > index b55be84..2a5e9db 100644
> > > --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> > > +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> > > @@ -239,7 +239,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
> > >  	struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
> > > -	struct drm_framebuffer *fb = crtc->fb;
> > > +	struct drm_framebuffer *fb = crtc->primary->fb;
> > >  
> > >  	/* Calculate our timings */
> > >  	int horizDisplay	= (mode->crtc_hdisplay >> 3)		- 1;
> > > @@ -574,7 +574,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
> > >  		regp->CRTC[NV_CIO_CRE_86] = 0x1;
> > >  	}
> > >  
> > > -	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->fb->depth + 1) / 8;
> > > +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->primary->fb->depth + 1) / 8;
> > >  	/* Enable slaved mode (called MODE_TV in nv4ref.h) */
> > >  	if (lvds_output || tmds_output || tv_output)
> > >  		regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7);
> > > @@ -588,7 +588,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
> > >  	regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
> > >  				NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL |
> > >  				NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON;
> > > -	if (crtc->fb->depth == 16)
> > > +	if (crtc->primary->fb->depth == 16)
> > >  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
> > >  	if (nv_device(drm->device)->chipset >= 0x11)
> > >  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG;
> > > @@ -609,7 +609,7 @@ static int
> > >  nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
> > >  {
> > >  	struct nv04_display *disp = nv04_display(crtc->dev);
> > > -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
> > > +	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
> > >  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
> > >  	int ret;
> > >  
> > > @@ -808,7 +808,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
> > >  	 * mark the lut values as dirty by setting depth==0, and it'll be
> > >  	 * uploaded on the first mode_set_base()
> > >  	 */
> > > -	if (!nv_crtc->base.fb) {
> > > +	if (!nv_crtc->base.primary->fb) {
> > >  		nv_crtc->lut.depth = 0;
> > >  		return;
> > >  	}
> > > @@ -832,7 +832,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
> > >  	NV_DEBUG(drm, "index %d\n", nv_crtc->index);
> > >  
> > >  	/* no fb bound */
> > > -	if (!atomic && !crtc->fb) {
> > > +	if (!atomic && !crtc->primary->fb) {
> > >  		NV_DEBUG(drm, "No FB bound\n");
> > >  		return 0;
> > >  	}
> > > @@ -844,8 +844,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
> > >  		drm_fb = passed_fb;
> > >  		fb = nouveau_framebuffer(passed_fb);
> > >  	} else {
> > > -		drm_fb = crtc->fb;
> > > -		fb = nouveau_framebuffer(crtc->fb);
> > > +		drm_fb = crtc->primary->fb;
> > > +		fb = nouveau_framebuffer(crtc->primary->fb);
> > >  	}
> > >  
> > >  	nv_crtc->fb.offset = fb->nvbo->bo.offset;
> > > @@ -857,9 +857,9 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
> > >  
> > >  	/* Update the framebuffer format. */
> > >  	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3;
> > > -	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8;
> > > +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->primary->fb->depth + 1) / 8;
> > >  	regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
> > > -	if (crtc->fb->depth == 16)
> > > +	if (crtc->primary->fb->depth == 16)
> > >  		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
> > >  	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX);
> > >  	NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL,
> > > diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> > > index 7fdc51e..a2d669b 100644
> > > --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> > > +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
> > > @@ -415,7 +415,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
> > >  	/* Output property. */
> > >  	if ((nv_connector->dithering_mode == DITHERING_MODE_ON) ||
> > >  	    (nv_connector->dithering_mode == DITHERING_MODE_AUTO &&
> > > -	     encoder->crtc->fb->depth > connector->display_info.bpc * 3)) {
> > > +	     encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) {
> > >  		if (nv_device(drm->device)->chipset == 0x11)
> > >  			regp->dither = savep->dither | 0x00010000;
> > >  		else {
> > > diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
> > > index 2401159..4e24c72 100644
> > > --- a/drivers/gpu/drm/nouveau/nouveau_display.c
> > > +++ b/drivers/gpu/drm/nouveau/nouveau_display.c
> > > @@ -569,7 +569,7 @@ nouveau_display_suspend(struct drm_device *dev)
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > >  		struct nouveau_framebuffer *nouveau_fb;
> > >  
> > > -		nouveau_fb = nouveau_framebuffer(crtc->fb);
> > > +		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
> > >  		if (!nouveau_fb || !nouveau_fb->nvbo)
> > >  			continue;
> > >  
> > > @@ -596,7 +596,7 @@ nouveau_display_repin(struct drm_device *dev)
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > >  		struct nouveau_framebuffer *nouveau_fb;
> > >  
> > > -		nouveau_fb = nouveau_framebuffer(crtc->fb);
> > > +		nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
> > >  		if (!nouveau_fb || !nouveau_fb->nvbo)
> > >  			continue;
> > >  
> > > @@ -693,7 +693,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
> > >  	const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct nouveau_drm *drm = nouveau_drm(dev);
> > > -	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
> > > +	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo;
> > >  	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
> > >  	struct nouveau_page_flip_state *s;
> > >  	struct nouveau_channel *chan = drm->channel;
> > > @@ -767,7 +767,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
> > >  		goto fail_unreserve;
> > >  
> > >  	/* Update the crtc struct and cleanup */
> > > -	crtc->fb = fb;
> > > +	crtc->primary->fb = fb;
> > >  
> > >  	nouveau_bo_fence(old_bo, fence);
> > >  	ttm_bo_unreserve(&old_bo->bo);
> > > diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> > > index 5706842..c744bf6 100644
> > > --- a/drivers/gpu/drm/nouveau/nv50_display.c
> > > +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> > > @@ -651,7 +651,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
> > >  	nv_connector = nouveau_crtc_connector_get(nv_crtc);
> > >  	connector = &nv_connector->base;
> > >  	if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
> > > -		if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
> > > +		if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3)
> > >  			mode = DITHERING_MODE_DYNAMIC2X2;
> > >  	} else {
> > >  		mode = nv_connector->dithering_mode;
> > > @@ -785,7 +785,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
> > >  
> > >  		if (update) {
> > >  			nv50_display_flip_stop(crtc);
> > > -			nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> > > +			nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
> > >  		}
> > >  	}
> > >  
> > > @@ -1028,7 +1028,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
> > >  	}
> > >  
> > >  	nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
> > > -	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> > > +	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
> > >  }
> > >  
> > >  static bool
> > > @@ -1042,7 +1042,8 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
> > >  static int
> > >  nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
> > >  {
> > > -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
> > > +	struct nouveau_framebuffer *nvfb =
> > > +		nouveau_framebuffer(crtc->primary->fb);
> > >  	struct nv50_head *head = nv50_head(crtc);
> > >  	int ret;
> > >  
> > > @@ -1139,7 +1140,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
> > >  	nv50_crtc_set_dither(nv_crtc, false);
> > >  	nv50_crtc_set_scale(nv_crtc, false);
> > >  	nv50_crtc_set_color_vibrance(nv_crtc, false);
> > > -	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
> > > +	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
> > >  	return 0;
> > >  }
> > >  
> > > @@ -1151,7 +1152,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> > >  	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
> > >  	int ret;
> > >  
> > > -	if (!crtc->fb) {
> > > +	if (!crtc->primary->fb) {
> > >  		NV_DEBUG(drm, "No FB bound\n");
> > >  		return 0;
> > >  	}
> > > @@ -1161,8 +1162,8 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> > >  		return ret;
> > >  
> > >  	nv50_display_flip_stop(crtc);
> > > -	nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
> > > -	nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
> > > +	nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
> > > +	nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
> > >  	return 0;
> > >  }
> > >  
> > > diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> > > index 24b6112..5be0b87 100644
> > > --- a/drivers/gpu/drm/qxl/qxl_display.c
> > > +++ b/drivers/gpu/drm/qxl/qxl_display.c
> > > @@ -527,7 +527,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
> > >  	bool recreate_primary = false;
> > >  	int ret;
> > >  	int surf_id;
> > > -	if (!crtc->fb) {
> > > +	if (!crtc->primary->fb) {
> > >  		DRM_DEBUG_KMS("No FB bound\n");
> > >  		return 0;
> > >  	}
> > > @@ -536,7 +536,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
> > >  		qfb = to_qxl_framebuffer(old_fb);
> > >  		old_bo = gem_to_qxl_bo(qfb->obj);
> > >  	}
> > > -	qfb = to_qxl_framebuffer(crtc->fb);
> > > +	qfb = to_qxl_framebuffer(crtc->primary->fb);
> > >  	bo = gem_to_qxl_bo(qfb->obj);
> > >  	if (!m)
> > >  		/* and do we care? */
> > > @@ -609,14 +609,15 @@ static void qxl_crtc_disable(struct drm_crtc *crtc)
> > >  	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
> > >  	struct drm_device *dev = crtc->dev;
> > >  	struct qxl_device *qdev = dev->dev_private;
> > > -	if (crtc->fb) {
> > > -		struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb);
> > > +	if (crtc->primary->fb) {
> > > +		struct qxl_framebuffer *qfb =
> > > +			to_qxl_framebuffer(crtc->primary->fb);
> > >  		struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
> > >  		int ret;
> > >  		ret = qxl_bo_reserve(bo, false);
> > >  		qxl_bo_unpin(bo);
> > >  		qxl_bo_unreserve(bo);
> > > -		crtc->fb = NULL;
> > > +		crtc->primary->fb = NULL;
> > >  	}
> > >  
> > >  	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
> > > diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
> > > index daa4dd3..fb187c7 100644
> > > --- a/drivers/gpu/drm/radeon/atombios_crtc.c
> > > +++ b/drivers/gpu/drm/radeon/atombios_crtc.c
> > > @@ -1106,7 +1106,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
> > >  	int r;
> > >  
> > >  	/* no fb bound */
> > > -	if (!atomic && !crtc->fb) {
> > > +	if (!atomic && !crtc->primary->fb) {
> > >  		DRM_DEBUG_KMS("No FB bound\n");
> > >  		return 0;
> > >  	}
> > > @@ -1116,8 +1116,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
> > >  		target_fb = fb;
> > >  	}
> > >  	else {
> > > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > > -		target_fb = crtc->fb;
> > > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > > +		target_fb = crtc->primary->fb;
> > >  	}
> > >  
> > >  	/* If atomic, assume fb object is pinned & idle & fenced and
> > > @@ -1316,7 +1316,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
> > >  	/* set pageflip to happen anywhere in vblank interval */
> > >  	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
> > >  
> > > -	if (!atomic && fb && fb != crtc->fb) {
> > > +	if (!atomic && fb && fb != crtc->primary->fb) {
> > >  		radeon_fb = to_radeon_framebuffer(fb);
> > >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> > >  		r = radeon_bo_reserve(rbo, false);
> > > @@ -1350,7 +1350,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
> > >  	int r;
> > >  
> > >  	/* no fb bound */
> > > -	if (!atomic && !crtc->fb) {
> > > +	if (!atomic && !crtc->primary->fb) {
> > >  		DRM_DEBUG_KMS("No FB bound\n");
> > >  		return 0;
> > >  	}
> > > @@ -1360,8 +1360,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
> > >  		target_fb = fb;
> > >  	}
> > >  	else {
> > > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > > -		target_fb = crtc->fb;
> > > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > > +		target_fb = crtc->primary->fb;
> > >  	}
> > >  
> > >  	obj = radeon_fb->obj;
> > > @@ -1485,7 +1485,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
> > >  	/* set pageflip to happen anywhere in vblank interval */
> > >  	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
> > >  
> > > -	if (!atomic && fb && fb != crtc->fb) {
> > > +	if (!atomic && fb && fb != crtc->primary->fb) {
> > >  		radeon_fb = to_radeon_framebuffer(fb);
> > >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> > >  		r = radeon_bo_reserve(rbo, false);
> > > @@ -1972,12 +1972,12 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
> > >  	int i;
> > >  
> > >  	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> > > -	if (crtc->fb) {
> > > +	if (crtc->primary->fb) {
> > >  		int r;
> > >  		struct radeon_framebuffer *radeon_fb;
> > >  		struct radeon_bo *rbo;
> > >  
> > > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> > >  		r = radeon_bo_reserve(rbo, false);
> > >  		if (unlikely(r))
> > > diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
> > > index 030f8e4..b6c3264 100644
> > > --- a/drivers/gpu/drm/radeon/r100.c
> > > +++ b/drivers/gpu/drm/radeon/r100.c
> > > @@ -3220,12 +3220,12 @@ void r100_bandwidth_update(struct radeon_device *rdev)
> > >  
> > >  	if (rdev->mode_info.crtcs[0]->base.enabled) {
> > >  		mode1 = &rdev->mode_info.crtcs[0]->base.mode;
> > > -		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8;
> > > +		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;
> > > -			pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8;
> > > +			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 82d4f86..33b482b 100644
> > > --- a/drivers/gpu/drm/radeon/radeon_connectors.c
> > > +++ b/drivers/gpu/drm/radeon/radeon_connectors.c
> > > @@ -89,7 +89,7 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)
> > >  
> > >  	if (crtc && crtc->enabled) {
> > >  		drm_crtc_helper_set_mode(crtc, &crtc->mode,
> > > -					 crtc->x, crtc->y, crtc->fb);
> > > +					 crtc->x, crtc->y, crtc->primary->fb);
> > >  	}
> > >  }
> > >  
> > > diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
> > > index 2e72dcd..c524aba 100644
> > > --- a/drivers/gpu/drm/radeon/radeon_device.c
> > > +++ b/drivers/gpu/drm/radeon/radeon_device.c
> > > @@ -1424,7 +1424,8 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
> > >  
> > >  	/* unpin the front buffers */
> > >  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> > > -		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
> > > +		struct radeon_framebuffer *rfb =
> > > +			to_radeon_framebuffer(crtc->primary->fb);
> > >  		struct radeon_bo *robj;
> > >  
> > >  		if (rfb == NULL || rfb->obj == NULL) {
> > > diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> > > index a29d217..4e90049 100644
> > > --- a/drivers/gpu/drm/radeon/radeon_display.c
> > > +++ b/drivers/gpu/drm/radeon/radeon_display.c
> > > @@ -369,7 +369,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
> > >  	work->event = event;
> > >  	work->rdev = rdev;
> > >  	work->crtc_id = radeon_crtc->crtc_id;
> > > -	old_radeon_fb = to_radeon_framebuffer(crtc->fb);
> > > +	old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > >  	new_radeon_fb = to_radeon_framebuffer(fb);
> > >  	/* schedule unpin of the old buffer */
> > >  	obj = old_radeon_fb->obj;
> > > @@ -460,7 +460,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
> > >  	spin_unlock_irqrestore(&dev->event_lock, flags);
> > >  
> > >  	/* update crtc fb */
> > > -	crtc->fb = fb;
> > > +	crtc->primary->fb = fb;
> > >  
> > >  	r = drm_vblank_get(dev, radeon_crtc->crtc_id);
> > >  	if (r) {
> > > diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> > > index 0b158f9..cafb1cc 100644
> > > --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> > > +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
> > > @@ -385,7 +385,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
> > >  
> > >  	DRM_DEBUG_KMS("\n");
> > >  	/* no fb bound */
> > > -	if (!atomic && !crtc->fb) {
> > > +	if (!atomic && !crtc->primary->fb) {
> > >  		DRM_DEBUG_KMS("No FB bound\n");
> > >  		return 0;
> > >  	}
> > > @@ -395,8 +395,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
> > >  		target_fb = fb;
> > >  	}
> > >  	else {
> > > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > > -		target_fb = crtc->fb;
> > > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > > +		target_fb = crtc->primary->fb;
> > >  	}
> > >  
> > >  	switch (target_fb->bits_per_pixel) {
> > > @@ -444,7 +444,7 @@ retry:
> > >  		 * We don't shutdown the display controller because new buffer
> > >  		 * will end up in same spot.
> > >  		 */
> > > -		if (!atomic && fb && fb != crtc->fb) {
> > > +		if (!atomic && fb && fb != crtc->primary->fb) {
> > >  			struct radeon_bo *old_rbo;
> > >  			unsigned long nsize, osize;
> > >  
> > > @@ -555,7 +555,7 @@ retry:
> > >  	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
> > >  	WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
> > >  
> > > -	if (!atomic && fb && fb != crtc->fb) {
> > > +	if (!atomic && fb && fb != crtc->primary->fb) {
> > >  		radeon_fb = to_radeon_framebuffer(fb);
> > >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> > >  		r = radeon_bo_reserve(rbo, false);
> > > @@ -599,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
> > >  		}
> > >  	}
> > >  
> > > -	switch (crtc->fb->bits_per_pixel) {
> > > +	switch (crtc->primary->fb->bits_per_pixel) {
> > >  	case 8:
> > >  		format = 2;
> > >  		break;
> > > @@ -1087,12 +1087,12 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
> > >  static void radeon_crtc_disable(struct drm_crtc *crtc)
> > >  {
> > >  	radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> > > -	if (crtc->fb) {
> > > +	if (crtc->primary->fb) {
> > >  		int r;
> > >  		struct radeon_framebuffer *radeon_fb;
> > >  		struct radeon_bo *rbo;
> > >  
> > > -		radeon_fb = to_radeon_framebuffer(crtc->fb);
> > > +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
> > >  		rbo = gem_to_radeon_bo(radeon_fb->obj);
> > >  		r = radeon_bo_reserve(rbo, false);
> > >  		if (unlikely(r))
> > > diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> > > index 1255944..c63b5e7 100644
> > > --- a/drivers/gpu/drm/udl/udl_modeset.c
> > > +++ b/drivers/gpu/drm/udl/udl_modeset.c
> > > @@ -310,7 +310,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
> > >  
> > >  {
> > >  	struct drm_device *dev = crtc->dev;
> > > -	struct udl_framebuffer *ufb = to_udl_fb(crtc->fb);
> > > +	struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb);
> > >  	struct udl_device *udl = dev->dev_private;
> > >  	char *buf;
> > >  	char *wrptr;
> > > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> > > index 8a65041..1d59ed3 100644
> > > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> > > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> > > @@ -468,7 +468,7 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
> > >  	num_units = 0;
> > >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
> > >  			    head) {
> > > -		if (crtc->fb != &framebuffer->base)
> > > +		if (crtc->primary->fb != &framebuffer->base)
> > >  			continue;
> > >  		units[num_units++] = vmw_crtc_to_du(crtc);
> > >  	}
> > > @@ -883,7 +883,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
> > >  
> > >  	num_units = 0;
> > >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> > > -		if (crtc->fb != &framebuffer->base)
> > > +		if (crtc->primary->fb != &framebuffer->base)
> > >  			continue;
> > >  		units[num_units++] = vmw_crtc_to_du(crtc);
> > >  	}
> > > @@ -1245,7 +1245,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
> > >  
> > >  	num_units = 0;
> > >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> > > -		if (crtc->fb != &vfb->base)
> > > +		if (crtc->primary->fb != &vfb->base)
> > >  			continue;
> > >  		units[num_units++] = vmw_crtc_to_du(crtc);
> > >  	}
> > > @@ -1382,7 +1382,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
> > >  
> > >  	num_units = 0;
> > >  	list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
> > > -		if (crtc->fb != &vfb->base)
> > > +		if (crtc->primary->fb != &vfb->base)
> > >  			continue;
> > >  		units[num_units++] = vmw_crtc_to_du(crtc);
> > >  	}
> > > @@ -1725,7 +1725,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
> > >  		     uint32_t page_flip_flags)
> > >  {
> > >  	struct vmw_private *dev_priv = vmw_priv(crtc->dev);
> > > -	struct drm_framebuffer *old_fb = crtc->fb;
> > > +	struct drm_framebuffer *old_fb = crtc->primary->fb;
> > >  	struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
> > >  	struct drm_file *file_priv ;
> > >  	struct vmw_fence_obj *fence = NULL;
> > > @@ -1743,7 +1743,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
> > >  	if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
> > >  		return -EINVAL;
> > >  
> > > -	crtc->fb = fb;
> > > +	crtc->primary->fb = fb;
> > >  
> > >  	/* do a full screen dirty update */
> > >  	clips.x1 = clips.y1 = 0;
> > > @@ -1783,7 +1783,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
> > >  	return ret;
> > >  
> > >  out_no_fence:
> > > -	crtc->fb = old_fb;
> > > +	crtc->primary->fb = old_fb;
> > >  	return ret;
> > >  }
> > >  
> > > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> > > index 001ec81..08fdd7f 100644
> > > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> > > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> > > @@ -93,7 +93,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
> > >  
> > >  		if (crtc == NULL)
> > >  			return 0;
> > > -		fb = entry->base.crtc.fb;
> > > +		fb = entry->base.crtc.primary->fb;
> > >  
> > >  		return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0],
> > >  					  fb->bits_per_pixel, fb->depth);
> > > @@ -101,7 +101,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
> > >  
> > >  	if (!list_empty(&lds->active)) {
> > >  		entry = list_entry(lds->active.next, typeof(*entry), active);
> > > -		fb = entry->base.crtc.fb;
> > > +		fb = entry->base.crtc.primary->fb;
> > >  
> > >  		vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0],
> > >  				   fb->bits_per_pixel, fb->depth);
> > > @@ -259,7 +259,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
> > >  
> > >  		connector->encoder = NULL;
> > >  		encoder->crtc = NULL;
> > > -		crtc->fb = NULL;
> > > +		crtc->primary->fb = NULL;
> > >  		crtc->enabled = false;
> > >  
> > >  		vmw_ldu_del_active(dev_priv, ldu);
> > > @@ -280,7 +280,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
> > >  
> > >  	vmw_fb_off(dev_priv);
> > >  
> > > -	crtc->fb = fb;
> > > +	crtc->primary->fb = fb;
> > >  	encoder->crtc = crtc;
> > >  	connector->encoder = encoder;
> > >  	crtc->x = set->x;
> > > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> > > index 585da43..46ea096 100644
> > > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> > > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> > > @@ -307,7 +307,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
> > >  
> > >  		connector->encoder = NULL;
> > >  		encoder->crtc = NULL;
> > > -		crtc->fb = NULL;
> > > +		crtc->primary->fb = NULL;
> > >  		crtc->x = 0;
> > >  		crtc->y = 0;
> > >  		crtc->enabled = false;
> > > @@ -368,7 +368,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
> > >  
> > >  		connector->encoder = NULL;
> > >  		encoder->crtc = NULL;
> > > -		crtc->fb = NULL;
> > > +		crtc->primary->fb = NULL;
> > >  		crtc->x = 0;
> > >  		crtc->y = 0;
> > >  		crtc->enabled = false;
> > > @@ -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;
> > > -	crtc->fb = fb;
> > > +	crtc->primary->fb = fb;
> > >  	crtc->x = set->x;
> > >  	crtc->y = set->y;
> > >  	crtc->enabled = true;
> > > @@ -574,5 +574,5 @@ void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
> > >  	BUG_ON(!sou->base.is_implicit);
> > >  
> > >  	dev_priv->sou_priv->implicit_fb =
> > > -		vmw_framebuffer_to_vfb(sou->base.crtc.fb);
> > > +		vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
> > >  }
> > > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> > > index 4dc84f8..9f7824d 100644
> > > --- a/include/drm/drm_crtc.h
> > > +++ b/include/drm/drm_crtc.h
> > > @@ -309,9 +309,6 @@ struct drm_crtc {
> > >  	/* primary plane for CRTC */
> > >  	struct drm_plane *primary;
> > >  
> > > -	/* framebuffer the connector is currently bound to */
> > > -	struct drm_framebuffer *fb;
> > > -
> > >  	/* Temporary tracking of the old fb while a modeset is ongoing. Used
> > >  	 * by drm_mode_set_config_internal to implement correct refcounting. */
> > >  	struct drm_framebuffer *old_fb;
> > > -- 
> > > 1.8.5.1
> > > 
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> 
> -- 
> Matt Roper
> Graphics Software Engineer
> ISG Platform Enabling & Development
> Intel Corporation
> (916) 356-2795

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization
  2014-03-19  0:22 ` [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization Matt Roper
@ 2014-03-28 21:04   ` Daniel Vetter
  2014-04-07 10:05     ` Thierry Reding
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2014-03-28 21:04 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Mar 18, 2014 at 05:22:57PM -0700, Matt Roper wrote:
> Add cursor plane as a parameter to drm_crtc_init() and update all
> existing DRM drivers to use a helper-provided primary plane.  Passing
> NULL for this parameter indicates that there is no hardware cursor
> supported by the driver and no cursor plane should be provided to
> userspace.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Ok, cursor planes. I've poked around in this a lot and unfortunately I
don't think we can achieve nirvana :(

The first direction is automatically getting cursor plane support from
existing drivers using the existing callbacks. The irky thing is that we
don't have any means to sanely unwrap the framebuffer since both the bo
handle used by the legacy cursor ioctl and how a framebuffer would wrap
such a handle isn't generic. And e.g. vmwgfx doesn't even use gem for
those.

So I think we'll have to give up on that and drivers which want to expose
cursors with the atomic ioctls simply have to have proper support.

The other direction is that converted drivers don't need to have support
for legacy ioctls should be possible and is imo something we want - at
least for i915 I don't want to carry around two interfaces doing the same.

Which means we need some way to forward the legacy cursor ioctls to the
new plane callbacks exposed when using cursor planes. Unfortunately we
have a bit an api mismatch between the legacy cursor interfaces:

int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv,
		   uint32_t handle, uint32_t width, uint32_t height,
		   int32_t hot_x, int32_t hot_y);
int (*cursor_move)(struct drm_crtc *crtc, int x, int y);

And the plane interfaces:

int (*update_plane)(struct drm_plane *plane,
		    struct drm_crtc *crtc, struct drm_framebuffer *fb,
		    int crtc_x, int crtc_y,
		    unsigned int crtc_w, unsigned int crtc_h,
		    uint32_t src_x, uint32_t src_y,
		    uint32_t src_w, uint32_t src_h);
int (*disable_plane)(struct drm_plane *plane);

cursor_set2 with handle == 0 simply maps to a disable_plane call. But any
other call of the legacy ioctls simply maps to an update_plane, but we
don't have all the information available all the time.

- width, height and handle isn't a real concern - we can just wrap this
  all up into a drm private drm framebuffer. As long as the only reference
  to that framebuffer is held by crtc->cursor->fb it will also get cleaned
  up at the right time and so won't extend the lifetime of the underlying
  buffer object. And we don't need to cache width/height anywhere since
  they're accessible through crtc->cursor->fb.

- For the pixel format I think it's ok to always assume RGBA.

- hot_x and hot_y can simply be mapped to new plane properties. I think
  it'd be good for this to be generally available, just to have a
  consistent interface.

- The x/y coordinates of cursor_move are more annoying - userspace
  potentially doesn't supply them, so we need to cache them in the crtc
  struct somewhere. Originally I've thought it would be good to have a
  special struct drm_cursor_plane and use that as the blessed cursor plane
  object in drm_crtc_init_with_planes. But that will wreak havoc with hw
  platforms which have fully unified planes and want to use the same
  struct everywhere. So I think we need to add crtc->cursor_x/y fields.

With these bits we should be able to always create a valid call to
update_plane. Which allows drivers to not implement the legacy
cursor_set/move interface. Of course we also need to go through the drm
core to make sure that all the cursor code also works when crtc->cursor is
set.

To make driver writers life as easy as possible I think we should provide
a default helper for their cursor_update_plane callback which checks that
the update_plane call is indeed valid for a cursor:

- Checks that widht == pitch*bpp since that's what we assume with cursors.

- Checks that there's no scaling going on.

- Checks that the viewport matches the full cursor size.

- Checks that there's no subpixel positioning.

With that the only thing drivers need to do is:
- Kill the handle to bo pointer lookup, just use the one wrapped up in the
  framebuffer object.
- Call the above helper.
- Call into the low-level set_cursor_bo/move_cursor functions - all the
  arguments of the old ioctls have a 1:1 mapping in update_plane, so this
  should be simple.

... and of course they need to set up the cursor plane object.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization
  2014-03-28 21:04   ` Daniel Vetter
@ 2014-04-07 10:05     ` Thierry Reding
  2014-04-07 17:23       ` Rob Clark
  0 siblings, 1 reply; 46+ messages in thread
From: Thierry Reding @ 2014-04-07 10:05 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 1135 bytes --]

On Fri, Mar 28, 2014 at 10:04:09PM +0100, Daniel Vetter wrote:
> On Tue, Mar 18, 2014 at 05:22:57PM -0700, Matt Roper wrote:
> > Add cursor plane as a parameter to drm_crtc_init() and update all
> > existing DRM drivers to use a helper-provided primary plane.  Passing
> > NULL for this parameter indicates that there is no hardware cursor
> > supported by the driver and no cursor plane should be provided to
> > userspace.
> > 
> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> 
> Ok, cursor planes. I've poked around in this a lot and unfortunately I
> don't think we can achieve nirvana :(
[...]
> - For the pixel format I think it's ok to always assume RGBA.

How so? We do have hardware on Tegra that doesn't support RGBA cursors
and if at all possible I'd very much like to support that as well. New
generations can do RGBA but still support the old pixel format. Having
the option of supporting all formats would be nice.

There was some discussion about implementing a bunch of plane properties
so I think having one to enumerate a set of pixel formats wouldn't be
such a big deal.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization
  2014-04-07 10:05     ` Thierry Reding
@ 2014-04-07 17:23       ` Rob Clark
  2014-04-07 20:03         ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Rob Clark @ 2014-04-07 17:23 UTC (permalink / raw)
  To: Thierry Reding; +Cc: dri-devel

On Mon, Apr 7, 2014 at 6:05 AM, Thierry Reding <thierry.reding@gmail.com> wrote:
> On Fri, Mar 28, 2014 at 10:04:09PM +0100, Daniel Vetter wrote:
>> On Tue, Mar 18, 2014 at 05:22:57PM -0700, Matt Roper wrote:
>> > Add cursor plane as a parameter to drm_crtc_init() and update all
>> > existing DRM drivers to use a helper-provided primary plane.  Passing
>> > NULL for this parameter indicates that there is no hardware cursor
>> > supported by the driver and no cursor plane should be provided to
>> > userspace.
>> >
>> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
>>
>> Ok, cursor planes. I've poked around in this a lot and unfortunately I
>> don't think we can achieve nirvana :(
> [...]
>> - For the pixel format I think it's ok to always assume RGBA.
>
> How so? We do have hardware on Tegra that doesn't support RGBA cursors
> and if at all possible I'd very much like to support that as well. New
> generations can do RGBA but still support the old pixel format. Having
> the option of supporting all formats would be nice.
>
> There was some discussion about implementing a bunch of plane properties
> so I think having one to enumerate a set of pixel formats wouldn't be
> such a big deal.

No need for properties to expose formats, we already have that in
getplane ioctl.  But would be nice to support more than just RGBA.

BR,
-R

> Thierry
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization
  2014-04-07 17:23       ` Rob Clark
@ 2014-04-07 20:03         ` Daniel Vetter
  2014-04-07 20:05           ` Rob Clark
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2014-04-07 20:03 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Mon, Apr 7, 2014 at 7:23 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Mon, Apr 7, 2014 at 6:05 AM, Thierry Reding <thierry.reding@gmail.com> wrote:
>> On Fri, Mar 28, 2014 at 10:04:09PM +0100, Daniel Vetter wrote:
>>> On Tue, Mar 18, 2014 at 05:22:57PM -0700, Matt Roper wrote:
>>> > Add cursor plane as a parameter to drm_crtc_init() and update all
>>> > existing DRM drivers to use a helper-provided primary plane.  Passing
>>> > NULL for this parameter indicates that there is no hardware cursor
>>> > supported by the driver and no cursor plane should be provided to
>>> > userspace.
>>> >
>>> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
>>>
>>> Ok, cursor planes. I've poked around in this a lot and unfortunately I
>>> don't think we can achieve nirvana :(
>> [...]
>>> - For the pixel format I think it's ok to always assume RGBA.
>>
>> How so? We do have hardware on Tegra that doesn't support RGBA cursors
>> and if at all possible I'd very much like to support that as well. New
>> generations can do RGBA but still support the old pixel format. Having
>> the option of supporting all formats would be nice.
>>
>> There was some discussion about implementing a bunch of plane properties
>> so I think having one to enumerate a set of pixel formats wouldn't be
>> such a big deal.
>
> No need for properties to expose formats, we already have that in
> getplane ioctl.  But would be nice to support more than just RGBA.

This is _just_ for the compat cursor plane setup helper. Of course we
can add whatever insane cursor formats exist out there as fourcc codes
and then drivers can add them for their custom-created cursor planes.
This is similar to the current primary plane helper code which only
exposes 32bit XRGB atm. If you want to take full advantage of this you
need to do a bit of work in your driver ;-)
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization
  2014-04-07 20:03         ` Daniel Vetter
@ 2014-04-07 20:05           ` Rob Clark
  0 siblings, 0 replies; 46+ messages in thread
From: Rob Clark @ 2014-04-07 20:05 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Mon, Apr 7, 2014 at 4:03 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Mon, Apr 7, 2014 at 7:23 PM, Rob Clark <robdclark@gmail.com> wrote:
>> On Mon, Apr 7, 2014 at 6:05 AM, Thierry Reding <thierry.reding@gmail.com> wrote:
>>> On Fri, Mar 28, 2014 at 10:04:09PM +0100, Daniel Vetter wrote:
>>>> On Tue, Mar 18, 2014 at 05:22:57PM -0700, Matt Roper wrote:
>>>> > Add cursor plane as a parameter to drm_crtc_init() and update all
>>>> > existing DRM drivers to use a helper-provided primary plane.  Passing
>>>> > NULL for this parameter indicates that there is no hardware cursor
>>>> > supported by the driver and no cursor plane should be provided to
>>>> > userspace.
>>>> >
>>>> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
>>>>
>>>> Ok, cursor planes. I've poked around in this a lot and unfortunately I
>>>> don't think we can achieve nirvana :(
>>> [...]
>>>> - For the pixel format I think it's ok to always assume RGBA.
>>>
>>> How so? We do have hardware on Tegra that doesn't support RGBA cursors
>>> and if at all possible I'd very much like to support that as well. New
>>> generations can do RGBA but still support the old pixel format. Having
>>> the option of supporting all formats would be nice.
>>>
>>> There was some discussion about implementing a bunch of plane properties
>>> so I think having one to enumerate a set of pixel formats wouldn't be
>>> such a big deal.
>>
>> No need for properties to expose formats, we already have that in
>> getplane ioctl.  But would be nice to support more than just RGBA.
>
> This is _just_ for the compat cursor plane setup helper. Of course we
> can add whatever insane cursor formats exist out there as fourcc codes
> and then drivers can add them for their custom-created cursor planes.
> This is similar to the current primary plane helper code which only
> exposes 32bit XRGB atm. If you want to take full advantage of this you
> need to do a bit of work in your driver ;-)

oh, heh.. should have read the whole thread first :-P

yeah, for compat helpers, only ARGB makes sense

BR,
-R


> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2014-04-07 20:05 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-19  0:22 [RFCv3 00/14] Unified plane support Matt Roper
2014-03-19  0:22 ` [RFCv3 01/14] SQUASH! drm/i915: Do not dereference pointers from ring buffer in evict event Matt Roper
2014-03-19  0:22 ` [RFCv3 02/14] drm: Add support for multiple plane types Matt Roper
2014-03-19  0:22 ` [RFCv3 03/14] drm: Add primary plane helpers Matt Roper
2014-03-19 11:28   ` Daniel Vetter
2014-03-19 12:56     ` Rob Clark
2014-03-19 18:15     ` Matt Roper
2014-03-19 19:29       ` Daniel Vetter
2014-03-19 11:50   ` Daniel Vetter
2014-03-19 12:24   ` Daniel Vetter
2014-03-19 23:01     ` Matt Roper
2014-03-20 12:39       ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 04/14] drm/exynos: Restrict plane loops to only operate on overlay planes Matt Roper
2014-03-19 11:51   ` Daniel Vetter
2014-03-19 14:26     ` Daniel Kurtz
2014-03-19 19:31       ` Daniel Vetter
2014-03-20  1:56         ` Daniel Kurtz
2014-03-20 15:35           ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 05/14] drm/i915: " Matt Roper
2014-03-19  0:22 ` [RFCv3 06/14] drm: Add plane type property Matt Roper
2014-03-19 11:31   ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 07/14] drm: Specify primary plane at CRTC initialization (v2) Matt Roper
2014-03-19 11:41   ` Daniel Vetter
2014-03-20  5:43   ` Inki Dae
2014-03-20 15:38     ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 08/14] drm: Replace crtc fb with primary plane fb (v2) Matt Roper
2014-03-19 11:57   ` Daniel Vetter
2014-03-25  1:20     ` Matt Roper
2014-03-25 10:32       ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 09/14] drm: Allow userspace to ask for full plane list (universal planes) Matt Roper
2014-03-19 14:27   ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 10/14] drm/i915: Rename similar plane functions to avoid confusion Matt Roper
2014-03-19 12:05   ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 11/14] drm/i915: Intel-specific primary plane handling Matt Roper
2014-03-19 12:11   ` [Intel-gfx] " Daniel Vetter
2014-03-19 14:37     ` Daniel Vetter
2014-03-19  0:22 ` [RFCv3 12/14] drm: Specify cursor plane at CRTC initialization Matt Roper
2014-03-28 21:04   ` Daniel Vetter
2014-04-07 10:05     ` Thierry Reding
2014-04-07 17:23       ` Rob Clark
2014-04-07 20:03         ` Daniel Vetter
2014-04-07 20:05           ` Rob Clark
2014-03-19  0:22 ` [RFCv3 13/14] drm/i915: Split cursor update code from cursor ioctl handling Matt Roper
2014-03-19  8:03   ` Chris Wilson
2014-03-19  0:22 ` [RFCv3 14/14] drm/i915: Add cursor handlers and create cursor at crtc init Matt Roper
2014-03-19  0:37 ` [RFCv3 00/14] Unified plane support Rob Clark

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.