[RFC] drm: implement DRM_IOCTL_MODE_SETROTATION

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Paulo Zanoni <paulo.r.zanoni at intel.com>

This ioctl is used to signal the drivers that the screen is rotated,
not to make the drivers rotate the screen.
 - add a driver-specific "rotation_set" function
 - implement Intel's rotation_set by setting the right values to the
   PIPECONF registers.

The idea is that when user-space does rotation, it can call this ioctl
to inform the Kernel that we have a rotation. This feature is needed
by the KVMr feature of VPro.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
---

Hi

We need this feature for the KVMr feature of VPro. I'm not sure how useful this
will be for the non-Intel drivers, so maybe the current approach is not the
best. I'm open to suggestions.

I also have a patch to libdrm that just implements a wrapper for the ioctl
(drmModeCrtcSetRotation) and a patch for xf86-video-intel that callss the libdrm
function whenever needed.

I already have the libdrm and xf86-video-intel patches (they're simple) but I'll
wait until I get some comments on this one before I send the others.

 drivers/gpu/drm/drm_crtc.c           |   28 ++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_drv.c            |    3 ++-
 drivers/gpu/drm/i915/i915_reg.h      |    5 +++++
 drivers/gpu/drm/i915/intel_display.c |   34 ++++++++++++++++++++++++++++++++++
 include/drm/drm.h                    |    2 ++
 include/drm/drm_crtc.h               |    8 +++++++-
 include/drm/drm_mode.h               |   15 +++++++++++++++
 7 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f259a25..4a33ea1 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3125,6 +3125,34 @@ out:
 	return ret;
 }
 
+int drm_crtc_rotation_set_ioctl(struct drm_device *dev, void *data,
+				struct drm_file *file_priv)
+{
+	struct drm_mode_crtc_rotation *rotation = data;
+	struct drm_mode_object *obj;
+	struct drm_crtc *crtc;
+	int ret = 0;
+
+	DRM_DEBUG_KMS("changing rotation to %d\n", rotation->rotation);
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return -EINVAL;
+
+	mutex_lock(&dev->mode_config.mutex);
+	obj = drm_mode_object_find(dev, rotation->crtc_id, DRM_MODE_OBJECT_CRTC);
+	if (!obj) {
+		ret = -EINVAL;
+		goto out;
+	}
+	crtc = obj_to_crtc(obj);
+
+	if (crtc->funcs->rotation_set)
+		crtc->funcs->rotation_set(crtc, rotation->rotation);
+out:
+	mutex_unlock(&dev->mode_config.mutex);
+	return ret;
+}
+
 int drm_mode_page_flip_ioctl(struct drm_device *dev,
 			     void *data, struct drm_file *file_priv)
 {
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index bc5febe..ba0dac1 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -159,7 +159,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETROTATION, drm_crtc_rotation_set_ioctl, DRM_MASTER|DRM_UNLOCKED)
 };
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 194d987..3d9d46e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2323,6 +2323,11 @@
 #define   PIPECONF_INTERLACE_FIELD_0_ONLY		(7 << 21)
 #define   PIPECONF_INTERLACE_MASK	(7 << 21)
 #define   PIPECONF_CXSR_DOWNCLOCK	(1<<16)
+#define   PIPECONF_ROTATION_MASK	(3 << 14)
+#define   PIPECONF_ROTATION_0		(0 << 14)
+#define   PIPECONF_ROTATION_90		(1 << 14)
+#define   PIPECONF_ROTATION_180		(2 << 14)
+#define   PIPECONF_ROTATION_270		(3 << 14)
 #define   PIPECONF_BPP_MASK	(0x000000e0)
 #define   PIPECONF_BPP_8	(0<<5)
 #define   PIPECONF_BPP_10	(1<<5)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 55a5b4c..08780f5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6317,6 +6317,39 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 	intel_crtc_load_lut(crtc);
 }
 
