All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv4 00/13] Universal plane preparation patches
@ 2014-03-28  0:44 Matt Roper
  2014-03-28  0:44 ` [PATCHv4 01/13] drm: Add support for multiple plane types (v2) Matt Roper
                   ` (13 more replies)
  0 siblings, 14 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

Previous series revisions & explanation at [1], [2], and [3]

This version of the patch series focuses on isolating the DRM core changes from
individual driver changes to (hopefully) make this a bit easier to merge.  New
plane and crtc initialization functions have been added to allow drivers to
migrate to the new infrastructure at their own pace; existing drivers that do
not update should continue to function as expected.  The one remaining painful
patch here is patch #12, which replaces crtc->fb with crtc->primary->fb.  That
patch is now auto-generated via a Coccinelle semantic patch with the rules
described in the commit message; hopefully that will make life slightly easier
for tree maintainers who want to pull it in.

Daniel mentioned that we should try to merge the underlying infrastructure here
without the actual userspace-facing capability bit to make sure things continue
to run as expected without breaking; I've dropped the capability bit patch for
now, but the previous version from [4] should work on top of this patch set.
I've also dropped the i915 cursor support for the moment to keep the patch set
simple.

I believe the only userspace-visible changes in this series are the plane type
property (which will always return "overlay" since there's no switch to turn on
the other plane types) and max width/height plane properties.  I figured
properties were a little bit cleaner than extending GetPlane() to return
additional information, although I can change that if people feel differently.
Presumably we're still going to need a lot more properties that describe the
limits and capabilities of planes as we go forward (stride, scaling, tiling,
etc.)

[1] http://lists.freedesktop.org/archives/dri-devel/2014-March/055855.html
[2] http://lists.freedesktop.org/archives/dri-devel/2014-March/055222.html
[3] http://lists.freedesktop.org/archives/dri-devel/2014-February/054719.html
[4] http://lists.freedesktop.org/archives/dri-devel/2014-March/055216.html

Matt Roper (13):
  drm: Add support for multiple plane types (v2)
  drm/exynos: Restrict plane loops to only operate on overlay planes
    (v2)
  drm/i915: Restrict plane loops to only operate on overlay planes (v2)
  drm/shmobile: Restrict plane loops to only operate on legacy planes
  drm: Make drm_crtc_check_viewport non-static
  drm: Add primary plane helpers (v2)
  drm: Add drm_universal_plane_init()
  drm: Add plane type property (v2)
  drm: Add plane max width/height properties
  drm: Add drm_crtc_init_with_planes()
  drm/msm: Switch to universal plane API's
  drm: Replace crtc fb with primary plane fb (v3)
  drm: Remove unused drm_crtc->fb

 drivers/gpu/drm/Makefile                     |   3 +-
 drivers/gpu/drm/armada/armada_crtc.c         |  23 +-
 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                   | 228 ++++++++++++++++----
 drivers/gpu/drm/drm_crtc_helper.c            |  20 +-
 drivers/gpu/drm/drm_fb_helper.c              |   9 +-
 drivers/gpu/drm/drm_plane_helper.c           | 312 +++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_crtc.c     |  22 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c  |   2 +-
 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      |   2 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
 drivers/gpu/drm/gma500/gma_display.c         |  16 +-
 drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
 drivers/gpu/drm/gma500/mdfld_intel_display.c |  16 +-
 drivers/gpu/drm/gma500/oaktrail_crtc.c       |  12 +-
 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         | 148 +++++++------
 drivers/gpu/drm/i915/intel_dp.c              |   4 +-
 drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
 drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
 drivers/gpu/drm/i915/intel_pm.c              |  38 ++--
 drivers/gpu/drm/mgag200/mgag200_mode.c       |  26 +--
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  33 +--
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c    |   8 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  27 +--
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c    |   8 +-
 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/omapdrm/omap_crtc.c          |  10 +-
 drivers/gpu/drm/omapdrm/omap_fb.c            |   2 +-
 drivers/gpu/drm/qxl/qxl_display.c            |  10 +-
 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       |   2 +-
 drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
 drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +-
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c       |  10 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c    |  16 +-
 drivers/gpu/drm/tegra/dc.c                   |  16 +-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c         |   8 +-
 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 +-
 drivers/staging/imx-drm/ipuv3-crtc.c         |   6 +-
 include/drm/drm_crtc.h                       |  52 ++++-
 include/drm/drm_plane_helper.h               |  49 +++++
 58 files changed, 940 insertions(+), 381 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_plane_helper.c
 create mode 100644 include/drm/drm_plane_helper.h

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

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

* [PATCHv4 01/13] drm: Add support for multiple plane types (v2)
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  0:44 ` [PATCHv4 02/13] drm/exynos: Restrict plane loops to only operate on overlay planes (v2) Matt Roper
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 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.

v2: Add drm_for_each_legacy_plane() iterator to smooth transition
    of drivers with plane loops.

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          | 24 +++++++++++++++++++++++-
 3 files changed, 41 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 16f271e..f30bf7b 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..3894f85 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;
@@ -1036,4 +1053,9 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
 	return mo ? obj_to_encoder(mo) : NULL;
 }
 
+/* Plane list iterator for legacy (overlay only) planes. */
+#define drm_for_each_legacy_plane(plane, planelist) \
+	list_for_each_entry(plane, planelist, head) \
+		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+
 #endif /* __DRM_CRTC_H__ */
-- 
1.8.5.1

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

* [PATCHv4 02/13] drm/exynos: Restrict plane loops to only operate on overlay planes (v2)
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
  2014-03-28  0:44 ` [PATCHv4 01/13] drm: Add support for multiple plane types (v2) Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  0:44 ` [PATCHv4 03/13] drm/i915: " Matt Roper
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

Ensure that existing driver loops over all planes do not change behavior
when we begin adding new types of planes (primary and cursor) to the DRM
plane list in future patches.

v2: Switch to using drm_for_each_legacy_plane()

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

diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 9cc92ae..c70b380 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -190,7 +190,7 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
 
 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 
-	list_for_each_entry(plane, &crtc->dev->mode_config.plane_list, head) {
+	drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list, head) {
 		if (plane->crtc != crtc)
 			continue;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 835c0f1..7e282e3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -101,7 +101,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
 	exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
 	/* all planes connected to this encoder should be also disabled. */
-	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
 		if (plane->crtc == encoder->crtc)
 			plane->funcs->disable_plane(plane);
 	}
-- 
1.8.5.1

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

* [PATCHv4 03/13] drm/i915: Restrict plane loops to only operate on overlay planes (v2)
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
  2014-03-28  0:44 ` [PATCHv4 01/13] drm: Add support for multiple plane types (v2) Matt Roper
  2014-03-28  0:44 ` [PATCHv4 02/13] drm/exynos: Restrict plane loops to only operate on overlay planes (v2) Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  0:44 ` [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes Matt Roper
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel; +Cc: Intel Graphics Development

Ensure that existing driver loops over all planes do not change behavior
when we begin adding new types of planes (primary and cursor) to the DRM
plane list in future patches.

v2: Switch to using drm_for_each_legacy_plane()

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 | 10 ++++++++--
 drivers/gpu/drm/i915/intel_pm.c      |  2 +-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e0a87aa..69591db 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3536,22 +3536,28 @@ static void intel_enable_planes(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+	struct drm_plane *plane;
 	struct intel_plane *intel_plane;
 
-	list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
+		intel_plane = to_intel_plane(plane);
 		if (intel_plane->pipe == pipe)
 			intel_plane_restore(&intel_plane->base);
+	}
 }
 
 static void intel_disable_planes(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+	struct drm_plane *plane;
 	struct intel_plane *intel_plane;
 
-	list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
+		intel_plane = to_intel_plane(plane);
 		if (intel_plane->pipe == pipe)
 			intel_plane_disable(&intel_plane->base);
+	}
 }
 
 void hsw_enable_ips(struct intel_crtc *crtc)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index b66a43b..2c78a8f 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2129,7 +2129,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
 		config->num_pipes_active += intel_crtc_active(crtc);
 
-	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
 		struct intel_plane *intel_plane = to_intel_plane(plane);
 
 		if (intel_plane->pipe == pipe)
-- 
1.8.5.1

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

* [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (2 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 03/13] drm/i915: " Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28 15:50   ` Laurent Pinchart
  2014-03-28  0:44 ` [PATCHv4 05/13] drm: Make drm_crtc_check_viewport non-static Matt Roper
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel; +Cc: Laurent Pinchart

Ensure that existing driver loops over all planes do not change behavior
when we begin adding new types of planes (primary and cursor) to the DRM
plane list in future patches.

Cc: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 0428076..ea543b4 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -247,7 +247,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
 	lcdc_write(sdev, LDDDSR, value);
 
 	/* Setup planes. */
-	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
 		if (plane->crtc == crtc)
 			shmob_drm_plane_setup(plane);
 	}
-- 
1.8.5.1

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

* [PATCHv4 05/13] drm: Make drm_crtc_check_viewport non-static
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (3 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  0:44 ` [PATCHv4 06/13] drm: Add primary plane helpers (v2) Matt Roper
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

This function will be used by the universal plane helpers and may also
be useful for individual drivers.

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

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0983996..12525c7 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2185,14 +2185,19 @@ 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)
+/**
+ * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
+ *     CRTC viewport
+ * @crtc: CRTC that framebuffer will be displayed on
+ * @x: x panning
+ * @y: y panning
+ * @mode: mode that framebuffer will be displayed under
+ * @fb: framebuffer to check size of
  */
-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 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;
@@ -2223,6 +2228,7 @@ static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
 
 	return 0;
 }
+EXPORT_SYMBOL(drm_crtc_check_viewport);
 
 /**
  * drm_mode_setcrtc - set CRTC configuration
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3894f85..2765a4e 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -882,6 +882,10 @@ extern int drm_plane_init(struct drm_device *dev,
 			  bool priv);
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern void drm_plane_force_disable(struct drm_plane *plane);
+extern 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);
 
 extern void drm_encoder_cleanup(struct drm_encoder *encoder);
 
-- 
1.8.5.1

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

* [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (4 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 05/13] drm: Make drm_crtc_check_viewport non-static Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  8:32   ` Daniel Vetter
  2014-03-28  0:44 ` [PATCHv4 07/13] drm: Add drm_universal_plane_init() Matt Roper
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 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 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.

v2:
 - Move plane helpers to a new file (drm_plane_helper.c)
 - Tighten checks on update handler (check for scaling, CRTC coverage,
   subpixel positioning)
 - Pass proper panning parameters to modeset interface
 - Disallow disabling primary plane (and thus CRTC) if other planes are
   still active on the CRTC.
 - Use a minimal format list that should work on all hardware/drivers.
   Drivers may call this function with a more accurate plane list to
   enable additional formats they can support.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/Makefile           |   3 +-
 drivers/gpu/drm/drm_plane_helper.c | 312 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_plane_helper.h     |  49 ++++++
 3 files changed, 363 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_plane_helper.c
 create mode 100644 include/drm/drm_plane_helper.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5e792b0..9d25dbb 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -13,7 +13,8 @@ drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
 		drm_crtc.o drm_modes.o drm_edid.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
-		drm_rect.o drm_vma_manager.o drm_flip_work.o
+		drm_rect.o drm_vma_manager.o drm_flip_work.o \
+		drm_plane_helper.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
new file mode 100644
index 0000000..374a98d
--- /dev/null
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * DRM universal plane helper functions
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/list.h>
+#include <drm/drmP.h>
+#include <drm/drm_rect.h>
+
+#define SUBPIXEL_MASK 0xffff
+
+/*
+ * This is the minimal list of formats that seem to be safe for modeset use
+ * with all current DRM drivers.  Most hardware can actually support more
+ * formats than this and drivers may specify a more accurate list when
+ * creating the primary plane.  However drivers that still call
+ * drm_plane_init() will use this minimal format list as the default.
+ */
+const static uint32_t safe_modeset_formats[] = {
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ARGB8888,
+};
+
+/*
+ * 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 modeset 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 make some assumptions about hardware limitations that may not be
+ * true for all hardware:
+ *   - primary plane cannot be repositioned
+ *   - primary plane cannot be scaled
+ *   - primary plane must cover the entire CRTC
+ *   - subpixel positioning is not supported
+ * 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 = src_x >> 16,
+		.y = src_y >> 16,
+	};
+	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,
+	};
+	struct drm_connector **connector_list;
+	struct drm_framebuffer *tmpfb;
+	int num_connectors, ret;
+
+	if (!crtc->enabled) {
+		DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n");
+		return -EINVAL;
+	}
+
+	/* Disallow subpixel positioning */
+	if ((src_x | src_y | src_w | src_h) & SUBPIXEL_MASK) {
+		DRM_DEBUG_KMS("Primary plane does not support subpixel positioning\n");
+		return -EINVAL;
+	}
+
+	/* 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;
+	}
+
+	/* Disallow scaling */
+	if (crtc_w != src_w || crtc_h != src_h) {
+		DRM_DEBUG_KMS("Can't scale primary plane\n");
+		return -EINVAL;
+	}
+
+	/* Make sure primary plane covers entire CRTC */
+	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;
+	}
+
+	/* Framebuffer must be big enough to cover entire plane */
+	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.
+	 *
+	 * N.B., we call set_config() directly here rather than using
+	 * drm_mode_set_config_internal.  We're reprogramming the same
+	 * connectors that were already in use, so we shouldn't need the extra
+	 * cross-CRTC fb refcounting to accomodate stealing connectors.
+	 * drm_mode_setplane() already handles the basic refcounting for the
+	 * framebuffers involved in this operation.
+	 */
+	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 if no other planes are currently enabled.
+ * If other planes are still enabled on the same CRTC, we return -EBUSY.
+ *
+ * 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_plane *p;
+	struct drm_mode_set set = {
+		.crtc = plane->crtc,
+		.fb = NULL,
+	};
+
+	if (plane->crtc == NULL || plane->fb == NULL)
+		/* Already disabled */
+		return 0;
+
+	list_for_each_entry(p, &plane->dev->mode_config.plane_list, head)
+		if (p != plane && p->fb) {
+			DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n");
+			return -EBUSY;
+		}
+
+	/*
+	 * N.B.  We call set_config() directly here rather than
+	 * drm_mode_set_config_internal() since drm_mode_setplane() already
+	 * handles the basic refcounting and we don't need the special
+	 * cross-CRTC refcounting (no chance of stealing connectors from
+	 * other CRTC's with this update).
+	 */
+	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
+ * @formats: pixel formats supported, or NULL for a default safe list
+ * @num_formats: size of @formats; ignored if @formats is NULL
+ *
+ * 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,
+						  const uint32_t *formats,
+						  int num_formats)
+{
+	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;
+	}
+
+	if (formats == NULL) {
+		formats = safe_modeset_formats;
+		num_formats = ARRAY_SIZE(safe_modeset_formats);
+	}
+
+	/* possible_crtc's will be filled in later by crtc_init */
+	ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
+			     formats, num_formats,
+			     DRM_PLANE_TYPE_PRIMARY);
+	if (ret) {
+		kfree(primary);
+		primary = NULL;
+	}
+
+	return primary;
+}
+EXPORT_SYMBOL(drm_primary_helper_create_plane);
+
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
new file mode 100644
index 0000000..09824be
--- /dev/null
+++ b/include/drm/drm_plane_helper.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011-2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef DRM_PLANE_HELPER_H
+#define DRM_PLANE_HELPER_H
+
+/**
+ * DOC: plane helpers
+ *
+ * Helper functions to assist with creation and handling of CRTC primary
+ * planes.
+ */
+
+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,
+							 uint32_t *formats,
+							 int num_formats);
+
+
+#endif
-- 
1.8.5.1

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

* [PATCHv4 07/13] drm: Add drm_universal_plane_init()
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (5 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 06/13] drm: Add primary plane helpers (v2) Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  0:44 ` [PATCHv4 08/13] drm: Add plane type property (v2) Matt Roper
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

Add a new plane initialization interface for universal plane support
that allows a specific plane type (primary, cursor, or overlay) to
be specified.

drm_plane_init() remains as a compatibility API to reduce churn in
existing drivers.  The 'bool priv' parameter has been changed to
'bool is_primary' under the assumption that all existing uses of
private planes were representing primary planes.

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

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 12525c7..42aea88 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1000,26 +1000,25 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
 EXPORT_SYMBOL(drm_encoder_cleanup);
 
 /**
- * drm_plane_init - Initialise a new plane object
+ * drm_universal_plane_init - Initialize a new universal plane object
  * @dev: DRM device
  * @plane: plane object to init
  * @possible_crtcs: bitmask of possible CRTCs
  * @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.
+ * Initializes a plane object of type @type.
  *
  * Returns:
  * Zero on success, error code on failure.
  */
-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)
+int drm_universal_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,
+			     enum drm_plane_type type)
 {
 	int ret;
 
@@ -1044,26 +1043,53 @@ 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);
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_universal_plane_init);
+
+/**
+ * drm_plane_init - Initialize a legacy plane
+ * @dev: DRM device
+ * @plane: plane object to init
+ * @possible_crtcs: bitmask of possible CRTCs
+ * @funcs: callbacks for the new plane
+ * @formats: array of supported formats (%DRM_FORMAT_*)
+ * @format_count: number of elements in @formats
+ * @is_primary: plane type (primary vs overlay)
+ *
+ * Legacy API to initialize a DRM plane.
+ *
+ * New drivers should call drm_universal_plane_init() instead.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+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 is_primary)
+{
+	enum drm_plane_type type;
+
+	type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
+					formats, format_count, type);
+}
 EXPORT_SYMBOL(drm_plane_init);
 
 /**
@@ -1081,13 +1107,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);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 2765a4e..201d8c2 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -874,12 +874,19 @@ static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
 	return !!(encoder->possible_crtcs & drm_crtc_mask(crtc));
 }
 
+extern int drm_universal_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,
+				    enum drm_plane_type type);
 extern 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);
+			  bool is_primary);
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern void drm_plane_force_disable(struct drm_plane *plane);
 extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
-- 
1.8.5.1

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

* [PATCHv4 08/13] drm: Add plane type property (v2)
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (6 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 07/13] drm: Add drm_universal_plane_init() Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  0:44 ` [PATCHv4 09/13] drm: Add plane max width/height properties Matt Roper
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

Add a plane type property to allow userspace to distinguish plane types.

v2: Driver-specific churn eliminated now that drm_plane_init() and
    drm_universal_plane_init() were separated out in a previous patch.

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

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 42aea88..0c70101 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -121,6 +121,13 @@ 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" },
+};
+
 /*
  * Optional properties
  */
@@ -1165,6 +1172,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
@@ -4566,6 +4588,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/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 201d8c2..4c4f792 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -771,6 +771,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;
-- 
1.8.5.1

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

* [PATCHv4 09/13] drm: Add plane max width/height properties
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (7 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 08/13] drm: Add plane type property (v2) Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  8:21   ` Daniel Vetter
  2014-03-28  0:44 ` [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes() Matt Roper
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

Some hardware has different size limits for different planes (e.g.,
sprites/overlays can't always be as large as the upper bound for the
primary plane).  Adding read-only plane properties allows userspace
to check these limits.  By default, mode_config.max_{width,height} are
used for non-cursor planes and mode_config.cursor_{width,height} are
used for cursors; drivers should override these defaults after calling
plane_init, if necessary.

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

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0c70101..24226de 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1028,6 +1028,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 			     enum drm_plane_type type)
 {
 	int ret;
+	uint32_t maxwidth, maxheight;
 
 	drm_modeset_lock_all(dev);
 
@@ -1061,6 +1062,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 				   dev->mode_config.plane_type_property,
 				   plane->type);
 
+	/*
+	 * Drivers may override default max width/height after calling
+	 * plane_init.
+	 */
+	if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+		maxwidth = dev->mode_config.cursor_width;
+		if (!maxwidth)
+			maxwidth = 64;
+		maxheight = dev->mode_config.cursor_height;
+		if (!maxheight)
+			maxheight = 64;
+	} else {
+		maxwidth = dev->mode_config.max_width;
+		maxheight = dev->mode_config.max_height;
+	}
+	drm_object_attach_property(&plane->base,
+				   dev->mode_config.plane_maxwidth_property,
+				   maxwidth);
+	drm_object_attach_property(&plane->base,
+				   dev->mode_config.plane_maxheight_property,
+				   maxheight);
+
  out:
 	drm_modeset_unlock_all(dev);
 
@@ -1175,6 +1198,7 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
 {
 	struct drm_property *type;
+	struct drm_property *maxwidth, *maxheight;
 
 	/*
 	 * Standard properties (apply to all planes)
@@ -1182,7 +1206,13 @@ static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
 	type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
 					"type", drm_plane_type_enum_list,
 					ARRAY_SIZE(drm_plane_type_enum_list));
+	maxwidth = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
+					     "max width", 1, INT_MAX);
+	maxheight = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
+					      "max height", 1, INT_MAX);
 	dev->mode_config.plane_type_property = type;
+	dev->mode_config.plane_maxwidth_property = maxwidth;
+	dev->mode_config.plane_maxheight_property = maxheight;
 
 	return 0;
 }
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 4c4f792..78cf825 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -772,6 +772,8 @@ struct drm_mode_config {
 	struct drm_property *edid_property;
 	struct drm_property *dpms_property;
 	struct drm_property *plane_type_property;
+	struct drm_property *plane_maxwidth_property;
+	struct drm_property *plane_maxheight_property;
 
 	/* DVI-I properties */
 	struct drm_property *dvi_i_subconnector_property;
-- 
1.8.5.1

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

* [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes()
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (8 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 09/13] drm: Add plane max width/height properties Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  9:11   ` Daniel Vetter
  2014-03-28 17:56   ` Daniel Vetter
  2014-03-28  0:44 ` [PATCHv4 11/13] drm/msm: Switch to universal plane API's Matt Roper
                   ` (3 subsequent siblings)
  13 siblings, 2 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

Add a new drm_crtc_init_with_planes() to allow drivers to provide
specific primary and cursor planes at CRTC initialization.  The existing
drm_crtc_init() interface remains to avoid driver churn in existing
drivers; it will initialize the CRTC with a plane helper-created primary
plane and no cursor plane.

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

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 24226de..a983311 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -37,6 +37,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_plane_helper.h>
 
 #include "drm_crtc_internal.h"
 
@@ -692,9 +693,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 EXPORT_SYMBOL(drm_framebuffer_remove);
 
 /**
- * drm_crtc_init - Initialise a new CRTC object
+ * drm_crtc_init_with_planes - Initialise a new CRTC object with
+ *    specified primary and cursor planes.
  * @dev: DRM device
  * @crtc: CRTC object to init
+ * @primary: Primary plane for CRTC
+ * @cursor: Cursor plane for CRTC
  * @funcs: callbacks for the new CRTC
  *
  * Inits a new object created as base part of a driver crtc object.
@@ -702,8 +706,10 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
  * Returns:
  * 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)
+int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
+			      struct drm_plane *primary,
+			      struct drm_plane *cursor,
+			      const struct drm_crtc_funcs *funcs)
 {
 	int ret;
 
@@ -724,11 +730,41 @@ 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;
+	if (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);
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_crtc_init_with_planes);
+
+/**
+ * drm_crtc_init - Legacy CRTC initialization function
+ * @dev: DRM device
+ * @crtc: CRTC object to init
+ * @funcs: callbacks for the new CRTC
+ *
+ * Initialize a CRTC object with a default helper-provided primary plane and no
+ * cursor plane.
+ *
+ * Returns:
+ * 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;
+
+	primary = drm_primary_helper_create_plane(dev, NULL, 0);
+	return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
+}
 EXPORT_SYMBOL(drm_crtc_init);
 
 /**
@@ -2248,6 +2284,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/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 78cf825..e7ed766 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -270,6 +270,8 @@ 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
+ * @cursor: cursor plane for this CRTC
  * @enabled: is this CRTC enabled?
  * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
@@ -305,6 +307,10 @@ struct drm_crtc {
 
 	struct drm_mode_object base;
 
+	/* primary and cursor planes for CRTC */
+	struct drm_plane *primary;
+	struct drm_plane *cursor;
+
 	/* framebuffer the connector is currently bound to */
 	struct drm_framebuffer *fb;
 
@@ -826,6 +832,11 @@ extern void drm_modeset_lock_all(struct drm_device *dev);
 extern void drm_modeset_unlock_all(struct drm_device *dev);
 extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
 
+extern int drm_crtc_init_with_planes(struct drm_device *dev,
+				     struct drm_crtc *crtc,
+				     struct drm_plane *primary,
+				     struct drm_plane *cursor,
+				     const struct drm_crtc_funcs *funcs);
 extern int drm_crtc_init(struct drm_device *dev,
 			 struct drm_crtc *crtc,
 			 const struct drm_crtc_funcs *funcs);
-- 
1.8.5.1

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

* [PATCHv4 11/13] drm/msm: Switch to universal plane API's
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (9 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes() Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  0:44 ` [PATCHv4 12/13] drm: Replace crtc fb with primary plane fb (v3) Matt Roper
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

Use drm_universal_plane_init() and drm_crtc_init_with_planes() rather
than the legacy drm_plane_init() / drm_crtc_init().  This will ensure
that the proper primary plane is registered with the DRM (and eventually
exposed to userspace in future patches).

Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c  | 5 ++++-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c | 8 +++++---
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c  | 5 ++++-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 8 +++++---
 4 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 84c5b13..fc1cdfa 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_with_planes(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/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 1e893dd..66f33db 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));
 
-	drm_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
-			mdp4_plane->formats, mdp4_plane->nformats,
-			private_plane);
+	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
+				 mdp4_plane->formats, mdp4_plane->nformats,
+				 type);
 
 	mdp4_plane_install_properties(plane, &plane->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..54afdb2 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_with_planes(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/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 0ac8bb5..47f7bbb 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -358,6 +358,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 	struct drm_plane *plane = NULL;
 	struct mdp5_plane *mdp5_plane;
 	int ret;
+	enum drm_plane_type type;
 
 	mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
 	if (!mdp5_plane) {
@@ -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));
 
-	drm_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
-			mdp5_plane->formats, mdp5_plane->nformats,
-			private_plane);
+	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
+				 mdp5_plane->formats, mdp5_plane->nformats,
+				 type);
 
 	mdp5_plane_install_properties(plane, &plane->base);
 
-- 
1.8.5.1

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

* [PATCHv4 12/13] drm: Replace crtc fb with primary plane fb (v3)
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (10 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 11/13] drm/msm: Switch to universal plane API's Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  8:40   ` Daniel Vetter
  2014-03-28  0:44 ` [PATCHv4 13/13] drm: Remove unused drm_crtc->fb Matt Roper
  2014-03-28  8:15 ` [Intel-gfx] [PATCHv4 00/13] Universal plane preparation patches Daniel Vetter
  13 siblings, 1 reply; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 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.

This patch was generated by the Coccinelle semantic patching tool using
the following rules:

        @@ struct drm_crtc C; @@
        -   (C).fb
        +   C.primary->fb

        @@ struct drm_crtc *C; @@
        -   (C)->fb
        +   C->primary->fb

v3: Generate patch via coccinelle.  Actual removal of crtc->fb has been
    moved to a subsequent patch.

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

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---

This patch will cause some heartache for tree maintainers since it's pretty
much a point of no return and touches so many drivers.  There's been some
discussion on the mailing list about how this might be split into a multi-step
process, although it's still pretty painful.  The hope is that since this can
be auto-generated via Coccinelle (spatch), the pain should be reduced a bit.

Note that if you're using Coccinelle by hand, you need to be careful to get the
command line right and make sure all of the headers are found and processed;
failure to do so may result in some forms of {foo}->crtc->fb not being properly
expanded.

 drivers/gpu/drm/armada/armada_crtc.c         |  23 ++---
 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                   |  26 ++---
 drivers/gpu/drm/drm_crtc_helper.c            |  20 ++--
 drivers/gpu/drm/drm_fb_helper.c              |   6 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c     |  20 ++--
 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      |   2 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
 drivers/gpu/drm/gma500/gma_display.c         |  16 ++--
 drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
 drivers/gpu/drm/gma500/mdfld_intel_display.c |  16 ++--
 drivers/gpu/drm/gma500/oaktrail_crtc.c       |  12 +--
 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         | 138 +++++++++++++--------------
 drivers/gpu/drm/i915/intel_dp.c              |   4 +-
 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       |  26 ++---
 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/omapdrm/omap_crtc.c          |  10 +-
 drivers/gpu/drm/omapdrm/omap_fb.c            |   2 +-
 drivers/gpu/drm/qxl/qxl_display.c            |  10 +-
 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       |   2 +-
 drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
 drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 ++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c       |  10 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c    |  14 +--
 drivers/gpu/drm/tegra/dc.c                   |  16 ++--
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c         |   8 +-
 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 +-
 drivers/staging/imx-drm/ipuv3-crtc.c         |   6 +-
 51 files changed, 329 insertions(+), 327 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index d8e3982..5831e41 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -478,11 +478,12 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
 	unsigned i;
 	bool interlaced;
 
-	drm_framebuffer_reference(crtc->fb);
+	drm_framebuffer_reference(crtc->primary->fb);
 
 	interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
 
-	i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced);
+	i = armada_drm_crtc_calc_fb(dcrtc->crtc.primary->fb,
+				    x, y, regs, interlaced);
 
 	rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
 	lm = adj->crtc_htotal - adj->crtc_hsync_end;
@@ -567,10 +568,10 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
 	}
 
 	val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
-	val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt);
-	val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod);
+	val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt);
+	val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod);
 
-	if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420)
+	if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420)
 		val |= CFG_PALETTE_ENA;
 
 	if (interlaced)
@@ -608,7 +609,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	struct armada_regs regs[4];
 	unsigned i;
 
-	i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs,
+	i = armada_drm_crtc_calc_fb(crtc->primary->fb, crtc->x, crtc->y, regs,
 				    dcrtc->interlaced);
 	armada_reg_queue_end(regs, i);
 
@@ -616,7 +617,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
 
 	/* Take a reference to the new fb as we're using it */
-	drm_framebuffer_reference(crtc->fb);
+	drm_framebuffer_reference(crtc->primary->fb);
 
 	/* Update the base in the CRTC */
 	armada_drm_crtc_update_regs(dcrtc, regs);
@@ -637,7 +638,7 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc)
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
 
 	armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-	armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true);
+	armada_drm_crtc_finish_fb(dcrtc, crtc->primary->fb, true);
 
 	/* Power down most RAMs and FIFOs */
 	writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
@@ -904,7 +905,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
 	int ret;
 
 	/* We don't support changing the pixel format */
-	if (fb->pixel_format != crtc->fb->pixel_format)
+	if (fb->pixel_format != crtc->primary->fb->pixel_format)
 		return -EINVAL;
 
 	work = kmalloc(sizeof(*work), GFP_KERNEL);
@@ -912,7 +913,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
 		return -ENOMEM;
 
 	work->event = event;
-	work->old_fb = dcrtc->crtc.fb;
+	work->old_fb = dcrtc->crtc.primary->fb;
 
 	i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs,
 				    dcrtc->interlaced);
@@ -941,7 +942,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
 	 * will _not_ drop that reference on successful return from this
 	 * function.  Simply mark this new framebuffer as the current one.
 	 */
-	dcrtc->crtc.fb = fb;
+	dcrtc->crtc.primary->fb = fb;
 
 	/*
 	 * Finally, if the display is blanked, we won't receive an
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index cca063b..a4afdc8 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 62ec7d4..dcf2e55 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 530f78f..2d64aea 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 a983311..c8c903a 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -670,7 +670,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 		drm_modeset_lock_all(dev);
 		/* remove from any CRTC */
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-			if (crtc->fb == fb) {
+			if (crtc->primary->fb == fb) {
 				/* should turn off the crtc */
 				memset(&set, 0, sizeof(struct drm_mode_set));
 				set.crtc = crtc;
@@ -1770,8 +1770,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;
 
@@ -2278,7 +2278,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;
 
@@ -2287,12 +2287,12 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 		crtc->primary->crtc = crtc;
 
 		/* crtc->fb must be updated by ->set_config, enforces this. */
-		WARN_ON(fb != crtc->fb);
+		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);
 	}
@@ -2396,12 +2396,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 {
@@ -4194,7 +4194,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.
@@ -4216,7 +4216,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;
@@ -4249,7 +4249,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) {
@@ -4267,7 +4267,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 		 * 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 c0f2d62..2dd806b 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -309,7 +309,7 @@ static 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;
 		}
 	}
 }
@@ -653,19 +653,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;
@@ -766,13 +766,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;
 			}
@@ -787,13 +787,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;
 		}
 	}
@@ -990,7 +990,7 @@ 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 f30bf7b..9795c06 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/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index c70b380..f66dcd3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -132,19 +132,19 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 	 */
 	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
-	crtc_w = crtc->fb->width - x;
-	crtc_h = crtc->fb->height - y;
+	crtc_w = crtc->primary->fb->width - x;
+	crtc_h = crtc->primary->fb->height - y;
 
 	if (manager->ops->mode_set)
 		manager->ops->mode_set(manager, &crtc->mode);
 
-	ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+	ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
 				    x, y, crtc_w, crtc_h);
 	if (ret)
 		return ret;
 
 	plane->crtc = crtc;
-	plane->fb = crtc->fb;
+	plane->fb = crtc->primary->fb;
 
 	return 0;
 }
@@ -164,10 +164,10 @@ static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
 		return -EPERM;
 	}
 
