Add DRM driver abstraction

This adds an abstraction interface in src/drmmode_driver.h for the
driver-specific values (and in future functions) that we need. It
also adds documentation and build system support (--with-drmmode)
to choose your supported driver.

Initially, the dumb allocation flags and page flip events flags
are abstracted with support for pl111 and eynos.

A template implementation is also provided for ease of adding new
driver support.

Change-Id: I98890ddab6b907c3007b72a662ecd7ee6caa4402
diff --git a/README b/README
index 10bd463..8d05217 100644
--- a/README
+++ b/README
@@ -1,23 +1,28 @@
 xf86-video-armsoc
 Open-source X.org graphics driver for ARM graphics
 
-Platform specific values
-------------------------
-The meaning of the bits in the 'flags' element in the drm_mode_create_dumb struct
-used by DRM_IOCTL_MODE_CREATE_DUMB is platform dependent.  
-The defines for the flag values in omap_drmif_fb.h should be modified for the target platform in use. 
+DRM driver selection
+--------------------
+While most operations use only the standard DRM modesetting interfaces, certain operations
+unavoidably rely on specific driver behaviour (including dumb buffer allocation flags and cursor
+plane z-ordering). As such, the armsoc driver must be configured for a particular DRM driver.
 
-The example given is for a DRM driver which uses bit 0 of flags to select the buffer type. 
-In this case a value of 1 for bit 0 selects a buffer with a scanoutable allocation.
+The currently supported DRM drivers are:
+- pl111
+- exynos
 
-The platform specific defines are :
+To configure armsoc for one of these, pass the --with-drmmode option to ./configure. For example:
 
-	/* Platform specific values for the flags element of the drm_mode_create_dumb struct
- 	* used by DRM_IOCTL_MODE_CREATE_DUMB. Substitute appropriate values for the target drm driver.
- 	*/
-	#define DRM_BO_SCANOUT				0x00000001			/* request scanout compatible buffer */
-	#define DRM_BO_NON_SCANOUT			0x00000000			/* request non-scanout compatible buffer */
+$ ./configure --with-drmmode=pl111
 
+For other drivers, you will need to implement this support yourself. A template implementation is
+provided in src/drmmode_template which can be built by passing --with-drmmode=template to ./configure.
+The interface is defined and documented in src/drmmode_driver.h, and you should refer to this while
+modifying the template to set up your DRM driver's abstraction appropriately.
+
+You can also copy src/drmmode_template into src/drmmode_<yourdrivername> and build with:
+
+$ ./configure --with-drmmode=<yourdrivername>
 
 HW Cursors support
 -------------------
@@ -35,4 +40,4 @@
 
 For example to set HW_CURSOR_PL111 cursor support set DRM_CURSOR_PLANE_FORMAT in the following way:
 
-#define DRM_CURSOR_PLANE_FORMAT	HW_CURSOR_PL111
\ No newline at end of file
+#define DRM_CURSOR_PLANE_FORMAT	HW_CURSOR_PL111
diff --git a/configure.ac b/configure.ac
index d47f8ef..258de0d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,15 @@
             [moduledir="$withval"],
             [moduledir="$libdir/xorg/modules"])
 
+AC_MSG_CHECKING([which DRM driver to use])
+AC_ARG_WITH(drmmode,
+            AC_HELP_STRING([--with-drmmode],
+                           [Which DRM driver to use (see README)]),
+            [drmmode=$withval],
+            AC_MSG_FAILURE([You must specify which DRM driver to build for - see README]))
+AC_MSG_RESULT([$drmmode])
+AC_SUBST(drmmode)
+
 # Checks for extensions
 XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
 XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
diff --git a/src/Makefile.am b/src/Makefile.am
index 632c656..c66f875 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,6 +40,7 @@
 armsoc_drv_la_LDFLAGS = -module -avoid-version -no-undefined
 armsoc_drv_la_LIBADD = @XORG_LIBS@
 armsoc_drv_ladir = @moduledir@/drivers
