diff mbox

[RFC,3/4] video: adf: add display core helper

Message ID 1377741081-30189-4-git-send-email-ghackmann@google.com (mailing list archive)
State New, archived
Headers show

Commit Message

Greg Hackmann Aug. 29, 2013, 1:51 a.m. UTC
Optional helper which implements some ADF interface ops for displays
using the Display Core framework

Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 drivers/video/adf/Kconfig       |   5 ++
 drivers/video/adf/Makefile      |   2 +
 drivers/video/adf/adf.c         |  28 ++++++++-
 drivers/video/adf/adf.h         |   1 +
 drivers/video/adf/adf_display.c | 123 ++++++++++++++++++++++++++++++++++++++++
 include/video/adf_display.h     |  31 ++++++++++
 6 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 drivers/video/adf/adf_display.c
 create mode 100644 include/video/adf_display.h
diff mbox

Patch

diff --git a/drivers/video/adf/Kconfig b/drivers/video/adf/Kconfig
index 0b64408..30b0611 100644
--- a/drivers/video/adf/Kconfig
+++ b/drivers/video/adf/Kconfig
@@ -3,3 +3,8 @@  menuconfig ADF
 	depends on SW_SYNC
 	depends on DMA_SHARED_BUFFER
 	tristate "Atomic Display Framework"
+
+menuconfig ADF_DISPLAY_CORE
+	depends on ADF
+	depends on DISPLAY_CORE
+	tristate "Helper for implementing ADF interface ops with Display Core devices"
diff --git a/drivers/video/adf/Makefile b/drivers/video/adf/Makefile
index 2af5f79..30164ee 100644
--- a/drivers/video/adf/Makefile
+++ b/drivers/video/adf/Makefile
@@ -8,3 +8,5 @@  obj-$(CONFIG_ADF) += adf.o \
 	adf_sysfs.o
 
 obj-$(CONFIG_COMPAT) += adf_fops32.o