-	crtc_w = crtc->fb->width - x;
-	crtc_h = crtc->fb->height - y;
+	crtc_w = crtc->primary->fb->width - x;
+	crtc_h = crtc->primary->fb->height - y;
 
-	ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+	ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
 				    x, y, crtc_w, crtc_h);
 	if (ret)
 		return ret;
@@ -218,7 +218,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-	struct drm_framebuffer *old_fb = crtc->fb;
+	struct drm_framebuffer *old_fb = crtc->primary->fb;
 	int ret = -EINVAL;
 
 	/* when the page flip is requested, crtc's dpms should be on */
@@ -249,11 +249,11 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
 		atomic_set(&exynos_crtc->pending_flip, 1);
 		spin_unlock_irq(&dev->event_lock);
 
-		crtc->fb = fb;
+		crtc->primary->fb = fb;
 		ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
 						    NULL);
 		if (ret) {
-			crtc->fb = old_fb;
+			crtc->primary->fb = old_fb;
 
 			spin_lock_irq(&dev->event_lock);
 			drm_vblank_put(dev, exynos_crtc->pipe);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 7ff91ce..6672732 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -469,7 +469,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 968b42a..b99084b 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -192,7 +192,7 @@ 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 66a41c0..8ecc920 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 d45476b..9bb9bdd 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,19 @@ 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;
@@ -518,8 +518,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..8cc8a5a 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,18 @@ 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 +700,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..2de216c 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,19 @@ 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 21aed85..87b50ba 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 891a028..d7778d0 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 1a35215..b23f5b1 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2217,8 +2217,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 0858189..da6669c 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2381,8 +2381,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 69591db..5641bf3 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,17 @@ 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 +2121,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 +2140,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;
 		}
 	}
@@ -2398,9 +2398,9 @@ void intel_display_handle_reset(struct drm_device *dev)
 		 * disabling them without disabling the entire crtc) allow again
 		 * a NULL crtc->fb.
 		 */
-		if (intel_crtc->active && crtc->fb)
+		if (intel_crtc->active && crtc->primary->fb)
 			dev_priv->display.update_primary_plane(crtc,
-							       crtc->fb,
+							       crtc->primary->fb,
 							       crtc->x,
 							       crtc->y);
 		mutex_unlock(&crtc->mutex);
@@ -2527,8 +2527,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;
 
@@ -3122,7 +3122,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));
@@ -3131,7 +3131,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);
 }
 
@@ -4587,11 +4587,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. */
@@ -5742,8 +5742,8 @@ 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;
 	}
@@ -5756,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) {
@@ -5772,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);
 
 }
@@ -6750,8 +6750,8 @@ 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;
 	}
@@ -6764,8 +6764,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;
@@ -6780,23 +6780,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);
 }
 
@@ -8450,7 +8450,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);
@@ -8473,10 +8473,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);
@@ -8904,7 +8904,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;
@@ -8912,7 +8912,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;
 
 	/*
@@ -8920,8 +8920,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))
@@ -8964,7 +8964,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;
 
@@ -8987,7 +8987,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);
@@ -10028,7 +10028,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
@@ -10152,9 +10152,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);
 
@@ -10168,7 +10168,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;
@@ -10381,7 +10381,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
@@ -11746,7 +11746,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);
@@ -11771,15 +11771,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);
@@ -11818,7 +11818,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 6f767e5..54ae22e 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1634,7 +1634,7 @@ 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 +1667,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 2c78a8f..5de33a0 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 = intel_crtc->cursor_width;
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 9683747..a034ed4 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,8 @@ 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 +974,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 +1034,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 +1277,8 @@ 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 +1287,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 fc1cdfa..3e6c0f3 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 54afdb2..6ea10bd 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 1caef1f..41be342 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 b1547b0..3ff030d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -571,7 +571,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;
 
@@ -598,7 +598,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;
 
@@ -695,7 +695,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;
@@ -769,7 +769,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 2dccafc..58af547 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,8 @@ 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 +1029,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 +1043,7 @@ 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/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 4313bb0..74fcde9 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -245,7 +245,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
 	copy_timings_drm_to_omap(&omap_crtc->timings, mode);
 	omap_crtc->full_update = true;
 
-	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
+	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16,
@@ -273,7 +273,7 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	struct drm_plane *plane = omap_crtc->plane;
 	struct drm_display_mode *mode = &crtc->mode;
 
-	return omap_plane_mode_set(plane, crtc, crtc->fb,
+	return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16,
@@ -308,14 +308,14 @@ static void page_flip_worker(struct work_struct *work)
 	struct drm_gem_object *bo;
 
 	mutex_lock(&crtc->mutex);
-	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
+	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			crtc->x << 16, crtc->y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16,
 			vblank_cb, crtc);
 	mutex_unlock(&crtc->mutex);
 
-	bo = omap_framebuffer_bo(crtc->fb, 0);
+	bo = omap_framebuffer_bo(crtc->primary->fb, 0);
 	drm_gem_object_unreference_unlocked(bo);
 }
 
@@ -347,7 +347,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 	}
 
 	omap_crtc->event = event;
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 
 	/*
 	 * Hold a reference temporarily until the crtc is updated
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index f466c4a..0d5e9b7 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -312,7 +312,7 @@ struct drm_connector *omap_framebuffer_get_next_connector(
 		if (connector != from) {
 			struct drm_encoder *encoder = connector->encoder;
 			struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
-			if (crtc && crtc->fb == fb)
+			if (crtc && crtc->primary->fb == fb)
 				return connector;
 
 		}
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 798bde2..41bdd17 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,14 @@ 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 ec958e86..c566b48 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..15f954c 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1424,7 +1424,7 @@ 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 fbd8b93..5701fbb 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/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index fbf4be3..299267d 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -299,7 +299,7 @@ static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc)
 {
 	struct drm_crtc *crtc = &rcrtc->crtc;
 
-	rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
+	rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
 	rcar_du_plane_update_base(rcrtc->plane);
 }
 
@@ -358,10 +358,10 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
 	const struct rcar_du_format_info *format;
 	int ret;
 
-	format = rcar_du_format_info(crtc->fb->pixel_format);
+	format = rcar_du_format_info(crtc->primary->fb->pixel_format);
 	if (format == NULL) {
 		dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n",
-			crtc->fb->pixel_format);
+			crtc->primary->fb->pixel_format);
 		ret = -EINVAL;
 		goto error;
 	}
@@ -377,7 +377,7 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
 	rcrtc->plane->width = mode->hdisplay;
 	rcrtc->plane->height = mode->vdisplay;
 
-	rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
+	rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
 
 	rcrtc->outputs = 0;
 
@@ -510,7 +510,7 @@ static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
 	}
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 	rcar_du_crtc_update_base(rcrtc);
 
 	if (event) {
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index ea543b4..e9e5e6d 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -173,7 +173,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
 	if (scrtc->started)
 		return;
 
-	format = shmob_drm_format_info(crtc->fb->pixel_format);
+	format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
 	if (WARN_ON(format == NULL))
 		return;
 
@@ -303,7 +303,7 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc,
 					int x, int y)
 {
 	struct drm_crtc *crtc = &scrtc->crtc;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 	struct shmob_drm_device *sdev = crtc->dev->dev_private;
 	struct drm_gem_cma_object *gem;
 	unsigned int bpp;
@@ -382,15 +382,15 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
 	const struct shmob_drm_format_info *format;
 	void *cache;
 
-	format = shmob_drm_format_info(crtc->fb->pixel_format);
+	format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
 	if (format == NULL) {
 		dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n",
-			crtc->fb->pixel_format);
+			crtc->primary->fb->pixel_format);
 		return -EINVAL;
 	}
 
 	scrtc->format = format;
-	scrtc->line_size = crtc->fb->pitches[0];
+	scrtc->line_size = crtc->primary->fb->pitches[0];
 
 	if (sdev->meram) {
 		/* Enable MERAM cache if configured. We need to de-init
@@ -402,7 +402,7 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
 		}
 
 		cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata,
-						    crtc->fb->pitches[0],
+						    crtc->primary->fb->pitches[0],
 						    adjusted_mode->vdisplay,
 						    format->meram,
 						    &scrtc->line_size);
@@ -489,7 +489,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
 	}
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 	shmob_drm_crtc_update_base(scrtc);
 
 	if (event) {
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 9336006..36c717a 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -235,14 +235,14 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
 	if (!dc->event)
 		return;
 
-	bo = tegra_fb_get_plane(crtc->fb, 0);
+	bo = tegra_fb_get_plane(crtc->primary->fb, 0);
 
 	/* check if new start address has been latched */
 	tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
 	base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
 	tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
 
-	if (base == bo->paddr + crtc->fb->offsets[0]) {
+	if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
 		spin_lock_irqsave(&drm->event_lock, flags);
 		drm_send_vblank_event(drm, dc->pipe, dc->event);
 		drm_vblank_put(drm, dc->pipe);
@@ -284,7 +284,7 @@ static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	}
 
 	tegra_dc_set_base(dc, 0, 0, fb);
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 
 	return 0;
 }
@@ -645,7 +645,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
 			       struct drm_display_mode *adjusted,
 			       int x, int y, struct drm_framebuffer *old_fb)
 {
-	struct tegra_bo *bo = tegra_fb_get_plane(crtc->fb, 0);
+	struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
 	struct tegra_dc *dc = to_tegra_dc(crtc);
 	struct tegra_dc_window window;
 	unsigned long div, value;
@@ -682,9 +682,9 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
 	window.dst.y = 0;
 	window.dst.w = mode->hdisplay;
 	window.dst.h = mode->vdisplay;
-	window.format = tegra_dc_format(crtc->fb->pixel_format);
-	window.bits_per_pixel = crtc->fb->bits_per_pixel;
-	window.stride[0] = crtc->fb->pitches[0];
+	window.format = tegra_dc_format(crtc->primary->fb->pixel_format);
+	window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
+	window.stride[0] = crtc->primary->fb->pitches[0];
 	window.base[0] = bo->paddr;
 
 	err = tegra_dc_setup_window(dc, 0, &window);
@@ -699,7 +699,7 @@ static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 {
 	struct tegra_dc *dc = to_tegra_dc(crtc);
 
-	return tegra_dc_set_base(dc, x, y, crtc->fb);
+	return tegra_dc_set_base(dc, x, y, crtc->primary->fb);
 }
 
 static void tegra_crtc_prepare(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index d36efc1..d642d4a 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -74,7 +74,7 @@ static void set_scanout(struct drm_crtc *crtc, int n)
 		drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]);
 		drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
 	}
-	tilcdc_crtc->scanout[n] = crtc->fb;
+	tilcdc_crtc->scanout[n] = crtc->primary->fb;
 	drm_framebuffer_reference(tilcdc_crtc->scanout[n]);
 	tilcdc_crtc->dirty &= ~stat[n];
 	pm_runtime_put_sync(dev->dev);
@@ -84,7 +84,7 @@ static void update_scanout(struct drm_crtc *crtc)
 {
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_framebuffer *fb = crtc->primary->fb;
 	struct drm_gem_cma_object *gem;
 	unsigned int depth, bpp;
 
@@ -159,7 +159,7 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
 		return -EBUSY;
 	}
 
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 	tilcdc_crtc->event = event;
 	update_scanout(crtc);
 
@@ -339,7 +339,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
 	if (priv->rev == 2) {
 		unsigned int depth, bpp;
 
-		drm_fb_get_bpp_depth(crtc->fb->pixel_format, &depth, &bpp);
+		drm_fb_get_bpp_depth(crtc->primary->fb->pixel_format, &depth, &bpp);
 		switch (bpp) {
 		case 16:
 			break;
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 2ae1eb7..cddc4fc 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 a055a26..b2b9bd2 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 22406c8..a95d3a0 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;
@@ -572,5 +572,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/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 22be104..39a7519 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -120,7 +120,7 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 
 	ipu_crtc->newfb = fb;
 	ipu_crtc->page_flip_event = event;
-	crtc->fb = fb;
+	crtc->primary->fb = fb;
 
 	return 0;
 }
@@ -192,7 +192,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 		return ret;
 	}
 
-	return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb,
+	return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->primary->fb,
 				  0, 0, mode->hdisplay, mode->vdisplay,
 				  x, y, mode->hdisplay, mode->vdisplay);
 }
@@ -218,7 +218,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 
 	if (ipu_crtc->newfb) {
 		ipu_crtc->newfb = NULL;
-		ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb,
+		ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.primary->fb,
 				ipu_crtc->plane[0]->x, ipu_crtc->plane[0]->y);
 		ipu_crtc_handle_pageflip(ipu_crtc);
 	}
-- 
1.8.5.1

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

* [PATCHv4 13/13] drm: Remove unused drm_crtc->fb
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (11 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 12/13] drm: Replace crtc fb with primary plane fb (v3) Matt Roper
@ 2014-03-28  0:44 ` Matt Roper
  2014-03-28  8:15 ` [Intel-gfx] [PATCHv4 00/13] Universal plane preparation patches Daniel Vetter
  13 siblings, 0 replies; 35+ messages in thread
From: Matt Roper @ 2014-03-28  0:44 UTC (permalink / raw)
  To: dri-devel

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 include/drm/drm_crtc.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index e7ed766..282f823 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -311,9 +311,6 @@ struct drm_crtc {
 	struct drm_plane *primary;
 	struct drm_plane *cursor;
 
-	/* 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] 35+ messages in thread

* Re: [Intel-gfx] [PATCHv4 00/13] Universal plane preparation patches
  2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
                   ` (12 preceding siblings ...)
  2014-03-28  0:44 ` [PATCHv4 13/13] drm: Remove unused drm_crtc->fb Matt Roper
@ 2014-03-28  8:15 ` Daniel Vetter
  13 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28  8:15 UTC (permalink / raw)
  To: Matt Roper; +Cc: Intel Graphics Development, dri-devel

On Thu, Mar 27, 2014 at 05:44:25PM -0700, Matt Roper wrote:
> Previous series revisions & explanation at [1], [2], and [3]
> 
> This version of the patch series focuses on isolating the DRM core changes from
> individual driver changes to (hopefully) make this a bit easier to merge.  New
> plane and crtc initialization functions have been added to allow drivers to
> migrate to the new infrastructure at their own pace; existing drivers that do
> not update should continue to function as expected.  The one remaining painful
> patch here is patch #12, which replaces crtc->fb with crtc->primary->fb.  That
> patch is now auto-generated via a Coccinelle semantic patch with the rules
> described in the commit message; hopefully that will make life slightly easier
> for tree maintainers who want to pull it in.
> 
> Daniel mentioned that we should try to merge the underlying infrastructure here
> without the actual userspace-facing capability bit to make sure things continue
> to run as expected without breaking; I've dropped the capability bit patch for
> now, but the previous version from [4] should work on top of this patch set.
> I've also dropped the i915 cursor support for the moment to keep the patch set
> simple.

The usual way to expose experimental feature is to hide them by default,
but have a moduel option for developers like drm.universal_planes=1. So
for the next round I think you can add the capability again with that drm
module option added.
-Daniel
 
> I believe the only userspace-visible changes in this series are the plane type
> property (which will always return "overlay" since there's no switch to turn on
> the other plane types) and max width/height plane properties.  I figured
> properties were a little bit cleaner than extending GetPlane() to return
> additional information, although I can change that if people feel differently.
> Presumably we're still going to need a lot more properties that describe the
> limits and capabilities of planes as we go forward (stride, scaling, tiling,
> etc.)
> 
> [1] http://lists.freedesktop.org/archives/dri-devel/2014-March/055855.html
> [2] http://lists.freedesktop.org/archives/dri-devel/2014-March/055222.html
> [3] http://lists.freedesktop.org/archives/dri-devel/2014-February/054719.html
> [4] http://lists.freedesktop.org/archives/dri-devel/2014-March/055216.html
> 
> Matt Roper (13):
>   drm: Add support for multiple plane types (v2)
>   drm/exynos: Restrict plane loops to only operate on overlay planes
>     (v2)
>   drm/i915: Restrict plane loops to only operate on overlay planes (v2)
>   drm/shmobile: Restrict plane loops to only operate on legacy planes
>   drm: Make drm_crtc_check_viewport non-static
>   drm: Add primary plane helpers (v2)
>   drm: Add drm_universal_plane_init()
>   drm: Add plane type property (v2)
>   drm: Add plane max width/height properties
>   drm: Add drm_crtc_init_with_planes()
>   drm/msm: Switch to universal plane API's
>   drm: Replace crtc fb with primary plane fb (v3)
>   drm: Remove unused drm_crtc->fb
> 
>  drivers/gpu/drm/Makefile                     |   3 +-
>  drivers/gpu/drm/armada/armada_crtc.c         |  23 +-
>  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                   | 228 ++++++++++++++++----
>  drivers/gpu/drm/drm_crtc_helper.c            |  20 +-
>  drivers/gpu/drm/drm_fb_helper.c              |   9 +-
>  drivers/gpu/drm/drm_plane_helper.c           | 312 +++++++++++++++++++++++++++
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c     |  22 +-
>  drivers/gpu/drm/exynos/exynos_drm_encoder.c  |   2 +-
>  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      |   2 +-
>  drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
>  drivers/gpu/drm/gma500/gma_display.c         |  16 +-
>  drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
>  drivers/gpu/drm/gma500/mdfld_intel_display.c |  16 +-
>  drivers/gpu/drm/gma500/oaktrail_crtc.c       |  12 +-
>  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         | 148 +++++++------
>  drivers/gpu/drm/i915/intel_dp.c              |   4 +-
>  drivers/gpu/drm/i915/intel_fbdev.c           |   6 +-
>  drivers/gpu/drm/i915/intel_overlay.c         |   4 +-
>  drivers/gpu/drm/i915/intel_pm.c              |  38 ++--
>  drivers/gpu/drm/mgag200/mgag200_mode.c       |  26 +--
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c     |  33 +--
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c    |   8 +-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c     |  27 +--
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c    |   8 +-
>  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/omapdrm/omap_crtc.c          |  10 +-
>  drivers/gpu/drm/omapdrm/omap_fb.c            |   2 +-
>  drivers/gpu/drm/qxl/qxl_display.c            |  10 +-
>  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       |   2 +-
>  drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
>  drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 +-
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c       |  10 +-
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c    |  16 +-
>  drivers/gpu/drm/tegra/dc.c                   |  16 +-
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c         |   8 +-
>  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 +-
>  drivers/staging/imx-drm/ipuv3-crtc.c         |   6 +-
>  include/drm/drm_crtc.h                       |  52 ++++-
>  include/drm/drm_plane_helper.h               |  49 +++++
>  58 files changed, 940 insertions(+), 381 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_plane_helper.c
>  create mode 100644 include/drm/drm_plane_helper.h
> 
> Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>
> -- 
> 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] 35+ messages in thread

* Re: [PATCHv4 09/13] drm: Add plane max width/height properties
  2014-03-28  0:44 ` [PATCHv4 09/13] drm: Add plane max width/height properties Matt Roper
@ 2014-03-28  8:21   ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28  8:21 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Thu, Mar 27, 2014 at 05:44:34PM -0700, Matt Roper wrote:
> Some hardware has different size limits for different planes (e.g.,
> sprites/overlays can't always be as large as the upper bound for the
> primary plane).  Adding read-only plane properties allows userspace
> to check these limits.  By default, mode_config.max_{width,height} are
> used for non-cursor planes and mode_config.cursor_{width,height} are
> used for cursors; drivers should override these defaults after calling
> plane_init, if necessary.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Hm, I think we should wait with exposing this to userspace. In some other
thread which I've dragged onto dri-devel we've discussed this and we might
actually need per pixel format limits. And a lot more limits than just max
width/height.

So for now I think we should just leave the current mess which presumes
that userspace knows, and tackle it later. Also this avoids that universal
planes get bogged down in some minute detail bikeshed discusssion which is
really just auxilliary to the main concept. And I don't want this to
happen.
-Daniel

> ---
>  drivers/gpu/drm/drm_crtc.c | 30 ++++++++++++++++++++++++++++++
>  include/drm/drm_crtc.h     |  2 ++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 0c70101..24226de 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1028,6 +1028,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
>  			     enum drm_plane_type type)
>  {
>  	int ret;
> +	uint32_t maxwidth, maxheight;
>  
>  	drm_modeset_lock_all(dev);
>  
> @@ -1061,6 +1062,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
>  				   dev->mode_config.plane_type_property,
>  				   plane->type);
>  
> +	/*
> +	 * Drivers may override default max width/height after calling
> +	 * plane_init.
> +	 */
> +	if (plane->type == DRM_PLANE_TYPE_CURSOR) {
> +		maxwidth = dev->mode_config.cursor_width;
> +		if (!maxwidth)
> +			maxwidth = 64;
> +		maxheight = dev->mode_config.cursor_height;
> +		if (!maxheight)
> +			maxheight = 64;
> +	} else {
> +		maxwidth = dev->mode_config.max_width;
> +		maxheight = dev->mode_config.max_height;
> +	}
> +	drm_object_attach_property(&plane->base,
> +				   dev->mode_config.plane_maxwidth_property,
> +				   maxwidth);
> +	drm_object_attach_property(&plane->base,
> +				   dev->mode_config.plane_maxheight_property,
> +				   maxheight);
> +
>   out:
>  	drm_modeset_unlock_all(dev);
>  
> @@ -1175,6 +1198,7 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
>  static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
>  {
>  	struct drm_property *type;
> +	struct drm_property *maxwidth, *maxheight;
>  
>  	/*
>  	 * Standard properties (apply to all planes)
> @@ -1182,7 +1206,13 @@ static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
>  	type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
>  					"type", drm_plane_type_enum_list,
>  					ARRAY_SIZE(drm_plane_type_enum_list));
> +	maxwidth = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
> +					     "max width", 1, INT_MAX);
> +	maxheight = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
> +					      "max height", 1, INT_MAX);
>  	dev->mode_config.plane_type_property = type;
> +	dev->mode_config.plane_maxwidth_property = maxwidth;
> +	dev->mode_config.plane_maxheight_property = maxheight;
>  
>  	return 0;
>  }
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 4c4f792..78cf825 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -772,6 +772,8 @@ struct drm_mode_config {
>  	struct drm_property *edid_property;
>  	struct drm_property *dpms_property;
>  	struct drm_property *plane_type_property;
> +	struct drm_property *plane_maxwidth_property;
> +	struct drm_property *plane_maxheight_property;
>  
>  	/* DVI-I properties */
>  	struct drm_property *dvi_i_subconnector_property;
> -- 
> 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] 35+ messages in thread

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-03-28  0:44 ` [PATCHv4 06/13] drm: Add primary plane helpers (v2) Matt Roper
@ 2014-03-28  8:32   ` Daniel Vetter
  2014-03-28 15:48     ` Laurent Pinchart
                       ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28  8:32 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Thu, Mar 27, 2014 at 05:44:31PM -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 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.
> 
> v2:
>  - Move plane helpers to a new file (drm_plane_helper.c)
>  - Tighten checks on update handler (check for scaling, CRTC coverage,
>    subpixel positioning)
>  - Pass proper panning parameters to modeset interface
>  - Disallow disabling primary plane (and thus CRTC) if other planes are
>    still active on the CRTC.
>  - Use a minimal format list that should work on all hardware/drivers.
>    Drivers may call this function with a more accurate plane list to
>    enable additional formats they can support.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/Makefile           |   3 +-
>  drivers/gpu/drm/drm_plane_helper.c | 312 +++++++++++++++++++++++++++++++++++++
>  include/drm/drm_plane_helper.h     |  49 ++++++

DocBook integration is missing for all the great kerneldoc you've written.
That boils down to adding a new section next to the other helper libraries
in the drm docbook to pull the kerneldoc in and running make htmldocs to
make sure the kerneldoc checks out.

If you want you can add a DOC: overview section and pull that into the
docbook too, see e.g. how the drm prime helpers are integrated.

>  3 files changed, 363 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/drm_plane_helper.c
>  create mode 100644 include/drm/drm_plane_helper.h
> 
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 5e792b0..9d25dbb 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -13,7 +13,8 @@ drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
>  		drm_crtc.o drm_modes.o drm_edid.o \
>  		drm_info.o drm_debugfs.o drm_encoder_slave.o \
>  		drm_trace_points.o drm_global.o drm_prime.o \
> -		drm_rect.o drm_vma_manager.o drm_flip_work.o
> +		drm_rect.o drm_vma_manager.o drm_flip_work.o \
> +		drm_plane_helper.o
>  
>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
> diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
> new file mode 100644
> index 0000000..374a98d
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_plane_helper.c
> @@ -0,0 +1,312 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * DRM universal plane helper functions
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#include <linux/list.h>
> +#include <drm/drmP.h>
> +#include <drm/drm_rect.h>
> +
> +#define SUBPIXEL_MASK 0xffff
> +
> +/*
> + * This is the minimal list of formats that seem to be safe for modeset use
> + * with all current DRM drivers.  Most hardware can actually support more
> + * formats than this and drivers may specify a more accurate list when
> + * creating the primary plane.  However drivers that still call
> + * drm_plane_init() will use this minimal format list as the default.
> + */
> +const static uint32_t safe_modeset_formats[] = {
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_ARGB8888,
> +};

Yeah, I think this is safe enough ;-) And it's really not a big change for
drivers to enable primary planes properly with these helpers here. So even
if we decide to switch to them fully (e.g. to make the fbdev helpers a
test-vehicle for atomic modesets) it shouldn't be a lot of fuzz to get
this going. Since for fbdev support we definitely want 15/16 and C8
support back for some especially low-powered chips.

> +
> +/*
> + * 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 modeset 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 make some assumptions about hardware limitations that may not be
> + * true for all hardware:
> + *   - primary plane cannot be repositioned
> + *   - primary plane cannot be scaled
> + *   - primary plane must cover the entire CRTC
> + *   - subpixel positioning is not supported
> + * 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 = src_x >> 16,
> +		.y = src_y >> 16,
> +	};
> +	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,
> +	};
> +	struct drm_connector **connector_list;
> +	struct drm_framebuffer *tmpfb;
> +	int num_connectors, ret;
> +
> +	if (!crtc->enabled) {
> +		DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Disallow subpixel positioning */
> +	if ((src_x | src_y | src_w | src_h) & SUBPIXEL_MASK) {
> +		DRM_DEBUG_KMS("Primary plane does not support subpixel positioning\n");
> +		return -EINVAL;
> +	}
> +
> +	/* 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;
> +	}
> +
> +	/* Disallow scaling */
> +	if (crtc_w != src_w || crtc_h != src_h) {
> +		DRM_DEBUG_KMS("Can't scale primary plane\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Make sure primary plane covers entire CRTC */
> +	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;
> +	}
> +
> +	/* Framebuffer must be big enough to cover entire plane */
> +	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.
> +	 *
> +	 * N.B., we call set_config() directly here rather than using
> +	 * drm_mode_set_config_internal.  We're reprogramming the same
> +	 * connectors that were already in use, so we shouldn't need the extra
> +	 * cross-CRTC fb refcounting to accomodate stealing connectors.
> +	 * drm_mode_setplane() already handles the basic refcounting for the
> +	 * framebuffers involved in this operation.

Wrong. The current crtc helper logic disables all disconnected connectors
forcefully on each set_config. Nope, I didn't make those semantics ... So
I think we need to think a bit harder here again.

See drm_helper_disable_unused_functions.

> +	 */
> +	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 if no other planes are currently enabled.
> + * If other planes are still enabled on the same CRTC, we return -EBUSY.
> + *
> + * 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_plane *p;
> +	struct drm_mode_set set = {
> +		.crtc = plane->crtc,
> +		.fb = NULL,
> +	};
> +
> +	if (plane->crtc == NULL || plane->fb == NULL)
> +		/* Already disabled */
> +		return 0;
> +
> +	list_for_each_entry(p, &plane->dev->mode_config.plane_list, head)
> +		if (p != plane && p->fb) {
> +			DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n");
> +			return -EBUSY;
> +		}
> +
> +	/*
> +	 * N.B.  We call set_config() directly here rather than
> +	 * drm_mode_set_config_internal() since drm_mode_setplane() already
> +	 * handles the basic refcounting and we don't need the special
> +	 * cross-CRTC refcounting (no chance of stealing connectors from
> +	 * other CRTC's with this update).

Same comment as above applies. Calling ->set_config is considered harmful
... Maybe we need to add another wrapper here for the primary plane
helpers to wrap this all up safely?

> +	 */
> +	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
> + * @formats: pixel formats supported, or NULL for a default safe list
> + * @num_formats: size of @formats; ignored if @formats is NULL
> + *
> + * 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,
> +						  const uint32_t *formats,
> +						  int num_formats)
> +{
> +	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;
> +	}
> +
> +	if (formats == NULL) {
> +		formats = safe_modeset_formats;
> +		num_formats = ARRAY_SIZE(safe_modeset_formats);
> +	}
> +
> +	/* possible_crtc's will be filled in later by crtc_init */
> +	ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
> +			     formats, num_formats,
> +			     DRM_PLANE_TYPE_PRIMARY);
> +	if (ret) {
> +		kfree(primary);
> +		primary = NULL;
> +	}
> +
> +	return primary;
> +}
> +EXPORT_SYMBOL(drm_primary_helper_create_plane);
> +
> diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
> new file mode 100644
> index 0000000..09824be
> --- /dev/null
> +++ b/include/drm/drm_plane_helper.h
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright (C) 2011-2013 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#ifndef DRM_PLANE_HELPER_H
> +#define DRM_PLANE_HELPER_H
> +
> +/**
> + * DOC: plane helpers
> + *
> + * Helper functions to assist with creation and handling of CRTC primary
> + * planes.
> + */
> +
> +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,
> +							 uint32_t *formats,
> +							 int num_formats);
> +
> +
> +#endif
> -- 
> 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] 35+ messages in thread

* Re: [PATCHv4 12/13] drm: Replace crtc fb with primary plane fb (v3)
  2014-03-28  0:44 ` [PATCHv4 12/13] drm: Replace crtc fb with primary plane fb (v3) Matt Roper
@ 2014-03-28  8:40   ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28  8:40 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Thu, Mar 27, 2014 at 05:44:37PM -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.
> 
> This patch was generated by the Coccinelle semantic patching tool using
> the following rules:
> 
>         @@ struct drm_crtc C; @@
>         -   (C).fb
>         +   C.primary->fb
> 
>         @@ struct drm_crtc *C; @@
>         -   (C)->fb
>         +   C->primary->fb
> 
> v3: Generate patch via coccinelle.  Actual removal of crtc->fb has been
>     moved to a subsequent patch.
> 
> v2: Fixup several lingering crtc->fb instances that were missed in the
>     first patch iteration.  [Rob Clark]
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
> 
> This patch will cause some heartache for tree maintainers since it's pretty
> much a point of no return and touches so many drivers.  There's been some
> discussion on the mailing list about how this might be split into a multi-step
> process, although it's still pretty painful.  The hope is that since this can
> be auto-generated via Coccinelle (spatch), the pain should be reduced a bit.

Yeah I agree that there doesn't seem to be an easy solution at hand. All
the approaches we've discussed bring a good amount of subtle fail risk in
the fb refcounting with them, and historically we've not been good at
catching that. With this approach we can enlist the help of some solid
tools at least (cocinelle + gcc catching fallout).
> 
> Note that if you're using Coccinelle by hand, you need to be careful to get the
> command line right and make sure all of the headers are found and processed;
> failure to do so may result in some forms of {foo}->crtc->fb not being properly
> expanded.

The exact cocinelle cmdline you're using might be useful here ;-)

Cheers, Daniel

> 
>  drivers/gpu/drm/armada/armada_crtc.c         |  23 ++---
>  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                   |  26 ++---
>  drivers/gpu/drm/drm_crtc_helper.c            |  20 ++--
>  drivers/gpu/drm/drm_fb_helper.c              |   6 +-
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c     |  20 ++--
>  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      |   2 +-
>  drivers/gpu/drm/gma500/cdv_intel_lvds.c      |   2 +-
>  drivers/gpu/drm/gma500/gma_display.c         |  16 ++--
>  drivers/gpu/drm/gma500/mdfld_dsi_output.c    |   2 +-
>  drivers/gpu/drm/gma500/mdfld_intel_display.c |  16 ++--
>  drivers/gpu/drm/gma500/oaktrail_crtc.c       |  12 +--
>  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         | 138 +++++++++++++--------------
>  drivers/gpu/drm/i915/intel_dp.c              |   4 +-
>  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       |  26 ++---
>  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/omapdrm/omap_crtc.c          |  10 +-
>  drivers/gpu/drm/omapdrm/omap_fb.c            |   2 +-
>  drivers/gpu/drm/qxl/qxl_display.c            |  10 +-
>  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       |   2 +-
>  drivers/gpu/drm/radeon/radeon_display.c      |   4 +-
>  drivers/gpu/drm/radeon/radeon_legacy_crtc.c  |  16 ++--
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c       |  10 +-
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c    |  14 +--
>  drivers/gpu/drm/tegra/dc.c                   |  16 ++--
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c         |   8 +-
>  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 +-
>  drivers/staging/imx-drm/ipuv3-crtc.c         |   6 +-
>  51 files changed, 329 insertions(+), 327 deletions(-)
> 
> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
> index d8e3982..5831e41 100644
> --- a/drivers/gpu/drm/armada/armada_crtc.c
> +++ b/drivers/gpu/drm/armada/armada_crtc.c
> @@ -478,11 +478,12 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
>  	unsigned i;
>  	bool interlaced;
>  
> -	drm_framebuffer_reference(crtc->fb);
> +	drm_framebuffer_reference(crtc->primary->fb);
>  
>  	interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
>  
> -	i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced);
> +	i = armada_drm_crtc_calc_fb(dcrtc->crtc.primary->fb,
> +				    x, y, regs, interlaced);
>  
>  	rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
>  	lm = adj->crtc_htotal - adj->crtc_hsync_end;
> @@ -567,10 +568,10 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
>  	}
>  
>  	val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
> -	val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt);
> -	val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod);
> +	val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt);
> +	val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod);
>  
> -	if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420)
> +	if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420)
>  		val |= CFG_PALETTE_ENA;
>  
>  	if (interlaced)
> @@ -608,7 +609,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  	struct armada_regs regs[4];
>  	unsigned i;
>  
> -	i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs,
> +	i = armada_drm_crtc_calc_fb(crtc->primary->fb, crtc->x, crtc->y, regs,
>  				    dcrtc->interlaced);
>  	armada_reg_queue_end(regs, i);
>  
> @@ -616,7 +617,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  	wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
>  
>  	/* Take a reference to the new fb as we're using it */
> -	drm_framebuffer_reference(crtc->fb);
> +	drm_framebuffer_reference(crtc->primary->fb);
>  
>  	/* Update the base in the CRTC */
>  	armada_drm_crtc_update_regs(dcrtc, regs);
> @@ -637,7 +638,7 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc)
>  	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
>  
>  	armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> -	armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true);
> +	armada_drm_crtc_finish_fb(dcrtc, crtc->primary->fb, true);
>  
>  	/* Power down most RAMs and FIFOs */
>  	writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
> @@ -904,7 +905,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
>  	int ret;
>  
>  	/* We don't support changing the pixel format */
> -	if (fb->pixel_format != crtc->fb->pixel_format)
> +	if (fb->pixel_format != crtc->primary->fb->pixel_format)
>  		return -EINVAL;
>  
>  	work = kmalloc(sizeof(*work), GFP_KERNEL);
> @@ -912,7 +913,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
>  		return -ENOMEM;
>  
>  	work->event = event;
> -	work->old_fb = dcrtc->crtc.fb;
> +	work->old_fb = dcrtc->crtc.primary->fb;
>  
>  	i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs,
>  				    dcrtc->interlaced);
> @@ -941,7 +942,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
>  	 * will _not_ drop that reference on successful return from this
>  	 * function.  Simply mark this new framebuffer as the current one.
>  	 */
> -	dcrtc->crtc.fb = fb;
> +	dcrtc->crtc.primary->fb = fb;
>  
>  	/*
>  	 * Finally, if the display is blanked, we won't receive an
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> index cca063b..a4afdc8 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 62ec7d4..dcf2e55 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 530f78f..2d64aea 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 a983311..c8c903a 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -670,7 +670,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
>  		drm_modeset_lock_all(dev);
>  		/* remove from any CRTC */
>  		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> -			if (crtc->fb == fb) {
> +			if (crtc->primary->fb == fb) {
>  				/* should turn off the crtc */
>  				memset(&set, 0, sizeof(struct drm_mode_set));
>  				set.crtc = crtc;
> @@ -1770,8 +1770,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;
>  
> @@ -2278,7 +2278,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;
>  
> @@ -2287,12 +2287,12 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>  		crtc->primary->crtc = crtc;
>  
>  		/* crtc->fb must be updated by ->set_config, enforces this. */
> -		WARN_ON(fb != crtc->fb);
> +		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);
>  	}
> @@ -2396,12 +2396,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 {
> @@ -4194,7 +4194,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.
> @@ -4216,7 +4216,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;
> @@ -4249,7 +4249,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) {
> @@ -4267,7 +4267,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  		 * 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 c0f2d62..2dd806b 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -309,7 +309,7 @@ static 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;
>  		}
>  	}
>  }
> @@ -653,19 +653,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;
> @@ -766,13 +766,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;
>  			}
> @@ -787,13 +787,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;
>  		}
>  	}
> @@ -990,7 +990,7 @@ 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 f30bf7b..9795c06 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/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> index c70b380..f66dcd3 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> @@ -132,19 +132,19 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
>  	 */
>  	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
>  
> -	crtc_w = crtc->fb->width - x;
> -	crtc_h = crtc->fb->height - y;
> +	crtc_w = crtc->primary->fb->width - x;
> +	crtc_h = crtc->primary->fb->height - y;
>  
>  	if (manager->ops->mode_set)
>  		manager->ops->mode_set(manager, &crtc->mode);
>  
> -	ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
> +	ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
>  				    x, y, crtc_w, crtc_h);
>  	if (ret)
>  		return ret;
>  
>  	plane->crtc = crtc;
> -	plane->fb = crtc->fb;
> +	plane->fb = crtc->primary->fb;
>  
>  	return 0;
>  }
> @@ -164,10 +164,10 @@ static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
>  		return -EPERM;
>  	}
>  
> -	crtc_w = crtc->fb->width - x;
> -	crtc_h = crtc->fb->height - y;
> +	crtc_w = crtc->primary->fb->width - x;
> +	crtc_h = crtc->primary->fb->height - y;
>  
> -	ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
> +	ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
>  				    x, y, crtc_w, crtc_h);
>  	if (ret)
>  		return ret;
> @@ -218,7 +218,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
>  	struct drm_device *dev = crtc->dev;
>  	struct exynos_drm_private *dev_priv = dev->dev_private;
>  	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
> -	struct drm_framebuffer *old_fb = crtc->fb;
> +	struct drm_framebuffer *old_fb = crtc->primary->fb;
>  	int ret = -EINVAL;
>  
>  	/* when the page flip is requested, crtc's dpms should be on */
> @@ -249,11 +249,11 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
>  		atomic_set(&exynos_crtc->pending_flip, 1);
>  		spin_unlock_irq(&dev->event_lock);
>  
> -		crtc->fb = fb;
> +		crtc->primary->fb = fb;
>  		ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
>  						    NULL);
>  		if (ret) {
> -			crtc->fb = old_fb;
> +			crtc->primary->fb = old_fb;
>  
>  			spin_lock_irq(&dev->event_lock);
>  			drm_vblank_put(dev, exynos_crtc->pipe);
> diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
> index 7ff91ce..6672732 100644
> --- a/drivers/gpu/drm/gma500/cdv_intel_display.c
> +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
> @@ -469,7 +469,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 968b42a..b99084b 100644
> --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
> @@ -192,7 +192,7 @@ 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 66a41c0..8ecc920 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 d45476b..9bb9bdd 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,19 @@ 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;
> @@ -518,8 +518,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..8cc8a5a 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,18 @@ 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 +700,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..2de216c 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,19 @@ 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 21aed85..87b50ba 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 891a028..d7778d0 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 1a35215..b23f5b1 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -2217,8 +2217,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 0858189..da6669c 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2381,8 +2381,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 69591db..5641bf3 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,17 @@ 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 +2121,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 +2140,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;
>  		}
>  	}
> @@ -2398,9 +2398,9 @@ void intel_display_handle_reset(struct drm_device *dev)
>  		 * disabling them without disabling the entire crtc) allow again
>  		 * a NULL crtc->fb.
>  		 */
> -		if (intel_crtc->active && crtc->fb)
> +		if (intel_crtc->active && crtc->primary->fb)
>  			dev_priv->display.update_primary_plane(crtc,
> -							       crtc->fb,
> +							       crtc->primary->fb,
>  							       crtc->x,
>  							       crtc->y);
>  		mutex_unlock(&crtc->mutex);
> @@ -2527,8 +2527,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;
>  
> @@ -3122,7 +3122,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));
> @@ -3131,7 +3131,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);
>  }
>  
> @@ -4587,11 +4587,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. */
> @@ -5742,8 +5742,8 @@ 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;
>  	}
> @@ -5756,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) {
> @@ -5772,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);
>  
>  }
> @@ -6750,8 +6750,8 @@ 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;
>  	}
> @@ -6764,8 +6764,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;
> @@ -6780,23 +6780,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);
>  }
>  
> @@ -8450,7 +8450,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);
> @@ -8473,10 +8473,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);
> @@ -8904,7 +8904,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;
> @@ -8912,7 +8912,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;
>  
>  	/*
> @@ -8920,8 +8920,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))
> @@ -8964,7 +8964,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;
>  
> @@ -8987,7 +8987,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);
> @@ -10028,7 +10028,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
> @@ -10152,9 +10152,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);
>  
> @@ -10168,7 +10168,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;
> @@ -10381,7 +10381,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
> @@ -11746,7 +11746,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);
> @@ -11771,15 +11771,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);
> @@ -11818,7 +11818,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 6f767e5..54ae22e 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1634,7 +1634,7 @@ 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 +1667,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 2c78a8f..5de33a0 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 = intel_crtc->cursor_width;
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index 9683747..a034ed4 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,8 @@ 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 +974,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 +1034,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 +1277,8 @@ 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 +1287,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 fc1cdfa..3e6c0f3 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 54afdb2..6ea10bd 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 1caef1f..41be342 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 b1547b0..3ff030d 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_display.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_display.c
> @@ -571,7 +571,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;
>  
> @@ -598,7 +598,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;
>  
> @@ -695,7 +695,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;
> @@ -769,7 +769,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 2dccafc..58af547 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,8 @@ 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 +1029,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 +1043,7 @@ 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/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index 4313bb0..74fcde9 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -245,7 +245,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
>  	copy_timings_drm_to_omap(&omap_crtc->timings, mode);
>  	omap_crtc->full_update = true;
>  
> -	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
> +	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
>  			0, 0, mode->hdisplay, mode->vdisplay,
>  			x << 16, y << 16,
>  			mode->hdisplay << 16, mode->vdisplay << 16,
> @@ -273,7 +273,7 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  	struct drm_plane *plane = omap_crtc->plane;
>  	struct drm_display_mode *mode = &crtc->mode;
>  
> -	return omap_plane_mode_set(plane, crtc, crtc->fb,
> +	return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
>  			0, 0, mode->hdisplay, mode->vdisplay,
>  			x << 16, y << 16,
>  			mode->hdisplay << 16, mode->vdisplay << 16,
> @@ -308,14 +308,14 @@ static void page_flip_worker(struct work_struct *work)
>  	struct drm_gem_object *bo;
>  
>  	mutex_lock(&crtc->mutex);
> -	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
> +	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
>  			0, 0, mode->hdisplay, mode->vdisplay,
>  			crtc->x << 16, crtc->y << 16,
>  			mode->hdisplay << 16, mode->vdisplay << 16,
>  			vblank_cb, crtc);
>  	mutex_unlock(&crtc->mutex);
>  
> -	bo = omap_framebuffer_bo(crtc->fb, 0);
> +	bo = omap_framebuffer_bo(crtc->primary->fb, 0);
>  	drm_gem_object_unreference_unlocked(bo);
>  }
>  
> @@ -347,7 +347,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
>  	}
>  
>  	omap_crtc->event = event;
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  
>  	/*
>  	 * Hold a reference temporarily until the crtc is updated
> diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
> index f466c4a..0d5e9b7 100644
> --- a/drivers/gpu/drm/omapdrm/omap_fb.c
> +++ b/drivers/gpu/drm/omapdrm/omap_fb.c
> @@ -312,7 +312,7 @@ struct drm_connector *omap_framebuffer_get_next_connector(
>  		if (connector != from) {
>  			struct drm_encoder *encoder = connector->encoder;
>  			struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
> -			if (crtc && crtc->fb == fb)
> +			if (crtc && crtc->primary->fb == fb)
>  				return connector;
>  
>  		}
> diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> index 798bde2..41bdd17 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,14 @@ 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 ec958e86..c566b48 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..15f954c 100644
> --- a/drivers/gpu/drm/radeon/radeon_device.c
> +++ b/drivers/gpu/drm/radeon/radeon_device.c
> @@ -1424,7 +1424,7 @@ 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 fbd8b93..5701fbb 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/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index fbf4be3..299267d 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -299,7 +299,7 @@ static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc)
>  {
>  	struct drm_crtc *crtc = &rcrtc->crtc;
>  
> -	rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
> +	rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
>  	rcar_du_plane_update_base(rcrtc->plane);
>  }
>  
> @@ -358,10 +358,10 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
>  	const struct rcar_du_format_info *format;
>  	int ret;
>  
> -	format = rcar_du_format_info(crtc->fb->pixel_format);
> +	format = rcar_du_format_info(crtc->primary->fb->pixel_format);
>  	if (format == NULL) {
>  		dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n",
> -			crtc->fb->pixel_format);
> +			crtc->primary->fb->pixel_format);
>  		ret = -EINVAL;
>  		goto error;
>  	}
> @@ -377,7 +377,7 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
>  	rcrtc->plane->width = mode->hdisplay;
>  	rcrtc->plane->height = mode->vdisplay;
>  
> -	rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
> +	rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
>  
>  	rcrtc->outputs = 0;
>  
> @@ -510,7 +510,7 @@ static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
>  	}
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  	rcar_du_crtc_update_base(rcrtc);
>  
>  	if (event) {
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> index ea543b4..e9e5e6d 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -173,7 +173,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
>  	if (scrtc->started)
>  		return;
>  
> -	format = shmob_drm_format_info(crtc->fb->pixel_format);
> +	format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
>  	if (WARN_ON(format == NULL))
>  		return;
>  
> @@ -303,7 +303,7 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc,
>  					int x, int y)
>  {
>  	struct drm_crtc *crtc = &scrtc->crtc;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  	struct shmob_drm_device *sdev = crtc->dev->dev_private;
>  	struct drm_gem_cma_object *gem;
>  	unsigned int bpp;
> @@ -382,15 +382,15 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
>  	const struct shmob_drm_format_info *format;
>  	void *cache;
>  
> -	format = shmob_drm_format_info(crtc->fb->pixel_format);
> +	format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
>  	if (format == NULL) {
>  		dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n",
> -			crtc->fb->pixel_format);
> +			crtc->primary->fb->pixel_format);
>  		return -EINVAL;
>  	}
>  
>  	scrtc->format = format;
> -	scrtc->line_size = crtc->fb->pitches[0];
> +	scrtc->line_size = crtc->primary->fb->pitches[0];
>  
>  	if (sdev->meram) {
>  		/* Enable MERAM cache if configured. We need to de-init
> @@ -402,7 +402,7 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
>  		}
>  
>  		cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata,
> -						    crtc->fb->pitches[0],
> +						    crtc->primary->fb->pitches[0],
>  						    adjusted_mode->vdisplay,
>  						    format->meram,
>  						    &scrtc->line_size);
> @@ -489,7 +489,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
>  	}
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  	shmob_drm_crtc_update_base(scrtc);
>  
>  	if (event) {
> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
> index 9336006..36c717a 100644
> --- a/drivers/gpu/drm/tegra/dc.c
> +++ b/drivers/gpu/drm/tegra/dc.c
> @@ -235,14 +235,14 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
>  	if (!dc->event)
>  		return;
>  
> -	bo = tegra_fb_get_plane(crtc->fb, 0);
> +	bo = tegra_fb_get_plane(crtc->primary->fb, 0);
>  
>  	/* check if new start address has been latched */
>  	tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
>  	base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
>  	tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
>  
> -	if (base == bo->paddr + crtc->fb->offsets[0]) {
> +	if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
>  		spin_lock_irqsave(&drm->event_lock, flags);
>  		drm_send_vblank_event(drm, dc->pipe, dc->event);
>  		drm_vblank_put(drm, dc->pipe);
> @@ -284,7 +284,7 @@ static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	}
>  
>  	tegra_dc_set_base(dc, 0, 0, fb);
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  
>  	return 0;
>  }
> @@ -645,7 +645,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
>  			       struct drm_display_mode *adjusted,
>  			       int x, int y, struct drm_framebuffer *old_fb)
>  {
> -	struct tegra_bo *bo = tegra_fb_get_plane(crtc->fb, 0);
> +	struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
>  	struct tegra_dc *dc = to_tegra_dc(crtc);
>  	struct tegra_dc_window window;
>  	unsigned long div, value;
> @@ -682,9 +682,9 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
>  	window.dst.y = 0;
>  	window.dst.w = mode->hdisplay;
>  	window.dst.h = mode->vdisplay;
> -	window.format = tegra_dc_format(crtc->fb->pixel_format);
> -	window.bits_per_pixel = crtc->fb->bits_per_pixel;
> -	window.stride[0] = crtc->fb->pitches[0];
> +	window.format = tegra_dc_format(crtc->primary->fb->pixel_format);
> +	window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
> +	window.stride[0] = crtc->primary->fb->pitches[0];
>  	window.base[0] = bo->paddr;
>  
>  	err = tegra_dc_setup_window(dc, 0, &window);
> @@ -699,7 +699,7 @@ static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>  {
>  	struct tegra_dc *dc = to_tegra_dc(crtc);
>  
> -	return tegra_dc_set_base(dc, x, y, crtc->fb);
> +	return tegra_dc_set_base(dc, x, y, crtc->primary->fb);
>  }
>  
>  static void tegra_crtc_prepare(struct drm_crtc *crtc)
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index d36efc1..d642d4a 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -74,7 +74,7 @@ static void set_scanout(struct drm_crtc *crtc, int n)
>  		drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]);
>  		drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
>  	}
> -	tilcdc_crtc->scanout[n] = crtc->fb;
> +	tilcdc_crtc->scanout[n] = crtc->primary->fb;
>  	drm_framebuffer_reference(tilcdc_crtc->scanout[n]);
>  	tilcdc_crtc->dirty &= ~stat[n];
>  	pm_runtime_put_sync(dev->dev);
> @@ -84,7 +84,7 @@ static void update_scanout(struct drm_crtc *crtc)
>  {
>  	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
>  	struct drm_device *dev = crtc->dev;
> -	struct drm_framebuffer *fb = crtc->fb;
> +	struct drm_framebuffer *fb = crtc->primary->fb;
>  	struct drm_gem_cma_object *gem;
>  	unsigned int depth, bpp;
>  
> @@ -159,7 +159,7 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
>  		return -EBUSY;
>  	}
>  
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  	tilcdc_crtc->event = event;
>  	update_scanout(crtc);
>  
> @@ -339,7 +339,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
>  	if (priv->rev == 2) {
>  		unsigned int depth, bpp;
>  
> -		drm_fb_get_bpp_depth(crtc->fb->pixel_format, &depth, &bpp);
> +		drm_fb_get_bpp_depth(crtc->primary->fb->pixel_format, &depth, &bpp);
>  		switch (bpp) {
>  		case 16:
>  			break;
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index 2ae1eb7..cddc4fc 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 a055a26..b2b9bd2 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 22406c8..a95d3a0 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;
> @@ -572,5 +572,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/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
> index 22be104..39a7519 100644
> --- a/drivers/staging/imx-drm/ipuv3-crtc.c
> +++ b/drivers/staging/imx-drm/ipuv3-crtc.c
> @@ -120,7 +120,7 @@ static int ipu_page_flip(struct drm_crtc *crtc,
>  
>  	ipu_crtc->newfb = fb;
>  	ipu_crtc->page_flip_event = event;
> -	crtc->fb = fb;
> +	crtc->primary->fb = fb;
>  
>  	return 0;
>  }
> @@ -192,7 +192,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
>  		return ret;
>  	}
>  
> -	return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb,
> +	return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->primary->fb,
>  				  0, 0, mode->hdisplay, mode->vdisplay,
>  				  x, y, mode->hdisplay, mode->vdisplay);
>  }
> @@ -218,7 +218,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
>  
>  	if (ipu_crtc->newfb) {
>  		ipu_crtc->newfb = NULL;
> -		ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb,
> +		ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.primary->fb,
>  				ipu_crtc->plane[0]->x, ipu_crtc->plane[0]->y);
>  		ipu_crtc_handle_pageflip(ipu_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] 35+ messages in thread

* Re: [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes()
  2014-03-28  0:44 ` [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes() Matt Roper
@ 2014-03-28  9:11   ` Daniel Vetter
  2014-03-28 17:56   ` Daniel Vetter
  1 sibling, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28  9:11 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Fri, Mar 28, 2014 at 1:44 AM, Matt Roper <matthew.d.roper@intel.com> wrote:
> Add a new drm_crtc_init_with_planes() to allow drivers to provide
> specific primary and cursor planes at CRTC initialization.  The existing
> drm_crtc_init() interface remains to avoid driver churn in existing
> drivers; it will initialize the CRTC with a plane helper-created primary
> plane and no cursor plane.
>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/drm_crtc.c | 44 +++++++++++++++++++++++++++++++++++++++++---
>  include/drm/drm_crtc.h     | 11 +++++++++++
>  2 files changed, 52 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 24226de..a983311 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -37,6 +37,7 @@
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_fourcc.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include "drm_crtc_internal.h"
>
> @@ -692,9 +693,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
>  EXPORT_SYMBOL(drm_framebuffer_remove);
>
>  /**
> - * drm_crtc_init - Initialise a new CRTC object
> + * drm_crtc_init_with_planes - Initialise a new CRTC object with
> + *    specified primary and cursor planes.
>   * @dev: DRM device
>   * @crtc: CRTC object to init
> + * @primary: Primary plane for CRTC
> + * @cursor: Cursor plane for CRTC
>   * @funcs: callbacks for the new CRTC
>   *
>   * Inits a new object created as base part of a driver crtc object.
> @@ -702,8 +706,10 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
>   * Returns:
>   * 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)
> +int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
> +                             struct drm_plane *primary,
> +                             struct drm_plane *cursor,
> +                             const struct drm_crtc_funcs *funcs)
>  {

I'm not sure we should add a spare parameter for the cursor planes
just yet. Or at least not quite with this type, just a void * to avoid
driver changes once we do add cursor plane support. I'll explain my
reasoning in a mail to your rfc re the cursor patches.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-03-28  8:32   ` Daniel Vetter
@ 2014-03-28 15:48     ` Laurent Pinchart
  2014-03-28 17:54       ` Daniel Vetter
  2014-04-01  1:03     ` Matt Roper
  2014-04-01  1:04     ` Rob Clark
  2 siblings, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2014-03-28 15:48 UTC (permalink / raw)
  To: dri-devel

On Friday 28 March 2014 09:32:06 Daniel Vetter wrote:
> On Thu, Mar 27, 2014 at 05:44:31PM -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 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.
> > 
> > v2:
> >  - Move plane helpers to a new file (drm_plane_helper.c)
> >  - Tighten checks on update handler (check for scaling, CRTC coverage,
> >    subpixel positioning)
> >  - Pass proper panning parameters to modeset interface
> >  - Disallow disabling primary plane (and thus CRTC) if other planes are
> >    still active on the CRTC.
> >  - Use a minimal format list that should work on all hardware/drivers.
> >    Drivers may call this function with a more accurate plane list to
> >    enable additional formats they can support.
> > 
> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> > ---
> > 
> >  drivers/gpu/drm/Makefile           |   3 +-
> >  drivers/gpu/drm/drm_plane_helper.c | 312 ++++++++++++++++++++++++++++++++
> >  include/drm/drm_plane_helper.h     |  49 ++++++
> 
> DocBook integration is missing for all the great kerneldoc you've written.

I'd go a bit further than that, there's a chapter on planes in the DocBook 
documentation that should also be updated, otherwise it would get outdated.

> That boils down to adding a new section next to the other helper libraries
> in the drm docbook to pull the kerneldoc in and running make htmldocs to
> make sure the kerneldoc checks out.
> 
> If you want you can add a DOC: overview section and pull that into the
> docbook too, see e.g. how the drm prime helpers are integrated.
> 
> >  3 files changed, 363 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/gpu/drm/drm_plane_helper.c
> >  create mode 100644 include/drm/drm_plane_helper.h

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes
  2014-03-28  0:44 ` [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes Matt Roper
@ 2014-03-28 15:50   ` Laurent Pinchart
  2014-03-28 17:52     ` Daniel Vetter
  0 siblings, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2014-03-28 15:50 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

Hi Matt,

Thank you for the patch.

On Thursday 27 March 2014 17:44:29 Matt Roper wrote:
> Ensure that existing driver loops over all planes do not change behavior
> when we begin adding new types of planes (primary and cursor) to the DRM
> plane list in future patches.
> 
> Cc: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

I have a question though. The patch set introduces three plane types, OVERLAY, 
PRIMARY and CURSOR. What should a driver that has no concept of primary plane 
do ? Expose all planes as OVERLAY planes only ?

> ---
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 0428076..ea543b4 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -247,7 +247,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc
> *scrtc) lcdc_write(sdev, LDDDSR, value);
> 
>  	/* Setup planes. */
> -	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> +	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
>  		if (plane->crtc == crtc)
>  			shmob_drm_plane_setup(plane);
>  	}

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes
  2014-03-28 15:50   ` Laurent Pinchart
@ 2014-03-28 17:52     ` Daniel Vetter
  2014-03-28 17:53       ` Daniel Vetter
  0 siblings, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28 17:52 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: dri-devel

On Fri, Mar 28, 2014 at 04:50:13PM +0100, Laurent Pinchart wrote:
> Hi Matt,
> 
> Thank you for the patch.
> 
> On Thursday 27 March 2014 17:44:29 Matt Roper wrote:
> > Ensure that existing driver loops over all planes do not change behavior
> > when we begin adding new types of planes (primary and cursor) to the DRM
> > plane list in future patches.
> > 
> > Cc: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> 
> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> I have a question though. The patch set introduces three plane types, OVERLAY, 
> PRIMARY and CURSOR. What should a driver that has no concept of primary plane 
> do ? Expose all planes as OVERLAY planes only ?

It's a matter of backwards compat with old userspace. primary/cursor are
simply ways to tell the drm core which planes to use to forward the legacy
cursor crtc and which plane will be used for the framebuffer in setCrtc.

So until we have the new atomic interface ready your driver kinda needs to
expose at least a primary plane, otherwise there's no way to even switch
on the crtc.

But besides this backwards compat issue there's no difference and you can
specify whatever plane you want as primary/cursor (or none if you don't
care about old userspace).
-Daniel

> 
> > ---
> >  drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> > b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 0428076..ea543b4 100644
> > --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> > +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> > @@ -247,7 +247,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc
> > *scrtc) lcdc_write(sdev, LDDDSR, value);
> > 
> >  	/* Setup planes. */
> > -	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> > +	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
> >  		if (plane->crtc == crtc)
> >  			shmob_drm_plane_setup(plane);
> >  	}
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> _______________________________________________
> 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] 35+ messages in thread

* Re: [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes
  2014-03-28 17:52     ` Daniel Vetter
@ 2014-03-28 17:53       ` Daniel Vetter
  2014-04-01 15:27         ` Laurent Pinchart
  0 siblings, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28 17:53 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: dri-devel

On Fri, Mar 28, 2014 at 06:52:50PM +0100, Daniel Vetter wrote:
> On Fri, Mar 28, 2014 at 04:50:13PM +0100, Laurent Pinchart wrote:
> > Hi Matt,
> > 
> > Thank you for the patch.
> > 
> > On Thursday 27 March 2014 17:44:29 Matt Roper wrote:
> > > Ensure that existing driver loops over all planes do not change behavior
> > > when we begin adding new types of planes (primary and cursor) to the DRM
> > > plane list in future patches.
> > > 
> > > Cc: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> > > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> > 
> > Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > I have a question though. The patch set introduces three plane types, OVERLAY, 
> > PRIMARY and CURSOR. What should a driver that has no concept of primary plane 
> > do ? Expose all planes as OVERLAY planes only ?
> 
> It's a matter of backwards compat with old userspace. primary/cursor are
> simply ways to tell the drm core which planes to use to forward the legacy
> cursor crtc and which plane will be used for the framebuffer in setCrtc.
> 
> So until we have the new atomic interface ready your driver kinda needs to
> expose at least a primary plane, otherwise there's no way to even switch
> on the crtc.
> 
> But besides this backwards compat issue there's no difference and you can
> specify whatever plane you want as primary/cursor (or none if you don't
> care about old userspace).

Well the NULL primary plane probably needs a bit of work on top of Matt's
patch series here ...
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-03-28 15:48     ` Laurent Pinchart
@ 2014-03-28 17:54       ` Daniel Vetter
  2014-04-01 15:25         ` Laurent Pinchart
  0 siblings, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28 17:54 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: dri-devel

On Fri, Mar 28, 2014 at 04:48:42PM +0100, Laurent Pinchart wrote:
> On Friday 28 March 2014 09:32:06 Daniel Vetter wrote:
> > On Thu, Mar 27, 2014 at 05:44:31PM -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 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.
> > > 
> > > v2:
> > >  - Move plane helpers to a new file (drm_plane_helper.c)
> > >  - Tighten checks on update handler (check for scaling, CRTC coverage,
> > >    subpixel positioning)
> > >  - Pass proper panning parameters to modeset interface
> > >  - Disallow disabling primary plane (and thus CRTC) if other planes are
> > >    still active on the CRTC.
> > >  - Use a minimal format list that should work on all hardware/drivers.
> > >    Drivers may call this function with a more accurate plane list to
> > >    enable additional formats they can support.
> > > 
> > > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> > > ---
> > > 
> > >  drivers/gpu/drm/Makefile           |   3 +-
> > >  drivers/gpu/drm/drm_plane_helper.c | 312 ++++++++++++++++++++++++++++++++
> > >  include/drm/drm_plane_helper.h     |  49 ++++++
> > 
> > DocBook integration is missing for all the great kerneldoc you've written.
> 
> I'd go a bit further than that, there's a chapter on planes in the DocBook 
> documentation that should also be updated, otherwise it would get outdated.

Probably better done as part of the patch which actually adds primary
planes, since this here is just the convenience helpers for easier
transition ...
-Daniel

> 
> > That boils down to adding a new section next to the other helper libraries
> > in the drm docbook to pull the kerneldoc in and running make htmldocs to
> > make sure the kerneldoc checks out.
> > 
> > If you want you can add a DOC: overview section and pull that into the
> > docbook too, see e.g. how the drm prime helpers are integrated.
> > 
> > >  3 files changed, 363 insertions(+), 1 deletion(-)
> > >  create mode 100644 drivers/gpu/drm/drm_plane_helper.c
> > >  create mode 100644 include/drm/drm_plane_helper.h
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

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

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

* Re: [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes()
  2014-03-28  0:44 ` [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes() Matt Roper
  2014-03-28  9:11   ` Daniel Vetter
@ 2014-03-28 17:56   ` Daniel Vetter
  1 sibling, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-03-28 17:56 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Thu, Mar 27, 2014 at 05:44:35PM -0700, Matt Roper wrote:
> Add a new drm_crtc_init_with_planes() to allow drivers to provide
> specific primary and cursor planes at CRTC initialization.  The existing
> drm_crtc_init() interface remains to avoid driver churn in existing
> drivers; it will initialize the CRTC with a plane helper-created primary
> plane and no cursor plane.
> 
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/drm_crtc.c | 44 +++++++++++++++++++++++++++++++++++++++++---
>  include/drm/drm_crtc.h     | 11 +++++++++++
>  2 files changed, 52 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 24226de..a983311 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -37,6 +37,7 @@
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_fourcc.h>
> +#include <drm/drm_plane_helper.h>
>  
>  #include "drm_crtc_internal.h"
>  
> @@ -692,9 +693,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
>  EXPORT_SYMBOL(drm_framebuffer_remove);
>  
>  /**
> - * drm_crtc_init - Initialise a new CRTC object
> + * drm_crtc_init_with_planes - Initialise a new CRTC object with
> + *    specified primary and cursor planes.
>   * @dev: DRM device
>   * @crtc: CRTC object to init
> + * @primary: Primary plane for CRTC
> + * @cursor: Cursor plane for CRTC
>   * @funcs: callbacks for the new CRTC
>   *
>   * Inits a new object created as base part of a driver crtc object.
> @@ -702,8 +706,10 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
>   * Returns:
>   * 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)
> +int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
> +			      struct drm_plane *primary,
> +			      struct drm_plane *cursor,
> +			      const struct drm_crtc_funcs *funcs)
>  {
>  	int ret;
>  
> @@ -724,11 +730,41 @@ 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;
> +	if (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);
>  
>  	return ret;
>  }
> +EXPORT_SYMBOL(drm_crtc_init_with_planes);
> +
> +/**
> + * drm_crtc_init - Legacy CRTC initialization function
> + * @dev: DRM device
> + * @crtc: CRTC object to init
> + * @funcs: callbacks for the new CRTC
> + *
> + * Initialize a CRTC object with a default helper-provided primary plane and no
> + * cursor plane.
> + *
> + * Returns:
> + * 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;
> +
> +	primary = drm_primary_helper_create_plane(dev, NULL, 0);
> +	return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
> +}
>  EXPORT_SYMBOL(drm_crtc_init);

I think we should move the drm_crtc_init to drm_plane_helpers.c to be
perfectly strict with the "nothing in drm core should depend upon helpers"
rule for avoiding midlayer mistakes.
-Daniel

>  
>  /**
> @@ -2248,6 +2284,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/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 78cf825..e7ed766 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -270,6 +270,8 @@ 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
> + * @cursor: cursor plane for this CRTC
>   * @enabled: is this CRTC enabled?
>   * @mode: current mode timings
>   * @hwmode: mode timings as programmed to hw regs
> @@ -305,6 +307,10 @@ struct drm_crtc {
>  
>  	struct drm_mode_object base;
>  
> +	/* primary and cursor planes for CRTC */
> +	struct drm_plane *primary;
> +	struct drm_plane *cursor;
> +
>  	/* framebuffer the connector is currently bound to */
>  	struct drm_framebuffer *fb;
>  
> @@ -826,6 +832,11 @@ extern void drm_modeset_lock_all(struct drm_device *dev);
>  extern void drm_modeset_unlock_all(struct drm_device *dev);
>  extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
>  
> +extern int drm_crtc_init_with_planes(struct drm_device *dev,
> +				     struct drm_crtc *crtc,
> +				     struct drm_plane *primary,
> +				     struct drm_plane *cursor,
> +				     const struct drm_crtc_funcs *funcs);
>  extern int drm_crtc_init(struct drm_device *dev,
>  			 struct drm_crtc *crtc,
>  			 const struct drm_crtc_funcs *funcs);
> -- 
> 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] 35+ messages in thread

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-03-28  8:32   ` Daniel Vetter
  2014-03-28 15:48     ` Laurent Pinchart
@ 2014-04-01  1:03     ` Matt Roper
  2014-04-01  7:45       ` Daniel Vetter
  2014-04-01  1:04     ` Rob Clark
  2 siblings, 1 reply; 35+ messages in thread
From: Matt Roper @ 2014-04-01  1:03 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Fri, Mar 28, 2014 at 09:32:06AM +0100, Daniel Vetter wrote:
> On Thu, Mar 27, 2014 at 05:44:31PM -0700, Matt Roper wrote:
...
> > +	 * N.B., we call set_config() directly here rather than using
> > +	 * drm_mode_set_config_internal.  We're reprogramming the same
> > +	 * connectors that were already in use, so we shouldn't need the extra
> > +	 * cross-CRTC fb refcounting to accomodate stealing connectors.
> > +	 * drm_mode_setplane() already handles the basic refcounting for the
> > +	 * framebuffers involved in this operation.
> 
> Wrong. The current crtc helper logic disables all disconnected connectors
> forcefully on each set_config. Nope, I didn't make those semantics ... So
> I think we need to think a bit harder here again.
> 
> See drm_helper_disable_unused_functions.

I think I'm still missing something here; can you clarify what the
problematic case would be?

I only see a call to __drm_helper_disable_unused_functions() in the CRTC
helper in cases where mode_changed = 1, which I don't believe it ever
should be through the setplane() calls.  We should just be updating the
framebuffer (and possibly panning) without touching any of the
connectors, so I don't see how unrelated CRTC's would get disabled.  Am
I overlooking another case here that the basic refcounting in setplane
doesn't already handle?

Thanks.


Matt

> 
> > +	 */
> > +	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 if no other planes are currently enabled.
> > + * If other planes are still enabled on the same CRTC, we return -EBUSY.
> > + *
> > + * 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_plane *p;
> > +	struct drm_mode_set set = {
> > +		.crtc = plane->crtc,
> > +		.fb = NULL,
> > +	};
> > +
> > +	if (plane->crtc == NULL || plane->fb == NULL)
> > +		/* Already disabled */
> > +		return 0;
> > +
> > +	list_for_each_entry(p, &plane->dev->mode_config.plane_list, head)
> > +		if (p != plane && p->fb) {
> > +			DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n");
> > +			return -EBUSY;
> > +		}
> > +
> > +	/*
> > +	 * N.B.  We call set_config() directly here rather than
> > +	 * drm_mode_set_config_internal() since drm_mode_setplane() already
> > +	 * handles the basic refcounting and we don't need the special
> > +	 * cross-CRTC refcounting (no chance of stealing connectors from
> > +	 * other CRTC's with this update).
> 
> Same comment as above applies. Calling ->set_config is considered harmful
> ... Maybe we need to add another wrapper here for the primary plane
> helpers to wrap this all up safely?
> 
> > +	 */
> > +	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
> > + * @formats: pixel formats supported, or NULL for a default safe list
> > + * @num_formats: size of @formats; ignored if @formats is NULL
> > + *
> > + * 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,
> > +						  const uint32_t *formats,
> > +						  int num_formats)
> > +{
> > +	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;
> > +	}
> > +
> > +	if (formats == NULL) {
> > +		formats = safe_modeset_formats;
> > +		num_formats = ARRAY_SIZE(safe_modeset_formats);
> > +	}
> > +
> > +	/* possible_crtc's will be filled in later by crtc_init */
> > +	ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
> > +			     formats, num_formats,
> > +			     DRM_PLANE_TYPE_PRIMARY);
> > +	if (ret) {
> > +		kfree(primary);
> > +		primary = NULL;
> > +	}
> > +
> > +	return primary;
> > +}
> > +EXPORT_SYMBOL(drm_primary_helper_create_plane);
> > +
> > diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
> > new file mode 100644
> > index 0000000..09824be
> > --- /dev/null
> > +++ b/include/drm/drm_plane_helper.h
> > @@ -0,0 +1,49 @@
> > +/*
> > + * Copyright (C) 2011-2013 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaining a
> > + * copy of this software and associated documentation files (the "Software"),
> > + * to deal in the Software without restriction, including without limitation
> > + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> > + * and/or sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice (including the next
> > + * paragraph) shall be included in all copies or substantial portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> > + * SOFTWARE.
> > + */
> > +
> > +#ifndef DRM_PLANE_HELPER_H
> > +#define DRM_PLANE_HELPER_H
> > +
> > +/**
> > + * DOC: plane helpers
> > + *
> > + * Helper functions to assist with creation and handling of CRTC primary
> > + * planes.
> > + */
> > +
> > +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,
> > +							 uint32_t *formats,
> > +							 int num_formats);
> > +
> > +
> > +#endif
> > -- 
> > 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] 35+ messages in thread

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-03-28  8:32   ` Daniel Vetter
  2014-03-28 15:48     ` Laurent Pinchart
  2014-04-01  1:03     ` Matt Roper
@ 2014-04-01  1:04     ` Rob Clark
  2 siblings, 0 replies; 35+ messages in thread
From: Rob Clark @ 2014-04-01  1:04 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Fri, Mar 28, 2014 at 4:32 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.
>> +      *
>> +      * N.B., we call set_config() directly here rather than using
>> +      * drm_mode_set_config_internal.  We're reprogramming the same
>> +      * connectors that were already in use, so we shouldn't need the extra
>> +      * cross-CRTC fb refcounting to accomodate stealing connectors.
>> +      * drm_mode_setplane() already handles the basic refcounting for the
>> +      * framebuffers involved in this operation.
>
> Wrong. The current crtc helper logic disables all disconnected connectors
> forcefully on each set_config. Nope, I didn't make those semantics ... So
> I think we need to think a bit harder here again.

Hmm, I'm not really seeing the problem.  The worst setplane could do
is enable a crtc which otherwise already has an encoder+connector
pointing to it.  Which would mean that encoder+connector could not be
pointing to another crtc.

So yeah, we'll end up calling dpms(OFF) on a bunch of stuff that is
already off.. is that a problem?

>
> See drm_helper_disable_unused_functions.
>
>> +      */
>> +     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 if no other planes are currently enabled.
>> + * If other planes are still enabled on the same CRTC, we return -EBUSY.
>> + *
>> + * 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_plane *p;
>> +     struct drm_mode_set set = {
>> +             .crtc = plane->crtc,
>> +             .fb = NULL,
>> +     };
>> +
>> +     if (plane->crtc == NULL || plane->fb == NULL)
>> +             /* Already disabled */
>> +             return 0;
>> +
>> +     list_for_each_entry(p, &plane->dev->mode_config.plane_list, head)
>> +             if (p != plane && p->fb) {
>> +                     DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n");
>> +                     return -EBUSY;
>> +             }
>> +
>> +     /*
>> +      * N.B.  We call set_config() directly here rather than
>> +      * drm_mode_set_config_internal() since drm_mode_setplane() already
>> +      * handles the basic refcounting and we don't need the special
>> +      * cross-CRTC refcounting (no chance of stealing connectors from
>> +      * other CRTC's with this update).
>
> Same comment as above applies. Calling ->set_config is considered harmful
> ... Maybe we need to add another wrapper here for the primary plane
> helpers to wrap this all up safely?


actually, again, I think calling .set_config() directly here is the
correct thing.  There should be no connector/encoder changes.  and the
drm_mode_set_config_internal() refcounting would be wrong for
drm_mode_setplane().  In the helpers he undoes the plane->fb update
done by the driver in .set_config() so that drm_mode_setplane() dtrt..


As an aside, that inconsistency between who updates the fb ptr between
setcrtc and setplane has been bothering me for a while now with the
atomic stuff.  Maybe it's just the OCD talking, but I'd *really* like
to clean that up.  The rough thinking I have, with the atomic stuff we
introduce a second fb pointer (and reference) in the state object.  So
initially we have:

   plane->fb    ---   current rules
   plane->state->fb   ---   immutable, set to new incoming fb before
calling in to driver.. drm core manages the refcnt, read-only access
for the driver

what I'd like to do is request that all drivers add their own internal
scanout references, etc.  And we eventually remove plane->fb when no
one still references it.  The outgoing state object will hold a ref to
old_fb until after we return from calling in to the driver.  The only
thing left is for each driver to (if it cannot cancel scanout
mid-frame) hold a reference until next vblank.

BR,
-R

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

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-04-01  1:03     ` Matt Roper
@ 2014-04-01  7:45       ` Daniel Vetter
  2014-04-01 11:45         ` Rob Clark
  2014-04-01 19:46         ` Dave Airlie
  0 siblings, 2 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-04-01  7:45 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Mon, Mar 31, 2014 at 06:03:24PM -0700, Matt Roper wrote:
> On Fri, Mar 28, 2014 at 09:32:06AM +0100, Daniel Vetter wrote:
> > On Thu, Mar 27, 2014 at 05:44:31PM -0700, Matt Roper wrote:
> ...
> > > +	 * N.B., we call set_config() directly here rather than using
> > > +	 * drm_mode_set_config_internal.  We're reprogramming the same
> > > +	 * connectors that were already in use, so we shouldn't need the extra
> > > +	 * cross-CRTC fb refcounting to accomodate stealing connectors.
> > > +	 * drm_mode_setplane() already handles the basic refcounting for the
> > > +	 * framebuffers involved in this operation.
> > 
> > Wrong. The current crtc helper logic disables all disconnected connectors
> > forcefully on each set_config. Nope, I didn't make those semantics ... So
> > I think we need to think a bit harder here again.
> > 
> > See drm_helper_disable_unused_functions.
> 
> I think I'm still missing something here; can you clarify what the
> problematic case would be?
> 
> I only see a call to __drm_helper_disable_unused_functions() in the CRTC
> helper in cases where mode_changed = 1, which I don't believe it ever
> should be through the setplane() calls.  We should just be updating the
> framebuffer (and possibly panning) without touching any of the
> connectors, so I don't see how unrelated CRTC's would get disabled.  Am
> I overlooking another case here that the basic refcounting in setplane
> doesn't already handle?

Looking at drm_helper_disable_unused_functions we'll spot

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (!connector->encoder)
			continue;
		if (connector->status == connector_status_disconnected)
			connector->encoder = NULL;
	}


So as soon as a connector is disconnected and you do _any_ kind of
->set_config call with modesetting helpers that crtc gets killed. Even if
it's completely unrelated. Dave originally changed this with an imo rather
thin justification:

commit a3a0544b2c84e1d7a2022b558ecf66d8c6a8dd93
Author: Dave Airlie <airlied@redhat.com>
Date:   Mon Aug 31 15:16:30 2009 +1000

    drm/kms: add explicit encoder disable function and detach harder.
    
    For shared tv-out and VGA encoders, we really need to know if
    the encoder is just being switched off temporarily in blanking
    or if we are really disabling it hard.
    
    Also we need to try harder to disconnect encoders from unused
    connectors so we can share more efficently.
    
    (shared encoders stuff is coming in radeon tv-out support)
    
    Signed-off-by: Dave Airlie <airlied@redhat.com>

To me this always smelled like papering over broken userspace. I've killed
this in the i915 modeset rewrite and we didn't really have angry users
scaling our walls. But I'm not sure what'll happen if we do this for all
other drivers.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-04-01  7:45       ` Daniel Vetter
@ 2014-04-01 11:45         ` Rob Clark
  2014-04-01 12:33           ` Daniel Vetter
  2014-04-01 19:46         ` Dave Airlie
  1 sibling, 1 reply; 35+ messages in thread
From: Rob Clark @ 2014-04-01 11:45 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Tue, Apr 1, 2014 at 3:45 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Mon, Mar 31, 2014 at 06:03:24PM -0700, Matt Roper wrote:
>> On Fri, Mar 28, 2014 at 09:32:06AM +0100, Daniel Vetter wrote:
>> > On Thu, Mar 27, 2014 at 05:44:31PM -0700, Matt Roper wrote:
>> ...
>> > > +  * N.B., we call set_config() directly here rather than using
>> > > +  * drm_mode_set_config_internal.  We're reprogramming the same
>> > > +  * connectors that were already in use, so we shouldn't need the extra
>> > > +  * cross-CRTC fb refcounting to accomodate stealing connectors.
>> > > +  * drm_mode_setplane() already handles the basic refcounting for the
>> > > +  * framebuffers involved in this operation.
>> >
>> > Wrong. The current crtc helper logic disables all disconnected connectors
>> > forcefully on each set_config. Nope, I didn't make those semantics ... So
>> > I think we need to think a bit harder here again.
>> >
>> > See drm_helper_disable_unused_functions.
>>
>> I think I'm still missing something here; can you clarify what the
>> problematic case would be?
>>
>> I only see a call to __drm_helper_disable_unused_functions() in the CRTC
>> helper in cases where mode_changed = 1, which I don't believe it ever
>> should be through the setplane() calls.  We should just be updating the
>> framebuffer (and possibly panning) without touching any of the
>> connectors, so I don't see how unrelated CRTC's would get disabled.  Am
>> I overlooking another case here that the basic refcounting in setplane
>> doesn't already handle?
>
> Looking at drm_helper_disable_unused_functions we'll spot
>
>         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
>                 if (!connector->encoder)
>                         continue;
>                 if (connector->status == connector_status_disconnected)
>                         connector->encoder = NULL;
>         }
>
>
> So as soon as a connector is disconnected and you do _any_ kind of
> ->set_config call with modesetting helpers that crtc gets killed. Even if
> it's completely unrelated. Dave originally changed this with an imo rather
> thin justification:

sure, so this could change the timing of things a bit..  but it would
be a bug if a HPD event or poll didn't eventually detect that and shut
things off..

BR,
-R

> commit a3a0544b2c84e1d7a2022b558ecf66d8c6a8dd93
> Author: Dave Airlie <airlied@redhat.com>
> Date:   Mon Aug 31 15:16:30 2009 +1000
>
>     drm/kms: add explicit encoder disable function and detach harder.
>
>     For shared tv-out and VGA encoders, we really need to know if
>     the encoder is just being switched off temporarily in blanking
>     or if we are really disabling it hard.
>
>     Also we need to try harder to disconnect encoders from unused
>     connectors so we can share more efficently.
>
>     (shared encoders stuff is coming in radeon tv-out support)
>
>     Signed-off-by: Dave Airlie <airlied@redhat.com>
>
> To me this always smelled like papering over broken userspace. I've killed
> this in the i915 modeset rewrite and we didn't really have angry users
> scaling our walls. But I'm not sure what'll happen if we do this for all
> other drivers.
> -Daniel
> --
> 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] 35+ messages in thread

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-04-01 11:45         ` Rob Clark
@ 2014-04-01 12:33           ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-04-01 12:33 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Tue, Apr 1, 2014 at 1:45 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Tue, Apr 1, 2014 at 3:45 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
>> On Mon, Mar 31, 2014 at 06:03:24PM -0700, Matt Roper wrote:
>>> On Fri, Mar 28, 2014 at 09:32:06AM +0100, Daniel Vetter wrote:
>>> > On Thu, Mar 27, 2014 at 05:44:31PM -0700, Matt Roper wrote:
>>> ...
>>> > > +  * N.B., we call set_config() directly here rather than using
>>> > > +  * drm_mode_set_config_internal.  We're reprogramming the same
>>> > > +  * connectors that were already in use, so we shouldn't need the extra
>>> > > +  * cross-CRTC fb refcounting to accomodate stealing connectors.
>>> > > +  * drm_mode_setplane() already handles the basic refcounting for the
>>> > > +  * framebuffers involved in this operation.
>>> >
>>> > Wrong. The current crtc helper logic disables all disconnected connectors
>>> > forcefully on each set_config. Nope, I didn't make those semantics ... So
>>> > I think we need to think a bit harder here again.
>>> >
>>> > See drm_helper_disable_unused_functions.
>>>
>>> I think I'm still missing something here; can you clarify what the
>>> problematic case would be?
>>>
>>> I only see a call to __drm_helper_disable_unused_functions() in the CRTC
>>> helper in cases where mode_changed = 1, which I don't believe it ever
>>> should be through the setplane() calls.  We should just be updating the
>>> framebuffer (and possibly panning) without touching any of the
>>> connectors, so I don't see how unrelated CRTC's would get disabled.  Am
>>> I overlooking another case here that the basic refcounting in setplane
>>> doesn't already handle?
>>
>> Looking at drm_helper_disable_unused_functions we'll spot
>>
>>         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
>>                 if (!connector->encoder)
>>                         continue;
>>                 if (connector->status == connector_status_disconnected)
>>                         connector->encoder = NULL;
>>         }
>>
>>
>> So as soon as a connector is disconnected and you do _any_ kind of
>> ->set_config call with modesetting helpers that crtc gets killed. Even if
>> it's completely unrelated. Dave originally changed this with an imo rather
>> thin justification:
>
> sure, so this could change the timing of things a bit..  but it would
> be a bug if a HPD event or poll didn't eventually detect that and shut
> things off..

Well on the semantics imo this is userspace's decision, or should be
at least. And there's no driver which kills the output in the hdp
handler at all. So I'm all in favour of just removing this and letting
DEs handle hpd events (like they currently all do). But until we have
that completely unrelated crtcs _can_ get disabled when you call
->set_config, and that means we do have to handle the refcounting
correctly by doing what set_config_internal does essentially.
-Daniel
--
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-03-28 17:54       ` Daniel Vetter
@ 2014-04-01 15:25         ` Laurent Pinchart
  0 siblings, 0 replies; 35+ messages in thread
From: Laurent Pinchart @ 2014-04-01 15:25 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

Hi Daniel,

On Friday 28 March 2014 18:54:49 Daniel Vetter wrote:
> On Fri, Mar 28, 2014 at 04:48:42PM +0100, Laurent Pinchart wrote:
> > On Friday 28 March 2014 09:32:06 Daniel Vetter wrote:
> > > On Thu, Mar 27, 2014 at 05:44:31PM -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 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.
> > > > 
> > > > v2:
> > > >  - Move plane helpers to a new file (drm_plane_helper.c)
> > > >  - Tighten checks on update handler (check for scaling, CRTC coverage,
> > > >    subpixel positioning)
> > > >  - Pass proper panning parameters to modeset interface
> > > >  - Disallow disabling primary plane (and thus CRTC) if other planes
> > > >    are still active on the CRTC.
> > > >  - Use a minimal format list that should work on all hardware/drivers.
> > > >    Drivers may call this function with a more accurate plane list to
> > > >    enable additional formats they can support.
> > > > 
> > > > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> > > > ---
> > > > 
> > > >  drivers/gpu/drm/Makefile           |   3 +-
> > > >  drivers/gpu/drm/drm_plane_helper.c | 312 ++++++++++++++++++++++++++++
> > > >  include/drm/drm_plane_helper.h     |  49 ++++++
> > > 
> > > DocBook integration is missing for all the great kerneldoc you've
> > > written.
> > 
> > I'd go a bit further than that, there's a chapter on planes in the DocBook
> > documentation that should also be updated, otherwise it would get
> > outdated.
> 
> Probably better done as part of the patch which actually adds primary
> planes, since this here is just the convenience helpers for easier
> transition ...

Sure, that's perfectly fine with me.

> > > That boils down to adding a new section next to the other helper
> > > libraries in the drm docbook to pull the kerneldoc in and running make
> > > htmldocs to make sure the kerneldoc checks out.
> > > 
> > > If you want you can add a DOC: overview section and pull that into the
> > > docbook too, see e.g. how the drm prime helpers are integrated.
> > > 
> > > >  3 files changed, 363 insertions(+), 1 deletion(-)
> > > >  create mode 100644 drivers/gpu/drm/drm_plane_helper.c
> > > >  create mode 100644 include/drm/drm_plane_helper.h

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes
  2014-03-28 17:53       ` Daniel Vetter
@ 2014-04-01 15:27         ` Laurent Pinchart
  2014-04-01 21:43           ` Daniel Vetter
  0 siblings, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2014-04-01 15:27 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

Hi Daniel,

On Friday 28 March 2014 18:53:40 Daniel Vetter wrote:
> On Fri, Mar 28, 2014 at 06:52:50PM +0100, Daniel Vetter wrote:
> > On Fri, Mar 28, 2014 at 04:50:13PM +0100, Laurent Pinchart wrote:
> > > On Thursday 27 March 2014 17:44:29 Matt Roper wrote:
> > > > Ensure that existing driver loops over all planes do not change
> > > > behavior when we begin adding new types of planes (primary and cursor)
> > > > to the DRM plane list in future patches.
> > > > 
> > > > Cc: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> > > > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> > > 
> > > Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > 
> > > I have a question though. The patch set introduces three plane types,
> > > OVERLAY, PRIMARY and CURSOR. What should a driver that has no concept
> > > of primary plane do ? Expose all planes as OVERLAY planes only ?
> > 
> > It's a matter of backwards compat with old userspace. primary/cursor are
> > simply ways to tell the drm core which planes to use to forward the legacy
> > cursor crtc and which plane will be used for the framebuffer in setCrtc.
> > 
> > So until we have the new atomic interface ready your driver kinda needs to
> > expose at least a primary plane, otherwise there's no way to even switch
> > on the crtc.
> > 
> > But besides this backwards compat issue there's no difference and you can
> > specify whatever plane you want as primary/cursor (or none if you don't
> > care about old userspace).
> 
> Well the NULL primary plane probably needs a bit of work on top of Matt's
> patch series here ...

It's the NULL primary plane I'm interested about, to allow a "root" plane not 
to span the whole display. I have no urgent need for this though, I was just 
curious to see if that feature was planned.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-04-01  7:45       ` Daniel Vetter
  2014-04-01 11:45         ` Rob Clark
@ 2014-04-01 19:46         ` Dave Airlie
  2014-04-01 21:47           ` Daniel Vetter
  1 sibling, 1 reply; 35+ messages in thread
From: Dave Airlie @ 2014-04-01 19:46 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Tue, Apr 1, 2014 at 5:45 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Mon, Mar 31, 2014 at 06:03:24PM -0700, Matt Roper wrote:
>> On Fri, Mar 28, 2014 at 09:32:06AM +0100, Daniel Vetter wrote:
>> > On Thu, Mar 27, 2014 at 05:44:31PM -0700, Matt Roper wrote:
>> ...
>> > > +  * N.B., we call set_config() directly here rather than using
>> > > +  * drm_mode_set_config_internal.  We're reprogramming the same
>> > > +  * connectors that were already in use, so we shouldn't need the extra
>> > > +  * cross-CRTC fb refcounting to accomodate stealing connectors.
>> > > +  * drm_mode_setplane() already handles the basic refcounting for the
>> > > +  * framebuffers involved in this operation.
>> >
>> > Wrong. The current crtc helper logic disables all disconnected connectors
>> > forcefully on each set_config. Nope, I didn't make those semantics ... So
>> > I think we need to think a bit harder here again.
>> >
>> > See drm_helper_disable_unused_functions.
>>
>> I think I'm still missing something here; can you clarify what the
>> problematic case would be?
>>
>> I only see a call to __drm_helper_disable_unused_functions() in the CRTC
>> helper in cases where mode_changed = 1, which I don't believe it ever
>> should be through the setplane() calls.  We should just be updating the
>> framebuffer (and possibly panning) without touching any of the
>> connectors, so I don't see how unrelated CRTC's would get disabled.  Am
>> I overlooking another case here that the basic refcounting in setplane
>> doesn't already handle?
>
> Looking at drm_helper_disable_unused_functions we'll spot
>
>         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
>                 if (!connector->encoder)
>                         continue;
>                 if (connector->status == connector_status_disconnected)
>                         connector->encoder = NULL;
>         }
>
>
> So as soon as a connector is disconnected and you do _any_ kind of
> ->set_config call with modesetting helpers that crtc gets killed. Even if
> it's completely unrelated. Dave originally changed this with an imo rather
> thin justification:
>
> commit a3a0544b2c84e1d7a2022b558ecf66d8c6a8dd93
> Author: Dave Airlie <airlied@redhat.com>
> Date:   Mon Aug 31 15:16:30 2009 +1000
>
>     drm/kms: add explicit encoder disable function and detach harder.
>
>     For shared tv-out and VGA encoders, we really need to know if
>     the encoder is just being switched off temporarily in blanking
>     or if we are really disabling it hard.
>
>     Also we need to try harder to disconnect encoders from unused
>     connectors so we can share more efficently.
>
>     (shared encoders stuff is coming in radeon tv-out support)
>
>     Signed-off-by: Dave Airlie <airlied@redhat.com>
>
> To me this always smelled like papering over broken userspace. I've killed
> this in the i915 modeset rewrite and we didn't really have angry users
> scaling our walls. But I'm not sure what'll happen if we do this for all
> other drivers.

I've had to look at this again recently, and while I still don't like
my commit, its
not papering over userspace, it might be papering over fbcon :-)

You don't have any hw that operates like this, so I'd be surprised if
you had users falling over,

The problem is if I have a single DAC encoder, with tv-out and VGA
connectors, and I unplug the VGA connector, and plug in the tv
connector, how do I get fbcon to pop-up,

Though that said this commit caused a regression that I'm not sure I
liked either, since I think we used to allow you to force a mode on
disconnected outputs, and this stops that from working, I noticed in a
virtual env.

Dave.

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

* Re: [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes
  2014-04-01 15:27         ` Laurent Pinchart
@ 2014-04-01 21:43           ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-04-01 21:43 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: dri-devel

On Tue, Apr 01, 2014 at 05:27:33PM +0200, Laurent Pinchart wrote:
> Hi Daniel,
> 
> On Friday 28 March 2014 18:53:40 Daniel Vetter wrote:
> > On Fri, Mar 28, 2014 at 06:52:50PM +0100, Daniel Vetter wrote:
> > > On Fri, Mar 28, 2014 at 04:50:13PM +0100, Laurent Pinchart wrote:
> > > > On Thursday 27 March 2014 17:44:29 Matt Roper wrote:
> > > > > Ensure that existing driver loops over all planes do not change
> > > > > behavior when we begin adding new types of planes (primary and cursor)
> > > > > to the DRM plane list in future patches.
> > > > > 
> > > > > Cc: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> > > > > Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> > > > 
> > > > Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > > 
> > > > I have a question though. The patch set introduces three plane types,
> > > > OVERLAY, PRIMARY and CURSOR. What should a driver that has no concept
> > > > of primary plane do ? Expose all planes as OVERLAY planes only ?
> > > 
> > > It's a matter of backwards compat with old userspace. primary/cursor are
> > > simply ways to tell the drm core which planes to use to forward the legacy
> > > cursor crtc and which plane will be used for the framebuffer in setCrtc.
> > > 
> > > So until we have the new atomic interface ready your driver kinda needs to
> > > expose at least a primary plane, otherwise there's no way to even switch
> > > on the crtc.
> > > 
> > > But besides this backwards compat issue there's no difference and you can
> > > specify whatever plane you want as primary/cursor (or none if you don't
> > > care about old userspace).
> > 
> > Well the NULL primary plane probably needs a bit of work on top of Matt's
> > patch series here ...
> 
> It's the NULL primary plane I'm interested about, to allow a "root" plane not 
> to span the whole display. I have no urgent need for this though, I was just 
> curious to see if that feature was planned.

That should work and is kinda one of the features we want ot enable with
this. At least on i915 with a bit of frobbing we should be able to allow a
root/primary fb not spanning the entire crtc (with black as background
color). Or entirely disable the primary plane and just display a (again
boxed) yuv plane for fullscreen video with aspect ratio mismatching.

When I talk that NULL primary plane needs work I mean a driver which
doesn't register _any_ primary plane at all and only supports
free-floating over planes. So wouldn't work with fbcon or any current
generic userspace at all, but would allow you to reassign all planes to a
single crtc (if your hw can do it) without pulling tricks with fake
primary planes.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCHv4 06/13] drm: Add primary plane helpers (v2)
  2014-04-01 19:46         ` Dave Airlie
@ 2014-04-01 21:47           ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2014-04-01 21:47 UTC (permalink / raw)
  To: Dave Airlie; +Cc: dri-devel

On Tue, Apr 1, 2014 at 9:46 PM, Dave Airlie <airlied@gmail.com> wrote:
> On Tue, Apr 1, 2014 at 5:45 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
>> commit a3a0544b2c84e1d7a2022b558ecf66d8c6a8dd93
>> Author: Dave Airlie <airlied@redhat.com>
>> Date:   Mon Aug 31 15:16:30 2009 +1000
>>
>>     drm/kms: add explicit encoder disable function and detach harder.
>>
>>     For shared tv-out and VGA encoders, we really need to know if
>>     the encoder is just being switched off temporarily in blanking
>>     or if we are really disabling it hard.
>>
>>     Also we need to try harder to disconnect encoders from unused
>>     connectors so we can share more efficently.
>>
>>     (shared encoders stuff is coming in radeon tv-out support)
>>
>>     Signed-off-by: Dave Airlie <airlied@redhat.com>
>>
>> To me this always smelled like papering over broken userspace. I've killed
>> this in the i915 modeset rewrite and we didn't really have angry users
>> scaling our walls. But I'm not sure what'll happen if we do this for all
>> other drivers.
>
> I've had to look at this again recently, and while I still don't like
> my commit, its
> not papering over userspace, it might be papering over fbcon :-)
>
> You don't have any hw that operates like this, so I'd be surprised if
> you had users falling over,
>
> The problem is if I have a single DAC encoder, with tv-out and VGA
> connectors, and I unplug the VGA connector, and plug in the tv
> connector, how do I get fbcon to pop-up,
>
> Though that said this commit caused a regression that I'm not sure I
> liked either, since I think we used to allow you to force a mode on
> disconnected outputs, and this stops that from working, I noticed in a
> virtual env.

As discussed on irc I think we should be able to fix the issue with
fbcon by using an atomic modeset. The bug only happens when fbcon
tries to enable the newly plugged-in connector before it disabled the
old one and then can't get at the shared encoder needed to enable
either. If we have atomic modesets the crtc helpers can always first
disable all the unused stuff and then light up the new things, which
should make this work. So imo disabling this hunk as in the patch I've
just sent out looks like the way forward for primary planes and atomic
modeset.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

end of thread, other threads:[~2014-04-01 21:47 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-28  0:44 [PATCHv4 00/13] Universal plane preparation patches Matt Roper
2014-03-28  0:44 ` [PATCHv4 01/13] drm: Add support for multiple plane types (v2) Matt Roper
2014-03-28  0:44 ` [PATCHv4 02/13] drm/exynos: Restrict plane loops to only operate on overlay planes (v2) Matt Roper
2014-03-28  0:44 ` [PATCHv4 03/13] drm/i915: " Matt Roper
2014-03-28  0:44 ` [PATCHv4 04/13] drm/shmobile: Restrict plane loops to only operate on legacy planes Matt Roper
2014-03-28 15:50   ` Laurent Pinchart
2014-03-28 17:52     ` Daniel Vetter
2014-03-28 17:53       ` Daniel Vetter
2014-04-01 15:27         ` Laurent Pinchart
2014-04-01 21:43           ` Daniel Vetter
2014-03-28  0:44 ` [PATCHv4 05/13] drm: Make drm_crtc_check_viewport non-static Matt Roper
2014-03-28  0:44 ` [PATCHv4 06/13] drm: Add primary plane helpers (v2) Matt Roper
2014-03-28  8:32   ` Daniel Vetter
2014-03-28 15:48     ` Laurent Pinchart
2014-03-28 17:54       ` Daniel Vetter
2014-04-01 15:25         ` Laurent Pinchart
2014-04-01  1:03     ` Matt Roper
2014-04-01  7:45       ` Daniel Vetter
2014-04-01 11:45         ` Rob Clark
2014-04-01 12:33           ` Daniel Vetter
2014-04-01 19:46         ` Dave Airlie
2014-04-01 21:47           ` Daniel Vetter
2014-04-01  1:04     ` Rob Clark
2014-03-28  0:44 ` [PATCHv4 07/13] drm: Add drm_universal_plane_init() Matt Roper
2014-03-28  0:44 ` [PATCHv4 08/13] drm: Add plane type property (v2) Matt Roper
2014-03-28  0:44 ` [PATCHv4 09/13] drm: Add plane max width/height properties Matt Roper
2014-03-28  8:21   ` Daniel Vetter
2014-03-28  0:44 ` [PATCHv4 10/13] drm: Add drm_crtc_init_with_planes() Matt Roper
2014-03-28  9:11   ` Daniel Vetter
2014-03-28 17:56   ` Daniel Vetter
2014-03-28  0:44 ` [PATCHv4 11/13] drm/msm: Switch to universal plane API's Matt Roper
2014-03-28  0:44 ` [PATCHv4 12/13] drm: Replace crtc fb with primary plane fb (v3) Matt Roper
2014-03-28  8:40   ` Daniel Vetter
2014-03-28  0:44 ` [PATCHv4 13/13] drm: Remove unused drm_crtc->fb Matt Roper
2014-03-28  8:15 ` [Intel-gfx] [PATCHv4 00/13] Universal plane preparation patches Daniel Vetter

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.