+DRMMODE_SRCS = drmmode_@drmmode@/drmmode_@drmmode@.c
 
 armsoc_drv_la_SOURCES = \
          drmmode_display.c \
@@ -50,5 +51,5 @@
          omap_dri2.c \
          omap_driver.c \
          omap_dumb.c \
-         drm_pl111_cursor.c
-
+         drm_pl111_cursor.c \
+         $(DRMMODE_SRCS)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index be041a9..5973e8e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -94,6 +94,8 @@
 #include <sys/ioctl.h>
 #include <libudev.h>
 
+#include "drmmode_driver.h"
+
 typedef struct {
 	/* hardware cursor: */
 	drmModePlane *ovr;
@@ -1237,16 +1239,16 @@
 int
 drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
 {
-	ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
-	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+	ScrnInfoPtr pScrn = xf86Screens[draw->pScreen->myNum];
+	OMAPPtr pOMAP = OMAPPTR(pScrn);
+	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
 	drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
 	drmmode_ptr mode = crtc->drmmode;
 	int ret, i, failed = 0, num_flipped = 0;
 	unsigned int flags = 0;
 
-#if OMAP_USE_PAGE_FLIP_EVENTS
-	flags |= DRM_MODE_PAGE_FLIP_EVENT;
-#endif
+	if (pOMAP->drmmode->use_page_flip_events)
+		flags |= DRM_MODE_PAGE_FLIP_EVENT;
 
 	/* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
 	for (i = 0; i < config->num_crtc; i++) {
@@ -1255,7 +1257,7 @@
 		ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
 				fb_id, flags, priv);
 		if (ret) {
-			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
 					"flip queue failed: %s\n", strerror(errno));
 			failed = 1;
 		}
diff --git a/src/drmmode_driver.h b/src/drmmode_driver.h
new file mode 100644
index 0000000..dfb5daf
--- /dev/null
+++ b/src/drmmode_driver.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2013 ARM Limited.
+ *
+ * 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 DRMMODE_DRIVER_H
+#define DRMMODE_DRIVER_H
+
+#include <stdint.h>
+
+struct drmmode_interface {
+	/* Flags value to pass to DRM_IOCTL_MODE_CREATE_DUMB to allocate a scanout-capable
+	 * buffer. A buffer allocated with these flags must be able to be wrapped in a
+	 * DRM framebuffer (via DRM_IOCTL_MODE_ADDFB or DRM_IOCTL_MODE_ADDFB2).
+	 */
+	uint32_t dumb_scanout_flags;
+
+	/* Flags value to pass to DRM_IOCTL_MODE_CREATE_DUMB to allocate a
+	 * non-scanout-capable buffer. It is acceptable for the driver to create a
+	 * scanout-capable buffer when given this flag, this flag is used to give the
+	 * option of preserving scarce scanout-capable memory if applicable.
+	 */
+	uint32_t dumb_no_scanout_flags;
+
+	/* Boolean value indicating whether DRM page flip events should be requested and
+	 * waited for during DRM_IOCTL_MODE_PAGE_FLIP.
+	 */
+	int use_page_flip_events;
+};
+
+struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd);
+
+#endif
diff --git a/src/drmmode_exynos/drmmode_exynos.c b/src/drmmode_exynos/drmmode_exynos.c
new file mode 100644
index 0000000..1bd174e
--- /dev/null
+++ b/src/drmmode_exynos/drmmode_exynos.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2013 ARM Limited.
+ *
+ * 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 "../drmmode_driver.h"
+
+struct drmmode_interface exynos_interface = {
+	0x00000001 /* dumb_scanout_flags */,
+	0x00000001 /* dumb_no_scanout_flags */,
+	1 /* use_page_flip_events */
+};
+
+struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd)
+{
+	return &exynos_interface;
+}
diff --git a/src/drmmode_pl111/drmmode_pl111.c b/src/drmmode_pl111/drmmode_pl111.c
new file mode 100644
index 0000000..7795246
--- /dev/null
+++ b/src/drmmode_pl111/drmmode_pl111.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2013 ARM Limited.
+ *
+ * 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 "../drmmode_driver.h"
+
+struct drmmode_interface pl111_interface = {
+	0x00000001 /* dumb_scanout_flags */,
+	0x00000000 /* dumb_no_scanout_flags */,
+	0 /* use_page_flip_events */
+};
+
+struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd)
+{
+	return &pl111_interface;
+}
diff --git a/src/drmmode_template/drmmode_template.c b/src/drmmode_template/drmmode_template.c
new file mode 100644
index 0000000..39af8e4
--- /dev/null
+++ b/src/drmmode_template/drmmode_template.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2013 ARM Limited.
+ *
+ * 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 "../drmmode_driver.h"
+
+struct drmmode_interface template_interface = {
+	0x00000000 /* dumb_scanout_flags */,
+	0x00000000 /* dumb_no_scanout_flags */,
+	1 /* use_page_flip_events */
+};
+
+struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd)
+{
+	return &template_interface;
+}
diff --git a/src/omap_dri2.c b/src/omap_dri2.c
index ebcaebe..4e2587c 100644
--- a/src/omap_dri2.c
+++ b/src/omap_dri2.c
@@ -41,6 +41,8 @@
 #	error "Requires newer DRI2"
 #endif
 