+
+obj-$(CONFIG_ADF_DISPLAY_CORE) += adf_display.o
diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c
index 5dc04af..b3b57dd 100644
--- a/drivers/video/adf/adf.c
+++ b/drivers/video/adf/adf.c
@@ -1,6 +1,6 @@ 
 /*
  * Copyright (C) 2013 Google, Inc.
- * adf_modeinfo_set_name modified from drm_mode_set_name in
+ * adf_modeinfo_{set_name,set_vrefresh} modified from
  * drivers/gpu/drm/drm_modes.c
  *
  * This software is licensed under the terms of the GNU General Public
@@ -966,6 +966,32 @@  void adf_modeinfo_set_name(struct drm_mode_modeinfo *mode)
 		 interlaced ? "i" : "");
 }
 
+void adf_modeinfo_set_vrefresh(struct drm_mode_modeinfo *mode)
+{
+	int refresh = 0;
+	unsigned int calc_val;
+
+	if (mode->vrefresh > 0)
+		return;
+	else if (mode->htotal > 0 && mode->vtotal > 0) {
+		int vtotal;
+		vtotal = mode->vtotal;
+		/* work out vrefresh the value will be x1000 */
+		calc_val = (mode->clock * 1000);
+		calc_val /= mode->htotal;
+		refresh = (calc_val + vtotal / 2) / vtotal;
+
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			refresh *= 2;
+		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+			refresh /= 2;
+		if (mode->vscan > 1)
+			refresh /= mode->vscan;
+
+		mode->vrefresh = refresh;
+	}
+}
+
 static void __exit adf_exit(void);
 static int __init adf_init(void)
 {
diff --git a/drivers/video/adf/adf.h b/drivers/video/adf/adf.h
index acad631..5f7260d 100644
--- a/drivers/video/adf/adf.h
+++ b/drivers/video/adf/adf.h
@@ -44,5 +44,6 @@  struct adf_event_refcount *adf_obj_find_refcount(struct adf_obj *obj,
 		enum adf_event_type type);
 
 void adf_modeinfo_set_name(struct drm_mode_modeinfo *mode);
+void adf_modeinfo_set_vrefresh(struct drm_mode_modeinfo *mode);
 
 #endif /* __ADF_H */
diff --git a/drivers/video/adf/adf_display.c b/drivers/video/adf/adf_display.c
new file mode 100644
index 0000000..c87f6a5
--- /dev/null
+++ b/drivers/video/adf/adf_display.c
@@ -0,0 +1,123 @@ 
+/*
+ * Copyright (C) 2013 Google, Inc.
+ * adf_modeinfo_from_videomode modified from drm_display_mode_from_videomode in
+ * drivers/gpu/drm/drm_modes.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <video/adf.h>
+#include <video/adf_display.h>
+
+#include "adf.h"
+
+/**
+ * adf_display_entity_screen_size - handle the screen_size interface op
+ * by querying a display core entity
+ */
+int adf_display_entity_screen_size(struct display_entity *display,
+		u16 *width_mm, u16 *height_mm)
+{
+	unsigned int cdf_width, cdf_height;
+	int ret;
+
+	ret = display_entity_get_size(display, &cdf_width, &cdf_height);
+	if (!ret) {
+		*width_mm = cdf_width;
+		*height_mm = cdf_height;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(adf_display_entity_screen_size);
+
+/**
+ * adf_display_entity_notify_connected - notify ADF of a display core entity
+ * being connected to an interface
+ *
+ * @intf: the interface
+ * @display: the display
+ *
+ * adf_display_entity_notify_connected() wraps adf_hotplug_notify_connected()
+ * but does not require a hardware modelist.  @display is queried to
+ * automatically populate the modelist.
+ *
+ * Returns 0 on success or error code (<0) on failure.
+ */
+int adf_display_entity_notify_connected(struct adf_interface *intf,
+		struct display_entity *display)
+{
+	const struct videomode *vmodes;
+	struct drm_mode_modeinfo *dmodes = NULL;
+	int ret;
+	size_t i, n_modes;
+
+	ret = display_entity_get_modes(display, &vmodes);
+	if (ret < 0)
+		return ret;
+
+	n_modes = ret;
+	if (n_modes) {
+		dmodes = kzalloc(n_modes * sizeof(dmodes[0]), GFP_KERNEL);
+		if (!dmodes)
+			return -ENOMEM;
+	}
+
+	for (i = 0; i < n_modes; i++)
+		adf_modeinfo_from_videomode(&vmodes[i], &dmodes[i]);
+
+	ret = adf_hotplug_notify_connected(intf, dmodes, n_modes);
+	kfree(dmodes);
+	return ret;
+}
+EXPORT_SYMBOL(adf_display_entity_notify_connected);
+
+/**
+ * adf_modeinfo_from_videomode - copy a display core videomode into
+ * an equivalent &struct drm_mode_modeinfo
+ *
+ * @vm: the input display core videomode
+ * @dmode: the output DRM/ADF modeinfo
+ */
+void adf_modeinfo_from_videomode(const struct videomode *vm,
+		struct drm_mode_modeinfo *dmode)
+{
+	memset(dmode, 0, sizeof(*dmode));
+
+	dmode->hdisplay = vm->hactive;
+	dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
+	dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
+	dmode->htotal = dmode->hsync_end + vm->hback_porch;
+
+	dmode->vdisplay = vm->vactive;
+	dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
+	dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
+	dmode->vtotal = dmode->vsync_end + vm->vback_porch;
+
+	dmode->clock = vm->pixelclock / 1000;
+
+	if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+		dmode->flags |= DRM_MODE_FLAG_PHSYNC;
+	else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
+		dmode->flags |= DRM_MODE_FLAG_NHSYNC;
+	if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+		dmode->flags |= DRM_MODE_FLAG_PVSYNC;
+	else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
+		dmode->flags |= DRM_MODE_FLAG_NVSYNC;
+	if (vm->flags & DISPLAY_FLAGS_INTERLACED)
+		dmode->flags |= DRM_MODE_FLAG_INTERLACE;
+	if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
+		dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
+
+	adf_modeinfo_set_name(dmode);
+	adf_modeinfo_set_vrefresh(dmode);
+}
+EXPORT_SYMBOL_GPL(adf_modeinfo_from_videomode);
diff --git a/include/video/adf_display.h b/include/video/adf_display.h
new file mode 100644
index 0000000..af8cb6b
--- /dev/null
+++ b/include/video/adf_display.h
@@ -0,0 +1,31 @@ 
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _VIDEO_ADF_DISPLAY_H
+#define _VIDEO_ADF_DISPLAY_H
+
+#include <video/adf.h>
+#include <video/display.h>
+#include <video/videomode.h>
+
+int adf_display_entity_screen_size(struct display_entity *display,
+		u16 *width_mm, u16 *height_mm);
+
+int adf_display_entity_notify_connected(struct adf_interface *intf,
+		struct display_entity *display);
+
+void adf_modeinfo_from_videomode(const struct videomode *vm,
+		struct drm_mode_modeinfo *dmode);
+
+#endif /* _VIDEO_ADF_DISPLAY_H */