bo: Refactor bo allocation layer to support both exynos and rockchip

Extract common interfaces in src/omap_dumb.c, implmented abstraction
layer in bo.h, and move driver specific parts to bo_exynos.c and
bo_rockchip.c

BUG=chrome-os-partner:29594
TEST=emerge xf86-video-armsoc

Change-Id: I3a3a72ff2eb589094128d841097055931a8d0c0e
Reviewed-on: https://chromium-review.googlesource.com/203587
Reviewed-by: Doug Anderson <dianders@chromium.org>
Commit-Queue: Doug Anderson <dianders@chromium.org>
Tested-by: Doug Anderson <dianders@chromium.org>
diff --git a/configure.ac b/configure.ac
index 8da756d..e22500d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,6 +60,15 @@
             [moduledir="$withval"],
             [moduledir="$libdir/xorg/modules"])
 
+AC_MSG_CHECKING([which DRM driver to use])
+AC_ARG_WITH(driver,
+            AS_HELP_STRING([--with-driver],
+                          [driver need select one : rockchip exynos]),
+            [driver="$withval"],
+            AC_MSG_FAILURE([You must specify which DRM driver to build for - see README]))
+AC_MSG_RESULT([$driver])
+AC_SUBST(driver)
+
 # Checks for extensions
 XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
 XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
@@ -68,7 +77,14 @@
 # Checks for pkg-config packages
 PKG_CHECK_MODULES(XORG, [xorg-server >= 1.10] xproto fontsproto dri2proto $REQUIRED_MODULES)
 PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1])
-PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.30] [libdrm_exynos >= 0.6])
+
+if test "x${driver}" == "xexynos"; then
+    PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.30] [libdrm_exynos >= 0.6])
+fi
+
+if test "x${driver}" == "xrockchip"; then
+    PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.30] [libdrm_rockchip >= 0.1])
+fi
 
 # Checks for header files.
 AC_HEADER_STDC
diff --git a/src/Makefile.am b/src/Makefile.am
index 74ee31e..094d94e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,12 +34,13 @@
 	-Wwrite-strings -Wformat-nonliteral  -Wformat-security \
 	-Wold-style-definition -Winit-self -Wmissing-include-dirs \
 	-Waddress -Waggregate-return -Wno-multichar -Wnested-externs
- 
+
 AM_CFLAGS = @XORG_CFLAGS@ @DRM_CFLAGS@ $(ERROR_CFLAGS)
 armsoc_drv_la_LTLIBRARIES = armsoc_drv.la
 armsoc_drv_la_LDFLAGS = -module -avoid-version -no-undefined
 armsoc_drv_la_LIBADD = @XORG_LIBS@ @DRM_LIBS@
 armsoc_drv_ladir = @moduledir@/drivers
+BO_SRCS = bo_@driver@.c
 
 armsoc_drv_la_SOURCES = \
          drmmode_display.c \
@@ -47,4 +48,5 @@
          omap_exa_null.c \
          omap_dri2.c \
          omap_driver.c \