+static void intel_crtc_rotation_set(struct drm_crtc *crtc,
+				    enum drm_crtc_rotation rotation)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int reg = PIPECONF(intel_crtc->pipe);
+	u32 val = I915_READ(reg);
+
+	val &= ~PIPECONF_ROTATION_MASK;
+
+	switch (rotation & ~(DRM_CRTC_ROTATION_INV_X |
+			     DRM_CRTC_ROTATION_INV_Y)) {
+	case DRM_CRTC_ROTATION_0:
+		val |= PIPECONF_ROTATION_0;
+		break;
+	case DRM_CRTC_ROTATION_90:
+		val |= PIPECONF_ROTATION_90;
+		break;
+	case DRM_CRTC_ROTATION_180:
+		val |= PIPECONF_ROTATION_180;
+		break;
+	case DRM_CRTC_ROTATION_270:
+		val |= PIPECONF_ROTATION_270;
+		break;
+	default:
+		DRM_ERROR("Invalid rotation: 0x%x\n", rotation);
+		val |= PIPECONF_ROTATION_0;
+	}
+
+	I915_WRITE(reg, val);
+}
+
 /**
  * Get a pipe with a simple mode set on it for doing load-based monitor
  * detection.
@@ -7383,6 +7416,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.set_config = drm_crtc_helper_set_config,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
+	.rotation_set = intel_crtc_rotation_set,
 };
 
 static void intel_crtc_init(struct drm_device *dev, int pipe)
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 49d94ed..f33b09a 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -719,6 +719,8 @@ struct drm_get_cap {
 #define DRM_IOCTL_MODE_SETPLANE	DRM_IOWR(0xB7, struct drm_mode_set_plane)
 #define DRM_IOCTL_MODE_ADDFB2		DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
 
+#define DRM_IOCTL_MODE_SETROTATION	DRM_IOWR(0xB9, struct drm_mode_crtc_rotation)
+
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x99.
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 2deb6f9..3515ee7 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -297,7 +297,8 @@ struct drm_plane;
  * @mode_fixup: fixup proposed mode
  * @mode_set: set the desired mode on the CRTC
  * @gamma_set: specify color ramp for CRTC
- * @destroy: deinit and free object.
+ * @destroy: deinit and free object
+ * @rotation_set: specify the CRTC rotation
  *
  * The drm_crtc_funcs structure is the central CRTC management structure
  * in the DRM.  Each CRTC controls one or more connectors (note that the name
@@ -341,6 +342,9 @@ struct drm_crtc_funcs {
 	int (*page_flip)(struct drm_crtc *crtc,
 			 struct drm_framebuffer *fb,
 			 struct drm_pending_vblank_event *event);
+
+	void (*rotation_set)(struct drm_crtc *crtc,
+			     enum drm_crtc_rotation rotation);
 };
 
 /**
@@ -975,6 +979,8 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 				    void *data, struct drm_file *file_priv);
 extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 				    void *data, struct drm_file *file_priv);
+extern int drm_crtc_rotation_set_ioctl(struct drm_device *dev,
+				    void *data, struct drm_file *file_priv);
 extern u8 *drm_find_cea_extension(struct edid *edid);
 extern bool drm_detect_hdmi_monitor(struct edid *edid);
 extern bool drm_detect_monitor_audio(struct edid *edid);
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 2a2acda..58200e8 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -379,6 +379,21 @@ struct drm_mode_crtc_lut {
 	__u64 blue;
 };
 
+/* Matches randr.h for convenience */
+enum drm_crtc_rotation {
+	DRM_CRTC_ROTATION_0     = 1,
+	DRM_CRTC_ROTATION_90    = 2,
+	DRM_CRTC_ROTATION_180   = 4,
+	DRM_CRTC_ROTATION_270   = 8,
+	DRM_CRTC_ROTATION_INV_X = 16,
+	DRM_CRTC_ROTATION_INV_Y = 32
+};
+
+struct drm_mode_crtc_rotation {
+	__u32 crtc_id;
+	enum drm_crtc_rotation rotation;
+};
+
 #define DRM_MODE_PAGE_FLIP_EVENT 0x01
 #define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT
 
-- 
1.7.7.3



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux