diff mbox

[RFCv3,12/14] drm: Specify cursor plane at CRTC initialization

Message ID 1395188579-17191-13-git-send-email-matthew.d.roper@intel.com
State Superseded
Headers show

Commit Message

Matt Roper March 19, 2014, 12:22 a.m. UTC
Add cursor plane as a parameter to drm_crtc_init() and update all
existing DRM drivers to use a helper-provided primary plane.  Passing
NULL for this parameter indicates that there is no hardware cursor
supported by the driver and no cursor plane should be provided to
userspace.

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

Comments

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

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

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

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

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

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

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

And the plane interfaces:

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

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

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

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

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

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

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

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

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

- Checks that there's no scaling going on.

- Checks that the viewport matches the full cursor size.

- Checks that there's no subpixel positioning.

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

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

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

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

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

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

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

BR,
-R

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

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

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

yeah, for compat helpers, only ARGB makes sense

BR,
-R


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

Patch

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