-         omap_dumb.c
+         omap_dumb.c \
+         $(BO_SRCS)
diff --git a/src/bo.h b/src/bo.h
new file mode 100644
index 0000000..78a99a5
--- /dev/null
+++ b/src/bo.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2014 ROCKCHIP, Inc.
+ *
+ * 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 _BO_H_
+#define _BO_H_
+
+struct omap_bo;
+struct omap_device;
+enum omap_gem_op;
+struct bo_ops {
+	void *(*bo_create)(struct omap_device *dev,
+			size_t size, uint32_t flags, uint32_t *handle);
+	void (*bo_destroy)(struct omap_bo *bo);
+	int (*bo_get_name)(struct omap_bo *bo, uint32_t *name);
+	void *(*bo_map)(struct omap_bo *bo);
+	int (*bo_cpu_prep)(struct omap_bo *bo, enum omap_gem_op op);
+	int (*bo_cpu_fini)(struct omap_bo *bo, enum omap_gem_op op);
+};
+
+int bo_device_init(struct omap_device *dev);
+void bo_device_deinit(struct omap_device *dev);
+#endif
diff --git a/src/bo_exynos.c b/src/bo_exynos.c
new file mode 100644
index 0000000..93604fe
--- /dev/null
+++ b/src/bo_exynos.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <errno.h>
+#include <xf86.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <exynos_drm.h>
+#include <libdrm/exynos_drmif.h>
+
+#include "omap_dumb.h"
+#include "omap_msg.h"
+
+enum {
+	DRM_EXYNOS_GEM_CPU_ACQUIRE_SHARED = 0x0,
+	DRM_EXYNOS_GEM_CPU_ACQUIRE_EXCLUSIVE = 0x1,
+};
+
+struct drm_exynos_gem_cpu_acquire {
+	unsigned int handle;
+	unsigned int flags;
+};
+
+struct drm_exynos_gem_cpu_release {
+	unsigned int handle;
+};
+
+/* TODO: use exynos_drm.h kernel headers (http://crosbug.com/37294) */
+#define DRM_EXYNOS_GEM_CPU_ACQUIRE     0x08
+#define DRM_IOCTL_EXYNOS_GEM_CPU_ACQUIRE       DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_GEM_CPU_ACQUIRE, struct drm_exynos_gem_cpu_acquire)
+#define DRM_EXYNOS_GEM_CPU_RELEASE     0x09
+#define DRM_IOCTL_EXYNOS_GEM_CPU_RELEASE       DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_GEM_CPU_RELEASE, struct drm_exynos_gem_cpu_release)
+
+static void *bo_exynos_create(struct omap_device *dev,
+			size_t size, uint32_t flags, uint32_t *handle)
+
+{
+	struct exynos_bo *exynos_bo;
+
+	flags |= EXYNOS_BO_NONCONTIG;
+
+	exynos_bo = exynos_bo_create(dev->bo_dev, size, flags);
+	*handle = exynos_bo_handle(exynos_bo);
+
+	return exynos_bo;
+}
+
+static void bo_exynos_destroy(struct omap_bo *bo)
+{
+	exynos_bo_destroy(bo->priv_bo);
+}
+
+static int bo_exynos_get_name(struct omap_bo *bo, uint32_t *name)
+{
+	return exynos_bo_get_name(bo->priv_bo, name);
+}
+
+static void *bo_exynos_map(struct omap_bo *bo)
+{
+	struct exynos_bo *exynos_bo = bo->priv_bo;
+	if (exynos_bo->vaddr)
+		return exynos_bo->vaddr;
+	return exynos_bo_map(bo->priv_bo);
+}
+
+static int bo_exynos_cpu_prep(struct omap_bo *bo, enum omap_gem_op op)
+{
+	ScrnInfoPtr pScrn = bo->dev->pScrn;
+	struct drm_exynos_gem_cpu_acquire acquire;
+	int ret;
+
+	acquire.handle = bo->handle;
+	acquire.flags = (op & OMAP_GEM_WRITE)
+		? DRM_EXYNOS_GEM_CPU_ACQUIRE_EXCLUSIVE
+		: DRM_EXYNOS_GEM_CPU_ACQUIRE_SHARED;
+	ret = drmIoctl(bo->dev->fd, DRM_IOCTL_EXYNOS_GEM_CPU_ACQUIRE,
+			&acquire);
+	if (ret)
+		ERROR_MSG("DRM_IOCTL_EXYNOS_GEM_CPU_ACQUIRE failed: %s",
+				strerror(errno));
+	return ret;
+}
+
+static int bo_exynos_cpu_fini(struct omap_bo *bo, enum omap_gem_op op)
+{
+	ScrnInfoPtr pScrn = bo->dev->pScrn;
+	struct drm_exynos_gem_cpu_release release;
+	int ret;
+
+	release.handle = bo->handle;
+	ret = drmIoctl(bo->dev->fd, DRM_IOCTL_EXYNOS_GEM_CPU_RELEASE,
+			&release);
+	if (ret)
+		ERROR_MSG("DRM_IOCTL_EXYNOS_GEM_CPU_RELEASE failed: %s",
+				strerror(errno));
+	return ret;
+}
+
+static const struct bo_ops bo_exynos_ops = {
+	.bo_create = bo_exynos_create,
+	.bo_destroy = bo_exynos_destroy,
+	.bo_get_name = bo_exynos_get_name,
+	.bo_map = bo_exynos_map,
+	.bo_cpu_prep = bo_exynos_cpu_prep,
+	.bo_cpu_fini = bo_exynos_cpu_fini,
+};
+
+int bo_device_init(struct omap_device *dev)
+{
+	struct exynos_device *new_exynos_dev;
+
+	new_exynos_dev = exynos_device_create(dev->fd);
+	if (!new_exynos_dev)
+		return FALSE;
+
+	dev->bo_dev = new_exynos_dev;
+	dev->ops = &bo_exynos_ops;
+
+	return TRUE;
+}
+
+void bo_device_deinit(struct omap_device *dev)
+{
+	if (dev->bo_dev)
+		exynos_device_destroy(dev->bo_dev);
+}
diff --git a/src/bo_rockchip.c b/src/bo_rockchip.c
new file mode 100644
index 0000000..919f54a
--- /dev/null
+++ b/src/bo_rockchip.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2014 ROCKCHIP, Inc.
+ *
+ * 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 <stdlib.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <errno.h>
+#include <xf86.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <libdrm/rockchip_drmif.h>
+#include "omap_dumb.h"
+#include "omap_msg.h"
+
+static void *bo_rockchip_create(struct omap_device *dev,
+			size_t size, uint32_t flags, uint32_t *handle)
+{
+	struct rockchip_bo *rockchip_bo;
+
+	rockchip_bo = rockchip_bo_create(dev->bo_dev, size, flags);
+	*handle = rockchip_bo_handle(rockchip_bo);
+
+	return rockchip_bo;
+}
+
+static void bo_rockchip_destroy(struct omap_bo *bo)
+{
+	rockchip_bo_destroy(bo->priv_bo);
+}
+
+static int bo_rockchip_get_name(struct omap_bo *bo, uint32_t *name)
+{
+	return rockchip_bo_get_name(bo->priv_bo, name);
+}
+
+static void *bo_rockchip_map(struct omap_bo *bo)
+{
+	struct rockchip_bo *rockchip_bo = bo->priv_bo;
+	if (rockchip_bo->vaddr)
+		return rockchip_bo->vaddr;
+	return rockchip_bo_map(bo->priv_bo);
+}
+
+static int bo_rockchip_cpu_prep(struct omap_bo *bo, enum omap_gem_op op)
+{
+	return 0;
+}
+
+static int bo_rockchip_cpu_fini(struct omap_bo *bo, enum omap_gem_op op)
+{
+	return 0;
+}
+
+static const struct bo_ops bo_rockchip_ops = {
+	.bo_create = bo_rockchip_create,
+	.bo_destroy = bo_rockchip_destroy,
+	.bo_get_name = bo_rockchip_get_name,
+	.bo_map = bo_rockchip_map,
+	.bo_cpu_prep = bo_rockchip_cpu_prep,
+	.bo_cpu_fini = bo_rockchip_cpu_fini,
+};
+
+int bo_device_init(struct omap_device *dev)
+{
+	struct rockchip_device *new_rockchip_dev;
+
+	new_rockchip_dev = rockchip_device_create(dev->fd);
+	if (!new_rockchip_dev)
+		return FALSE;
+
+	dev->bo_dev = new_rockchip_dev;
+	dev->ops = &bo_rockchip_ops;
+
+	return TRUE;
+}
+
+void bo_device_deinit(struct omap_device *dev)
+{
+	if (dev->bo_dev)
+		rockchip_device_destroy(dev->bo_dev);
+}
diff --git a/src/omap_dumb.c b/src/omap_dumb.c
index 742d959..a3b5152 100644
--- a/src/omap_dumb.c
+++ b/src/omap_dumb.c
@@ -29,72 +29,49 @@
 #include <xf86.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
-#include <exynos_drm.h>
-#include <libdrm/exynos_drmif.h>
 
 #include "omap_dumb.h"
 #include "omap_msg.h"
 
-struct omap_device {
-	struct exynos_device exynos_dev;
-	ScrnInfoPtr pScrn;
-};
-
-struct omap_bo {
-	struct omap_device *dev;
-	struct exynos_bo *exynos_bo;
-	uint32_t fb_id;
-	uint32_t width;
-	uint32_t height;
-	uint32_t pitch;
-	uint8_t depth;
-	uint8_t bpp;
-	uint32_t pixel_format;
-	int refcnt;
-	int acquired_exclusive;
-	int acquire_cnt;
-	int dirty;
-};
-
-enum {
-	DRM_EXYNOS_GEM_CPU_ACQUIRE_SHARED = 0x0,
-	DRM_EXYNOS_GEM_CPU_ACQUIRE_EXCLUSIVE = 0x1,
-};
-
-struct drm_exynos_gem_cpu_acquire {
-	unsigned int handle;
-	unsigned int flags;
-};
-
-struct drm_exynos_gem_cpu_release {
-	unsigned int handle;
-};
-
-/* TODO: use exynos_drm.h kernel headers (http://crosbug.com/37294) */
-#define DRM_EXYNOS_GEM_CPU_ACQUIRE	0x08
-#define DRM_IOCTL_EXYNOS_GEM_CPU_ACQUIRE	DRM_IOWR(DRM_COMMAND_BASE + \
-		DRM_EXYNOS_GEM_CPU_ACQUIRE, struct drm_exynos_gem_cpu_acquire)
-#define DRM_EXYNOS_GEM_CPU_RELEASE	0x09
-#define DRM_IOCTL_EXYNOS_GEM_CPU_RELEASE	DRM_IOWR(DRM_COMMAND_BASE + \
-		DRM_EXYNOS_GEM_CPU_RELEASE, struct drm_exynos_gem_cpu_release)
-
 /* device related functions:
  */
 
 struct omap_device *omap_device_new(int fd, ScrnInfoPtr pScrn)
 {
 	struct omap_device *new_dev = calloc(1, sizeof *new_dev);
+	const struct bo_ops *bo_ops;
+
 	if (!new_dev)
 		return NULL;
 
-	new_dev->exynos_dev.fd = fd;
+	new_dev->fd = fd;
 	new_dev->pScrn = pScrn;
 
+	if (!bo_device_init(new_dev))
+		goto err_free_dev;
+
+	bo_ops = new_dev->ops;
+
+	if (!(bo_ops->bo_create && bo_ops->bo_destroy
+			&& bo_ops->bo_get_name
+			&& bo_ops->bo_map
+			&& bo_ops->bo_cpu_prep
+			&& bo_ops->bo_cpu_fini)) {
+		ERROR_MSG("Omap Dev New Fail: bo_ops setting is Incomplete");
+		goto err_deinit_bodev;
+	}
+
 	return new_dev;
+err_deinit_bodev:
+	bo_device_deinit(new_dev);
+err_free_dev:
+	free(new_dev);
+	return NULL;
 }
 
 void omap_device_del(struct omap_device *dev)
 {
+	bo_device_deinit(dev);
 	free(dev);
 }
 
@@ -106,10 +83,11 @@
 		uint32_t pixel_format)
 {
 	ScrnInfoPtr pScrn = dev->pScrn;
+	const struct bo_ops *bo_ops = dev->ops;
 	struct omap_bo *new_buf;
 	uint32_t pitch;
 	size_t size;
-	const uint32_t flags = EXYNOS_BO_NONCONTIG;
+	const uint32_t flags = 0;
 	int ret;
 
 	new_buf = calloc(1, sizeof(*new_buf));
@@ -121,51 +99,45 @@
 	pitch = ((((width * bpp + 7) / 8) + 63) / 64) * 64;
 	size = height * pitch;
 
-	new_buf->exynos_bo = exynos_bo_create(&dev->exynos_dev, size, flags);
-	if (!new_buf->exynos_bo)
-	{
-		free(new_buf);
-		ERROR_MSG("EXYNOS_BO_CREATE(size: %zu flags: 0x%x) failed: %s",
+	new_buf->priv_bo = bo_ops->bo_create(dev, size, flags, &new_buf->handle);
+	if (!new_buf->priv_bo) {
+		ERROR_MSG("PLATFORM_BO_CREATE(size: %zu flags: 0x%x) failed: %s",
 				size, flags, strerror(errno));
-		return NULL;
+		goto free_buf;
 	}
 
-	DEBUG_MSG("Created [BO:%u] {size: %u flags: 0x%x}",
-			new_buf->exynos_bo->handle, new_buf->exynos_bo->size,
-			flags);
-
 	if (depth) {
-		ret = drmModeAddFB(dev->exynos_dev.fd, width, height, depth,
-				bpp, pitch, new_buf->exynos_bo->handle,
+		ret = drmModeAddFB(dev->fd, width, height, depth,
+				bpp, pitch, new_buf->handle,
 				&new_buf->fb_id);
 		if (ret < 0) {
 			ERROR_MSG("[BO:%u] add FB {%ux%u depth: %u bpp: %u pitch: %u} failed: %s",
-					new_buf->exynos_bo->handle, width,
+					new_buf->handle, width,
 					height, depth, bpp, pitch,
 					strerror(errno));
 			goto destroy_bo;
 		}
 		DEBUG_MSG("Created [FB:%u] {%ux%u depth: %u bpp: %u pitch: %u} using [BO:%u]",
 				new_buf->fb_id, width, height, depth, bpp,
-				pitch, new_buf->exynos_bo->handle);
+				pitch, new_buf->handle);
 	} else {
-		uint32_t handles[4] = { new_buf->exynos_bo->handle };
+		uint32_t handles[4] = { new_buf->handle };
 		uint32_t pitches[4] = { pitch };
 		uint32_t offsets[4] = { 0 };
 
-		ret = drmModeAddFB2(dev->exynos_dev.fd, width, height,
+		ret = drmModeAddFB2(dev->fd, width, height,
 				pixel_format, handles, pitches, offsets,
 				&new_buf->fb_id, 0);
 		if (ret < 0) {
 			ERROR_MSG("[BO:%u] add FB {%ux%u format: %.4s pitch: %u} failed: %s",
-					new_buf->exynos_bo->handle, width,
+					new_buf->handle, width,
 					height, (char *)&pixel_format, pitch,
 					strerror(errno));
 			goto destroy_bo;
 		}
 		/* print pixel_format as a 'four-cc' ASCII code */
 		DEBUG_MSG("[BO:%u] [FB:%u] Added FB: {%ux%u format: %.4s pitch: %u}",
-				new_buf->exynos_bo->handle, new_buf->fb_id,
+				new_buf->handle, new_buf->fb_id,
 				width, height, (char *)&pixel_format, pitch);
 	}
 
@@ -184,7 +156,8 @@
 	return new_buf;
 
 destroy_bo:
-	exynos_bo_destroy(new_buf->exynos_bo);
+	bo_ops->bo_destroy(new_buf);
+free_buf:
 	free(new_buf);
 	return NULL;
 }
@@ -203,25 +176,17 @@
 
 static void omap_bo_del(struct omap_bo *bo)
 {
-	ScrnInfoPtr pScrn;
+	struct omap_device *dev = bo->dev;
+	ScrnInfoPtr pScrn = dev->pScrn;
 	int res;
 
-	if (!bo)
-		return;
-
-	pScrn = bo->dev->pScrn;
-
-	DEBUG_MSG("[BO:%u] [FB:%u] [FLINK:%u] mmap: %p size: %u",
-			bo->exynos_bo->handle, bo->fb_id, bo->exynos_bo->name,
-			bo->exynos_bo->vaddr, bo->exynos_bo->size);
-
-	res = drmModeRmFB(bo->dev->exynos_dev.fd, bo->fb_id);
+	res = drmModeRmFB(dev->fd, bo->fb_id);
 	if (res)
 		ERROR_MSG("[BO:%u] Remove [FB:%u] failed: %s",
-				bo->exynos_bo->handle, bo->fb_id,
+				bo->handle, bo->fb_id,
 				strerror(errno));
 	assert(res == 0);
-	exynos_bo_destroy(bo->exynos_bo);
+	dev->ops->bo_destroy(bo);
 	free(bo);
 }
 
@@ -243,30 +208,27 @@
 
 uint32_t omap_bo_get_name(struct omap_bo *bo)
 {
-	ScrnInfoPtr pScrn = bo->dev->pScrn;
+	struct omap_device *dev = bo->dev;
+	ScrnInfoPtr pScrn = dev->pScrn;
 	uint32_t name;
 	int ret;
 
-	if (bo->exynos_bo->name)
-		return bo->exynos_bo->name;
-
-	ret = exynos_bo_get_name(bo->exynos_bo, &name);
+	ret = dev->ops->bo_get_name(bo, &name);
 	if (ret) {
-		ERROR_MSG("[BO:%u] EXYNOS_BO_GET_NAME failed: %s",
-				bo->exynos_bo->handle, strerror(errno));
+		ERROR_MSG("[BO:%u] BO_GET_NAME failed: %s",
+				bo->handle, strerror(errno));
 		return 0;
 	}
 
-	DEBUG_MSG("[BO:%u] [FB:%u] [FLINK:%u] mmap: %p",
-			bo->exynos_bo->handle, bo->fb_id, bo->exynos_bo->name,
-			bo->exynos_bo->vaddr);
+	DEBUG_MSG("[BO:%u] [FB:%u] [FLINK:%u] ",
+			bo->handle, bo->fb_id, name);
 
-	return bo->exynos_bo->name;
+	return name;
 }
 
 uint32_t omap_bo_handle(struct omap_bo *bo)
 {
-	return bo->exynos_bo->handle;
+	return bo->handle;
 }
 
 uint32_t omap_bo_width(struct omap_bo *bo)
@@ -307,29 +269,24 @@
 
 void *omap_bo_map(struct omap_bo *bo)
 {
-	ScrnInfoPtr pScrn = bo->dev->pScrn;
+	struct omap_device *dev = bo->dev;
+	ScrnInfoPtr pScrn = dev->pScrn;
 	void *map_addr;
 
-	if (bo->exynos_bo->vaddr)
-		return bo->exynos_bo->vaddr;
-
-	map_addr = exynos_bo_map(bo->exynos_bo);
+	map_addr = dev->ops->bo_map(bo);
 	if (!map_addr) {
-		ERROR_MSG("[BO:%u] EXYNOS_BO_MAP failed: %s",
-				bo->exynos_bo->handle, strerror(errno));
+		ERROR_MSG("[BO:%u] bo_MAP failed: %s",
+				bo->handle, strerror(errno));
 		return NULL;
 	}
 
-	DEBUG_MSG("[BO:%u] [FB:%u] [FLINK:%u] mmap: %p mapped %zu bytes",
-			bo->exynos_bo->handle, bo->fb_id, bo->exynos_bo->name,
-			bo->exynos_bo->vaddr, bo->exynos_bo->size);
 	return map_addr;
 }
 
 int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op)
 {
-	ScrnInfoPtr pScrn = bo->dev->pScrn;
-	struct drm_exynos_gem_cpu_acquire acquire;
+	struct omap_device *dev = bo->dev;
+	ScrnInfoPtr pScrn = dev->pScrn;
 	int ret;
 
 	if (bo->acquire_cnt) {
@@ -340,43 +297,30 @@
 		bo->acquire_cnt++;
 		return 0;
 	}
-	acquire.handle = bo->exynos_bo->handle;
-	acquire.flags = (op & OMAP_GEM_WRITE)
-		? DRM_EXYNOS_GEM_CPU_ACQUIRE_EXCLUSIVE
-		: DRM_EXYNOS_GEM_CPU_ACQUIRE_SHARED;
-	ret = drmIoctl(bo->dev->exynos_dev.fd, DRM_IOCTL_EXYNOS_GEM_CPU_ACQUIRE,
-			&acquire);
-	if (ret) {
-		ERROR_MSG("DRM_IOCTL_EXYNOS_GEM_CPU_ACQUIRE failed: %s",
-				strerror(errno));
-	} else {
+
+	ret = dev->ops->bo_cpu_prep(bo, op);
+	if (!ret) {
 		bo->acquired_exclusive = op & OMAP_GEM_WRITE;
 		bo->acquire_cnt++;
 		if (bo->acquired_exclusive) {
 			bo->dirty = TRUE;
 		}
 	}
+
 	return ret;
 }
 
 int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op)
 {
-	ScrnInfoPtr pScrn = bo->dev->pScrn;
-	struct drm_exynos_gem_cpu_release release;
-	int ret;
+	struct omap_device *dev = bo->dev;
 
 	assert(bo->acquire_cnt > 0);
 
 	if (--bo->acquire_cnt != 0) {
 		return 0;
 	}
-	release.handle = bo->exynos_bo->handle;
-	ret = drmIoctl(bo->dev->exynos_dev.fd, DRM_IOCTL_EXYNOS_GEM_CPU_RELEASE,
-			&release);
-	if (ret)
-		ERROR_MSG("DRM_IOCTL_EXYNOS_GEM_CPU_RELEASE failed: %s",
-				strerror(errno));
-	return ret;
+
+	return dev->ops->bo_cpu_fini(bo, op);
 }
 
 int omap_bo_get_dirty(struct omap_bo *bo)
diff --git a/src/omap_dumb.h b/src/omap_dumb.h
index c1f29e7..491a7f6 100644
--- a/src/omap_dumb.h
+++ b/src/omap_dumb.h
@@ -25,6 +25,7 @@
 #define OMAP_DUMB_H_
 
 #include <stdint.h>
+#include "bo.h"
 
 struct omap_bo;
 struct omap_device;
@@ -34,6 +35,30 @@
 	OMAP_GEM_WRITE = 0x02,
 };
 
+struct omap_device {
+	int fd;
+	void *bo_dev;
+	const struct bo_ops *ops;
+	ScrnInfoPtr pScrn;
+};
+
+struct omap_bo {
+	struct omap_device *dev;
+	void *priv_bo;
+	uint32_t handle;
+	uint32_t fb_id;
+	uint32_t width;
+	uint32_t height;
+	uint32_t pitch;
+	uint8_t depth;
+	uint8_t bpp;
+	uint32_t pixel_format;
+	int refcnt;
+	int acquired_exclusive;
+	int acquire_cnt;
+	int dirty;
+};
+
 struct omap_device *omap_device_new(int fd, ScrnInfoPtr pScrn);
 void omap_device_del(struct omap_device *dev);