+#include "drmmode_driver.h"
+
 typedef struct {
 	DRI2BufferRec base;
 
@@ -541,12 +543,13 @@
 			 * Error while flipping; bail.
 			 */
 			cmd->flags |= OMAP_SWAP_FAIL;
-#if !OMAP_USE_PAGE_FLIP_EVENTS
-			cmd->swapCount = 0;
-#else
-			cmd->swapCount = -(ret + 1);
+
+			if (pOMAP->drmmode->use_page_flip_events)
+				cmd->swapCount = -(ret + 1);
+			else
+				cmd->swapCount = 0;
+
 			if (cmd->swapCount == 0)
-#endif
 			{
 				OMAPDRI2SwapComplete(cmd);
 			}
@@ -554,12 +557,13 @@
 		} else {
 			if (ret == 0)
 				cmd->flags |= OMAP_SWAP_FAKE_FLIP;
-#if !OMAP_USE_PAGE_FLIP_EVENTS
-			cmd->swapCount = 0;
-#else
-			cmd->swapCount = ret;
+
+			if (pOMAP->drmmode->use_page_flip_events)
+				cmd->swapCount = ret;
+			else
+				cmd->swapCount = 0;
+
 			if (cmd->swapCount == 0)
-#endif
 			{
 				OMAPDRI2SwapComplete(cmd);
 			}
diff --git a/src/omap_driver.c b/src/omap_driver.c
index 1e488b1..884988c 100644
--- a/src/omap_driver.c
+++ b/src/omap_driver.c
@@ -38,6 +38,8 @@
 #include "omap_driver.h"
 #include "compat-api.h"
 
+#include "drmmode_driver.h"
+
 Bool omapDebug = 0;
 
 /*
@@ -483,8 +485,14 @@
 	}
 	DEBUG_MSG("Became DRM master.");
 
+	pOMAP->drmmode = drmmode_interface_get_implementation(pOMAP->drmFD);
+	if (!pOMAP->drmmode)
+		goto fail;
+
 	/* create DRM device instance: */
-	pOMAP->dev = omap_device_new(pOMAP->drmFD);
+	pOMAP->dev = omap_device_new(pOMAP->drmFD,
+			pOMAP->drmmode->dumb_scanout_flags,
+			pOMAP->drmmode->dumb_no_scanout_flags);
 
 	/* query chip-id: */
 	if (omap_get_param(pOMAP->dev, OMAP_PARAM_CHIPSET_ID, &value)) {
diff --git a/src/omap_driver.h b/src/omap_driver.h
index 93cd3b4..312ca6e 100644
--- a/src/omap_driver.h
+++ b/src/omap_driver.h
@@ -71,7 +71,6 @@
 #define OMAP_MINOR_VERSION	83
 #define OMAP_PATCHLEVEL		0
 
-#define OMAP_USE_PAGE_FLIP_EVENTS 0
 #define OMAP_SUPPORT_GAMMA 0
 
 #define CURSORW  (64)
@@ -137,6 +136,8 @@
 
 	char 				*deviceName;
 
+	struct drmmode_interface *drmmode;
+
 	/** DRM device instance */
 	struct omap_device	*dev;
 
diff --git a/src/omap_drmif_fb.h b/src/omap_drmif_fb.h
index b37acaa..25bf5ad 100644
--- a/src/omap_drmif_fb.h
+++ b/src/omap_drmif_fb.h
@@ -31,15 +31,6 @@
 #define HW_CURSOR_ARGB		(0)
 #define HW_CURSOR_PL111		(1)
 
-/* Platform specific values for the flags element of the drm_mode_create_dumb struct
- * used by DRM_IOCTL_MODE_CREATE_DUMB. These are used by omap_bo_new_with_dim() to
- * request either a scanoutable or non-scanoutable buffer
- */
-/*
- * THESE VALUES SHOULD BE CUSTOMISED FOR THE TARGET DRM DRIVER - SEE THE README FILE
- */
-#define DRM_BO_SCANOUT				0x00000001			/* request scanout compatible buffer */
-#define DRM_BO_NON_SCANOUT			0x00000000			/* request non-scanout compatible buffer */
 
 /*
  * HARDWARE CURSOR SUPORT CONFIGURATION
@@ -62,7 +53,7 @@
 	OMAP_BO_NON_SCANOUT
 };
 
-struct omap_device *omap_device_new(int fd);
+struct omap_device *omap_device_new(int fd, uint32_t dumb_scanout_flags, uint32_t dumb_no_scanout_flags);
 void omap_device_del(struct omap_device *dev);
 int omap_bo_get_name(struct omap_bo *bo, uint32_t *name);
 uint32_t omap_bo_handle(struct omap_bo *bo);
diff --git a/src/omap_dumb.c b/src/omap_dumb.c
index 90b61b3..a2a32db 100644
--- a/src/omap_dumb.c
+++ b/src/omap_dumb.c
@@ -32,9 +32,12 @@
 #include <xf86drmMode.h>
 
 #include "omap_drmif_fb.h"
+#include "drmmode_driver.h"
 
 struct omap_device {
 	int fd;
+	uint32_t dumb_scanout_flags;
+	uint32_t dumb_no_scanout_flags;
 };
 
 struct omap_bo {
@@ -55,13 +58,15 @@
 /* device related functions:
  */
 
-struct omap_device *omap_device_new(int fd)
+struct omap_device *omap_device_new(int fd, uint32_t dumb_scanout_flags, uint32_t dumb_no_scanout_flags)
 {
 	struct omap_device *new_dev = malloc(sizeof(*new_dev));
 	if (!new_dev)
 		return NULL;
 
 	new_dev->fd = fd;
+	new_dev->dumb_scanout_flags = dumb_scanout_flags;
+	new_dev->dumb_no_scanout_flags = dumb_no_scanout_flags;
 	return new_dev;
 }
 
@@ -126,11 +131,11 @@
 	assert((OMAP_BO_SCANOUT == buf_type) || (OMAP_BO_NON_SCANOUT == buf_type));
 	if (OMAP_BO_SCANOUT == buf_type)
 	{
-		create_dumb.flags = DRM_BO_SCANOUT;
+		create_dumb.flags = dev->dumb_scanout_flags;
 	}
 	else
 	{
-		create_dumb.flags = DRM_BO_NON_SCANOUT;
+		create_dumb.flags = dev->dumb_no_scanout_flags;
 	}
 
 	res = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);