Merge tag libdrm-2.4.75 into aosp/master

Below is a brief summary of patches pulled in:
0da99b8a (m/master, aosp/master) Move libdrm.so to vendor partition
d4b83443 (tag: libdrm-2.4.75) Bump version for 2.4.75 release
dae413e4 (tag: libdrm-2.4.74) Bump version for release
317bdff1 (tag: libdrm-2.4.73) Bump version for release
8cf43127 (tag: libdrm-2.4.72) Bump version for release
a44c9c31 (tag: libdrm-2.4.71) Bump version for release
20208455 (tag: android-o-preview-1, tag: android-n-mr2-preview-2, tag:
android-n-mr2-preview-1, aosp/sdk-release, aosp/o-preview) add a flag
control that private libdrm can be chosen

Bug: 35871718
Test: aosp_arm-eng compiles
Change-Id: I81985fd41d5c0d8a732705dc2a4bee8eb5d459bb
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..893b7be
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,19 @@
+# To use this config with your editor, follow the instructions at:
+# http://editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+insert_final_newline = true
+
+[*.{c,h}]
+indent_style = space
+indent_size = 4
+
+[{Makefile.*,*.mk}]
+indent_style = tab
+
+[*.m4]
+indent_style = space
+indent_size = 2
diff --git a/.gitignore b/.gitignore
index c1e87c5..d51e619 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,8 @@
 libdrm_exynos.pc
 libdrm_freedreno.pc
 libdrm_amdgpu.pc
+libdrm_vc4.pc
+libdrm_etnaviv.pc
 libkms.pc
 libtool
 ltmain.sh
@@ -92,10 +94,15 @@
 tests/modetest/modetest
 tests/name_from_fd
 tests/proptest/proptest
+tests/kms/kms-steal-crtc
+tests/kms/kms-universal-planes
 tests/kmstest/kmstest
 tests/vbltest/vbltest
 tests/radeon/radeon_ttm
 tests/exynos/exynos_fimg2d_event
 tests/exynos/exynos_fimg2d_perf
 tests/exynos/exynos_fimg2d_test
+tests/etnaviv/etnaviv_2d_test
+tests/etnaviv/etnaviv_cmd_stream_test
+tests/etnaviv/etnaviv_bo_cache_test
 man/*.3
diff --git a/Android.common.mk b/Android.common.mk
new file mode 100644
index 0000000..f57b8d3
--- /dev/null
+++ b/Android.common.mk
@@ -0,0 +1,12 @@
+# XXX: Consider moving these to config.h analogous to autoconf.
+LOCAL_CFLAGS += \
+	-DHAVE_VISIBILITY=1 \
+	-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
+
+LOCAL_CFLAGS += \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers
+
+# Quiet down the build system and remove any .h files from the sources
+LOCAL_SRC_FILES := $(patsubst %.h, , $(LOCAL_SRC_FILES))
+LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)
diff --git a/Android.mk b/Android.mk
index 42d254c..102c9a3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,21 +21,21 @@
 # IN THE SOFTWARE.
 #
 
+
 ifneq ($(TARGET_USE_PRIVATE_LIBDRM),true)
+
+LIBDRM_COMMON_MK := $(call my-dir)/Android.common.mk
+
 LOCAL_PATH := $(call my-dir)
 
 # Import variables LIBDRM_{,H_,INCLUDE_H_,INCLUDE_VMWGFX_H_}FILES
 include $(LOCAL_PATH)/Makefile.sources
 
 common_CFLAGS := \
-	-DHAVE_VISIBILITY=1 \
-	-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 \
 	-Wno-enum-conversion \
-	-Wno-missing-field-initializers \
 	-Wno-pointer-arith \
 	-Wno-sign-compare \
-	-Wno-tautological-compare \
-	-Wno-unused-parameter
+	-Wno-tautological-compare
 
 # Static library for the device (recovery)
 include $(CLEAR_VARS)
@@ -53,6 +53,7 @@
 LOCAL_CFLAGS := \
 	$(common_CFLAGS)
 
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_STATIC_LIBRARY)
 
 # Dynamic library for the device
@@ -72,6 +73,7 @@
 LOCAL_CFLAGS := \
 	$(common_CFLAGS)
 
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/Makefile.am b/Makefile.am
index 11ed102..2bf644b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,6 +22,7 @@
 
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
+AM_MAKEFLAGS = -s
 AM_DISTCHECK_CONFIGURE_FLAGS = \
 	--enable-udev \
 	--enable-libkms \
@@ -29,12 +30,14 @@
 	--enable-radeon \
 	--enable-amdgpu \
 	--enable-nouveau \
+	--enable-vc4 \
 	--enable-vmwgfx \
 	--enable-omap-experimental-api \
 	--enable-exynos-experimental-api \
 	--enable-freedreno \
 	--enable-freedreno-kgsl\
 	--enable-tegra-experimental-api \
+	--enable-etnaviv-experimental-api \
 	--enable-install-test-programs \
 	--enable-cairo-tests \
 	--enable-manpages \
@@ -79,6 +82,14 @@
 TEGRA_SUBDIR = tegra
 endif
 
+if HAVE_VC4
+VC4_SUBDIR = vc4
+endif
+
+if HAVE_ETNAVIV
+ETNAVIV_SUBDIR = etnaviv
+endif
+
 if BUILD_MANPAGES
 if HAVE_MANPAGES_STYLESHEET
 MAN_SUBDIR = man
@@ -100,6 +111,8 @@
 	$(EXYNOS_SUBDIR) \
 	$(FREEDRENO_SUBDIR) \
 	$(TEGRA_SUBDIR) \
+	$(VC4_SUBDIR) \
+	$(ETNAVIV_SUBDIR) \
 	tests \
 	$(MAN_SUBDIR) \
 	$(ROCKCHIP_SUBDIR)
@@ -119,8 +132,6 @@
 libdrmincludedir = ${includedir}
 libdrminclude_HEADERS = $(LIBDRM_H_FILES)
 
-EXTRA_DIST = Android.mk
-
 klibdrmincludedir = ${includedir}/libdrm
 klibdrminclude_HEADERS = $(LIBDRM_INCLUDE_H_FILES)
 
@@ -128,6 +139,7 @@
 klibdrminclude_HEADERS += $(LIBDRM_INCLUDE_VMWGFX_H_FILES)
 endif
 
+EXTRA_DIST = include/drm/README
 
 copy-headers :
 	cp -r $(kernel_source)/include/uapi/drm/*.h $(top_srcdir)/include/drm/
diff --git a/Makefile.sources b/Makefile.sources
index a77f48d..10aa1d0 100644
--- a/Makefile.sources
+++ b/Makefile.sources
@@ -13,6 +13,7 @@
 	util_math.h
 
 LIBDRM_H_FILES := \
+	libsync.h \
 	xf86drm.h \
 	xf86drmMode.h
 
@@ -32,7 +33,9 @@
 	include/drm/savage_drm.h \
 	include/drm/sis_drm.h \
 	include/drm/tegra_drm.h \
-	include/drm/via_drm.h
+	include/drm/vc4_drm.h \
+	include/drm/via_drm.h \
+	include/drm/virtgpu_drm.h
 
 LIBDRM_INCLUDE_VMWGFX_H_FILES := \
 	include/drm/vmwgfx_drm.h
diff --git a/README b/README
index 603a1c1..26cab9d 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 libdrm - userspace library for drm
 
 This  is libdrm,  a userspace  library for  accessing the  DRM, direct
-rendering  manager, on  Linux,  BSD and  other  operating systes  that
+rendering  manager, on  Linux,  BSD and  other  operating systems that
 support the  ioctl interface.  The library  provides wrapper functions
 for the  ioctls to avoid  exposing the kernel interface  directly, and
 for chipsets with drm memory manager, support for tracking relocations
@@ -15,7 +15,7 @@
 Compiling
 ---------
 
-libdrm  is  a  standard  autotools  packages and  follows  the  normal
+libdrm  is  a  standard  autotools  package and  follows  the  normal
 configure, build  and install steps.   The first step is  to configure
 the package, which is done by running the configure shell script:
 
@@ -37,5 +37,5 @@
 
 	make install
 
-If you are install into a system location, you will need to be root to
-perform the install step.
+If you are installing into a system location, you will need to be root
+to perform the install step.
diff --git a/RELEASING b/RELEASING
index 62c5be9..262ca08 100644
--- a/RELEASING
+++ b/RELEASING
@@ -9,21 +9,14 @@
 
 Follow these steps to release a new version of libdrm:
 
-  1) Ensure that there are no local, uncommitted/unpushed
-     modifications. You're probably in a good state if both "git diff
-     HEAD" and "git log master..origin/master" give no output.
-
-  2) Bump the version number in configure.ac. We seem to have settled
+  1) Bump the version number in configure.ac. We seem to have settled
      for 2.4.x as the versioning scheme for libdrm, so just bump the
      micro version.
 
-  3) Run autoconf and then re-run ./configure so the build system
+  2) Run autoconf and then re-run ./configure so the build system
      picks up the new version number.
 
-  4) (optional step, release.sh will make distcheck for you, but it can be
-      heart warming to verify that make distcheck passes)
-
-     Verify that the code passes "make distcheck".  Running "make
+  3) Verify that the code passes "make distcheck".  Running "make
      distcheck" should result in no warnings or errors and end with a
      message of the form:
 
@@ -36,20 +29,13 @@
      Make sure that the version number reported by distcheck and in
      the tarball names matches the number you bumped to in configure.ac.
 
-  5) Commit the configure.ac change and make an annotated tag for that
-     commit with the version number of the release as the name and a
-     message of "libdrm X.Y.Z".  For example, for the 2.4.16 release
-     the command is:
+  4) Push the updated master branch with the bumped version number:
 
-	git tag -a 2.4.16 -m "libdrm 2.4.16"
-
-  6) Push the commit and tag by saying
-
-	git push --tags origin master
+	git push origin master
 
      assuming the remote for the upstream libdrm repo is called origin.
 
-  7) Use the release.sh script from the xorg/util/modular repo to
+  5) Use the release.sh script from the xorg/util/modular repo to
      upload the tarballs to the freedesktop.org download area and
      create an announce email template.  The script takes one argument:
      the path to the libdrm checkout. So, if a checkout of modular is
diff --git a/amdgpu/Android.mk b/amdgpu/Android.mk
index e5777e5..bf0611b 100644
--- a/amdgpu/Android.mk
+++ b/amdgpu/Android.mk
@@ -5,14 +5,10 @@
 include $(LOCAL_PATH)/Makefile.sources
 
 LOCAL_MODULE := libdrm_amdgpu
-LOCAL_MODULE_TAGS := optional
 
 LOCAL_SHARED_LIBRARIES := libdrm
 
-LOCAL_SRC_FILES := $(filter-out %.h,$(LIBDRM_AMDGPU_FILES))
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_SRC_FILES := $(LIBDRM_AMDGPU_FILES)
 
-LOCAL_CFLAGS := \
-	-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
-
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_SHARED_LIBRARY)
diff --git a/amdgpu/Makefile.sources b/amdgpu/Makefile.sources
index 0c0b9a9..487b9e0 100644
--- a/amdgpu/Makefile.sources
+++ b/amdgpu/Makefile.sources
@@ -1,4 +1,5 @@
 LIBDRM_AMDGPU_FILES := \
+	amdgpu_asic_id.h \
 	amdgpu_bo.c \
 	amdgpu_cs.c \
 	amdgpu_device.c \
diff --git a/amdgpu/amdgpu-symbol-check b/amdgpu/amdgpu-symbol-check
index 9a0b36c..87f4fd2 100755
--- a/amdgpu/amdgpu-symbol-check
+++ b/amdgpu/amdgpu-symbol-check
@@ -24,13 +24,18 @@
 amdgpu_bo_va_op
 amdgpu_bo_wait_for_idle
 amdgpu_create_bo_from_user_mem
+amdgpu_cs_create_semaphore
 amdgpu_cs_ctx_create
 amdgpu_cs_ctx_free
+amdgpu_cs_destroy_semaphore
 amdgpu_cs_query_fence_status
 amdgpu_cs_query_reset_state
+amdgpu_cs_signal_semaphore
 amdgpu_cs_submit
+amdgpu_cs_wait_semaphore
 amdgpu_device_deinitialize
 amdgpu_device_initialize
+amdgpu_get_marketing_name
 amdgpu_query_buffer_size_alignment
 amdgpu_query_crtc_from_id
 amdgpu_query_firmware_version
diff --git a/amdgpu/amdgpu.h b/amdgpu/amdgpu.h
index e44d802..7b26a04 100644
--- a/amdgpu/amdgpu.h
+++ b/amdgpu/amdgpu.h
@@ -124,6 +124,11 @@
  */
 typedef struct amdgpu_va *amdgpu_va_handle;
 
+/**
+ * Define handle for semaphore
+ */
+typedef struct amdgpu_semaphore *amdgpu_semaphore_handle;
+
 /*--------------------------------------------------------------------------*/
 /* -------------------------- Structures ---------------------------------- */
 /*--------------------------------------------------------------------------*/
@@ -680,7 +685,7 @@
 int amdgpu_bo_free(amdgpu_bo_handle buf_handle);
 
 /**
- * Request CPU access to GPU accessable memory
+ * Request CPU access to GPU accessible memory
  *
  * \param   buf_handle - \c [in] Buffer handle
  * \param   cpu        - \c [out] CPU address to be used for access
@@ -846,7 +851,7 @@
  * order.
  *
  * The caller can specify the user fence buffer/location with the fence_info in the
- * cs_request.The sequence number is returned via the 'seq_no' paramter
+ * cs_request.The sequence number is returned via the 'seq_no' parameter
  * in ibs_request structure.
  *
  *
@@ -1180,4 +1185,74 @@
 		    uint64_t flags,
 		    uint32_t ops);
 
+/**
+ *  create semaphore
+ *
+ * \param   sem	   - \c [out] semaphore handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_create_semaphore(amdgpu_semaphore_handle *sem);
+
+/**
+ *  signal semaphore
+ *
+ * \param   context        - \c [in] GPU Context
+ * \param   ip_type        - \c [in] Hardware IP block type = AMDGPU_HW_IP_*
+ * \param   ip_instance    - \c [in] Index of the IP block of the same type
+ * \param   ring           - \c [in] Specify ring index of the IP
+ * \param   sem	           - \c [in] semaphore handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_signal_semaphore(amdgpu_context_handle ctx,
+			       uint32_t ip_type,
+			       uint32_t ip_instance,
+			       uint32_t ring,
+			       amdgpu_semaphore_handle sem);
+
+/**
+ *  wait semaphore
+ *
+ * \param   context        - \c [in] GPU Context
+ * \param   ip_type        - \c [in] Hardware IP block type = AMDGPU_HW_IP_*
+ * \param   ip_instance    - \c [in] Index of the IP block of the same type
+ * \param   ring           - \c [in] Specify ring index of the IP
+ * \param   sem	           - \c [in] semaphore handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_wait_semaphore(amdgpu_context_handle ctx,
+			     uint32_t ip_type,
+			     uint32_t ip_instance,
+			     uint32_t ring,
+			     amdgpu_semaphore_handle sem);
+
+/**
+ *  destroy semaphore
+ *
+ * \param   sem	    - \c [in] semaphore handle
+ *
+ * \return   0 on success\n
+ *          <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_cs_destroy_semaphore(amdgpu_semaphore_handle sem);
+
+/**
+ *  Get the ASIC marketing name
+ *
+ * \param   dev         - \c [in] Device handle. See #amdgpu_device_initialize()
+ *
+ * \return  the constant string of the marketing name
+ *          "NULL" means the ASIC is not found
+*/
+const char *amdgpu_get_marketing_name(amdgpu_device_handle dev);
+
 #endif /* #ifdef _AMDGPU_H_ */
diff --git a/amdgpu/amdgpu_asic_id.h b/amdgpu/amdgpu_asic_id.h
new file mode 100644
index 0000000..3e7d736
--- /dev/null
+++ b/amdgpu/amdgpu_asic_id.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright © 2016 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 __AMDGPU_ASIC_ID_H__
+#define __AMDGPU_ASIC_ID_H__
+
+static struct amdgpu_asic_id_table_t {
+	uint32_t did;
+	uint32_t rid;
+	const char *marketing_name;
+} const amdgpu_asic_id_table [] = {
+	{0x6600,	0x0,	"AMD Radeon HD 8600/8700M"},
+	{0x6600,	0x81,	"AMD Radeon R7 M370"},
+	{0x6601,	0x0,	"AMD Radeon HD 8500M/8700M"},
+	{0x6604,	0x0,	"AMD Radeon R7 M265 Series"},
+	{0x6604,	0x81,	"AMD Radeon R7 M350"},
+	{0x6605,	0x0,	"AMD Radeon R7 M260 Series"},
+	{0x6605,	0x81,	"AMD Radeon R7 M340"},
+	{0x6606,	0x0,	"AMD Radeon HD 8790M"},
+	{0x6607,	0x0,	"AMD Radeon HD8530M"},
+	{0x6608,	0x0,	"AMD FirePro W2100"},
+	{0x6610,	0x0,	"AMD Radeon HD 8600 Series"},
+	{0x6610,	0x81,	"AMD Radeon R7 350"},
+	{0x6610,	0x83,	"AMD Radeon R5 340"},
+	{0x6611,	0x0,	"AMD Radeon HD 8500 Series"},
+	{0x6613,	0x0,	"AMD Radeon HD 8500 series"},
+	{0x6617,	0xC7,	"AMD Radeon R7 240 Series"},
+	{0x6640,	0x0,	"AMD Radeon HD 8950"},
+	{0x6640,	0x80,	"AMD Radeon R9 M380"},
+	{0x6646,	0x0,	"AMD Radeon R9 M280X"},
+	{0x6646,	0x80,	"AMD Radeon R9 M470X"},
+	{0x6647,	0x0,	"AMD Radeon R9 M270X"},
+	{0x6647,	0x80,	"AMD Radeon R9 M380"},
+	{0x6649,	0x0,	"AMD FirePro W5100"},
+	{0x6658,	0x0,	"AMD Radeon R7 200 Series"},
+	{0x665C,	0x0,	"AMD Radeon HD 7700 Series"},
+	{0x665D,	0x0,	"AMD Radeon R7 200 Series"},
+	{0x665F,	0x81,	"AMD Radeon R7 300 Series"},
+	{0x6660,	0x0,	"AMD Radeon HD 8600M Series"},
+	{0x6660,	0x81,	"AMD Radeon R5 M335"},
+	{0x6660,	0x83,	"AMD Radeon R5 M330"},
+	{0x6663,	0x0,	"AMD Radeon HD 8500M Series"},
+	{0x6663,	0x83,	"AMD Radeon R5 M320"},
+	{0x6664,	0x0,	"AMD Radeon R5 M200 Series"},
+	{0x6665,	0x0,	"AMD Radeon R5 M200 Series"},
+	{0x6665,	0x83,	"AMD Radeon R5 M320"},
+	{0x6667,	0x0,	"AMD Radeon R5 M200 Series"},
+	{0x666F,	0x0,	"AMD Radeon HD 8500M"},
+	{0x6780,	0x0,	"ATI FirePro V (FireGL V) Graphics Adapter"},
+	{0x678A,	0x0,	"ATI FirePro V (FireGL V) Graphics Adapter"},
+	{0x6798,	0x0,	"AMD Radeon HD 7900 Series"},
+	{0x679A,	0x0,	"AMD Radeon HD 7900 Series"},
+	{0x679B,	0x0,	"AMD Radeon HD 7900 Series"},
+	{0x679E,	0x0,	"AMD Radeon HD 7800 Series"},
+	{0x67A0,	0x0,	"HAWAII XTGL (67A0)"},
+	{0x67A1,	0x0,	"HAWAII GL40 (67A1)"},
+	{0x67B0,	0x0,	"AMD Radeon R9 200 Series"},
+	{0x67B0,	0x80,	"AMD Radeon R9 390 Series"},
+	{0x67B1,	0x0,	"AMD Radeon R9 200 Series"},
+	{0x67B1,	0x80,	"AMD Radeon R9 390 Series"},
+	{0x67B9,	0x0,	"AMD Radeon R9 200 Series"},
+	{0x67DF,	0xC4,	"AMD Radeon RX 480 Graphics"},
+	{0x67DF,	0xC5,	"AMD Radeon RX 470 Graphics"},
+	{0x67DF,	0xC7,	"AMD Radeon RX 480 Graphics"},
+	{0x67DF,	0xCF,	"AMD Radeon RX 470 Graphics"},
+	{0x67C4,	0x00,	"AMD Radeon Pro WX 7100 Graphics"},
+	{0x67C7,	0x00,	"AMD Radeon Pro WX 5100 Graphics"},
+	{0x67C0,	0x00,	"AMD Radeon Pro WX 7100 Graphics"},
+	{0x67E0,	0x00,	"AMD Radeon Pro WX Series Graphics"},
+	{0x67E3,	0x00,	"AMD Radeon Pro WX 4100 Graphics"},
+	{0x67E8,	0x00,	"AMD Radeon Pro WX Series Graphics"},
+	{0x67E8,	0x01,	"AMD Radeon Pro WX Series Graphics"},
+	{0x67E8,	0x80,	"AMD Radeon E9260 Graphics"},
+	{0x67EB,	0x00,	"AMD Radeon Pro WX Series Graphics"},
+	{0x67EF,	0xC0,	"AMD Radeon RX Graphics"},
+	{0x67EF,	0xC1,	"AMD Radeon RX 460 Graphics"},
+	{0x67EF,	0xC5,	"AMD Radeon RX 460 Graphics"},
+	{0x67EF,	0xC7,	"AMD Radeon RX Graphics"},
+	{0x67EF,	0xCF,	"AMD Radeon RX 460 Graphics"},
+	{0x67EF,	0xEF,	"AMD Radeon RX Graphics"},
+	{0x67FF,	0xC0,	"AMD Radeon RX Graphics"},
+	{0x67FF,	0xC1,	"AMD Radeon RX Graphics"},
+	{0x6800,	0x0,	"AMD Radeon HD 7970M"},
+	{0x6801,	0x0,	"AMD Radeon(TM) HD8970M"},
+	{0x6808,	0x0,	"ATI FirePro V(FireGL V) Graphics Adapter"},
+	{0x6809,	0x0,	"ATI FirePro V(FireGL V) Graphics Adapter"},
+	{0x6810,	0x0,	"AMD Radeon(TM) HD 8800 Series"},
+	{0x6810,	0x81,	"AMD Radeon R7 370 Series"},
+	{0x6811,	0x0,	"AMD Radeon(TM) HD8800 Series"},
+	{0x6811,	0x81,	"AMD Radeon R7 300 Series"},
+	{0x6818,	0x0,	"AMD Radeon HD 7800 Series"},
+	{0x6819,	0x0,	"AMD Radeon HD 7800 Series"},
+	{0x6820,	0x0,	"AMD Radeon HD 8800M Series"},
+	{0x6820,	0x81,	"AMD Radeon R9 M375"},
+	{0x6820,	0x83,	"AMD Radeon R9 M375X"},
+	{0x6821,	0x0,	"AMD Radeon HD 8800M Series"},
+	{0x6821,	0x87,	"AMD Radeon R7 M380"},
+	{0x6821,	0x83,	"AMD Radeon R9 M370X"},
+	{0x6822,	0x0,	"AMD Radeon E8860"},
+	{0x6823,	0x0,	"AMD Radeon HD 8800M Series"},
+	{0x6825,	0x0,	"AMD Radeon HD 7800M Series"},
+	{0x6827,	0x0,	"AMD Radeon HD 7800M Series"},
+	{0x6828,	0x0,	"ATI FirePro V(FireGL V) Graphics Adapter"},
+	{0x682B,	0x0,	"AMD Radeon HD 8800M Series"},
+	{0x682B,	0x87,	"AMD Radeon R9 M360"},
+	{0x682C,	0x0,	"AMD FirePro W4100"},
+	{0x682D,	0x0,	"AMD Radeon HD 7700M Series"},
+	{0x682F,	0x0,	"AMD Radeon HD 7700M Series"},
+	{0x6835,	0x0,	"AMD Radeon R7 Series / HD 9000 Series"},
+	{0x6837,	0x0,	"AMD Radeon HD7700 Series"},
+	{0x683D,	0x0,	"AMD Radeon HD 7700 Series"},
+	{0x683F,	0x0,	"AMD Radeon HD 7700 Series"},
+	{0x6900,	0x0,	"AMD Radeon R7 M260"},
+	{0x6900,	0x81,	"AMD Radeon R7 M360"},
+	{0x6900,	0x83,	"AMD Radeon R7 M340"},
+	{0x6901,	0x0,	"AMD Radeon R5 M255"},
+	{0x6907,	0x0,	"AMD Radeon R5 M255"},
+	{0x6907,	0x87,	"AMD Radeon R5 M315"},
+	{0x6920,	0x0,	"AMD Radeon R9 M395X"},
+	{0x6920,	0x1,	"AMD Radeon R9 M390X"},
+	{0x6921,	0x0,	"AMD Radeon R9 M295X"},
+	{0x6929,	0x0,	"AMD FirePro S7150"},
+	{0x692B,	0x0,	"AMD FirePro W7100"},
+	{0x6938,	0x0,	"AMD Radeon R9 200 Series"},
+	{0x6938,	0xF0,	"AMD Radeon R9 200 Series"},
+	{0x6938,	0xF1,	"AMD Radeon R9 380 Series"},
+	{0x6939,	0xF0,	"AMD Radeon R9 200 Series"},
+	{0x6939,	0x0,	"AMD Radeon R9 200 Series"},
+	{0x6939,	0xF1,	"AMD Radeon R9 380 Series"},
+	{0x7300,	0xC8,	"AMD Radeon R9 Fury Series"},
+	{0x7300,	0xCB,	"AMD Radeon R9 Fury Series"},
+	{0x7300,	0xCA,	"AMD Radeon R9 Fury Series"},
+	{0x9874,	0xC4,	"AMD Radeon R7 Graphics"},
+	{0x9874,	0xC5,	"AMD Radeon R6 Graphics"},
+	{0x9874,	0xC6,	"AMD Radeon R6 Graphics"},
+	{0x9874,	0xC7,	"AMD Radeon R5 Graphics"},
+	{0x9874,	0x81,	"AMD Radeon R6 Graphics"},
+	{0x9874,	0x87,	"AMD Radeon R5 Graphics"},
+	{0x9874,	0x85,	"AMD Radeon R6 Graphics"},
+	{0x9874,	0x84,	"AMD Radeon R7 Graphics"},
+
+	{0x0000,	0x0,	"\0"},
+};
+#endif
diff --git a/amdgpu/amdgpu_bo.c b/amdgpu/amdgpu_bo.c
index 1a5a401..d30fd1e 100644
--- a/amdgpu/amdgpu_bo.c
+++ b/amdgpu/amdgpu_bo.c
@@ -537,18 +537,10 @@
 	int r;
 	struct amdgpu_bo *bo;
 	struct drm_amdgpu_gem_userptr args;
-	uintptr_t cpu0;
-	uint32_t ps, off;
 
-	memset(&args, 0, sizeof(args));
-	ps = getpagesize();
-
-	cpu0 = ROUND_DOWN((uintptr_t)cpu, ps);
-	off = (uintptr_t)cpu - cpu0;
-	size = ROUND_UP(size + off, ps);
-
-	args.addr = cpu0;
-	args.flags = AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_REGISTER;
+	args.addr = (uintptr_t)cpu;
+	args.flags = AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_REGISTER |
+		AMDGPU_GEM_USERPTR_VALIDATE;
 	args.size = size;
 	r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_USERPTR,
 				&args, sizeof(args));
diff --git a/amdgpu/amdgpu_cs.c b/amdgpu/amdgpu_cs.c
index 6747158..fb5b3a8 100644
--- a/amdgpu/amdgpu_cs.c
+++ b/amdgpu/amdgpu_cs.c
@@ -40,6 +40,9 @@
 #include "amdgpu_drm.h"
 #include "amdgpu_internal.h"
 
+static int amdgpu_cs_unreference_sem(amdgpu_semaphore_handle sem);
+static int amdgpu_cs_reset_sem(amdgpu_semaphore_handle sem);
+
 /**
  * Create command submission context
  *
@@ -53,6 +56,7 @@
 {
 	struct amdgpu_context *gpu_context;
 	union drm_amdgpu_ctx args;
+	int i, j, k;
 	int r;
 
 	if (NULL == dev)
@@ -66,6 +70,10 @@
 
 	gpu_context->dev = dev;
 
+	r = pthread_mutex_init(&gpu_context->sequence_mutex, NULL);
+	if (r)
+		goto error;
+
 	/* Create the context */
 	memset(&args, 0, sizeof(args));
 	args.in.op = AMDGPU_CTX_OP_ALLOC_CTX;
@@ -74,11 +82,16 @@
 		goto error;
 
 	gpu_context->id = args.out.alloc.ctx_id;
+	for (i = 0; i < AMDGPU_HW_IP_NUM; i++)
+		for (j = 0; j < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; j++)
+			for (k = 0; k < AMDGPU_CS_MAX_RINGS; k++)
+				list_inithead(&gpu_context->sem_list[i][j][k]);
 	*context = (amdgpu_context_handle)gpu_context;
 
 	return 0;
 
 error:
+	pthread_mutex_destroy(&gpu_context->sequence_mutex);
 	free(gpu_context);
 	return r;
 }
@@ -94,18 +107,32 @@
 int amdgpu_cs_ctx_free(amdgpu_context_handle context)
 {
 	union drm_amdgpu_ctx args;
+	int i, j, k;
 	int r;
 
 	if (NULL == context)
 		return -EINVAL;
 
+	pthread_mutex_destroy(&context->sequence_mutex);
+
 	/* now deal with kernel side */
 	memset(&args, 0, sizeof(args));
 	args.in.op = AMDGPU_CTX_OP_FREE_CTX;
 	args.in.ctx_id = context->id;
 	r = drmCommandWriteRead(context->dev->fd, DRM_AMDGPU_CTX,
 				&args, sizeof(args));
-
+	for (i = 0; i < AMDGPU_HW_IP_NUM; i++) {
+		for (j = 0; j < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; j++) {
+			for (k = 0; k < AMDGPU_CS_MAX_RINGS; k++) {
+				amdgpu_semaphore_handle sem;
+				LIST_FOR_EACH_ENTRY(sem, &context->sem_list[i][j][k], list) {
+					list_del(&sem->list);
+					amdgpu_cs_reset_sem(sem);
+					amdgpu_cs_unreference_sem(sem);
+				}
+			}
+		}
+	}
 	free(context);
 
 	return r;
@@ -150,7 +177,10 @@
 	struct drm_amdgpu_cs_chunk *chunks;
 	struct drm_amdgpu_cs_chunk_data *chunk_data;
 	struct drm_amdgpu_cs_chunk_dep *dependencies = NULL;
-	uint32_t i, size;
+	struct drm_amdgpu_cs_chunk_dep *sem_dependencies = NULL;
+	struct list_head *sem_list;
+	amdgpu_semaphore_handle sem, tmp;
+	uint32_t i, size, sem_count = 0;
 	bool user_fence;
 	int r = 0;
 
@@ -160,9 +190,13 @@
 		return -EINVAL;
 	if (ibs_request->number_of_ibs > AMDGPU_CS_MAX_IBS_PER_SUBMIT)
 		return -EINVAL;
+	if (ibs_request->number_of_ibs == 0) {
+		ibs_request->seq_no = AMDGPU_NULL_SUBMIT_SEQ;
+		return 0;
+	}
 	user_fence = (ibs_request->fence_info.handle != NULL);
 
-	size = ibs_request->number_of_ibs + (user_fence ? 2 : 1);
+	size = ibs_request->number_of_ibs + (user_fence ? 2 : 1) + 1;
 
 	chunk_array = alloca(sizeof(uint64_t) * size);
 	chunks = alloca(sizeof(struct drm_amdgpu_cs_chunk) * size);
@@ -196,6 +230,8 @@
 		chunk_data[i].ib_data.flags = ib->flags;
 	}
 
+	pthread_mutex_lock(&context->sequence_mutex);
+
 	if (user_fence) {
 		i = cs.in.num_chunks++;
 
@@ -240,15 +276,49 @@
 		chunks[i].chunk_data = (uint64_t)(uintptr_t)dependencies;
 	}
 
+	sem_list = &context->sem_list[ibs_request->ip_type][ibs_request->ip_instance][ibs_request->ring];
+	LIST_FOR_EACH_ENTRY(sem, sem_list, list)
+		sem_count++;
+	if (sem_count) {
+		sem_dependencies = malloc(sizeof(struct drm_amdgpu_cs_chunk_dep) * sem_count);
+		if (!sem_dependencies) {
+			r = -ENOMEM;
+			goto error_unlock;
+		}
+		sem_count = 0;
+		LIST_FOR_EACH_ENTRY_SAFE(sem, tmp, sem_list, list) {
+			struct amdgpu_cs_fence *info = &sem->signal_fence;
+			struct drm_amdgpu_cs_chunk_dep *dep = &sem_dependencies[sem_count++];
+			dep->ip_type = info->ip_type;
+			dep->ip_instance = info->ip_instance;
+			dep->ring = info->ring;
+			dep->ctx_id = info->context->id;
+			dep->handle = info->fence;
+
+			list_del(&sem->list);
+			amdgpu_cs_reset_sem(sem);
+			amdgpu_cs_unreference_sem(sem);
+		}
+		i = cs.in.num_chunks++;
+
+		/* dependencies chunk */
+		chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i];
+		chunks[i].chunk_id = AMDGPU_CHUNK_ID_DEPENDENCIES;
+		chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_dep) / 4 * sem_count;
+		chunks[i].chunk_data = (uint64_t)(uintptr_t)sem_dependencies;
+	}
+
 	r = drmCommandWriteRead(context->dev->fd, DRM_AMDGPU_CS,
 				&cs, sizeof(cs));
 	if (r)
 		goto error_unlock;
 
 	ibs_request->seq_no = cs.out.handle;
-
+	context->last_seq[ibs_request->ip_type][ibs_request->ip_instance][ibs_request->ring] = ibs_request->seq_no;
 error_unlock:
+	pthread_mutex_unlock(&context->sequence_mutex);
 	free(dependencies);
+	free(sem_dependencies);
 	return r;
 }
 
@@ -356,6 +426,10 @@
 		return -EINVAL;
 	if (fence->ring >= AMDGPU_CS_MAX_RINGS)
 		return -EINVAL;
+	if (fence->fence == AMDGPU_NULL_SUBMIT_SEQ) {
+		*expired = true;
+		return 0;
+	}
 
 	*expired = false;
 
@@ -369,3 +443,102 @@
 	return r;
 }
 
+int amdgpu_cs_create_semaphore(amdgpu_semaphore_handle *sem)
+{
+	struct amdgpu_semaphore *gpu_semaphore;
+
+	if (NULL == sem)
+		return -EINVAL;
+
+	gpu_semaphore = calloc(1, sizeof(struct amdgpu_semaphore));
+	if (NULL == gpu_semaphore)
+		return -ENOMEM;
+
+	atomic_set(&gpu_semaphore->refcount, 1);
+	*sem = gpu_semaphore;
+
+	return 0;
+}
+
+int amdgpu_cs_signal_semaphore(amdgpu_context_handle ctx,
+			       uint32_t ip_type,
+			       uint32_t ip_instance,
+			       uint32_t ring,
+			       amdgpu_semaphore_handle sem)
+{
+	if (NULL == ctx)
+		return -EINVAL;
+	if (ip_type >= AMDGPU_HW_IP_NUM)
+		return -EINVAL;
+	if (ring >= AMDGPU_CS_MAX_RINGS)
+		return -EINVAL;
+	if (NULL == sem)
+		return -EINVAL;
+	/* sem has been signaled */
+	if (sem->signal_fence.context)
+		return -EINVAL;
+	pthread_mutex_lock(&ctx->sequence_mutex);
+	sem->signal_fence.context = ctx;
+	sem->signal_fence.ip_type = ip_type;
+	sem->signal_fence.ip_instance = ip_instance;
+	sem->signal_fence.ring = ring;
+	sem->signal_fence.fence = ctx->last_seq[ip_type][ip_instance][ring];
+	update_references(NULL, &sem->refcount);
+	pthread_mutex_unlock(&ctx->sequence_mutex);
+	return 0;
+}
+
+int amdgpu_cs_wait_semaphore(amdgpu_context_handle ctx,
+			     uint32_t ip_type,
+			     uint32_t ip_instance,
+			     uint32_t ring,
+			     amdgpu_semaphore_handle sem)
+{
+	if (NULL == ctx)
+		return -EINVAL;
+	if (ip_type >= AMDGPU_HW_IP_NUM)
+		return -EINVAL;
+	if (ring >= AMDGPU_CS_MAX_RINGS)
+		return -EINVAL;
+	if (NULL == sem)
+		return -EINVAL;
+	/* must signal first */
+	if (NULL == sem->signal_fence.context)
+		return -EINVAL;
+
+	pthread_mutex_lock(&ctx->sequence_mutex);
+	list_add(&sem->list, &ctx->sem_list[ip_type][ip_instance][ring]);
+	pthread_mutex_unlock(&ctx->sequence_mutex);
+	return 0;
+}
+
+static int amdgpu_cs_reset_sem(amdgpu_semaphore_handle sem)
+{
+	if (NULL == sem)
+		return -EINVAL;
+	if (NULL == sem->signal_fence.context)
+		return -EINVAL;
+
+	sem->signal_fence.context = NULL;;
+	sem->signal_fence.ip_type = 0;
+	sem->signal_fence.ip_instance = 0;
+	sem->signal_fence.ring = 0;
+	sem->signal_fence.fence = 0;
+
+	return 0;
+}
+
+static int amdgpu_cs_unreference_sem(amdgpu_semaphore_handle sem)
+{
+	if (NULL == sem)
+		return -EINVAL;
+
+	if (update_references(&sem->refcount, NULL))
+		free(sem);
+	return 0;
+}
+
+int amdgpu_cs_destroy_semaphore(amdgpu_semaphore_handle sem)
+{
+	return amdgpu_cs_unreference_sem(sem);
+}
diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c
index e5a923e..f4ede03 100644
--- a/amdgpu/amdgpu_device.c
+++ b/amdgpu/amdgpu_device.c
@@ -44,6 +44,7 @@
 #include "amdgpu_internal.h"
 #include "util_hash_table.h"
 #include "util_math.h"
+#include "amdgpu_asic_id.h"
 
 #define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
 #define UINT_TO_PTR(x) ((void *)((intptr_t)(x)))
@@ -303,3 +304,17 @@
 	amdgpu_device_reference(&dev, NULL);
 	return 0;
 }
+
+const char *amdgpu_get_marketing_name(amdgpu_device_handle dev)
+{
+	const struct amdgpu_asic_id_table_t *t = amdgpu_asic_id_table;
+
+	while (t->did) {
+		if ((t->did == dev->info.asic_id) &&
+		    (t->rid == dev->info.pci_rev_id))
+			return t->marketing_name;
+		t++;
+	}
+
+	return NULL;
+}
diff --git a/amdgpu/amdgpu_gpu_info.c b/amdgpu/amdgpu_gpu_info.c
index 0cc17f1..66c7e0e 100644
--- a/amdgpu/amdgpu_gpu_info.c
+++ b/amdgpu/amdgpu_gpu_info.c
@@ -119,7 +119,7 @@
 				  uint32_t *version, uint32_t *feature)
 {
 	struct drm_amdgpu_info request;
-	struct drm_amdgpu_info_firmware firmware;
+	struct drm_amdgpu_info_firmware firmware = {};
 	int r;
 
 	memset(&request, 0, sizeof(request));
@@ -187,10 +187,12 @@
 		if (r)
 			return r;
 
-		r = amdgpu_read_mm_registers(dev, 0xa0d5, 1, instance, 0,
+		if (dev->info.family_id >= AMDGPU_FAMILY_CI) {
+			r = amdgpu_read_mm_registers(dev, 0xa0d5, 1, instance, 0,
 					     &dev->info.pa_sc_raster_cfg1[i]);
-		if (r)
-			return r;
+			if (r)
+				return r;
+		}
 	}
 
 	r = amdgpu_read_mm_registers(dev, 0x2644, 32, 0xffffffff, 0,
@@ -198,10 +200,12 @@
 	if (r)
 		return r;
 
-	r = amdgpu_read_mm_registers(dev, 0x2664, 16, 0xffffffff, 0,
-				     dev->info.gb_macro_tile_mode);
-	if (r)
-		return r;
+	if (dev->info.family_id >= AMDGPU_FAMILY_CI) {
+		r = amdgpu_read_mm_registers(dev, 0x2664, 16, 0xffffffff, 0,
+					     dev->info.gb_macro_tile_mode);
+		if (r)
+			return r;
+	}
 
 	r = amdgpu_read_mm_registers(dev, 0x263e, 1, 0xffffffff, 0,
 				     &dev->info.gb_addr_cfg);
@@ -226,6 +230,8 @@
 int amdgpu_query_gpu_info(amdgpu_device_handle dev,
 			struct amdgpu_gpu_info *info)
 {
+	if ((dev == NULL) || (info == NULL))
+		return -EINVAL;
 	/* Get ASIC info*/
 	*info = dev->info;
 
diff --git a/amdgpu/amdgpu_internal.h b/amdgpu/amdgpu_internal.h
index 7dd5c1c..4f039b6 100644
--- a/amdgpu/amdgpu_internal.h
+++ b/amdgpu/amdgpu_internal.h
@@ -44,6 +44,7 @@
 #define ROUND_DOWN(x, y) ((x) & ~__round_mask(x, y))
 
 #define AMDGPU_INVALID_VA_ADDRESS	0xffffffffffffffff
+#define AMDGPU_NULL_SUBMIT_SEQ		0
 
 struct amdgpu_bo_va_hole {
 	struct list_head list;
@@ -111,8 +112,23 @@
 
 struct amdgpu_context {
 	struct amdgpu_device *dev;
+	/** Mutex for accessing fences and to maintain command submissions
+	    in good sequence. */
+	pthread_mutex_t sequence_mutex;
 	/* context id*/
 	uint32_t id;
+	uint64_t last_seq[AMDGPU_HW_IP_NUM][AMDGPU_HW_IP_INSTANCE_MAX_COUNT][AMDGPU_CS_MAX_RINGS];
+	struct list_head sem_list[AMDGPU_HW_IP_NUM][AMDGPU_HW_IP_INSTANCE_MAX_COUNT][AMDGPU_CS_MAX_RINGS];
+};
+
+/**
+ * Structure describing sw semaphore based on scheduler
+ *
+ */
+struct amdgpu_semaphore {
+	atomic_t refcount;
+	struct list_head list;
+	struct amdgpu_cs_fence signal_fence;
 };
 
 /**
diff --git a/amdgpu/libdrm_amdgpu.pc.in b/amdgpu/libdrm_amdgpu.pc.in
index 417865e..f1c552a 100644
--- a/amdgpu/libdrm_amdgpu.pc.in
+++ b/amdgpu/libdrm_amdgpu.pc.in
@@ -8,3 +8,4 @@
 Version: @PACKAGE_VERSION@
 Libs: -L${libdir} -ldrm_amdgpu
 Cflags: -I${includedir} -I${includedir}/libdrm
+Requires.private: libdrm
diff --git a/autogen.sh b/autogen.sh
index c896097..d82ab18 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -9,6 +9,12 @@
 autoreconf --force --verbose --install || exit 1
 cd "$ORIGDIR" || exit $?
 
+git config --local --get format.subjectPrefix ||
+    git config --local format.subjectPrefix "PATCH libdrm" 2>/dev/null
+
+git config --local --get sendemail.to ||
+    git config --local sendemail.to "dri-devel@lists.freedesktop.org" 2>/dev/null
+
 if test -z "$NOCONFIGURE"; then
     "$srcdir"/configure "$@"
 fi
diff --git a/configure.ac b/configure.ac
index f729fd8..1da9d86 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@
 
 AC_PREREQ([2.63])
 AC_INIT([libdrm],
-        [2.4.66],
+        [2.4.75],
         [https://bugs.freedesktop.org/enter_bug.cgi?product=DRI],
         [libdrm])
 
@@ -53,14 +53,15 @@
 AC_SYS_LARGEFILE
 AC_FUNC_ALLOCA
 
-AC_CHECK_HEADERS([sys/mkdev.h sys/sysctl.h])
+AC_HEADER_MAJOR
+AC_CHECK_HEADERS([sys/sysctl.h sys/select.h])
 
 # Initialize libtool
 LT_PREREQ([2.2])
 LT_INIT([disable-static])
 
 
-PKG_CHECK_MODULES(PTHREADSTUBS, pthread-stubs)
+
 AC_SUBST(PTHREADSTUBS_CFLAGS)
 AC_SUBST(PTHREADSTUBS_LIBS)
 
@@ -131,6 +132,16 @@
 	      [Enable support for rockchip's experimental API (default: disabled)]),
 	      [ROCKCHIP=$enableval], [ROCKCHIP=no])
 
+AC_ARG_ENABLE(vc4,
+	      AS_HELP_STRING([--disable-vc4],
+	      [Enable support for vc4's API (default: auto, enabled on arm)]),
+	      [VC4=$enableval], [VC4=auto])
+
+AC_ARG_ENABLE(etnaviv-experimental-api,
+	      AS_HELP_STRING([--enable-etnaviv-experimental-api],
+	      [Enable support for etnaviv's experimental API (default: disabled)]),
+	      [ETNAVIV=$enableval], [ETNAVIV=no])
+
 AC_ARG_ENABLE(install-test-programs,
 		  AS_HELP_STRING([--enable-install-test-programs],
 		  [Install test programs (default: no)]),
@@ -179,7 +190,8 @@
 -Wstrict-aliasing=2 -Winit-self \
 -Wdeclaration-after-statement -Wold-style-definition \
 -Wno-unused-parameter \
--Wno-attributes -Wno-long-long -Winline -Wshadow"
+-Wno-attributes -Wno-long-long -Winline -Wshadow \
+-Wno-missing-field-initializers"
 
 # invalidate cached value if MAYBE_WARN has changed
 if test "x$libdrm_cv_warn_maybe" != "x$MAYBE_WARN"; then
@@ -272,6 +284,9 @@
 
 	LIBDRM_ATOMICS_NOT_FOUND_MSG($TEGRA, tegra, NVIDIA Tegra, tegra-experimental-api)
 	TEGRA=no
+
+	LIBDRM_ATOMICS_NOT_FOUND_MSG($ETNAVIV, etnaviv, Vivante, etnaviv-experimental-api)
+	ETNAVIV=no
 else
 	if test "x$INTEL" = xauto; then
 		case $host_cpu in
@@ -294,6 +309,12 @@
 			*)		FREEDRENO=no ;;
 		esac
 	fi
+	if test "x$VC4" = xauto; then
+		case $host_cpu in
+			arm*|aarch64)	VC4=yes ;;
+			*)		VC4=no ;;
+		esac
+	fi
 fi
 
 if test "x$INTEL" != "xno"; then
@@ -364,19 +385,23 @@
 	AC_DEFINE(HAVE_RADEON, 1, [Have radeon support])
 fi
 
-# Detect cunit library
-PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
-# If pkg-config does not find cunit, check it using AC_CHECK_LIB.  We
-# do this because Debian (Ubuntu) lacks pkg-config file for cunit.
-# fixed in 2.1-2.dfsg-3: http://anonscm.debian.org/cgit/collab-maint/cunit.git/commit/?h=debian
-if test "x${have_cunit}" = "xno"; then
-	AC_CHECK_LIB([cunit], [CU_initialize_registry], [have_cunit=yes], [have_cunit=no])
-	if test "x${have_cunit}" = "xyes"; then
-		CUNIT_LIBS="-lcunit"
-		CUNIT_CFLAGS=""
-		AC_SUBST([CUNIT_LIBS])
-		AC_SUBST([CUNIT_CFLAGS])
+if test "x$AMDGPU" != xno; then
+	# Detect cunit library
+	PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
+	# If pkg-config does not find cunit, check it using AC_CHECK_LIB.  We
+	# do this because Debian (Ubuntu) lacks pkg-config file for cunit.
+	# fixed in 2.1-2.dfsg-3: http://anonscm.debian.org/cgit/collab-maint/cunit.git/commit/?h=debian
+	if test "x${have_cunit}" = "xno"; then
+		AC_CHECK_LIB([cunit], [CU_initialize_registry], [have_cunit=yes], [have_cunit=no])
+		if test "x${have_cunit}" = "xyes"; then
+			CUNIT_LIBS="-lcunit"
+			CUNIT_CFLAGS=""
+			AC_SUBST([CUNIT_LIBS])
+			AC_SUBST([CUNIT_CFLAGS])
+		fi
 	fi
+else
+	have_cunit=no
 fi
 AM_CONDITIONAL(HAVE_CUNIT, [test "x$have_cunit" != "xno"])
 
@@ -399,6 +424,15 @@
 AM_CONDITIONAL(HAVE_ROCKCHIP, [test "x$ROCKCHIP" = xyes])
 if test "x$ROCKCHIP" = xyes; then
 	AC_DEFINE(HAVE_ROCKCHIP, 1, [Have ROCKCHIP support])
+
+AM_CONDITIONAL(HAVE_VC4, [test "x$VC4" = xyes])
+if test "x$VC4" = xyes; then
+	AC_DEFINE(HAVE_VC4, 1, [Have VC4 support])
+fi
+
+AM_CONDITIONAL(HAVE_ETNAVIV, [test "x$ETNAVIV" = xyes])
+if test "x$ETNAVIV" = xyes; then
+	AC_DEFINE(HAVE_ETNAVIV, 1, [Have etnaviv support])
 fi
 
 AM_CONDITIONAL(HAVE_INSTALL_TESTS, [test "x$INSTALL_TESTS" = xyes])
@@ -410,7 +444,9 @@
               [AS_HELP_STRING([--enable-cairo-tests],
                               [Enable support for Cairo rendering in tests (default: auto)])],
               [CAIRO=$enableval], [CAIRO=auto])
-PKG_CHECK_MODULES(CAIRO, cairo, [HAVE_CAIRO=yes], [HAVE_CAIRO=no])
+if test "x$CAIRO" != xno; then
+	PKG_CHECK_MODULES(CAIRO, cairo, [HAVE_CAIRO=yes], [HAVE_CAIRO=no])
+fi
 AC_MSG_CHECKING([whether to enable Cairo tests])
 if test "x$CAIRO" = xauto; then
 	CAIRO="$HAVE_CAIRO"
@@ -424,13 +460,6 @@
 AC_MSG_RESULT([$CAIRO])
 AM_CONDITIONAL(HAVE_CAIRO, [test "x$CAIRO" = xyes])
 
-# For enumerating devices in test case
-PKG_CHECK_MODULES(LIBUDEV, libudev, [HAVE_LIBUDEV=yes], [HAVE_LIBUDEV=no])
-if test "x$HAVE_LIBUDEV" = xyes; then
-   	AC_DEFINE(HAVE_LIBUDEV, 1, [Have libudev support])
-fi
-AM_CONDITIONAL(HAVE_LIBUDEV, [test "x$HAVE_LIBUDEV" = xyes])
-
 # xsltproc for docbook manpages
 AC_ARG_ENABLE([manpages],
               AS_HELP_STRING([--enable-manpages], [enable manpages @<:@default=auto@:>@]),
@@ -455,7 +484,9 @@
               [AS_HELP_STRING([--enable-valgrind],
                              [Build libdrm with  valgrind support (default: auto)])],
                              [VALGRIND=$enableval], [VALGRIND=auto])
-PKG_CHECK_MODULES(VALGRIND, [valgrind], [have_valgrind=yes], [have_valgrind=no])
+if test "x$VALGRIND" != xno; then
+	PKG_CHECK_MODULES(VALGRIND, [valgrind], [have_valgrind=yes], [have_valgrind=no])
+fi
 AC_MSG_CHECKING([whether to enable Valgrind support])
 if test "x$VALGRIND" = xauto; then
 	VALGRIND="$have_valgrind"
@@ -508,6 +539,10 @@
 	tegra/libdrm_tegra.pc
 	rockchip/Makefile
 	rockchip/libdrm_rockchip.pc
+	vc4/Makefile
+	vc4/libdrm_vc4.pc
+	etnaviv/Makefile
+	etnaviv/libdrm_etnaviv.pc
 	tests/Makefile
 	tests/modeprint/Makefile
 	tests/modetest/Makefile
@@ -521,6 +556,7 @@
 	tests/tegra/Makefile
 	tests/nouveau/Makefile
 	tests/planetest/Makefile
+	tests/etnaviv/Makefile
 	tests/util/Makefile
 	man/Makefile
 	libdrm.pc])
@@ -540,4 +576,6 @@
 echo "  Freedreno API  $FREEDRENO (kgsl: $FREEDRENO_KGSL)"
 echo "  Tegra API      $TEGRA"
 echo "  Rockchip API   $ROCKCHIP"
+echo "  VC4 API        $VC4"
+echo "  Etnaviv API    $ETNAVIV"
 echo ""
diff --git a/etnaviv/Android.mk b/etnaviv/Android.mk
new file mode 100644
index 0000000..390f9a9
--- /dev/null
+++ b/etnaviv/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_ETNAVIV_FILES, LIBDRM_ETNAVIV_H_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_MODULE := libdrm_etnaviv
+
+LOCAL_SHARED_LIBRARIES := libdrm
+
+LOCAL_SRC_FILES := $(LIBDRM_ETNAVIV_FILES)
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)
diff --git a/etnaviv/Makefile.am b/etnaviv/Makefile.am
new file mode 100644
index 0000000..be96ba8
--- /dev/null
+++ b/etnaviv/Makefile.am
@@ -0,0 +1,26 @@
+include Makefile.sources
+
+AM_CFLAGS = \
+	$(WARN_CFLAGS) \
+	-I$(top_srcdir) \
+	$(PTHREADSTUBS_CFLAGS) \
+	-I$(top_srcdir)/include/drm
+
+libdrm_etnaviv_ladir = $(libdir)
+libdrm_etnaviv_la_LTLIBRARIES = libdrm_etnaviv.la
+libdrm_etnaviv_la_LDFLAGS = -version-number 1:0:0 -no-undefined
+libdrm_etnaviv_la_LIBADD = \
+	../libdrm.la \
+	@PTHREADSTUBS_LIBS@ \
+	@CLOCK_LIB@
+
+libdrm_etnaviv_la_SOURCES = $(LIBDRM_ETNAVIV_FILES)
+
+libdrm_etnavivincludedir = ${includedir}/libdrm
+libdrm_etnavivinclude_HEADERS = $(LIBDRM_ETNAVIV_H_FILES)
+
+pkgconfigdir = @pkgconfigdir@
+pkgconfig_DATA = libdrm_etnaviv.pc
+
+TESTS = etnaviv-symbol-check
+EXTRA_DIST = $(TESTS)
diff --git a/etnaviv/Makefile.sources b/etnaviv/Makefile.sources
new file mode 100644
index 0000000..5258056
--- /dev/null
+++ b/etnaviv/Makefile.sources
@@ -0,0 +1,12 @@
+LIBDRM_ETNAVIV_FILES := \
+	etnaviv_device.c \
+	etnaviv_gpu.c \
+	etnaviv_bo.c \
+	etnaviv_bo_cache.c \
+	etnaviv_pipe.c \
+	etnaviv_cmd_stream.c \
+	etnaviv_drm.h \
+	etnaviv_priv.h
+
+LIBDRM_ETNAVIV_H_FILES := \
+	etnaviv_drmif.h
diff --git a/etnaviv/etnaviv-symbol-check b/etnaviv/etnaviv-symbol-check
new file mode 100755
index 0000000..22afd16
--- /dev/null
+++ b/etnaviv/etnaviv-symbol-check
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# The following symbols (past the first five) are taken from the public headers.
+# A list of the latter should be available Makefile.sources/LIBDRM_ETNAVIV_H_FILES
+
+FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_etnaviv.so} | awk '{print $3}'| while read func; do
+( grep -q "^$func$" || echo $func )  <<EOF
+__bss_start
+_edata
+_end
+_fini
+_init
+etna_device_new
+etna_device_new_dup
+etna_device_ref
+etna_device_del
+etna_device_fd
+etna_gpu_new
+etna_gpu_del
+etna_gpu_get_param
+etna_pipe_new
+etna_pipe_del
+etna_pipe_wait
+etna_pipe_wait_ns
+etna_bo_new
+etna_bo_from_handle
+etna_bo_from_name
+etna_bo_from_dmabuf
+etna_bo_ref
+etna_bo_del
+etna_bo_get_name
+etna_bo_handle
+etna_bo_dmabuf
+etna_bo_size
+etna_bo_map
+etna_bo_cpu_prep
+etna_bo_cpu_fini
+etna_cmd_stream_new
+etna_cmd_stream_del
+etna_cmd_stream_timestamp
+etna_cmd_stream_flush
+etna_cmd_stream_finish
+etna_cmd_stream_reloc
+EOF
+done)
+
+test ! -n "$FUNCS" || echo $FUNCS
+test ! -n "$FUNCS"
diff --git a/etnaviv/etnaviv_bo.c b/etnaviv/etnaviv_bo.c
new file mode 100644
index 0000000..4ad0434
--- /dev/null
+++ b/etnaviv/etnaviv_bo.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2014 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "etnaviv_priv.h"
+#include "etnaviv_drmif.h"
+
+drm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
+drm_private void bo_del(struct etna_bo *bo);
+
+/* set buffer name, and add to table, call w/ table_lock held: */
+static void set_name(struct etna_bo *bo, uint32_t name)
+{
+	bo->name = name;
+	/* add ourself into the name table: */
+	drmHashInsert(bo->dev->name_table, name, bo);
+}
+
+/* Called under table_lock */
+drm_private void bo_del(struct etna_bo *bo)
+{
+	if (bo->map)
+		drm_munmap(bo->map, bo->size);
+
+	if (bo->name)
+		drmHashDelete(bo->dev->name_table, bo->name);
+
+	if (bo->handle) {
+		struct drm_gem_close req = {
+			.handle = bo->handle,
+		};
+
+		drmHashDelete(bo->dev->handle_table, bo->handle);
+		drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
+	}
+
+	free(bo);
+}
+
+/* lookup a buffer from it's handle, call w/ table_lock held: */
+static struct etna_bo *lookup_bo(void *tbl, uint32_t handle)
+{
+	struct etna_bo *bo = NULL;
+
+	if (!drmHashLookup(tbl, handle, (void **)&bo)) {
+		/* found, incr refcnt and return: */
+		bo = etna_bo_ref(bo);
+
+		/* don't break the bucket if this bo was found in one */
+		list_delinit(&bo->list);
+	}
+
+	return bo;
+}
+
+/* allocate a new buffer object, call w/ table_lock held */
+static struct etna_bo *bo_from_handle(struct etna_device *dev,
+		uint32_t size, uint32_t handle, uint32_t flags)
+{
+	struct etna_bo *bo = calloc(sizeof(*bo), 1);
+
+	if (!bo) {
+		struct drm_gem_close req = {
+			.handle = handle,
+		};
+
+		drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
+
+		return NULL;
+	}
+
+	bo->dev = etna_device_ref(dev);
+	bo->size = size;
+	bo->handle = handle;
+	bo->flags = flags;
+	atomic_set(&bo->refcnt, 1);
+	list_inithead(&bo->list);
+	/* add ourselves to the handle table: */
+	drmHashInsert(dev->handle_table, handle, bo);
+
+	return bo;
+}
+
+/* allocate a new (un-tiled) buffer object */
+struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size,
+		uint32_t flags)
+{
+	struct etna_bo *bo;
+	int ret;
+	struct drm_etnaviv_gem_new req = {
+			.flags = flags,
+	};
+
+	bo = etna_bo_cache_alloc(&dev->bo_cache, &size, flags);
+	if (bo)
+		return bo;
+
+	req.size = size;
+	ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GEM_NEW,
+			&req, sizeof(req));
+	if (ret)
+		return NULL;
+
+	pthread_mutex_lock(&table_lock);
+	bo = bo_from_handle(dev, size, req.handle, flags);
+	bo->reuse = 1;
+	pthread_mutex_unlock(&table_lock);
+
+	return bo;
+}
+
+struct etna_bo *etna_bo_ref(struct etna_bo *bo)
+{
+	atomic_inc(&bo->refcnt);
+
+	return bo;
+}
+
+/* get buffer info */
+static int get_buffer_info(struct etna_bo *bo)
+{
+	int ret;
+	struct drm_etnaviv_gem_info req = {
+		.handle = bo->handle,
+	};
+
+	ret = drmCommandWriteRead(bo->dev->fd, DRM_ETNAVIV_GEM_INFO,
+			&req, sizeof(req));
+	if (ret) {
+		return ret;
+	}
+
+	/* really all we need for now is mmap offset */
+	bo->offset = req.offset;
+
+	return 0;
+}
+
+/* import a buffer object from DRI2 name */
+struct etna_bo *etna_bo_from_name(struct etna_device *dev, uint32_t name)
+{
+	struct etna_bo *bo;
+	struct drm_gem_open req = {
+		.name = name,
+	};
+
+	pthread_mutex_lock(&table_lock);
+
+	/* check name table first, to see if bo is already open: */
+	bo = lookup_bo(dev->name_table, req.handle);
+	if (bo)
+		goto out_unlock;
+
+	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
+		ERROR_MSG("gem-open failed: %s", strerror(errno));
+		goto out_unlock;
+	}
+
+	bo = lookup_bo(dev->handle_table, req.handle);
+	if (bo)
+		goto out_unlock;
+
+	bo = bo_from_handle(dev, req.size, req.handle, 0);
+	if (bo)
+		set_name(bo, name);
+
+out_unlock:
+	pthread_mutex_unlock(&table_lock);
+
+	return bo;
+}
+
+/* import a buffer from dmabuf fd, does not take ownership of the
+ * fd so caller should close() the fd when it is otherwise done
+ * with it (even if it is still using the 'struct etna_bo *')
+ */
+struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd)
+{
+	struct etna_bo *bo;
+	int ret, size;
+	uint32_t handle;
+
+	pthread_mutex_lock(&table_lock);
+
+	ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
+	if (ret) {
+		return NULL;
+	}
+
+	bo = lookup_bo(dev->handle_table, handle);
+	if (bo)
+		goto out_unlock;
+
+	/* lseek() to get bo size */
+	size = lseek(fd, 0, SEEK_END);
+	lseek(fd, 0, SEEK_CUR);
+
+	bo = bo_from_handle(dev, size, handle, 0);
+
+out_unlock:
+	pthread_mutex_unlock(&table_lock);
+
+	return bo;
+}
+
+/* destroy a buffer object */
+void etna_bo_del(struct etna_bo *bo)
+{
+	struct etna_device *dev = bo->dev;
+
+	if (!bo)
+		return;
+
+	if (!atomic_dec_and_test(&bo->refcnt))
+		return;
+
+	pthread_mutex_lock(&table_lock);
+
+	if (bo->reuse && (etna_bo_cache_free(&dev->bo_cache, bo) == 0))
+		goto out;
+
+	bo_del(bo);
+	etna_device_del_locked(dev);
+out:
+	pthread_mutex_unlock(&table_lock);
+}
+
+/* get the global flink/DRI2 buffer name */
+int etna_bo_get_name(struct etna_bo *bo, uint32_t *name)
+{
+	if (!bo->name) {
+		struct drm_gem_flink req = {
+			.handle = bo->handle,
+		};
+		int ret;
+
+		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
+		if (ret) {
+			return ret;
+		}
+
+		pthread_mutex_lock(&table_lock);
+		set_name(bo, req.name);
+		pthread_mutex_unlock(&table_lock);
+		bo->reuse = 0;
+	}
+
+	*name = bo->name;
+
+	return 0;
+}
+
+uint32_t etna_bo_handle(struct etna_bo *bo)
+{
+	return bo->handle;
+}
+
+/* caller owns the dmabuf fd that is returned and is responsible
+ * to close() it when done
+ */
+int etna_bo_dmabuf(struct etna_bo *bo)
+{
+	int ret, prime_fd;
+
+	ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
+				&prime_fd);
+	if (ret) {
+		ERROR_MSG("failed to get dmabuf fd: %d", ret);
+		return ret;
+	}
+
+	bo->reuse = 0;
+
+	return prime_fd;
+}
+
+uint32_t etna_bo_size(struct etna_bo *bo)
+{
+	return bo->size;
+}
+
+void *etna_bo_map(struct etna_bo *bo)
+{
+	if (!bo->map) {
+		if (!bo->offset) {
+			get_buffer_info(bo);
+		}
+
+		bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
+				MAP_SHARED, bo->dev->fd, bo->offset);
+		if (bo->map == MAP_FAILED) {
+			ERROR_MSG("mmap failed: %s", strerror(errno));
+			bo->map = NULL;
+		}
+	}
+
+	return bo->map;
+}
+
+int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op)
+{
+	struct drm_etnaviv_gem_cpu_prep req = {
+		.handle = bo->handle,
+		.op = op,
+	};
+
+	get_abs_timeout(&req.timeout, 5000000000);
+
+	return drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_PREP,
+			&req, sizeof(req));
+}
+
+void etna_bo_cpu_fini(struct etna_bo *bo)
+{
+	struct drm_etnaviv_gem_cpu_fini req = {
+		.handle = bo->handle,
+	};
+
+	drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_FINI,
+			&req, sizeof(req));
+}
diff --git a/etnaviv/etnaviv_bo_cache.c b/etnaviv/etnaviv_bo_cache.c
new file mode 100644
index 0000000..8924651
--- /dev/null
+++ b/etnaviv/etnaviv_bo_cache.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "etnaviv_priv.h"
+#include "etnaviv_drmif.h"
+
+drm_private void bo_del(struct etna_bo *bo);
+drm_private extern pthread_mutex_t table_lock;
+
+static void add_bucket(struct etna_bo_cache *cache, int size)
+{
+	unsigned i = cache->num_buckets;
+
+	assert(i < ARRAY_SIZE(cache->cache_bucket));
+
+	list_inithead(&cache->cache_bucket[i].list);
+	cache->cache_bucket[i].size = size;
+	cache->num_buckets++;
+}
+
+drm_private void etna_bo_cache_init(struct etna_bo_cache *cache)
+{
+	unsigned long size, cache_max_size = 64 * 1024 * 1024;
+
+	/* OK, so power of two buckets was too wasteful of memory.
+	 * Give 3 other sizes between each power of two, to hopefully
+	 * cover things accurately enough.  (The alternative is
+	 * probably to just go for exact matching of sizes, and assume
+	 * that for things like composited window resize the tiled
+	 * width/height alignment and rounding of sizes to pages will
+	 * get us useful cache hit rates anyway)
+	 */
+	add_bucket(cache, 4096);
+	add_bucket(cache, 4096 * 2);
+	add_bucket(cache, 4096 * 3);
+
+	/* Initialize the linked lists for BO reuse cache. */
+	for (size = 4 * 4096; size <= cache_max_size; size *= 2) {
+		add_bucket(cache, size);
+		add_bucket(cache, size + size * 1 / 4);
+		add_bucket(cache, size + size * 2 / 4);
+		add_bucket(cache, size + size * 3 / 4);
+	}
+}
+
+/* Frees older cached buffers.  Called under table_lock */
+drm_private void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time)
+{
+	unsigned i;
+
+	if (cache->time == time)
+		return;
+
+	for (i = 0; i < cache->num_buckets; i++) {
+		struct etna_bo_bucket *bucket = &cache->cache_bucket[i];
+		struct etna_bo *bo;
+
+		while (!LIST_IS_EMPTY(&bucket->list)) {
+			bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list);
+
+			/* keep things in cache for at least 1 second: */
+			if (time && ((time - bo->free_time) <= 1))
+				break;
+
+			list_del(&bo->list);
+			bo_del(bo);
+		}
+	}
+
+	cache->time = time;
+}
+
+static struct etna_bo_bucket *get_bucket(struct etna_bo_cache *cache, uint32_t size)
+{
+	unsigned i;
+
+	/* hmm, this is what intel does, but I suppose we could calculate our
+	 * way to the correct bucket size rather than looping..
+	 */
+	for (i = 0; i < cache->num_buckets; i++) {
+		struct etna_bo_bucket *bucket = &cache->cache_bucket[i];
+		if (bucket->size >= size) {
+			return bucket;
+		}
+	}
+
+	return NULL;
+}
+
+static int is_idle(struct etna_bo *bo)
+{
+	return etna_bo_cpu_prep(bo,
+			DRM_ETNA_PREP_READ |
+			DRM_ETNA_PREP_WRITE |
+			DRM_ETNA_PREP_NOSYNC) == 0;
+}
+
+static struct etna_bo *find_in_bucket(struct etna_bo_bucket *bucket, uint32_t flags)
+{
+	struct etna_bo *bo = NULL;
+
+	pthread_mutex_lock(&table_lock);
+	while (!LIST_IS_EMPTY(&bucket->list)) {
+		bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list);
+
+		if (bo->flags == flags && is_idle(bo)) {
+			list_del(&bo->list);
+			break;
+		}
+
+		bo = NULL;
+		break;
+	}
+	pthread_mutex_unlock(&table_lock);
+
+	return bo;
+}
+
+/* allocate a new (un-tiled) buffer object
+ *
+ * NOTE: size is potentially rounded up to bucket size
+ */
+drm_private struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache, uint32_t *size,
+    uint32_t flags)
+{
+	struct etna_bo *bo;
+	struct etna_bo_bucket *bucket;
+
+	*size = ALIGN(*size, 4096);
+	bucket = get_bucket(cache, *size);
+
+	/* see if we can be green and recycle: */
+	if (bucket) {
+		*size = bucket->size;
+		bo = find_in_bucket(bucket, flags);
+		if (bo) {
+			atomic_set(&bo->refcnt, 1);
+			etna_device_ref(bo->dev);
+			return bo;
+		}
+	}
+
+	return NULL;
+}
+
+drm_private int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo)
+{
+	struct etna_bo_bucket *bucket = get_bucket(cache, bo->size);
+
+	/* see if we can be green and recycle: */
+	if (bucket) {
+		struct timespec time;
+
+		clock_gettime(CLOCK_MONOTONIC, &time);
+
+		bo->free_time = time.tv_sec;
+		list_addtail(&bo->list, &bucket->list);
+		etna_bo_cache_cleanup(cache, time.tv_sec);
+
+		/* bo's in the bucket cache don't have a ref and
+		 * don't hold a ref to the dev:
+		 */
+		etna_device_del_locked(bo->dev);
+
+		return 0;
+	}
+
+	return -1;
+}
diff --git a/etnaviv/etnaviv_cmd_stream.c b/etnaviv/etnaviv_cmd_stream.c
new file mode 100644
index 0000000..9ce3f36
--- /dev/null
+++ b/etnaviv/etnaviv_cmd_stream.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014-2015 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "etnaviv_drmif.h"
+#include "etnaviv_priv.h"
+
+static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz)
+{
+	if ((nr + 1) > *max) {
+		if ((*max * 2) < (nr + 1))
+			*max = nr + 5;
+		else
+			*max = *max * 2;
+		ptr = realloc(ptr, *max * sz);
+	}
+
+	return ptr;
+}
+
+#define APPEND(x, name) ({ \
+	(x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \
+	(x)->nr_ ## name ++; \
+})
+
+static inline struct etna_cmd_stream_priv *
+etna_cmd_stream_priv(struct etna_cmd_stream *stream)
+{
+    return (struct etna_cmd_stream_priv *)stream;
+}
+
+struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, uint32_t size,
+		void (*reset_notify)(struct etna_cmd_stream *stream, void *priv),
+		void *priv)
+{
+	struct etna_cmd_stream_priv *stream = NULL;
+
+	if (size == 0) {
+		ERROR_MSG("invalid size of 0");
+		goto fail;
+	}
+
+	stream = calloc(1, sizeof(*stream));
+	if (!stream) {
+		ERROR_MSG("allocation failed");
+		goto fail;
+	}
+
+	/* allocate even number of 32-bit words */
+	size = ALIGN(size, 2);
+
+	stream->base.buffer = malloc(size * sizeof(uint32_t));
+	if (!stream->base.buffer) {
+		ERROR_MSG("allocation failed");
+		goto fail;
+	}
+
+	stream->base.size = size;
+	stream->pipe = pipe;
+	stream->reset_notify = reset_notify;
+	stream->reset_notify_priv = priv;
+
+	return &stream->base;
+
+fail:
+	if (stream)
+		etna_cmd_stream_del(&stream->base);
+
+	return NULL;
+}
+
+void etna_cmd_stream_del(struct etna_cmd_stream *stream)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+
+	free(stream->buffer);
+	free(priv->submit.relocs);
+	free(priv);
+}
+
+static void reset_buffer(struct etna_cmd_stream *stream)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+
+	stream->offset = 0;
+	priv->submit.nr_bos = 0;
+	priv->submit.nr_relocs = 0;
+	priv->nr_bos = 0;
+
+	if (priv->reset_notify)
+		priv->reset_notify(stream, priv->reset_notify_priv);
+}
+
+uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream)
+{
+	return etna_cmd_stream_priv(stream)->last_timestamp;
+}
+
+static uint32_t append_bo(struct etna_cmd_stream *stream, struct etna_bo *bo)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+	uint32_t idx;
+
+	idx = APPEND(&priv->submit, bos);
+	idx = APPEND(priv, bos);
+
+	priv->submit.bos[idx].flags = 0;
+	priv->submit.bos[idx].handle = bo->handle;
+
+	priv->bos[idx] = etna_bo_ref(bo);
+
+	return idx;
+}
+
+/* add (if needed) bo, return idx: */
+static uint32_t bo2idx(struct etna_cmd_stream *stream, struct etna_bo *bo,
+		uint32_t flags)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+	uint32_t idx;
+
+	pthread_mutex_lock(&idx_lock);
+
+	if (!bo->current_stream) {
+		idx = append_bo(stream, bo);
+		bo->current_stream = stream;
+		bo->idx = idx;
+	} else if (bo->current_stream == stream) {
+		idx = bo->idx;
+	} else {
+		/* slow-path: */
+		for (idx = 0; idx < priv->nr_bos; idx++)
+			if (priv->bos[idx] == bo)
+				break;
+		if (idx == priv->nr_bos) {
+			/* not found */
+			idx = append_bo(stream, bo);
+		}
+	}
+	pthread_mutex_unlock(&idx_lock);
+
+	if (flags & ETNA_RELOC_READ)
+		priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_READ;
+	if (flags & ETNA_RELOC_WRITE)
+		priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_WRITE;
+
+	return idx;
+}
+
+static void flush(struct etna_cmd_stream *stream)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+	int ret, id = priv->pipe->id;
+	struct etna_gpu *gpu = priv->pipe->gpu;
+
+	struct drm_etnaviv_gem_submit req = {
+		.pipe = gpu->core,
+		.exec_state = id,
+		.bos = VOID2U64(priv->submit.bos),
+		.nr_bos = priv->submit.nr_bos,
+		.relocs = VOID2U64(priv->submit.relocs),
+		.nr_relocs = priv->submit.nr_relocs,
+		.stream = VOID2U64(stream->buffer),
+		.stream_size = stream->offset * 4, /* in bytes */
+	};
+
+	ret = drmCommandWriteRead(gpu->dev->fd, DRM_ETNAVIV_GEM_SUBMIT,
+			&req, sizeof(req));
+
+	if (ret)
+		ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno));
+	else
+		priv->last_timestamp = req.fence;
+
+	for (uint32_t i = 0; i < priv->nr_bos; i++) {
+		struct etna_bo *bo = priv->bos[i];
+
+		bo->current_stream = NULL;
+		etna_bo_del(bo);
+	}
+}
+
+void etna_cmd_stream_flush(struct etna_cmd_stream *stream)
+{
+	flush(stream);
+	reset_buffer(stream);
+}
+
+void etna_cmd_stream_finish(struct etna_cmd_stream *stream)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+
+	flush(stream);
+	etna_pipe_wait(priv->pipe, priv->last_timestamp, 5000);
+	reset_buffer(stream);
+}
+
+void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, const struct etna_reloc *r)
+{
+	struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
+	struct drm_etnaviv_gem_submit_reloc *reloc;
+	uint32_t idx = APPEND(&priv->submit, relocs);
+	uint32_t addr = 0;
+
+	reloc = &priv->submit.relocs[idx];
+
+	reloc->reloc_idx = bo2idx(stream, r->bo, r->flags);
+	reloc->reloc_offset = r->offset;
+	reloc->submit_offset = stream->offset * 4; /* in bytes */
+	reloc->flags = 0;
+
+	etna_cmd_stream_emit(stream, addr);
+}
diff --git a/etnaviv/etnaviv_device.c b/etnaviv/etnaviv_device.c
new file mode 100644
index 0000000..3ce9203
--- /dev/null
+++ b/etnaviv/etnaviv_device.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <xf86drm.h>
+#include <xf86atomic.h>
+
+#include "etnaviv_priv.h"
+#include "etnaviv_drmif.h"
+
+static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct etna_device *etna_device_new(int fd)
+{
+	struct etna_device *dev = calloc(sizeof(*dev), 1);
+
+	if (!dev)
+		return NULL;
+
+	atomic_set(&dev->refcnt, 1);
+	dev->fd = fd;
+	dev->handle_table = drmHashCreate();
+	dev->name_table = drmHashCreate();
+	etna_bo_cache_init(&dev->bo_cache);
+
+	return dev;
+}
+
+/* like etna_device_new() but creates it's own private dup() of the fd
+ * which is close()d when the device is finalized. */
+struct etna_device *etna_device_new_dup(int fd)
+{
+	int dup_fd = dup(fd);
+	struct etna_device *dev = etna_device_new(dup_fd);
+
+	if (dev)
+		dev->closefd = 1;
+	else
+		close(dup_fd);
+
+	return dev;
+}
+
+struct etna_device *etna_device_ref(struct etna_device *dev)
+{
+	atomic_inc(&dev->refcnt);
+
+	return dev;
+}
+
+static void etna_device_del_impl(struct etna_device *dev)
+{
+	etna_bo_cache_cleanup(&dev->bo_cache, 0);
+	drmHashDestroy(dev->handle_table);
+	drmHashDestroy(dev->name_table);
+
+	if (dev->closefd)
+		close(dev->fd);
+
+	free(dev);
+}
+
+drm_private void etna_device_del_locked(struct etna_device *dev)
+{
+	if (!atomic_dec_and_test(&dev->refcnt))
+		return;
+
+	etna_device_del_impl(dev);
+}
+
+void etna_device_del(struct etna_device *dev)
+{
+	if (!atomic_dec_and_test(&dev->refcnt))
+		return;
+
+	pthread_mutex_lock(&table_lock);
+	etna_device_del_impl(dev);
+	pthread_mutex_unlock(&table_lock);
+}
+
+int etna_device_fd(struct etna_device *dev)
+{
+   return dev->fd;
+}
diff --git a/etnaviv/etnaviv_drm.h b/etnaviv/etnaviv_drm.h
new file mode 100644
index 0000000..2584c1c
--- /dev/null
+++ b/etnaviv/etnaviv_drm.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ETNAVIV_DRM_H__
+#define __ETNAVIV_DRM_H__
+
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Please note that modifications to all structs defined here are
+ * subject to backwards-compatibility constraints:
+ *  1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
+ *     user/kernel compatibility
+ *  2) Keep fields aligned to their size
+ *  3) Because of how drm_ioctl() works, we can add new fields at
+ *     the end of an ioctl if some care is taken: drm_ioctl() will
+ *     zero out the new fields at the tail of the ioctl, so a zero
+ *     value should have a backwards compatible meaning.  And for
+ *     output params, userspace won't see the newly added output
+ *     fields.. so that has to be somehow ok.
+ */
+
+/* timeouts are specified in clock-monotonic absolute times (to simplify
+ * restarting interrupted ioctls).  The following struct is logically the
+ * same as 'struct timespec' but 32/64b ABI safe.
+ */
+struct drm_etnaviv_timespec {
+	__s64 tv_sec;          /* seconds */
+	__s64 tv_nsec;         /* nanoseconds */
+};
+
+#define ETNAVIV_PARAM_GPU_MODEL                     0x01
+#define ETNAVIV_PARAM_GPU_REVISION                  0x02
+#define ETNAVIV_PARAM_GPU_FEATURES_0                0x03
+#define ETNAVIV_PARAM_GPU_FEATURES_1                0x04
+#define ETNAVIV_PARAM_GPU_FEATURES_2                0x05
+#define ETNAVIV_PARAM_GPU_FEATURES_3                0x06
+#define ETNAVIV_PARAM_GPU_FEATURES_4                0x07
+#define ETNAVIV_PARAM_GPU_FEATURES_5                0x08
+#define ETNAVIV_PARAM_GPU_FEATURES_6                0x09
+
+#define ETNAVIV_PARAM_GPU_STREAM_COUNT              0x10
+#define ETNAVIV_PARAM_GPU_REGISTER_MAX              0x11
+#define ETNAVIV_PARAM_GPU_THREAD_COUNT              0x12
+#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE         0x13
+#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT         0x14
+#define ETNAVIV_PARAM_GPU_PIXEL_PIPES               0x15
+#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16
+#define ETNAVIV_PARAM_GPU_BUFFER_SIZE               0x17
+#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT         0x18
+#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS             0x19
+#define ETNAVIV_PARAM_GPU_NUM_VARYINGS              0x1a
+
+#define ETNA_MAX_PIPES 4
+
+struct drm_etnaviv_param {
+	__u32 pipe;           /* in */
+	__u32 param;          /* in, ETNAVIV_PARAM_x */
+	__u64 value;          /* out (get_param) or in (set_param) */
+};
+
+/*
+ * GEM buffers:
+ */
+
+#define ETNA_BO_CACHE_MASK   0x000f0000
+/* cache modes */
+#define ETNA_BO_CACHED       0x00010000
+#define ETNA_BO_WC           0x00020000
+#define ETNA_BO_UNCACHED     0x00040000
+/* map flags */
+#define ETNA_BO_FORCE_MMU    0x00100000
+
+struct drm_etnaviv_gem_new {
+	__u64 size;           /* in */
+	__u32 flags;          /* in, mask of ETNA_BO_x */
+	__u32 handle;         /* out */
+};
+
+struct drm_etnaviv_gem_info {
+	__u32 handle;         /* in */
+	__u32 pad;
+	__u64 offset;         /* out, offset to pass to mmap() */
+};
+
+#define ETNA_PREP_READ        0x01
+#define ETNA_PREP_WRITE       0x02
+#define ETNA_PREP_NOSYNC      0x04
+
+struct drm_etnaviv_gem_cpu_prep {
+	__u32 handle;         /* in */
+	__u32 op;             /* in, mask of ETNA_PREP_x */
+	struct drm_etnaviv_timespec timeout;   /* in */
+};
+
+struct drm_etnaviv_gem_cpu_fini {
+	__u32 handle;         /* in */
+	__u32 flags;          /* in, placeholder for now, no defined values */
+};
+
+/*
+ * Cmdstream Submission:
+ */
+
+/* The value written into the cmdstream is logically:
+ * relocbuf->gpuaddr + reloc_offset
+ *
+ * NOTE that reloc's must be sorted by order of increasing submit_offset,
+ * otherwise EINVAL.
+ */
+struct drm_etnaviv_gem_submit_reloc {
+	__u32 submit_offset;  /* in, offset from submit_bo */
+	__u32 reloc_idx;      /* in, index of reloc_bo buffer */
+	__u64 reloc_offset;   /* in, offset from start of reloc_bo */
+	__u32 flags;          /* in, placeholder for now, no defined values */
+};
+
+/* Each buffer referenced elsewhere in the cmdstream submit (ie. the
+ * cmdstream buffer(s) themselves or reloc entries) has one (and only
+ * one) entry in the submit->bos[] table.
+ *
+ * As a optimization, the current buffer (gpu virtual address) can be
+ * passed back through the 'presumed' field.  If on a subsequent reloc,
+ * userspace passes back a 'presumed' address that is still valid,
+ * then patching the cmdstream for this entry is skipped.  This can
+ * avoid kernel needing to map/access the cmdstream bo in the common
+ * case.
+ */
+#define ETNA_SUBMIT_BO_READ             0x0001
+#define ETNA_SUBMIT_BO_WRITE            0x0002
+struct drm_etnaviv_gem_submit_bo {
+	__u32 flags;          /* in, mask of ETNA_SUBMIT_BO_x */
+	__u32 handle;         /* in, GEM handle */
+	__u64 presumed;       /* in/out, presumed buffer address */
+};
+
+/* Each cmdstream submit consists of a table of buffers involved, and
+ * one or more cmdstream buffers.  This allows for conditional execution
+ * (context-restore), and IB buffers needed for per tile/bin draw cmds.
+ */
+#define ETNA_PIPE_3D      0x00
+#define ETNA_PIPE_2D      0x01
+#define ETNA_PIPE_VG      0x02
+struct drm_etnaviv_gem_submit {
+	__u32 fence;          /* out */
+	__u32 pipe;           /* in */
+	__u32 exec_state;     /* in, initial execution state (ETNA_PIPE_x) */
+	__u32 nr_bos;         /* in, number of submit_bo's */
+	__u32 nr_relocs;      /* in, number of submit_reloc's */
+	__u32 stream_size;    /* in, cmdstream size */
+	__u64 bos;            /* in, ptr to array of submit_bo's */
+	__u64 relocs;         /* in, ptr to array of submit_reloc's */
+	__u64 stream;         /* in, ptr to cmdstream */
+};
+
+/* The normal way to synchronize with the GPU is just to CPU_PREP on
+ * a buffer if you need to access it from the CPU (other cmdstream
+ * submission from same or other contexts, PAGE_FLIP ioctl, etc, all
+ * handle the required synchronization under the hood).  This ioctl
+ * mainly just exists as a way to implement the gallium pipe_fence
+ * APIs without requiring a dummy bo to synchronize on.
+ */
+#define ETNA_WAIT_NONBLOCK      0x01
+struct drm_etnaviv_wait_fence {
+	__u32 pipe;           /* in */
+	__u32 fence;          /* in */
+	__u32 flags;          /* in, mask of ETNA_WAIT_x */
+	__u32 pad;
+	struct drm_etnaviv_timespec timeout;   /* in */
+};
+
+#define ETNA_USERPTR_READ	0x01
+#define ETNA_USERPTR_WRITE	0x02
+struct drm_etnaviv_gem_userptr {
+	__u64 user_ptr;	/* in, page aligned user pointer */
+	__u64 user_size;	/* in, page aligned user size */
+	__u32 flags;		/* in, flags */
+	__u32 handle;	/* out, non-zero handle */
+};
+
+struct drm_etnaviv_gem_wait {
+	__u32 pipe;				/* in */
+	__u32 handle;				/* in, bo to be waited for */
+	__u32 flags;				/* in, mask of ETNA_WAIT_x  */
+	__u32 pad;
+	struct drm_etnaviv_timespec timeout;	/* in */
+};
+
+#define DRM_ETNAVIV_GET_PARAM          0x00
+/* placeholder:
+#define DRM_ETNAVIV_SET_PARAM          0x01
+ */
+#define DRM_ETNAVIV_GEM_NEW            0x02
+#define DRM_ETNAVIV_GEM_INFO           0x03
+#define DRM_ETNAVIV_GEM_CPU_PREP       0x04
+#define DRM_ETNAVIV_GEM_CPU_FINI       0x05
+#define DRM_ETNAVIV_GEM_SUBMIT         0x06
+#define DRM_ETNAVIV_WAIT_FENCE         0x07
+#define DRM_ETNAVIV_GEM_USERPTR        0x08
+#define DRM_ETNAVIV_GEM_WAIT           0x09
+#define DRM_ETNAVIV_NUM_IOCTLS         0x0a
+
+#define DRM_IOCTL_ETNAVIV_GET_PARAM    DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
+#define DRM_IOCTL_ETNAVIV_GEM_NEW      DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
+#define DRM_IOCTL_ETNAVIV_GEM_INFO     DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info)
+#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep)
+#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini)
+#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT   DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit)
+#define DRM_IOCTL_ETNAVIV_WAIT_FENCE   DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
+#define DRM_IOCTL_ETNAVIV_GEM_USERPTR  DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
+#define DRM_IOCTL_ETNAVIV_GEM_WAIT     DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ETNAVIV_DRM_H__ */
diff --git a/etnaviv/etnaviv_drmif.h b/etnaviv/etnaviv_drmif.h
new file mode 100644
index 0000000..8119baa
--- /dev/null
+++ b/etnaviv/etnaviv_drmif.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2014-2015 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifndef ETNAVIV_DRMIF_H_
+#define ETNAVIV_DRMIF_H_
+
+#include <xf86drm.h>
+#include <stdint.h>
+
+struct etna_bo;
+struct etna_pipe;
+struct etna_gpu;
+struct etna_device;
+struct etna_cmd_stream;
+
+enum etna_pipe_id {
+	ETNA_PIPE_3D = 0,
+	ETNA_PIPE_2D = 1,
+	ETNA_PIPE_VG = 2,
+	ETNA_PIPE_MAX
+};
+
+enum etna_param_id {
+	ETNA_GPU_MODEL                     = 0x1,
+	ETNA_GPU_REVISION                  = 0x2,
+	ETNA_GPU_FEATURES_0                = 0x3,
+	ETNA_GPU_FEATURES_1                = 0x4,
+	ETNA_GPU_FEATURES_2                = 0x5,
+	ETNA_GPU_FEATURES_3                = 0x6,
+	ETNA_GPU_FEATURES_4                = 0x7,
+	ETNA_GPU_FEATURES_5                = 0x8,
+	ETNA_GPU_FEATURES_6                = 0x9,
+
+	ETNA_GPU_STREAM_COUNT              = 0x10,
+	ETNA_GPU_REGISTER_MAX              = 0x11,
+	ETNA_GPU_THREAD_COUNT              = 0x12,
+	ETNA_GPU_VERTEX_CACHE_SIZE         = 0x13,
+	ETNA_GPU_SHADER_CORE_COUNT         = 0x14,
+	ETNA_GPU_PIXEL_PIPES               = 0x15,
+	ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE = 0x16,
+	ETNA_GPU_BUFFER_SIZE               = 0x17,
+	ETNA_GPU_INSTRUCTION_COUNT         = 0x18,
+	ETNA_GPU_NUM_CONSTANTS             = 0x19,
+	ETNA_GPU_NUM_VARYINGS              = 0x1a
+};
+
+/* bo flags: */
+#define DRM_ETNA_GEM_CACHE_CACHED       0x00010000
+#define DRM_ETNA_GEM_CACHE_WC           0x00020000
+#define DRM_ETNA_GEM_CACHE_UNCACHED     0x00040000
+#define DRM_ETNA_GEM_CACHE_MASK         0x000f0000
+/* map flags */
+#define DRM_ETNA_GEM_FORCE_MMU          0x00100000
+
+/* bo access flags: (keep aligned to ETNA_PREP_x) */
+#define DRM_ETNA_PREP_READ              0x01
+#define DRM_ETNA_PREP_WRITE             0x02
+#define DRM_ETNA_PREP_NOSYNC            0x04
+
+/* device functions:
+ */
+
+struct etna_device *etna_device_new(int fd);
+struct etna_device *etna_device_new_dup(int fd);
+struct etna_device *etna_device_ref(struct etna_device *dev);
+void etna_device_del(struct etna_device *dev);
+int etna_device_fd(struct etna_device *dev);
+
+/* gpu functions:
+ */
+
+struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core);
+void etna_gpu_del(struct etna_gpu *gpu);
+int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param,
+		uint64_t *value);
+
+
+/* pipe functions:
+ */
+
+struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id);
+void etna_pipe_del(struct etna_pipe *pipe);
+int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms);
+int etna_pipe_wait_ns(struct etna_pipe *pipe, uint32_t timestamp, uint64_t ns);
+
+
+/* buffer-object functions:
+ */
+
+struct etna_bo *etna_bo_new(struct etna_device *dev,
+		uint32_t size, uint32_t flags);
+struct etna_bo *etna_bo_from_handle(struct etna_device *dev,
+		uint32_t handle, uint32_t size);
+struct etna_bo *etna_bo_from_name(struct etna_device *dev, uint32_t name);
+struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd);
+struct etna_bo *etna_bo_ref(struct etna_bo *bo);
+void etna_bo_del(struct etna_bo *bo);
+int etna_bo_get_name(struct etna_bo *bo, uint32_t *name);
+uint32_t etna_bo_handle(struct etna_bo *bo);
+int etna_bo_dmabuf(struct etna_bo *bo);
+uint32_t etna_bo_size(struct etna_bo *bo);
+void * etna_bo_map(struct etna_bo *bo);
+int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op);
+void etna_bo_cpu_fini(struct etna_bo *bo);
+
+
+/* cmd stream functions:
+ */
+
+struct etna_cmd_stream {
+	uint32_t *buffer;
+	uint32_t offset;	/* in 32-bit words */
+	uint32_t size;		/* in 32-bit words */
+};
+
+struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, uint32_t size,
+		void (*reset_notify)(struct etna_cmd_stream *stream, void *priv),
+		void *priv);
+void etna_cmd_stream_del(struct etna_cmd_stream *stream);
+uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream);
+void etna_cmd_stream_flush(struct etna_cmd_stream *stream);
+void etna_cmd_stream_finish(struct etna_cmd_stream *stream);
+
+static inline uint32_t etna_cmd_stream_avail(struct etna_cmd_stream *stream)
+{
+	static const uint32_t END_CLEARANCE = 2; /* LINK op code */
+
+	return stream->size - stream->offset - END_CLEARANCE;
+}
+
+static inline void etna_cmd_stream_reserve(struct etna_cmd_stream *stream, size_t n)
+{
+	if (etna_cmd_stream_avail(stream) < n)
+		etna_cmd_stream_flush(stream);
+}
+
+static inline void etna_cmd_stream_emit(struct etna_cmd_stream *stream, uint32_t data)
+{
+	stream->buffer[stream->offset++] = data;
+}
+
+static inline uint32_t etna_cmd_stream_get(struct etna_cmd_stream *stream, uint32_t offset)
+{
+	return stream->buffer[offset];
+}
+
+static inline void etna_cmd_stream_set(struct etna_cmd_stream *stream, uint32_t offset,
+		uint32_t data)
+{
+	stream->buffer[offset] = data;
+}
+
+static inline uint32_t etna_cmd_stream_offset(struct etna_cmd_stream *stream)
+{
+	return stream->offset;
+}
+
+struct etna_reloc {
+	struct etna_bo *bo;
+#define ETNA_RELOC_READ             0x0001
+#define ETNA_RELOC_WRITE            0x0002
+	uint32_t flags;
+	uint32_t offset;
+};
+
+void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, const struct etna_reloc *r);
+
+#endif /* ETNAVIV_DRMIF_H_ */
diff --git a/etnaviv/etnaviv_gpu.c b/etnaviv/etnaviv_gpu.c
new file mode 100644
index 0000000..35dec6c
--- /dev/null
+++ b/etnaviv/etnaviv_gpu.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "etnaviv_priv.h"
+#include "etnaviv_drmif.h"
+
+static uint64_t get_param(struct etna_device *dev, uint32_t core, uint32_t param)
+{
+	struct drm_etnaviv_param req = {
+		.pipe = core,
+		.param = param,
+	};
+	int ret;
+
+	ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GET_PARAM, &req, sizeof(req));
+	if (ret) {
+		ERROR_MSG("get-param (%x) failed! %d (%s)", param, ret, strerror(errno));
+		return 0;
+	}
+
+	return req.value;
+}
+
+struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core)
+{
+	struct etna_gpu *gpu;
+
+	gpu = calloc(1, sizeof(*gpu));
+	if (!gpu) {
+		ERROR_MSG("allocation failed");
+		goto fail;
+	}
+
+	gpu->dev = dev;
+	gpu->core = core;
+
+	/* get specs from kernel space */
+	gpu->specs.model    	= get_param(dev, core, ETNAVIV_PARAM_GPU_MODEL);
+	gpu->specs.revision 	= get_param(dev, core, ETNAVIV_PARAM_GPU_REVISION);
+	gpu->specs.features[0] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_0);
+	gpu->specs.features[1] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_1);
+	gpu->specs.features[2] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_2);
+	gpu->specs.features[3] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_3);
+	gpu->specs.features[4] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_4);
+	gpu->specs.features[5] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_5);
+	gpu->specs.features[6] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_6);
+	gpu->specs.stream_count = get_param(dev, core, ETNA_GPU_STREAM_COUNT);
+	gpu->specs.register_max = get_param(dev, core, ETNA_GPU_REGISTER_MAX);
+	gpu->specs.thread_count = get_param(dev, core, ETNA_GPU_THREAD_COUNT);
+	gpu->specs.vertex_cache_size = get_param(dev, core, ETNA_GPU_VERTEX_CACHE_SIZE);
+	gpu->specs.shader_core_count = get_param(dev, core, ETNA_GPU_SHADER_CORE_COUNT);
+	gpu->specs.pixel_pipes = get_param(dev, core, ETNA_GPU_PIXEL_PIPES);
+	gpu->specs.vertex_output_buffer_size = get_param(dev, core, ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE);
+	gpu->specs.buffer_size = get_param(dev, core, ETNA_GPU_BUFFER_SIZE);
+	gpu->specs.instruction_count = get_param(dev, core, ETNA_GPU_INSTRUCTION_COUNT);
+	gpu->specs.num_constants = get_param(dev, core, ETNA_GPU_NUM_CONSTANTS);
+	gpu->specs.num_varyings = get_param(dev, core, ETNA_GPU_NUM_VARYINGS);
+
+	if (!gpu->specs.model)
+		goto fail;
+
+	INFO_MSG(" GPU model:          0x%x (rev %x)", gpu->specs.model, gpu->specs.revision);
+
+	return gpu;
+fail:
+	if (gpu)
+		etna_gpu_del(gpu);
+
+	return NULL;
+}
+
+void etna_gpu_del(struct etna_gpu *gpu)
+{
+	free(gpu);
+}
+
+int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param,
+		uint64_t *value)
+{
+	switch(param) {
+	case ETNA_GPU_MODEL:
+		*value = gpu->specs.model;
+		return 0;
+	case ETNA_GPU_REVISION:
+		*value = gpu->specs.revision;
+		return 0;
+	case ETNA_GPU_FEATURES_0:
+		*value = gpu->specs.features[0];
+		return 0;
+	case ETNA_GPU_FEATURES_1:
+		*value = gpu->specs.features[1];
+		return 0;
+	case ETNA_GPU_FEATURES_2:
+		*value = gpu->specs.features[2];
+		return 0;
+	case ETNA_GPU_FEATURES_3:
+		*value = gpu->specs.features[3];
+		return 0;
+	case ETNA_GPU_FEATURES_4:
+		*value = gpu->specs.features[4];
+		return 0;
+	case ETNA_GPU_FEATURES_5:
+		*value = gpu->specs.features[5];
+		return 0;
+	case ETNA_GPU_FEATURES_6:
+		*value = gpu->specs.features[6];
+		return 0;
+	case ETNA_GPU_STREAM_COUNT:
+		*value = gpu->specs.stream_count;
+		return 0;
+	case ETNA_GPU_REGISTER_MAX:
+		*value = gpu->specs.register_max;
+		return 0;
+	case ETNA_GPU_THREAD_COUNT:
+		*value = gpu->specs.thread_count;
+		return 0;
+	case ETNA_GPU_VERTEX_CACHE_SIZE:
+		*value = gpu->specs.vertex_cache_size;
+		return 0;
+	case ETNA_GPU_SHADER_CORE_COUNT:
+		*value = gpu->specs.shader_core_count;
+		return 0;
+	case ETNA_GPU_PIXEL_PIPES:
+		*value = gpu->specs.pixel_pipes;
+		return 0;
+	case ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE:
+		*value = gpu->specs.vertex_output_buffer_size;
+		return 0;
+	case ETNA_GPU_BUFFER_SIZE:
+		*value = gpu->specs.buffer_size;
+		return 0;
+	case ETNA_GPU_INSTRUCTION_COUNT:
+		*value = gpu->specs.instruction_count;
+		return 0;
+	case ETNA_GPU_NUM_CONSTANTS:
+		*value = gpu->specs.num_constants;
+		return 0;
+	case ETNA_GPU_NUM_VARYINGS:
+		*value = gpu->specs.num_varyings;
+		return 0;
+
+	default:
+		ERROR_MSG("invalid param id: %d", param);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/etnaviv/etnaviv_pipe.c b/etnaviv/etnaviv_pipe.c
new file mode 100644
index 0000000..94c5d37
--- /dev/null
+++ b/etnaviv/etnaviv_pipe.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014-2015 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "etnaviv_priv.h"
+
+int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms)
+{
+	return etna_pipe_wait_ns(pipe, timestamp, ms * 1000000);
+}
+
+int etna_pipe_wait_ns(struct etna_pipe *pipe, uint32_t timestamp, uint64_t ns)
+{
+	struct etna_device *dev = pipe->gpu->dev;
+	int ret;
+
+	struct drm_etnaviv_wait_fence req = {
+		.pipe = pipe->gpu->core,
+		.fence = timestamp,
+	};
+
+	if (ns == 0)
+		req.flags |= ETNA_WAIT_NONBLOCK;
+
+	get_abs_timeout(&req.timeout, ns);
+
+	ret = drmCommandWrite(dev->fd, DRM_ETNAVIV_WAIT_FENCE, &req, sizeof(req));
+	if (ret) {
+		ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno));
+		return ret;
+	}
+
+	return 0;
+}
+
+void etna_pipe_del(struct etna_pipe *pipe)
+{
+	free(pipe);
+}
+
+struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id)
+{
+	struct etna_pipe *pipe;
+
+	pipe = calloc(1, sizeof(*pipe));
+	if (!pipe) {
+		ERROR_MSG("allocation failed");
+		goto fail;
+	}
+
+	pipe->id = id;
+	pipe->gpu = gpu;
+
+	return pipe;
+fail:
+	return NULL;
+}
diff --git a/etnaviv/etnaviv_priv.h b/etnaviv/etnaviv_priv.h
new file mode 100644
index 0000000..feaa5ad
--- /dev/null
+++ b/etnaviv/etnaviv_priv.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014-2015 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifndef ETNAVIV_PRIV_H_
+#define ETNAVIV_PRIV_H_
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "libdrm_macros.h"
+#include "xf86drm.h"
+#include "xf86atomic.h"
+
+#include "util_double_list.h"
+
+#include "etnaviv_drmif.h"
+#include "etnaviv_drm.h"
+
+#define VIV_FEATURES_WORD_COUNT 7
+
+struct etna_specs {
+	uint32_t model;
+	uint32_t revision;
+	uint32_t features[VIV_FEATURES_WORD_COUNT];
+	uint32_t stream_count;
+	uint32_t register_max;
+	uint32_t thread_count;
+	uint32_t shader_core_count;
+	uint32_t vertex_cache_size;
+	uint32_t vertex_output_buffer_size;
+	uint32_t pixel_pipes;
+	uint32_t instruction_count;
+	uint32_t num_constants;
+	uint32_t num_varyings;
+	uint32_t buffer_size;
+};
+
+struct etna_bo_bucket {
+	uint32_t size;
+	struct list_head list;
+};
+
+struct etna_bo_cache {
+	struct etna_bo_bucket cache_bucket[14 * 4];
+	unsigned num_buckets;
+	time_t time;
+};
+
+struct etna_device {
+	int fd;
+	atomic_t refcnt;
+
+	/* tables to keep track of bo's, to avoid "evil-twin" etna_bo objects:
+	 *
+	 *   handle_table: maps handle to etna_bo
+	 *   name_table: maps flink name to etna_bo
+	 *
+	 * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always
+	 * returns a new handle.  So we need to figure out if the bo is already
+	 * open in the process first, before calling gem-open.
+	 */
+	void *handle_table, *name_table;
+
+	struct etna_bo_cache bo_cache;
+
+	int closefd;        /* call close(fd) upon destruction */
+};
+
+drm_private void etna_bo_cache_init(struct etna_bo_cache *cache);
+drm_private void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time);
+drm_private struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache,
+		uint32_t *size, uint32_t flags);
+drm_private int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo);
+
+/* for where @table_lock is already held: */
+drm_private void etna_device_del_locked(struct etna_device *dev);
+
+/* a GEM buffer object allocated from the DRM device */
+struct etna_bo {
+	struct etna_device      *dev;
+	void            *map;           /* userspace mmap'ing (if there is one) */
+	uint32_t        size;
+	uint32_t        handle;
+	uint32_t        flags;
+	uint32_t        name;           /* flink global handle (DRI2 name) */
+	uint64_t        offset;         /* offset to mmap() */
+	atomic_t        refcnt;
+
+	/* in the common case, a bo won't be referenced by more than a single
+	 * command stream.  So to avoid looping over all the bo's in the
+	 * reloc table to find the idx of a bo that might already be in the
+	 * table, we cache the idx in the bo.  But in order to detect the
+	 * slow-path where bo is ref'd in multiple streams, we also must track
+	 * the current_stream for which the idx is valid.  See bo2idx().
+	 */
+	struct etna_cmd_stream *current_stream;
+	uint32_t idx;
+
+	int reuse;
+	struct list_head list;   /* bucket-list entry */
+	time_t free_time;        /* time when added to bucket-list */
+};
+
+struct etna_gpu {
+	struct etna_device *dev;
+	struct etna_specs specs;
+	uint32_t core;
+};
+
+struct etna_pipe {
+	enum etna_pipe_id id;
+	struct etna_gpu *gpu;
+};
+
+struct etna_cmd_stream_priv {
+	struct etna_cmd_stream base;
+	struct etna_pipe *pipe;
+
+	uint32_t last_timestamp;
+
+	/* submit ioctl related tables: */
+	struct {
+		/* bo's table: */
+		struct drm_etnaviv_gem_submit_bo *bos;
+		uint32_t nr_bos, max_bos;
+
+		/* reloc's table: */
+		struct drm_etnaviv_gem_submit_reloc *relocs;
+		uint32_t nr_relocs, max_relocs;
+	} submit;
+
+	/* should have matching entries in submit.bos: */
+	struct etna_bo **bos;
+	uint32_t nr_bos, max_bos;
+
+	/* notify callback if buffer reset happend */
+	void (*reset_notify)(struct etna_cmd_stream *stream, void *priv);
+	void *reset_notify_priv;
+};
+
+#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define enable_debug 1  /* TODO make dynamic */
+
+#define INFO_MSG(fmt, ...) \
+		do { drmMsg("[I] "fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+#define DEBUG_MSG(fmt, ...) \
+		do if (enable_debug) { drmMsg("[D] "fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+#define WARN_MSG(fmt, ...) \
+		do { drmMsg("[W] "fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+#define ERROR_MSG(fmt, ...) \
+		do { drmMsg("[E] " fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+
+#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
+
+static inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint64_t ns)
+{
+	struct timespec t;
+	uint32_t s = ns / 1000000000;
+	clock_gettime(CLOCK_MONOTONIC, &t);
+	tv->tv_sec = t.tv_sec + s;
+	tv->tv_nsec = t.tv_nsec + ns - (s * 1000000000);
+}
+
+#endif /* ETNAVIV_PRIV_H_ */
diff --git a/etnaviv/libdrm_etnaviv.pc.in b/etnaviv/libdrm_etnaviv.pc.in
new file mode 100644
index 0000000..13fed01
--- /dev/null
+++ b/etnaviv/libdrm_etnaviv.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdrm_etnaviv
+Description: Userspace interface to etnaviv kernel DRM services
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -ldrm_etnaviv
+Cflags: -I${includedir} -I${includedir}/libdrm
+Requires.private: libdrm
diff --git a/exynos/exynos_drm.c b/exynos/exynos_drm.c
index e689781..b961e52 100644
--- a/exynos/exynos_drm.c
+++ b/exynos/exynos_drm.c
@@ -347,7 +347,7 @@
  *
  * @dev: a exynos device object.
  * @connect: indicate whether connectoin or disconnection request.
- * @ext: indicate whether edid data includes extentions data or not.
+ * @ext: indicate whether edid data includes extensions data or not.
  * @edid: a pointer to edid data from Wireless Display device.
  *
  * this interface is used to request Virtual Display driver connection or
diff --git a/freedreno/Android.mk b/freedreno/Android.mk
index 162c804..2b582ae 100644
--- a/freedreno/Android.mk
+++ b/freedreno/Android.mk
@@ -8,9 +8,7 @@
 
 LOCAL_SHARED_LIBRARIES := libdrm
 
-LOCAL_SRC_FILES := $(filter-out %.h,$(LIBDRM_FREEDRENO_FILES))
+LOCAL_SRC_FILES := $(LIBDRM_FREEDRENO_FILES)
 
-LOCAL_CFLAGS := \
-	-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
-
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_SHARED_LIBRARY)
diff --git a/freedreno/Makefile.am b/freedreno/Makefile.am
index 9b7ec7d..0771d14 100644
--- a/freedreno/Makefile.am
+++ b/freedreno/Makefile.am
@@ -27,4 +27,4 @@
 pkgconfig_DATA = libdrm_freedreno.pc
 
 TESTS = freedreno-symbol-check
-EXTRA_DIST = Android.mk $(TESTS)
+EXTRA_DIST = $(TESTS)
diff --git a/freedreno/Makefile.sources b/freedreno/Makefile.sources
index 57a8bf1..68a679b 100644
--- a/freedreno/Makefile.sources
+++ b/freedreno/Makefile.sources
@@ -4,6 +4,7 @@
 	freedreno_priv.h \
 	freedreno_ringbuffer.c \
 	freedreno_bo.c \
+	freedreno_bo_cache.c \
 	msm/msm_bo.c \
 	msm/msm_device.c \
 	msm/msm_drm.h \
diff --git a/freedreno/freedreno-symbol-check b/freedreno/freedreno-symbol-check
index f517b6e..42f2c43 100755
--- a/freedreno/freedreno-symbol-check
+++ b/freedreno/freedreno-symbol-check
@@ -29,22 +29,28 @@
 fd_device_new
 fd_device_new_dup
 fd_device_ref
+fd_device_version
 fd_pipe_del
 fd_pipe_get_param
 fd_pipe_new
 fd_pipe_wait
 fd_pipe_wait_timeout
+fd_ringbuffer_cmd_count
 fd_ringbuffer_del
 fd_ringbuffer_emit_reloc_ring
+fd_ringbuffer_emit_reloc_ring_full
 fd_ringbuffer_flush
+fd_ringbuffer_grow
 fd_ringbuffer_new
 fd_ringbuffer_reloc
+fd_ringbuffer_reloc2
 fd_ringbuffer_reset
 fd_ringbuffer_set_parent
 fd_ringbuffer_timestamp
 fd_ringmarker_del
 fd_ringmarker_dwords
 fd_ringmarker_flush
+fd_ringbuffer_flush2
 fd_ringmarker_mark
 fd_ringmarker_new
 EOF
diff --git a/freedreno/freedreno_bo.c b/freedreno/freedreno_bo.c
index a23c65d..996d6b9 100644
--- a/freedreno/freedreno_bo.c
+++ b/freedreno/freedreno_bo.c
@@ -33,9 +33,8 @@
 #include "freedreno_drmif.h"
 #include "freedreno_priv.h"
 
-static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
-
-static void bo_del(struct fd_bo *bo);
+drm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
+drm_private void bo_del(struct fd_bo *bo);
 
 /* set buffer name, and add to table, call w/ table_lock held: */
 static void set_name(struct fd_bo *bo, uint32_t name)
@@ -83,114 +82,16 @@
 	return bo;
 }
 
-/* Frees older cached buffers.  Called under table_lock */
-drm_private void fd_cleanup_bo_cache(struct fd_device *dev, time_t time)
-{
-	int i;
-
-	if (dev->time == time)
-		return;
-
-	for (i = 0; i < dev->num_buckets; i++) {
-		struct fd_bo_bucket *bucket = &dev->cache_bucket[i];
-		struct fd_bo *bo;
-
-		while (!LIST_IS_EMPTY(&bucket->list)) {
-			bo = LIST_ENTRY(struct fd_bo, bucket->list.next, list);
-
-			/* keep things in cache for at least 1 second: */
-			if (time && ((time - bo->free_time) <= 1))
-				break;
-
-			list_del(&bo->list);
-			bo_del(bo);
-		}
-	}
-
-	dev->time = time;
-}
-
-static struct fd_bo_bucket * get_bucket(struct fd_device *dev, uint32_t size)
-{
-	int i;
-
-	/* hmm, this is what intel does, but I suppose we could calculate our
-	 * way to the correct bucket size rather than looping..
-	 */
-	for (i = 0; i < dev->num_buckets; i++) {
-		struct fd_bo_bucket *bucket = &dev->cache_bucket[i];
-		if (bucket->size >= size) {
-			return bucket;
-		}
-	}
-
-	return NULL;
-}
-
-static int is_idle(struct fd_bo *bo)
-{
-	return fd_bo_cpu_prep(bo, NULL,
-			DRM_FREEDRENO_PREP_READ |
-			DRM_FREEDRENO_PREP_WRITE |
-			DRM_FREEDRENO_PREP_NOSYNC) == 0;
-}
-
-static struct fd_bo *find_in_bucket(struct fd_device *dev,
-		struct fd_bo_bucket *bucket, uint32_t flags)
-{
-	struct fd_bo *bo = NULL;
-
-	/* TODO .. if we had an ALLOC_FOR_RENDER flag like intel, we could
-	 * skip the busy check.. if it is only going to be a render target
-	 * then we probably don't need to stall..
-	 *
-	 * NOTE that intel takes ALLOC_FOR_RENDER bo's from the list tail
-	 * (MRU, since likely to be in GPU cache), rather than head (LRU)..
-	 */
-	pthread_mutex_lock(&table_lock);
-	while (!LIST_IS_EMPTY(&bucket->list)) {
-		bo = LIST_ENTRY(struct fd_bo, bucket->list.next, list);
-		if (0 /* TODO: if madvise tells us bo is gone... */) {
-			list_del(&bo->list);
-			bo_del(bo);
-			bo = NULL;
-			continue;
-		}
-		/* TODO check for compatible flags? */
-		if (is_idle(bo)) {
-			list_del(&bo->list);
-			break;
-		}
-		bo = NULL;
-		break;
-	}
-	pthread_mutex_unlock(&table_lock);
-
-	return bo;
-}
-
-
 struct fd_bo *
 fd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags)
 {
 	struct fd_bo *bo = NULL;
-	struct fd_bo_bucket *bucket;
 	uint32_t handle;
 	int ret;
 
-	size = ALIGN(size, 4096);
-	bucket = get_bucket(dev, size);
-
-	/* see if we can be green and recycle: */
-	if (bucket) {
-		size = bucket->size;
-		bo = find_in_bucket(dev, bucket, flags);
-		if (bo) {
-			atomic_set(&bo->refcnt, 1);
-			fd_device_ref(bo->dev);
-			return bo;
-		}
-	}
+	bo = fd_bo_cache_alloc(&dev->bo_cache, &size, flags);
+	if (bo)
+		return bo;
 
 	ret = dev->funcs->bo_new_handle(dev, size, flags, &handle);
 	if (ret)
@@ -198,7 +99,7 @@
 
 	pthread_mutex_lock(&table_lock);
 	bo = bo_from_handle(dev, size, handle);
-	bo->bo_reuse = 1;
+	bo->bo_reuse = TRUE;
 	pthread_mutex_unlock(&table_lock);
 
 	return bo;
@@ -300,35 +201,17 @@
 
 	pthread_mutex_lock(&table_lock);
 
-	if (bo->bo_reuse) {
-		struct fd_bo_bucket *bucket = get_bucket(dev, bo->size);
-
-		/* see if we can be green and recycle: */
-		if (bucket) {
-			struct timespec time;
-
-			clock_gettime(CLOCK_MONOTONIC, &time);
-
-			bo->free_time = time.tv_sec;
-			list_addtail(&bo->list, &bucket->list);
-			fd_cleanup_bo_cache(dev, time.tv_sec);
-
-			/* bo's in the bucket cache don't have a ref and
-			 * don't hold a ref to the dev:
-			 */
-
-			goto out;
-		}
-	}
+	if (bo->bo_reuse && (fd_bo_cache_free(&dev->bo_cache, bo) == 0))
+		goto out;
 
 	bo_del(bo);
-out:
 	fd_device_del_locked(dev);
+out:
 	pthread_mutex_unlock(&table_lock);
 }
 
 /* Called under table_lock */
-static void bo_del(struct fd_bo *bo)
+drm_private void bo_del(struct fd_bo *bo)
 {
 	if (bo->map)
 		drm_munmap(bo->map, bo->size);
@@ -366,7 +249,7 @@
 		pthread_mutex_lock(&table_lock);
 		set_name(bo, req.name);
 		pthread_mutex_unlock(&table_lock);
-		bo->bo_reuse = 0;
+		bo->bo_reuse = FALSE;
 	}
 
 	*name = bo->name;
@@ -390,7 +273,7 @@
 		return ret;
 	}
 
-	bo->bo_reuse = 0;
+	bo->bo_reuse = FALSE;
 
 	return prime_fd;
 }
@@ -431,3 +314,10 @@
 {
 	bo->funcs->cpu_fini(bo);
 }
+
+#ifndef HAVE_FREEDRENO_KGSL
+struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size)
+{
+    return NULL;
+}
+#endif
diff --git a/freedreno/freedreno_bo_cache.c b/freedreno/freedreno_bo_cache.c
new file mode 100644
index 0000000..7becb0d
--- /dev/null
+++ b/freedreno/freedreno_bo_cache.c
@@ -0,0 +1,222 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2016 Rob Clark <robclark@freedesktop.org>
+ *
+ * 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.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "freedreno_drmif.h"
+#include "freedreno_priv.h"
+
+
+drm_private void bo_del(struct fd_bo *bo);
+drm_private extern pthread_mutex_t table_lock;
+
+static void
+add_bucket(struct fd_bo_cache *cache, int size)
+{
+	unsigned int i = cache->num_buckets;
+
+	assert(i < ARRAY_SIZE(cache->cache_bucket));
+
+	list_inithead(&cache->cache_bucket[i].list);
+	cache->cache_bucket[i].size = size;
+	cache->num_buckets++;
+}
+
+/**
+ * @coarse: if true, only power-of-two bucket sizes, otherwise
+ *    fill in for a bit smoother size curve..
+ */
+drm_private void
+fd_bo_cache_init(struct fd_bo_cache *cache, int course)
+{
+	unsigned long size, cache_max_size = 64 * 1024 * 1024;
+
+	/* OK, so power of two buckets was too wasteful of memory.
+	 * Give 3 other sizes between each power of two, to hopefully
+	 * cover things accurately enough.  (The alternative is
+	 * probably to just go for exact matching of sizes, and assume
+	 * that for things like composited window resize the tiled
+	 * width/height alignment and rounding of sizes to pages will
+	 * get us useful cache hit rates anyway)
+	 */
+	add_bucket(cache, 4096);
+	add_bucket(cache, 4096 * 2);
+	if (!course)
+		add_bucket(cache, 4096 * 3);
+
+	/* Initialize the linked lists for BO reuse cache. */
+	for (size = 4 * 4096; size <= cache_max_size; size *= 2) {
+		add_bucket(cache, size);
+		if (!course) {
+			add_bucket(cache, size + size * 1 / 4);
+			add_bucket(cache, size + size * 2 / 4);
+			add_bucket(cache, size + size * 3 / 4);
+		}
+	}
+}
+
+/* Frees older cached buffers.  Called under table_lock */
+drm_private void
+fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time)
+{
+	int i;
+
+	if (cache->time == time)
+		return;
+
+	for (i = 0; i < cache->num_buckets; i++) {
+		struct fd_bo_bucket *bucket = &cache->cache_bucket[i];
+		struct fd_bo *bo;
+
+		while (!LIST_IS_EMPTY(&bucket->list)) {
+			bo = LIST_ENTRY(struct fd_bo, bucket->list.next, list);
+
+			/* keep things in cache for at least 1 second: */
+			if (time && ((time - bo->free_time) <= 1))
+				break;
+
+			list_del(&bo->list);
+			bo_del(bo);
+		}
+	}
+
+	cache->time = time;
+}
+
+static struct fd_bo_bucket * get_bucket(struct fd_bo_cache *cache, uint32_t size)
+{
+	int i;
+
+	/* hmm, this is what intel does, but I suppose we could calculate our
+	 * way to the correct bucket size rather than looping..
+	 */
+	for (i = 0; i < cache->num_buckets; i++) {
+		struct fd_bo_bucket *bucket = &cache->cache_bucket[i];
+		if (bucket->size >= size) {
+			return bucket;
+		}
+	}
+
+	return NULL;
+}
+
+static int is_idle(struct fd_bo *bo)
+{
+	return fd_bo_cpu_prep(bo, NULL,
+			DRM_FREEDRENO_PREP_READ |
+			DRM_FREEDRENO_PREP_WRITE |
+			DRM_FREEDRENO_PREP_NOSYNC) == 0;
+}
+
+static struct fd_bo *find_in_bucket(struct fd_bo_bucket *bucket, uint32_t flags)
+{
+	struct fd_bo *bo = NULL;
+
+	/* TODO .. if we had an ALLOC_FOR_RENDER flag like intel, we could
+	 * skip the busy check.. if it is only going to be a render target
+	 * then we probably don't need to stall..
+	 *
+	 * NOTE that intel takes ALLOC_FOR_RENDER bo's from the list tail
+	 * (MRU, since likely to be in GPU cache), rather than head (LRU)..
+	 */
+	pthread_mutex_lock(&table_lock);
+	if (!LIST_IS_EMPTY(&bucket->list)) {
+		bo = LIST_ENTRY(struct fd_bo, bucket->list.next, list);
+		/* TODO check for compatible flags? */
+		if (is_idle(bo)) {
+			list_del(&bo->list);
+		} else {
+			bo = NULL;
+		}
+	}
+	pthread_mutex_unlock(&table_lock);
+
+	return bo;
+}
+
+/* NOTE: size is potentially rounded up to bucket size: */
+drm_private struct fd_bo *
+fd_bo_cache_alloc(struct fd_bo_cache *cache, uint32_t *size, uint32_t flags)
+{
+	struct fd_bo *bo = NULL;
+	struct fd_bo_bucket *bucket;
+
+	*size = ALIGN(*size, 4096);
+	bucket = get_bucket(cache, *size);
+
+	/* see if we can be green and recycle: */
+retry:
+	if (bucket) {
+		*size = bucket->size;
+		bo = find_in_bucket(bucket, flags);
+		if (bo) {
+			if (bo->funcs->madvise(bo, TRUE) <= 0) {
+				/* we've lost the backing pages, delete and try again: */
+				pthread_mutex_lock(&table_lock);
+				bo_del(bo);
+				pthread_mutex_unlock(&table_lock);
+				goto retry;
+			}
+			atomic_set(&bo->refcnt, 1);
+			fd_device_ref(bo->dev);
+			return bo;
+		}
+	}
+
+	return NULL;
+}
+
+drm_private int
+fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo)
+{
+	struct fd_bo_bucket *bucket = get_bucket(cache, bo->size);
+
+	/* see if we can be green and recycle: */
+	if (bucket) {
+		struct timespec time;
+
+		bo->funcs->madvise(bo, FALSE);
+
+		clock_gettime(CLOCK_MONOTONIC, &time);
+
+		bo->free_time = time.tv_sec;
+		list_addtail(&bo->list, &bucket->list);
+		fd_bo_cache_cleanup(cache, time.tv_sec);
+
+		/* bo's in the bucket cache don't have a ref and
+		 * don't hold a ref to the dev:
+		 */
+		fd_device_del_locked(bo->dev);
+
+		return 0;
+	}
+
+	return -1;
+}
diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c
index ddb9545..fcbf140 100644
--- a/freedreno/freedreno_device.c
+++ b/freedreno/freedreno_device.c
@@ -42,44 +42,6 @@
 struct fd_device * kgsl_device_new(int fd);
 struct fd_device * msm_device_new(int fd);
 
-static void
-add_bucket(struct fd_device *dev, int size)
-{
-	unsigned int i = dev->num_buckets;
-
-	assert(i < ARRAY_SIZE(dev->cache_bucket));
-
-	list_inithead(&dev->cache_bucket[i].list);
-	dev->cache_bucket[i].size = size;
-	dev->num_buckets++;
-}
-
-static void
-init_cache_buckets(struct fd_device *dev)
-{
-	unsigned long size, cache_max_size = 64 * 1024 * 1024;
-
-	/* OK, so power of two buckets was too wasteful of memory.
-	 * Give 3 other sizes between each power of two, to hopefully
-	 * cover things accurately enough.  (The alternative is
-	 * probably to just go for exact matching of sizes, and assume
-	 * that for things like composited window resize the tiled
-	 * width/height alignment and rounding of sizes to pages will
-	 * get us useful cache hit rates anyway)
-	 */
-	add_bucket(dev, 4096);
-	add_bucket(dev, 4096 * 2);
-	add_bucket(dev, 4096 * 3);
-
-	/* Initialize the linked lists for BO reuse cache. */
-	for (size = 4 * 4096; size <= cache_max_size; size *= 2) {
-		add_bucket(dev, size);
-		add_bucket(dev, size + size * 1 / 4);
-		add_bucket(dev, size + size * 2 / 4);
-		add_bucket(dev, size + size * 3 / 4);
-	}
-}
-
 struct fd_device * fd_device_new(int fd)
 {
 	struct fd_device *dev;
@@ -94,7 +56,15 @@
 
 	if (!strcmp(version->name, "msm")) {
 		DEBUG_MSG("msm DRM device");
+		if (version->version_major != 1) {
+			ERROR_MSG("unsupported version: %u.%u.%u", version->version_major,
+				version->version_minor, version->version_patchlevel);
+			dev = NULL;
+			goto out;
+		}
+
 		dev = msm_device_new(fd);
+		dev->version = version->version_minor;
 #ifdef HAVE_FREEDRENO_KGSL
 	} else if (!strcmp(version->name, "kgsl")) {
 		DEBUG_MSG("kgsl DRM device");
@@ -104,6 +74,8 @@
 		ERROR_MSG("unknown device: %s", version->name);
 		dev = NULL;
 	}
+
+out:
 	drmFreeVersion(version);
 
 	if (!dev)
@@ -113,7 +85,7 @@
 	dev->fd = fd;
 	dev->handle_table = drmHashCreate();
 	dev->name_table = drmHashCreate();
-	init_cache_buckets(dev);
+	fd_bo_cache_init(&dev->bo_cache, FALSE);
 
 	return dev;
 }
@@ -123,9 +95,12 @@
  */
 struct fd_device * fd_device_new_dup(int fd)
 {
-	struct fd_device *dev = fd_device_new(dup(fd));
+	int dup_fd = dup(fd);
+	struct fd_device *dev = fd_device_new(dup_fd);
 	if (dev)
 		dev->closefd = 1;
+	else
+		close(dup_fd);
 	return dev;
 }
 
@@ -137,7 +112,7 @@
 
 static void fd_device_del_impl(struct fd_device *dev)
 {
-	fd_cleanup_bo_cache(dev, 0);
+	fd_bo_cache_cleanup(&dev->bo_cache, 0);
 	drmHashDestroy(dev->handle_table);
 	drmHashDestroy(dev->name_table);
 	if (dev->closefd)
@@ -165,3 +140,8 @@
 {
 	return dev->fd;
 }
+
+enum fd_version fd_device_version(struct fd_device *dev)
+{
+	return dev->version;
+}
diff --git a/freedreno/freedreno_drmif.h b/freedreno/freedreno_drmif.h
index 5547e94..7a8073f 100644
--- a/freedreno/freedreno_drmif.h
+++ b/freedreno/freedreno_drmif.h
@@ -32,6 +32,15 @@
 #include <xf86drm.h>
 #include <stdint.h>
 
+#if defined(__GNUC__)
+#  define drm_deprecated __attribute__((__deprecated__))
+#else
+#  define drm_deprecated
+#endif
+
+/* an empty marker for things that will be deprecated in the future: */
+#define will_be_deprecated
+
 struct fd_bo;
 struct fd_pipe;
 struct fd_device;
@@ -50,6 +59,8 @@
 	FD_GMEM_SIZE,
 	FD_GPU_ID,
 	FD_CHIP_ID,
+	FD_MAX_FREQ,
+	FD_TIMESTAMP,
 };
 
 /* bo flags: */
@@ -78,6 +89,12 @@
 void fd_device_del(struct fd_device *dev);
 int fd_device_fd(struct fd_device *dev);
 
+enum fd_version {
+	FD_VERSION_MADVISE = 1,            /* kernel supports madvise */
+	FD_VERSION_UNLIMITED_CMDS = 1,     /* submits w/ >4 cmd buffers (growable ringbuffer) */
+	FD_VERSION_FENCE_FD = 2,           /* submit command supports in/out fences */
+};
+enum fd_version fd_device_version(struct fd_device *dev);
 
 /* pipe functions:
  */
diff --git a/freedreno/freedreno_pipe.c b/freedreno/freedreno_pipe.c
index 4a756d7..3f8c834 100644
--- a/freedreno/freedreno_pipe.c
+++ b/freedreno/freedreno_pipe.c
@@ -37,6 +37,7 @@
 fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id)
 {
 	struct fd_pipe *pipe = NULL;
+	uint64_t val;
 
 	if (id > FD_PIPE_MAX) {
 		ERROR_MSG("invalid pipe id: %d", id);
@@ -52,6 +53,9 @@
 	pipe->dev = dev;
 	pipe->id = id;
 
+	fd_pipe_get_param(pipe, FD_GPU_ID, &val);
+	pipe->gpu_id = val;
+
 	return pipe;
 fail:
 	if (pipe)
diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h
index 53817b1..3217039 100644
--- a/freedreno/freedreno_priv.h
+++ b/freedreno/freedreno_priv.h
@@ -54,6 +54,13 @@
 #include "freedreno_ringbuffer.h"
 #include "drm.h"
 
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+
 struct fd_device_funcs {
 	int (*bo_new_handle)(struct fd_device *dev, uint32_t size,
 			uint32_t flags, uint32_t *handle);
@@ -68,8 +75,15 @@
 	struct list_head list;
 };
 
+struct fd_bo_cache {
+	struct fd_bo_bucket cache_bucket[14 * 4];
+	int num_buckets;
+	time_t time;
+};
+
 struct fd_device {
 	int fd;
+	enum fd_version version;
 	atomic_t refcnt;
 
 	/* tables to keep track of bo's, to avoid "evil-twin" fd_bo objects:
@@ -85,14 +99,16 @@
 
 	const struct fd_device_funcs *funcs;
 
-	struct fd_bo_bucket cache_bucket[14 * 4];
-	int num_buckets;
-	time_t time;
+	struct fd_bo_cache bo_cache;
 
 	int closefd;        /* call close(fd) upon destruction */
 };
 
-drm_private void fd_cleanup_bo_cache(struct fd_device *dev, time_t time);
+drm_private void fd_bo_cache_init(struct fd_bo_cache *cache, int coarse);
+drm_private void fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time);
+drm_private struct fd_bo * fd_bo_cache_alloc(struct fd_bo_cache *cache,
+		uint32_t *size, uint32_t flags);
+drm_private int fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo);
 
 /* for where @table_lock is already held: */
 drm_private void fd_device_del_locked(struct fd_device *dev);
@@ -107,6 +123,7 @@
 struct fd_pipe {
 	struct fd_device *dev;
 	enum fd_pipe_id id;
+	uint32_t gpu_id;
 	const struct fd_pipe_funcs *funcs;
 };
 
@@ -117,12 +134,16 @@
 
 struct fd_ringbuffer_funcs {
 	void * (*hostptr)(struct fd_ringbuffer *ring);
-	int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start);
+	int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start,
+			int in_fence_fd, int *out_fence_fd);
+	void (*grow)(struct fd_ringbuffer *ring, uint32_t size);
 	void (*reset)(struct fd_ringbuffer *ring);
 	void (*emit_reloc)(struct fd_ringbuffer *ring,
 			const struct fd_reloc *reloc);
-	void (*emit_reloc_ring)(struct fd_ringbuffer *ring,
-			struct fd_ringmarker *target, struct fd_ringmarker *end);
+	uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring,
+			struct fd_ringbuffer *target, uint32_t cmd_idx,
+			uint32_t submit_offset, uint32_t size);
+	uint32_t (*cmd_count)(struct fd_ringbuffer *ring);
 	void (*destroy)(struct fd_ringbuffer *ring);
 };
 
@@ -130,6 +151,7 @@
 	int (*offset)(struct fd_bo *bo, uint64_t *offset);
 	int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op);
 	void (*cpu_fini)(struct fd_bo *bo);
+	int (*madvise)(struct fd_bo *bo, int willneed);
 	void (*destroy)(struct fd_bo *bo);
 };
 
@@ -168,4 +190,10 @@
 #define U642VOID(x) ((void *)(unsigned long)(x))
 #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
 
+static inline uint32_t
+offset_bytes(void *end, void *start)
+{
+	return ((char *)end) - ((char *)start);
+}
+
 #endif /* FREEDRENO_PRIV_H_ */
diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c
index 984da24..7310f1f 100644
--- a/freedreno/freedreno_ringbuffer.c
+++ b/freedreno/freedreno_ringbuffer.c
@@ -45,10 +45,9 @@
 	if (!ring)
 		return NULL;
 
-	ring->size = size;
 	ring->pipe = pipe;
 	ring->start = ring->funcs->hostptr(ring);
-	ring->end = &(ring->start[size/4]);
+	ring->end = &(ring->start[ring->size/4]);
 
 	ring->cur = ring->last_start = ring->start;
 
@@ -57,6 +56,7 @@
 
 void fd_ringbuffer_del(struct fd_ringbuffer *ring)
 {
+	fd_ringbuffer_reset(ring);
 	ring->funcs->destroy(ring);
 }
 
@@ -80,10 +80,31 @@
 		ring->funcs->reset(ring);
 }
 
-/* maybe get rid of this and use fd_ringmarker_flush() from DDX too? */
 int fd_ringbuffer_flush(struct fd_ringbuffer *ring)
 {
-	return ring->funcs->flush(ring, ring->last_start);
+	return ring->funcs->flush(ring, ring->last_start, -1, NULL);
+}
+
+int fd_ringbuffer_flush2(struct fd_ringbuffer *ring, int in_fence_fd,
+		int *out_fence_fd)
+{
+	return ring->funcs->flush(ring, ring->last_start, in_fence_fd, out_fence_fd);
+}
+
+void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords)
+{
+	assert(ring->funcs->grow);     /* unsupported on kgsl */
+
+	/* there is an upper bound on IB size, which appears to be 0x100000 */
+	if (ring->size < 0x100000)
+		ring->size *= 2;
+
+	ring->funcs->grow(ring, ring->size);
+
+	ring->start = ring->funcs->hostptr(ring);
+	ring->end = &(ring->start[ring->size/4]);
+
+	ring->cur = ring->last_start = ring->start;
 }
 
 uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring)
@@ -94,16 +115,44 @@
 void fd_ringbuffer_reloc(struct fd_ringbuffer *ring,
 				    const struct fd_reloc *reloc)
 {
+	assert(ring->pipe->gpu_id < 500);
 	ring->funcs->emit_reloc(ring, reloc);
 }
 
-void
-fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-			      struct fd_ringmarker *target,
-			      struct fd_ringmarker *end)
+void fd_ringbuffer_reloc2(struct fd_ringbuffer *ring,
+				     const struct fd_reloc *reloc)
 {
+	ring->funcs->emit_reloc(ring, reloc);
+}
+
+void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
+		struct fd_ringmarker *target, struct fd_ringmarker *end)
+{
+	uint32_t submit_offset, size;
+
+	/* This function is deprecated and not supported on 64b devices: */
+	assert(ring->pipe->gpu_id < 500);
 	assert(target->ring == end->ring);
-	ring->funcs->emit_reloc_ring(ring, target, end);
+
+	submit_offset = offset_bytes(target->cur, target->ring->start);
+	size = offset_bytes(end->cur, target->cur);
+
+	ring->funcs->emit_reloc_ring(ring, target->ring, 0, submit_offset, size);
+}
+
+uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring)
+{
+	if (!ring->funcs->cmd_count)
+		return 1;
+	return ring->funcs->cmd_count(ring);
+}
+
+uint32_t
+fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring,
+		struct fd_ringbuffer *target, uint32_t cmd_idx)
+{
+	uint32_t size = offset_bytes(target->cur, target->start);
+	return ring->funcs->emit_reloc_ring(ring, target, cmd_idx, 0, size);
 }
 
 struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring)
@@ -118,7 +167,7 @@
 
 	marker->ring = ring;
 
-	fd_ringmarker_mark(marker);
+	marker->cur = marker->ring->cur;
 
 	return marker;
 }
@@ -142,5 +191,5 @@
 int fd_ringmarker_flush(struct fd_ringmarker *marker)
 {
 	struct fd_ringbuffer *ring = marker->ring;
-	return ring->funcs->flush(ring, marker->cur);
+	return ring->funcs->flush(ring, marker->cur, -1, NULL);
 }
diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h
index 578cdb2..c501fba 100644
--- a/freedreno/freedreno_ringbuffer.h
+++ b/freedreno/freedreno_ringbuffer.h
@@ -56,6 +56,12 @@
 		struct fd_ringbuffer *parent);
 void fd_ringbuffer_reset(struct fd_ringbuffer *ring);
 int fd_ringbuffer_flush(struct fd_ringbuffer *ring);
+/* in_fence_fd: -1 for no in-fence, else fence fd
+ * out_fence_fd: NULL for no output-fence requested, else ptr to return out-fence
+ */
+int fd_ringbuffer_flush2(struct fd_ringbuffer *ring, int in_fence_fd,
+		int *out_fence_fd);
+void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords);
 uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring);
 
 static inline void fd_ringbuffer_emit(struct fd_ringbuffer *ring,
@@ -72,17 +78,24 @@
 	uint32_t offset;
 	uint32_t or;
 	int32_t  shift;
+	uint32_t orhi;      /* used for a5xx+ */
 };
 
-void fd_ringbuffer_reloc(struct fd_ringbuffer *ring, const struct fd_reloc *reloc);
-void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-		struct fd_ringmarker *target, struct fd_ringmarker *end);
+/* NOTE: relocs are 2 dwords on a5xx+ */
 
-struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring);
-void fd_ringmarker_del(struct fd_ringmarker *marker);
-void fd_ringmarker_mark(struct fd_ringmarker *marker);
-uint32_t fd_ringmarker_dwords(struct fd_ringmarker *start,
+void fd_ringbuffer_reloc2(struct fd_ringbuffer *ring, const struct fd_reloc *reloc);
+will_be_deprecated void fd_ringbuffer_reloc(struct fd_ringbuffer *ring, const struct fd_reloc *reloc);
+will_be_deprecated void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
+		struct fd_ringmarker *target, struct fd_ringmarker *end);
+uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring);
+uint32_t fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring,
+		struct fd_ringbuffer *target, uint32_t cmd_idx);
+
+will_be_deprecated struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring);
+will_be_deprecated void fd_ringmarker_del(struct fd_ringmarker *marker);
+will_be_deprecated void fd_ringmarker_mark(struct fd_ringmarker *marker);
+will_be_deprecated uint32_t fd_ringmarker_dwords(struct fd_ringmarker *start,
 		struct fd_ringmarker *end);
-int fd_ringmarker_flush(struct fd_ringmarker *marker);
+will_be_deprecated int fd_ringmarker_flush(struct fd_ringmarker *marker);
 
 #endif /* FREEDRENO_RINGBUFFER_H_ */
diff --git a/freedreno/README b/freedreno/kgsl/README
similarity index 70%
rename from freedreno/README
rename to freedreno/kgsl/README
index ae22e01..56874b4 100644
--- a/freedreno/README
+++ b/freedreno/kgsl/README
@@ -1,3 +1,13 @@
+This is a historical discription of what is now the kgsl backend
+in libdrm freedreno (before the upstream drm/msm driver).  Note
+that the kgsl backend requires the "kgsl-drm" shim driver, which
+usually is in disrepair (QCOM does not build it for android), and
+due to random differences between different downstream android
+kernel branches it may or may not work.  So YMMV.
+
+Original README:
+----------------
+
 Note that current msm kernel driver is a bit strange.  It provides a
 DRM interface for GEM, which is basically sufficient to have DRI2
 working.  But it does not provide KMS.  And interface to 2d and 3d
diff --git a/freedreno/kgsl/kgsl_bo.c b/freedreno/kgsl/kgsl_bo.c
index 2b45b5e..ab3485e 100644
--- a/freedreno/kgsl/kgsl_bo.c
+++ b/freedreno/kgsl/kgsl_bo.c
@@ -116,6 +116,11 @@
 {
 }
 
+static int kgsl_bo_madvise(struct fd_bo *bo, int willneed)
+{
+	return willneed; /* not supported by kgsl */
+}
+
 static void kgsl_bo_destroy(struct fd_bo *bo)
 {
 	struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo);
@@ -127,6 +132,7 @@
 		.offset = kgsl_bo_offset,
 		.cpu_prep = kgsl_bo_cpu_prep,
 		.cpu_fini = kgsl_bo_cpu_fini,
+		.madvise = kgsl_bo_madvise,
 		.destroy = kgsl_bo_destroy,
 };
 
diff --git a/freedreno/kgsl/kgsl_drm.h b/freedreno/kgsl/kgsl_drm.h
index f1c7f4e..281978e 100644
--- a/freedreno/kgsl/kgsl_drm.h
+++ b/freedreno/kgsl/kgsl_drm.h
@@ -81,7 +81,7 @@
 /* Memory types - these define the source and caching policies
    of the GEM memory chunk */
 
-/* Legacy definitions left for compatability */
+/* Legacy definitions left for compatibility */
 
 #define DRM_KGSL_GEM_TYPE_EBI          0
 #define DRM_KGSL_GEM_TYPE_SMI          1
diff --git a/freedreno/kgsl/kgsl_pipe.c b/freedreno/kgsl/kgsl_pipe.c
index 58b3b4d..8a39eb4 100644
--- a/freedreno/kgsl/kgsl_pipe.c
+++ b/freedreno/kgsl/kgsl_pipe.c
@@ -50,6 +50,10 @@
 	case FD_CHIP_ID:
 		*value = kgsl_pipe->devinfo.chip_id;
 		return 0;
+	case FD_MAX_FREQ:
+	case FD_TIMESTAMP:
+		/* unsupported on kgsl */
+		return -1;
 	default:
 		ERROR_MSG("invalid param id: %d", param);
 		return -1;
@@ -251,6 +255,11 @@
 	GETPROP(fd, VERSION,     kgsl_pipe->version);
 	GETPROP(fd, DEVICE_INFO, kgsl_pipe->devinfo);
 
+	if (kgsl_pipe->devinfo.gpu_id >= 500) {
+		ERROR_MSG("64b unsupported with kgsl");
+		goto fail;
+	}
+
 	INFO_MSG("Pipe Info:");
 	INFO_MSG(" Device:          %s", paths[id]);
 	INFO_MSG(" Chip-id:         %d.%d.%d.%d",
diff --git a/freedreno/kgsl/kgsl_ringbuffer.c b/freedreno/kgsl/kgsl_ringbuffer.c
index 6f68f2f..e4696b1 100644
--- a/freedreno/kgsl/kgsl_ringbuffer.c
+++ b/freedreno/kgsl/kgsl_ringbuffer.c
@@ -113,7 +113,8 @@
 	return kgsl_ring->bo->hostptr;
 }
 
-static int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start)
+static int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start,
+		int in_fence_fd, int *out_fence_fd)
 {
 	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
 	struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(ring->pipe);
@@ -131,6 +132,9 @@
 	};
 	int ret;
 
+	assert(in_fence_fd == -1);
+	assert(out_fence_fd == NULL);
+
 	kgsl_pipe_pre_submit(kgsl_pipe);
 
 	/* z180_cmdstream_issueibcmds() is made of fail: */
@@ -173,12 +177,14 @@
 	kgsl_pipe_add_submit(to_kgsl_pipe(ring->pipe), kgsl_bo);
 }
 
-static void kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-		struct fd_ringmarker *target, struct fd_ringmarker *end)
+static uint32_t kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
+		struct fd_ringbuffer *target, uint32_t cmd_idx,
+		uint32_t submit_offset, uint32_t size)
 {
-	struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target->ring);
-	(*ring->cur++) = target_ring->bo->gpuaddr +
-			(uint8_t *)target->cur - (uint8_t *)target->ring->start;
+	struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target);
+	assert(cmd_idx == 0);
+	(*ring->cur++) = target_ring->bo->gpuaddr + submit_offset;
+	return size;
 }
 
 static void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring)
@@ -213,6 +219,7 @@
 
 	ring = &kgsl_ring->base;
 	ring->funcs = &funcs;
+	ring->size = size;
 
 	kgsl_ring->bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), size);
 	if (!kgsl_ring->bo) {
diff --git a/freedreno/kgsl/msm_kgsl.h b/freedreno/kgsl/msm_kgsl.h
index e67190f..5b36eeb 100644
--- a/freedreno/kgsl/msm_kgsl.h
+++ b/freedreno/kgsl/msm_kgsl.h
@@ -31,7 +31,7 @@
 #define KGSL_FLAGS_SOFT_RESET  0x00000100
 #define KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS 0x00000200
 
-/* Clock flags to show which clocks should be controled by a given platform */
+/* Clock flags to show which clocks should be controlled by a given platform */
 #define KGSL_CLK_SRC	0x00000001
 #define KGSL_CLK_CORE	0x00000002
 #define KGSL_CLK_IFACE	0x00000004
@@ -295,7 +295,7 @@
 
 /* Previous versions of this header had incorrectly defined
    IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP as a read-only ioctl instead
-   of a write only ioctl.  To ensure binary compatability, the following
+   of a write only ioctl.  To ensure binary compatibility, the following
    #define will be used to intercept the incorrect ioctl
 */
 
diff --git a/freedreno/msm/msm_bo.c b/freedreno/msm/msm_bo.c
index cd05a6c..72471df 100644
--- a/freedreno/msm/msm_bo.c
+++ b/freedreno/msm/msm_bo.c
@@ -89,6 +89,25 @@
 	drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_CPU_FINI, &req, sizeof(req));
 }
 
+static int msm_bo_madvise(struct fd_bo *bo, int willneed)
+{
+	struct drm_msm_gem_madvise req = {
+			.handle = bo->handle,
+			.madv = willneed ? MSM_MADV_WILLNEED : MSM_MADV_DONTNEED,
+	};
+	int ret;
+
+	/* older kernels do not support this: */
+	if (bo->dev->version < FD_VERSION_MADVISE)
+		return willneed;
+
+	ret = drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_MADVISE, &req, sizeof(req));
+	if (ret)
+		return ret;
+
+	return req.retained;
+}
+
 static void msm_bo_destroy(struct fd_bo *bo)
 {
 	struct msm_bo *msm_bo = to_msm_bo(bo);
@@ -100,6 +119,7 @@
 		.offset = msm_bo_offset,
 		.cpu_prep = msm_bo_cpu_prep,
 		.cpu_fini = msm_bo_cpu_fini,
+		.madvise = msm_bo_madvise,
 		.destroy = msm_bo_destroy,
 };
 
diff --git a/freedreno/msm/msm_device.c b/freedreno/msm/msm_device.c
index 25c097c..727baa4 100644
--- a/freedreno/msm/msm_device.c
+++ b/freedreno/msm/msm_device.c
@@ -39,6 +39,7 @@
 static void msm_device_destroy(struct fd_device *dev)
 {
 	struct msm_device *msm_dev = to_msm_device(dev);
+	fd_bo_cache_cleanup(&msm_dev->ring_cache, 0);
 	free(msm_dev);
 }
 
@@ -61,5 +62,7 @@
 	dev = &msm_dev->base;
 	dev->funcs = &funcs;
 
+	fd_bo_cache_init(&msm_dev->ring_cache, TRUE);
+
 	return dev;
 }
diff --git a/freedreno/msm/msm_drm.h b/freedreno/msm/msm_drm.h
index f7474c5..ed4c8d4 100644
--- a/freedreno/msm/msm_drm.h
+++ b/freedreno/msm/msm_drm.h
@@ -28,9 +28,13 @@
 #include <stddef.h>
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* Please note that modifications to all structs defined here are
  * subject to backwards-compatibility constraints:
- *  1) Do not use pointers, use uint64_t instead for 32 bit / 64 bit
+ *  1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
  *     user/kernel compatibility
  *  2) Keep fields aligned to their size
  *  3) Because of how drm_ioctl() works, we can add new fields at
@@ -46,23 +50,34 @@
 #define MSM_PIPE_2D1         0x02
 #define MSM_PIPE_3D0         0x10
 
+/* The pipe-id just uses the lower bits, so can be OR'd with flags in
+ * the upper 16 bits (which could be extended further, if needed, maybe
+ * we extend/overload the pipe-id some day to deal with multiple rings,
+ * but even then I don't think we need the full lower 16 bits).
+ */
+#define MSM_PIPE_ID_MASK     0xffff
+#define MSM_PIPE_ID(x)       ((x) & MSM_PIPE_ID_MASK)
+#define MSM_PIPE_FLAGS(x)    ((x) & ~MSM_PIPE_ID_MASK)
+
 /* timeouts are specified in clock-monotonic absolute times (to simplify
  * restarting interrupted ioctls).  The following struct is logically the
  * same as 'struct timespec' but 32/64b ABI safe.
  */
 struct drm_msm_timespec {
-	int64_t tv_sec;          /* seconds */
-	int64_t tv_nsec;         /* nanoseconds */
+	__s64 tv_sec;          /* seconds */
+	__s64 tv_nsec;         /* nanoseconds */
 };
 
 #define MSM_PARAM_GPU_ID     0x01
 #define MSM_PARAM_GMEM_SIZE  0x02
 #define MSM_PARAM_CHIP_ID    0x03
+#define MSM_PARAM_MAX_FREQ   0x04
+#define MSM_PARAM_TIMESTAMP  0x05
 
 struct drm_msm_param {
-	uint32_t pipe;           /* in, MSM_PIPE_x */
-	uint32_t param;          /* in, MSM_PARAM_x */
-	uint64_t value;          /* out (get_param) or in (set_param) */
+	__u32 pipe;           /* in, MSM_PIPE_x */
+	__u32 param;          /* in, MSM_PARAM_x */
+	__u64 value;          /* out (get_param) or in (set_param) */
 };
 
 /*
@@ -84,15 +99,15 @@
                               MSM_BO_UNCACHED)
 
 struct drm_msm_gem_new {
-	uint64_t size;           /* in */
-	uint32_t flags;          /* in, mask of MSM_BO_x */
-	uint32_t handle;         /* out */
+	__u64 size;           /* in */
+	__u32 flags;          /* in, mask of MSM_BO_x */
+	__u32 handle;         /* out */
 };
 
 struct drm_msm_gem_info {
-	uint32_t handle;         /* in */
-	uint32_t pad;
-	uint64_t offset;         /* out, offset to pass to mmap() */
+	__u32 handle;         /* in */
+	__u32 pad;
+	__u64 offset;         /* out, offset to pass to mmap() */
 };
 
 #define MSM_PREP_READ        0x01
@@ -102,13 +117,13 @@
 #define MSM_PREP_FLAGS       (MSM_PREP_READ | MSM_PREP_WRITE | MSM_PREP_NOSYNC)
 
 struct drm_msm_gem_cpu_prep {
-	uint32_t handle;         /* in */
-	uint32_t op;             /* in, mask of MSM_PREP_x */
+	__u32 handle;         /* in */
+	__u32 op;             /* in, mask of MSM_PREP_x */
 	struct drm_msm_timespec timeout;   /* in */
 };
 
 struct drm_msm_gem_cpu_fini {
-	uint32_t handle;         /* in */
+	__u32 handle;         /* in */
 };
 
 /*
@@ -127,11 +142,11 @@
  * otherwise EINVAL.
  */
 struct drm_msm_gem_submit_reloc {
-	uint32_t submit_offset;  /* in, offset from submit_bo */
-	uint32_t or;             /* in, value OR'd with result */
-	int32_t  shift;          /* in, amount of left shift (can be negative) */
-	uint32_t reloc_idx;      /* in, index of reloc_bo buffer */
-	uint64_t reloc_offset;   /* in, offset from start of reloc_bo */
+	__u32 submit_offset;  /* in, offset from submit_bo */
+	__u32 or;             /* in, value OR'd with result */
+	__s32 shift;          /* in, amount of left shift (can be negative) */
+	__u32 reloc_idx;      /* in, index of reloc_bo buffer */
+	__u64 reloc_offset;   /* in, offset from start of reloc_bo */
 };
 
 /* submit-types:
@@ -146,13 +161,13 @@
 #define MSM_SUBMIT_CMD_IB_TARGET_BUF   0x0002
 #define MSM_SUBMIT_CMD_CTX_RESTORE_BUF 0x0003
 struct drm_msm_gem_submit_cmd {
-	uint32_t type;           /* in, one of MSM_SUBMIT_CMD_x */
-	uint32_t submit_idx;     /* in, index of submit_bo cmdstream buffer */
-	uint32_t submit_offset;  /* in, offset into submit_bo */
-	uint32_t size;           /* in, cmdstream size */
-	uint32_t pad;
-	uint32_t nr_relocs;      /* in, number of submit_reloc's */
-	uint64_t __user relocs;  /* in, ptr to array of submit_reloc's */
+	__u32 type;           /* in, one of MSM_SUBMIT_CMD_x */
+	__u32 submit_idx;     /* in, index of submit_bo cmdstream buffer */
+	__u32 submit_offset;  /* in, offset into submit_bo */
+	__u32 size;           /* in, cmdstream size */
+	__u32 pad;
+	__u32 nr_relocs;      /* in, number of submit_reloc's */
+	__u64 __user relocs;  /* in, ptr to array of submit_reloc's */
 };
 
 /* Each buffer referenced elsewhere in the cmdstream submit (ie. the
@@ -172,22 +187,33 @@
 #define MSM_SUBMIT_BO_FLAGS            (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE)
 
 struct drm_msm_gem_submit_bo {
-	uint32_t flags;          /* in, mask of MSM_SUBMIT_BO_x */
-	uint32_t handle;         /* in, GEM handle */
-	uint64_t presumed;       /* in/out, presumed buffer address */
+	__u32 flags;          /* in, mask of MSM_SUBMIT_BO_x */
+	__u32 handle;         /* in, GEM handle */
+	__u64 presumed;       /* in/out, presumed buffer address */
 };
 
+/* Valid submit ioctl flags: */
+#define MSM_SUBMIT_NO_IMPLICIT   0x80000000 /* disable implicit sync */
+#define MSM_SUBMIT_FENCE_FD_IN   0x40000000 /* enable input fence_fd */
+#define MSM_SUBMIT_FENCE_FD_OUT  0x20000000 /* enable output fence_fd */
+#define MSM_SUBMIT_FLAGS                ( \
+		MSM_SUBMIT_NO_IMPLICIT   | \
+		MSM_SUBMIT_FENCE_FD_IN   | \
+		MSM_SUBMIT_FENCE_FD_OUT  | \
+		0)
+
 /* Each cmdstream submit consists of a table of buffers involved, and
  * one or more cmdstream buffers.  This allows for conditional execution
  * (context-restore), and IB buffers needed for per tile/bin draw cmds.
  */
 struct drm_msm_gem_submit {
-	uint32_t pipe;           /* in, MSM_PIPE_x */
-	uint32_t fence;          /* out */
-	uint32_t nr_bos;         /* in, number of submit_bo's */
-	uint32_t nr_cmds;        /* in, number of submit_cmd's */
-	uint64_t __user bos;     /* in, ptr to array of submit_bo's */
-	uint64_t __user cmds;    /* in, ptr to array of submit_cmd's */
+	__u32 flags;          /* MSM_PIPE_x | MSM_SUBMIT_x */
+	__u32 fence;          /* out */
+	__u32 nr_bos;         /* in, number of submit_bo's */
+	__u32 nr_cmds;        /* in, number of submit_cmd's */
+	__u64 __user bos;     /* in, ptr to array of submit_bo's */
+	__u64 __user cmds;    /* in, ptr to array of submit_cmd's */
+	__s32 fence_fd;       /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */
 };
 
 /* The normal way to synchronize with the GPU is just to CPU_PREP on
@@ -198,11 +224,32 @@
  * APIs without requiring a dummy bo to synchronize on.
  */
 struct drm_msm_wait_fence {
-	uint32_t fence;          /* in */
-	uint32_t pad;
+	__u32 fence;          /* in */
+	__u32 pad;
 	struct drm_msm_timespec timeout;   /* in */
 };
 
+/* madvise provides a way to tell the kernel in case a buffers contents
+ * can be discarded under memory pressure, which is useful for userspace
+ * bo cache where we want to optimistically hold on to buffer allocate
+ * and potential mmap, but allow the pages to be discarded under memory
+ * pressure.
+ *
+ * Typical usage would involve madvise(DONTNEED) when buffer enters BO
+ * cache, and madvise(WILLNEED) if trying to recycle buffer from BO cache.
+ * In the WILLNEED case, 'retained' indicates to userspace whether the
+ * backing pages still exist.
+ */
+#define MSM_MADV_WILLNEED 0       /* backing pages are needed, status returned in 'retained' */
+#define MSM_MADV_DONTNEED 1       /* backing pages not needed */
+#define __MSM_MADV_PURGED 2       /* internal state */
+
+struct drm_msm_gem_madvise {
+	__u32 handle;         /* in, GEM handle */
+	__u32 madv;           /* in, MSM_MADV_x */
+	__u32 retained;       /* out, whether backing store still exists */
+};
+
 #define DRM_MSM_GET_PARAM              0x00
 /* placeholder:
 #define DRM_MSM_SET_PARAM              0x01
@@ -213,7 +260,8 @@
 #define DRM_MSM_GEM_CPU_FINI           0x05
 #define DRM_MSM_GEM_SUBMIT             0x06
 #define DRM_MSM_WAIT_FENCE             0x07
-#define DRM_MSM_NUM_IOCTLS             0x08
+#define DRM_MSM_GEM_MADVISE            0x08
+#define DRM_MSM_NUM_IOCTLS             0x09
 
 #define DRM_IOCTL_MSM_GET_PARAM        DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
 #define DRM_IOCTL_MSM_GEM_NEW          DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new)
@@ -222,5 +270,10 @@
 #define DRM_IOCTL_MSM_GEM_CPU_FINI     DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_GEM_CPU_FINI, struct drm_msm_gem_cpu_fini)
 #define DRM_IOCTL_MSM_GEM_SUBMIT       DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_SUBMIT, struct drm_msm_gem_submit)
 #define DRM_IOCTL_MSM_WAIT_FENCE       DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_WAIT_FENCE, struct drm_msm_wait_fence)
+#define DRM_IOCTL_MSM_GEM_MADVISE      DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_MADVISE, struct drm_msm_gem_madvise)
+
+#if defined(__cplusplus)
+}
+#endif
 
 #endif /* __MSM_DRM_H__ */
diff --git a/freedreno/msm/msm_pipe.c b/freedreno/msm/msm_pipe.c
index aa0866b..f872e24 100644
--- a/freedreno/msm/msm_pipe.c
+++ b/freedreno/msm/msm_pipe.c
@@ -32,6 +32,25 @@
 
 #include "msm_priv.h"
 
+static int query_param(struct fd_pipe *pipe, uint32_t param,
+		uint64_t *value)
+{
+	struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
+	struct drm_msm_param req = {
+			.pipe = msm_pipe->pipe,
+			.param = param,
+	};
+	int ret;
+
+	ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_GET_PARAM,
+			&req, sizeof(req));
+	if (ret)
+		return ret;
+
+	*value = req.value;
+
+	return 0;
+}
 
 static int msm_pipe_get_param(struct fd_pipe *pipe,
 		enum fd_param_id param, uint64_t *value)
@@ -48,6 +67,10 @@
 	case FD_CHIP_ID:
 		*value = msm_pipe->chip_id;
 		return 0;
+	case FD_MAX_FREQ:
+		return query_param(pipe, MSM_PARAM_MAX_FREQ, value);
+	case FD_TIMESTAMP:
+		return query_param(pipe, MSM_PARAM_TIMESTAMP, value);
 	default:
 		ERROR_MSG("invalid param id: %d", param);
 		return -1;
@@ -87,21 +110,15 @@
 		.destroy = msm_pipe_destroy,
 };
 
-static uint64_t get_param(struct fd_device *dev, uint32_t pipe, uint32_t param)
+static uint64_t get_param(struct fd_pipe *pipe, uint32_t param)
 {
-	struct drm_msm_param req = {
-			.pipe = pipe,
-			.param = param,
-	};
-	int ret;
-
-	ret = drmCommandWriteRead(dev->fd, DRM_MSM_GET_PARAM, &req, sizeof(req));
+	uint64_t value;
+	int ret = query_param(pipe, param, &value);
 	if (ret) {
 		ERROR_MSG("get-param failed! %d (%s)", ret, strerror(errno));
 		return 0;
 	}
-
-	return req.value;
+	return value;
 }
 
 drm_private struct fd_pipe * msm_pipe_new(struct fd_device *dev,
@@ -123,10 +140,14 @@
 	pipe = &msm_pipe->base;
 	pipe->funcs = &funcs;
 
+	/* initialize before get_param(): */
+	pipe->dev = dev;
 	msm_pipe->pipe = pipe_id[id];
-	msm_pipe->gpu_id = get_param(dev, pipe_id[id], MSM_PARAM_GPU_ID);
-	msm_pipe->gmem   = get_param(dev, pipe_id[id], MSM_PARAM_GMEM_SIZE);
-	msm_pipe->chip_id = get_param(dev, pipe_id[id], MSM_PARAM_CHIP_ID);
+
+	/* these params should be supported since the first version of drm/msm: */
+	msm_pipe->gpu_id = get_param(pipe, MSM_PARAM_GPU_ID);
+	msm_pipe->gmem   = get_param(pipe, MSM_PARAM_GMEM_SIZE);
+	msm_pipe->chip_id = get_param(pipe, MSM_PARAM_CHIP_ID);
 
 	if (! msm_pipe->gpu_id)
 		goto fail;
diff --git a/freedreno/msm/msm_priv.h b/freedreno/msm/msm_priv.h
index e499b3b..6d670aa 100644
--- a/freedreno/msm/msm_priv.h
+++ b/freedreno/msm/msm_priv.h
@@ -39,6 +39,8 @@
 
 struct msm_device {
 	struct fd_device base;
+	struct fd_bo_cache ring_cache;
+	unsigned ring_cnt;
 };
 
 static inline struct msm_device * to_msm_device(struct fd_device *x)
@@ -71,18 +73,11 @@
 	struct fd_bo base;
 	uint64_t offset;
 	uint64_t presumed;
-	/* in the common case, a bo won't be referenced by more than a single
-	 * (parent) ring[*].  So to avoid looping over all the bo's in the
-	 * reloc table to find the idx of a bo that might already be in the
-	 * table, we cache the idx in the bo.  But in order to detect the
-	 * slow-path where bo is ref'd in multiple rb's, we also must track
-	 * the current_ring for which the idx is valid.  See bo2idx().
-	 *
-	 * [*] in case multiple ringbuffers, ie. one toplevel and other rb(s)
-	 *     used for IB target(s), the toplevel rb is the parent which is
-	 *     tracking bo's for the submit
+	/* to avoid excess hashtable lookups, cache the ring this bo was
+	 * last emitted on (since that will probably also be the next ring
+	 * it is emitted on)
 	 */
-	struct fd_ringbuffer *current_ring;
+	unsigned current_ring_seqno;
 	uint32_t idx;
 };
 
diff --git a/freedreno/msm/msm_ringbuffer.c b/freedreno/msm/msm_ringbuffer.c
index becf245..17194f4 100644
--- a/freedreno/msm/msm_ringbuffer.c
+++ b/freedreno/msm/msm_ringbuffer.c
@@ -36,11 +36,30 @@
 #include "freedreno_ringbuffer.h"
 #include "msm_priv.h"
 
-struct msm_ringbuffer {
-	struct fd_ringbuffer base;
+/* represents a single cmd buffer in the submit ioctl.  Each cmd buffer has
+ * a backing bo, and a reloc table.
+ */
+struct msm_cmd {
+	struct list_head list;
+
+	struct fd_ringbuffer *ring;
 	struct fd_bo *ring_bo;
 
-	/* submit ioctl related tables: */
+	/* reloc's table: */
+	struct drm_msm_gem_submit_reloc *relocs;
+	uint32_t nr_relocs, max_relocs;
+
+	uint32_t size;
+};
+
+struct msm_ringbuffer {
+	struct fd_ringbuffer base;
+
+	/* submit ioctl related tables:
+	 * Note that bos and cmds are tracked by the parent ringbuffer, since
+	 * that is global to the submit ioctl call.  The reloc's table is tracked
+	 * per cmd-buffer.
+	 */
 	struct {
 		/* bo's table: */
 		struct drm_msm_gem_submit_bo *bos;
@@ -49,22 +68,111 @@
 		/* cmd's table: */
 		struct drm_msm_gem_submit_cmd *cmds;
 		uint32_t nr_cmds, max_cmds;
-
-		/* reloc's table: */
-		struct drm_msm_gem_submit_reloc *relocs;
-		uint32_t nr_relocs, max_relocs;
 	} submit;
 
 	/* should have matching entries in submit.bos: */
+	/* Note, only in parent ringbuffer */
 	struct fd_bo **bos;
 	uint32_t nr_bos, max_bos;
 
 	/* should have matching entries in submit.cmds: */
-	struct fd_ringbuffer **rings;
-	uint32_t nr_rings, max_rings;
+	struct msm_cmd **cmds;
+	uint32_t nr_cmds, max_cmds;
+
+	/* List of physical cmdstream buffers (msm_cmd) assocated with this
+	 * logical fd_ringbuffer.
+	 *
+	 * Note that this is different from msm_ringbuffer::cmds (which
+	 * shadows msm_ringbuffer::submit::cmds for tracking submit ioctl
+	 * related stuff, and *only* is tracked in the parent ringbuffer.
+	 * And only has "completed" cmd buffers (ie. we already know the
+	 * size) added via get_cmd().
+	 */
+	struct list_head cmd_list;
+
+	int is_growable;
+	unsigned cmd_count;
+
+	unsigned seqno;
+
+	/* maps fd_bo to idx: */
+	void *bo_table;
 };
 
+static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x)
+{
+	return (struct msm_ringbuffer *)x;
+}
+
+#define INIT_SIZE 0x1000
+
 static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER;
+drm_private extern pthread_mutex_t table_lock;
+
+static void ring_bo_del(struct fd_device *dev, struct fd_bo *bo)
+{
+	int ret;
+
+	pthread_mutex_lock(&table_lock);
+	ret = fd_bo_cache_free(&to_msm_device(dev)->ring_cache, bo);
+	pthread_mutex_unlock(&table_lock);
+
+	if (ret == 0)
+		return;
+
+	fd_bo_del(bo);
+}
+
+static struct fd_bo * ring_bo_new(struct fd_device *dev, uint32_t size)
+{
+	struct fd_bo *bo;
+
+	bo = fd_bo_cache_alloc(&to_msm_device(dev)->ring_cache, &size, 0);
+	if (bo)
+		return bo;
+
+	bo = fd_bo_new(dev, size, 0);
+	if (!bo)
+		return NULL;
+
+	/* keep ringbuffer bo's out of the normal bo cache: */
+	bo->bo_reuse = FALSE;
+
+	return bo;
+}
+
+static void ring_cmd_del(struct msm_cmd *cmd)
+{
+	if (cmd->ring_bo)
+		ring_bo_del(cmd->ring->pipe->dev, cmd->ring_bo);
+	list_del(&cmd->list);
+	to_msm_ringbuffer(cmd->ring)->cmd_count--;
+	free(cmd->relocs);
+	free(cmd);
+}
+
+static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size)
+{
+	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
+	struct msm_cmd *cmd = calloc(1, sizeof(*cmd));
+
+	if (!cmd)
+		return NULL;
+
+	cmd->ring = ring;
+	cmd->ring_bo = ring_bo_new(ring->pipe->dev, size);
+	if (!cmd->ring_bo)
+		goto fail;
+
+	list_addtail(&cmd->list, &msm_ring->cmd_list);
+	msm_ring->cmd_count++;
+
+	return cmd;
+
+fail:
+	ring_cmd_del(cmd);
+	return NULL;
+}
 
 static void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz)
 {
@@ -83,9 +191,11 @@
 	(x)->nr_ ## name ++; \
 })
 
-static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x)
+static struct msm_cmd *current_cmd(struct fd_ringbuffer *ring)
 {
-	return (struct msm_ringbuffer *)x;
+	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
+	assert(!LIST_IS_EMPTY(&msm_ring->cmd_list));
+	return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list);
 }
 
 static uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo)
@@ -112,21 +222,24 @@
 	struct msm_bo *msm_bo = to_msm_bo(bo);
 	uint32_t idx;
 	pthread_mutex_lock(&idx_lock);
-	if (!msm_bo->current_ring) {
-		idx = append_bo(ring, bo);
-		msm_bo->current_ring = ring;
-		msm_bo->idx = idx;
-	} else if (msm_bo->current_ring == ring) {
+	if (msm_bo->current_ring_seqno == msm_ring->seqno) {
 		idx = msm_bo->idx;
 	} else {
-		/* slow-path: */
-		for (idx = 0; idx < msm_ring->nr_bos; idx++)
-			if (msm_ring->bos[idx] == bo)
-				break;
-		if (idx == msm_ring->nr_bos) {
-			/* not found */
+		void *val;
+
+		if (!msm_ring->bo_table)
+			msm_ring->bo_table = drmHashCreate();
+
+		if (!drmHashLookup(msm_ring->bo_table, bo->handle, &val)) {
+			/* found */
+			idx = (uint32_t)(uintptr_t)val;
+		} else {
 			idx = append_bo(ring, bo);
+			val = (void *)(uintptr_t)idx;
+			drmHashInsert(msm_ring->bo_table, bo->handle, val);
 		}
+		msm_bo->current_ring_seqno = msm_ring->seqno;
+		msm_bo->idx = idx;
 	}
 	pthread_mutex_unlock(&idx_lock);
 	if (flags & FD_RELOC_READ)
@@ -143,17 +256,14 @@
 	return msm_ring->submit.bos[cmd->submit_idx].handle == bo->handle;
 }
 
-static uint32_t offset_bytes(void *end, void *start)
-{
-	return ((char *)end) - ((char *)start);
-}
-
-static struct drm_msm_gem_submit_cmd * get_cmd(struct fd_ringbuffer *ring,
-		struct fd_ringbuffer *target_ring, struct fd_bo *target_bo,
+/* Ensure that submit has corresponding entry in cmds table for the
+ * target cmdstream buffer:
+ */
+static void get_cmd(struct fd_ringbuffer *ring, struct msm_cmd *target_cmd,
 		uint32_t submit_offset, uint32_t size, uint32_t type)
 {
 	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
-	struct drm_msm_gem_submit_cmd *cmd = NULL;
+	struct drm_msm_gem_submit_cmd *cmd;
 	uint32_t i;
 
 	/* figure out if we already have a cmd buf: */
@@ -162,41 +272,37 @@
 		if ((cmd->submit_offset == submit_offset) &&
 				(cmd->size == size) &&
 				(cmd->type == type) &&
-				check_cmd_bo(ring, cmd, target_bo))
-			break;
-		cmd = NULL;
+				check_cmd_bo(ring, cmd, target_cmd->ring_bo))
+			return;
 	}
 
 	/* create cmd buf if not: */
-	if (!cmd) {
-		uint32_t idx = APPEND(&msm_ring->submit, cmds);
-		APPEND(msm_ring, rings);
-		msm_ring->rings[idx] = target_ring;
-		cmd = &msm_ring->submit.cmds[idx];
-		cmd->type = type;
-		cmd->submit_idx = bo2idx(ring, target_bo, FD_RELOC_READ);
-		cmd->submit_offset = submit_offset;
-		cmd->size = size;
-		cmd->pad = 0;
-	}
+	i = APPEND(&msm_ring->submit, cmds);
+	APPEND(msm_ring, cmds);
+	msm_ring->cmds[i] = target_cmd;
+	cmd = &msm_ring->submit.cmds[i];
+	cmd->type = type;
+	cmd->submit_idx = bo2idx(ring, target_cmd->ring_bo, FD_RELOC_READ);
+	cmd->submit_offset = submit_offset;
+	cmd->size = size;
+	cmd->pad = 0;
 
-	return cmd;
+	target_cmd->size = size;
 }
 
 static void * msm_ringbuffer_hostptr(struct fd_ringbuffer *ring)
 {
-	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
-	return fd_bo_map(msm_ring->ring_bo);
+	return fd_bo_map(current_cmd(ring)->ring_bo);
 }
 
-static uint32_t find_next_reloc_idx(struct msm_ringbuffer *msm_ring,
+static uint32_t find_next_reloc_idx(struct msm_cmd *msm_cmd,
 		uint32_t start, uint32_t offset)
 {
 	uint32_t i;
 
 	/* a binary search would be more clever.. */
-	for (i = start; i < msm_ring->submit.nr_relocs; i++) {
-		struct drm_msm_gem_submit_reloc *reloc = &msm_ring->submit.relocs[i];
+	for (i = start; i < msm_cmd->nr_relocs; i++) {
+		struct drm_msm_gem_submit_reloc *reloc = &msm_cmd->relocs[i];
 		if (reloc->submit_offset >= offset)
 			return i;
 	}
@@ -204,38 +310,111 @@
 	return i;
 }
 
+static void delete_cmds(struct msm_ringbuffer *msm_ring)
+{
+	struct msm_cmd *cmd, *tmp;
+
+	LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &msm_ring->cmd_list, list) {
+		ring_cmd_del(cmd);
+	}
+}
+
 static void flush_reset(struct fd_ringbuffer *ring)
 {
 	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
 	unsigned i;
 
-	/* for each of the cmd buffers, clear their reloc's: */
-	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
-		struct msm_ringbuffer *target_ring = to_msm_ringbuffer(msm_ring->rings[i]);
-		target_ring->submit.nr_relocs = 0;
+	for (i = 0; i < msm_ring->nr_bos; i++) {
+		struct msm_bo *msm_bo = to_msm_bo(msm_ring->bos[i]);
+		msm_bo->current_ring_seqno = 0;
+		fd_bo_del(&msm_bo->base);
 	}
 
-	msm_ring->submit.nr_relocs = 0;
+	/* for each of the cmd buffers, clear their reloc's: */
+	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
+		struct msm_cmd *target_cmd = msm_ring->cmds[i];
+		target_cmd->nr_relocs = 0;
+	}
+
 	msm_ring->submit.nr_cmds = 0;
 	msm_ring->submit.nr_bos = 0;
-	msm_ring->nr_rings = 0;
+	msm_ring->nr_cmds = 0;
 	msm_ring->nr_bos = 0;
+
+	if (msm_ring->bo_table) {
+		drmHashDestroy(msm_ring->bo_table);
+		msm_ring->bo_table = NULL;
+	}
+
+	if (msm_ring->is_growable) {
+		delete_cmds(msm_ring);
+	} else {
+		/* in old mode, just reset the # of relocs: */
+		current_cmd(ring)->nr_relocs = 0;
+	}
 }
 
-static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start)
+static void finalize_current_cmd(struct fd_ringbuffer *ring, uint32_t *last_start)
 {
-	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
-	struct fd_bo *ring_bo = msm_ring->ring_bo;
-	struct drm_msm_gem_submit req = {
-			.pipe = to_msm_pipe(ring->pipe)->pipe,
-	};
-	uint32_t i, j, submit_offset, size;
-	int ret;
+	uint32_t submit_offset, size, type;
+	struct fd_ringbuffer *parent;
+
+	if (ring->parent) {
+		parent = ring->parent;
+		type = MSM_SUBMIT_CMD_IB_TARGET_BUF;
+	} else {
+		parent = ring;
+		type = MSM_SUBMIT_CMD_BUF;
+	}
 
 	submit_offset = offset_bytes(last_start, ring->start);
 	size = offset_bytes(ring->cur, last_start);
 
-	get_cmd(ring, ring, ring_bo, submit_offset, size, MSM_SUBMIT_CMD_BUF);
+	get_cmd(parent, current_cmd(ring), submit_offset, size, type);
+}
+
+static void dump_submit(struct msm_ringbuffer *msm_ring)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < msm_ring->submit.nr_bos; i++) {
+		struct drm_msm_gem_submit_bo *bo = &msm_ring->submit.bos[i];
+		ERROR_MSG("  bos[%d]: handle=%u, flags=%x", i, bo->handle, bo->flags);
+	}
+	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
+		struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i];
+		struct drm_msm_gem_submit_reloc *relocs = U642VOID(cmd->relocs);
+		ERROR_MSG("  cmd[%d]: type=%u, submit_idx=%u, submit_offset=%u, size=%u",
+				i, cmd->type, cmd->submit_idx, cmd->submit_offset, cmd->size);
+		for (j = 0; j < cmd->nr_relocs; j++) {
+			struct drm_msm_gem_submit_reloc *r = &relocs[j];
+			ERROR_MSG("    reloc[%d]: submit_offset=%u, or=%08x, shift=%d, reloc_idx=%u"
+					", reloc_offset=%"PRIu64, j, r->submit_offset, r->or, r->shift,
+					r->reloc_idx, r->reloc_offset);
+		}
+	}
+}
+
+static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start,
+		int in_fence_fd, int *out_fence_fd)
+{
+	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
+	struct drm_msm_gem_submit req = {
+			.flags = to_msm_pipe(ring->pipe)->pipe,
+	};
+	uint32_t i;
+	int ret;
+
+	if (in_fence_fd != -1) {
+		req.flags |= MSM_SUBMIT_FENCE_FD_IN | MSM_SUBMIT_NO_IMPLICIT;
+		req.fence_fd = in_fence_fd;
+	}
+
+	if (out_fence_fd) {
+		req.flags |= MSM_SUBMIT_FENCE_FD_OUT;
+	}
+
+	finalize_current_cmd(ring, last_start);
 
 	/* needs to be after get_cmd() as that could create bos/cmds table: */
 	req.bos = VOID2U64(msm_ring->submit.bos),
@@ -246,10 +425,10 @@
 	/* for each of the cmd's fix up their reloc's: */
 	for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
 		struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i];
-		struct msm_ringbuffer *target_ring = to_msm_ringbuffer(msm_ring->rings[i]);
-		uint32_t a = find_next_reloc_idx(target_ring, 0, cmd->submit_offset);
-		uint32_t b = find_next_reloc_idx(target_ring, a, cmd->submit_offset + cmd->size);
-		cmd->relocs = VOID2U64(&target_ring->submit.relocs[a]);
+		struct msm_cmd *msm_cmd = msm_ring->cmds[i];
+		uint32_t a = find_next_reloc_idx(msm_cmd, 0, cmd->submit_offset);
+		uint32_t b = find_next_reloc_idx(msm_cmd, a, cmd->submit_offset + cmd->size);
+		cmd->relocs = VOID2U64(&msm_cmd->relocs[a]);
 		cmd->nr_relocs = (b > a) ? b - a : 0;
 	}
 
@@ -259,36 +438,17 @@
 			&req, sizeof(req));
 	if (ret) {
 		ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno));
-		ERROR_MSG("  pipe:  %u", req.pipe);
-		for (i = 0; i < msm_ring->submit.nr_bos; i++) {
-			struct drm_msm_gem_submit_bo *bo = &msm_ring->submit.bos[i];
-			ERROR_MSG("  bos[%d]: handle=%u, flags=%x", i, bo->handle, bo->flags);
-		}
-		for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
-			struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i];
-			struct drm_msm_gem_submit_reloc *relocs = U642VOID(cmd->relocs);
-			ERROR_MSG("  cmd[%d]: type=%u, submit_idx=%u, submit_offset=%u, size=%u",
-					i, cmd->type, cmd->submit_idx, cmd->submit_offset, cmd->size);
-			for (j = 0; j < cmd->nr_relocs; j++) {
-				struct drm_msm_gem_submit_reloc *r = &relocs[j];
-				ERROR_MSG("    reloc[%d]: submit_offset=%u, or=%08x, shift=%d, reloc_idx=%u"
-						", reloc_offset=%"PRIu64, j, r->submit_offset, r->or, r->shift,
-						r->reloc_idx, r->reloc_offset);
-			}
-		}
-	} else {
+		dump_submit(msm_ring);
+	} else if (!ret) {
 		/* update timestamp on all rings associated with submit: */
 		for (i = 0; i < msm_ring->submit.nr_cmds; i++) {
-			struct fd_ringbuffer *target_ring = msm_ring->rings[i];
-			if (!ret)
-				target_ring->last_timestamp = req.fence;
+			struct msm_cmd *msm_cmd = msm_ring->cmds[i];
+			msm_cmd->ring->last_timestamp = req.fence;
 		}
-	}
 
-	for (i = 0; i < msm_ring->nr_bos; i++) {
-		struct msm_bo *msm_bo = to_msm_bo(msm_ring->bos[i]);
-		msm_bo->current_ring = NULL;
-		fd_bo_del(&msm_bo->base);
+		if (out_fence_fd) {
+			*out_fence_fd = req.fence_fd;
+		}
 	}
 
 	flush_reset(ring);
@@ -296,6 +456,13 @@
 	return ret;
 }
 
+static void msm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size)
+{
+	assert(to_msm_ringbuffer(ring)->is_growable);
+	finalize_current_cmd(ring, ring->last_start);
+	ring_cmd_new(ring, size);
+}
+
 static void msm_ringbuffer_reset(struct fd_ringbuffer *ring)
 {
 	flush_reset(ring);
@@ -304,14 +471,14 @@
 static void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
 		const struct fd_reloc *r)
 {
-	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
 	struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring;
 	struct msm_bo *msm_bo = to_msm_bo(r->bo);
 	struct drm_msm_gem_submit_reloc *reloc;
-	uint32_t idx = APPEND(&msm_ring->submit, relocs);
+	struct msm_cmd *cmd = current_cmd(ring);
+	uint32_t idx = APPEND(cmd, relocs);
 	uint32_t addr;
 
-	reloc = &msm_ring->submit.relocs[idx];
+	reloc = &cmd->relocs[idx];
 
 	reloc->reloc_idx = bo2idx(parent, r->bo, r->flags);
 	reloc->reloc_offset = r->offset;
@@ -320,48 +487,96 @@
 	reloc->submit_offset = offset_bytes(ring->cur, ring->start);
 
 	addr = msm_bo->presumed;
-	if (r->shift < 0)
-		addr >>= -r->shift;
+	if (reloc->shift < 0)
+		addr >>= -reloc->shift;
 	else
-		addr <<= r->shift;
+		addr <<= reloc->shift;
 	(*ring->cur++) = addr | r->or;
+
+	if (ring->pipe->gpu_id >= 500) {
+		struct drm_msm_gem_submit_reloc *reloc_hi;
+
+		idx = APPEND(cmd, relocs);
+
+		reloc_hi = &cmd->relocs[idx];
+
+		reloc_hi->reloc_idx = reloc->reloc_idx;
+		reloc_hi->reloc_offset = r->offset;
+		reloc_hi->or = r->orhi;
+		reloc_hi->shift = r->shift - 32;
+		reloc_hi->submit_offset = offset_bytes(ring->cur, ring->start);
+
+		addr = msm_bo->presumed >> 32;
+		if (reloc_hi->shift < 0)
+			addr >>= -reloc_hi->shift;
+		else
+			addr <<= reloc_hi->shift;
+		(*ring->cur++) = addr | r->orhi;
+	}
 }
 
-static void msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
-		struct fd_ringmarker *target, struct fd_ringmarker *end)
+static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
+		struct fd_ringbuffer *target, uint32_t cmd_idx,
+		uint32_t submit_offset, uint32_t size)
 {
-	struct fd_bo *target_bo = to_msm_ringbuffer(target->ring)->ring_bo;
-	struct drm_msm_gem_submit_cmd *cmd;
-	uint32_t submit_offset, size;
+	struct msm_cmd *cmd = NULL;
+	uint32_t idx = 0;
 
-	submit_offset = offset_bytes(target->cur, target->ring->start);
-	size = offset_bytes(end->cur, target->cur);
+	LIST_FOR_EACH_ENTRY(cmd, &to_msm_ringbuffer(target)->cmd_list, list) {
+		if (idx == cmd_idx)
+			break;
+		idx++;
+	}
 
-	cmd = get_cmd(ring, target->ring, target_bo, submit_offset, size,
-			MSM_SUBMIT_CMD_IB_TARGET_BUF);
-	assert(cmd);
+	assert(cmd && (idx == cmd_idx));
+
+	if (idx < (to_msm_ringbuffer(target)->cmd_count - 1)) {
+		/* All but the last cmd buffer is fully "baked" (ie. already has
+		 * done get_cmd() to add it to the cmds table).  But in this case,
+		 * the size we get is invalid (since it is calculated from the
+		 * last cmd buffer):
+		 */
+		size = cmd->size;
+	} else {
+		get_cmd(ring, cmd, submit_offset, size, MSM_SUBMIT_CMD_IB_TARGET_BUF);
+	}
 
 	msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){
-		.bo = target_bo,
+		.bo = cmd->ring_bo,
 		.flags = FD_RELOC_READ,
 		.offset = submit_offset,
 	});
+
+	return size;
+}
+
+static uint32_t msm_ringbuffer_cmd_count(struct fd_ringbuffer *ring)
+{
+	return to_msm_ringbuffer(ring)->cmd_count;
 }
 
 static void msm_ringbuffer_destroy(struct fd_ringbuffer *ring)
 {
 	struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
-	if (msm_ring->ring_bo)
-		fd_bo_del(msm_ring->ring_bo);
+
+	flush_reset(ring);
+	delete_cmds(msm_ring);
+
+	free(msm_ring->submit.cmds);
+	free(msm_ring->submit.bos);
+	free(msm_ring->bos);
+	free(msm_ring->cmds);
 	free(msm_ring);
 }
 
 static const struct fd_ringbuffer_funcs funcs = {
 		.hostptr = msm_ringbuffer_hostptr,
 		.flush = msm_ringbuffer_flush,
+		.grow = msm_ringbuffer_grow,
 		.reset = msm_ringbuffer_reset,
 		.emit_reloc = msm_ringbuffer_emit_reloc,
 		.emit_reloc_ring = msm_ringbuffer_emit_reloc_ring,
+		.cmd_count = msm_ringbuffer_cmd_count,
 		.destroy = msm_ringbuffer_destroy,
 };
 
@@ -377,14 +592,21 @@
 		goto fail;
 	}
 
+	if (size == 0) {
+		assert(pipe->dev->version >= FD_VERSION_UNLIMITED_CMDS);
+		size = INIT_SIZE;
+		msm_ring->is_growable = TRUE;
+	}
+
+	list_inithead(&msm_ring->cmd_list);
+	msm_ring->seqno = ++to_msm_device(pipe->dev)->ring_cnt;
+
 	ring = &msm_ring->base;
 	ring->funcs = &funcs;
+	ring->size = size;
+	ring->pipe = pipe;   /* needed in ring_cmd_new() */
 
-	msm_ring->ring_bo = fd_bo_new(pipe->dev, size, 0);
-	if (!msm_ring->ring_bo) {
-		ERROR_MSG("ringbuffer allocation failed");
-		goto fail;
-	}
+	ring_cmd_new(ring, size);
 
 	return ring;
 fail:
diff --git a/include/drm/README b/include/drm/README
new file mode 100644
index 0000000..a50b02c
--- /dev/null
+++ b/include/drm/README
@@ -0,0 +1,157 @@
+What are these headers ?
+------------------------
+This is the canonical source of drm headers that user space should use for
+communicating with the kernel DRM subsystem.
+
+They flow from the kernel, thus any changes must be merged there first.
+Do _not_ attempt to "fix" these by deviating from the kernel ones !
+
+
+Non-linux platforms - changes/patches
+-------------------------------------
+If your platform has local changes, please send them upstream for inclusion.
+Even if your patches don't get accepted in their current form, devs will
+give you feedback on how to address things properly.
+
+git send-email --subject-prefix="PATCH libdrm" your patches to dri-devel
+mailing list.
+
+Before doing so, please consider the following:
+ - Have the [libdrm vs kernel] headers on your platform deviated ?
+Consider unifying them first.
+
+ - Have you introduced additional ABI that's not available in Linux ?
+Propose it for [Linux kernel] upstream inclusion.
+If that doesn't work out (hopefully it never does), move it to another header
+and/or keep the change(s) local ?
+
+ - Are your changes DRI1/UMS specific ?
+There is virtually no interest/power in keeping those legacy interfaces. They
+are around due to the kernel "thou shalt not break existing user space" rule.
+
+Consider porting the driver to DRI2/KMS - all (almost?) sensible hardware is
+capable of supporting those.
+
+
+Which headers go where ?
+------------------------
+A snipped from the, now removed, Makefile.am used to state:
+
+  XXX airlied says, nothing besides *_drm.h and drm*.h should be necessary.
+  however, r300 and via need their reg headers installed in order to build.
+  better solutions are welcome.
+
+Obviously the r300 and via headers are no longer around ;-)
+
+Reason behind is that the drm headers can be used as a basic communications
+channel with the respective kernel modules. If more advanced functionality is
+required one can pull the specific libdrm_$driver which is free to pull
+additional files from the kernel.
+
+For example: nouveau has nouveau/nvif/*.h while vc4 has vc4/*.h
+
+If your driver is still in prototyping/staging state, consider moving the
+$driver_drm.h into $driver and _not_ installing it. An header providing opaque
+definitions and access [via $driver_drmif.h or similar] would be better fit.
+
+
+When and which headers to update
+--------------------------------
+Ideally all files will be synced (updated) with the latest released kernel on
+each libdrm release. Sadly that's not yet possible since quite a few headers
+differ significantly - see Outdated or Broken Headers section below.
+
+That said, it's up-to the individual developers to sync with newer version
+(from drm-next) as they see fit.
+
+
+When and how to update these files
+----------------------------------
+In order to update the files do the following:
+ - Switch to a Linux kernel tree/branch which is not rebased.
+For example: airlied/drm-next
+ - Install the headers via `make headers_install' to a separate location.
+ - Copy the drm header[s] + git add + git commit.
+ - Note: Your commit message must include:
+   a) Brief summary on the delta. If there's any change that looks like an
+API/ABI break one _must_ explicitly state why it's safe to do so.
+   b) "Generated using make headers_install."
+   c) "Generated from $tree/branch commit $sha"
+
+
+Outdated or Broken Headers
+--------------------------
+This section contains a list of headers and the respective "issues" they might
+have relative to their kernel equivalent.
+
+Nearly all headers:
+ - Missing extern C notation.
+Status: Trivial.
+
+Most UMS headers:
+ - Not using fixed size integers - compat ioctls are broken.
+Status: ?
+Promote to fixed size ints, which match the current (32bit) ones.
+
+
+amdgpu_drm.h
+ - Using the stdint.h uint*_t over the respective __u* ones
+Status: Trivial.
+
+drm_mode.h
+ - Missing DPI encode/connector pair.
+Status: Trivial.
+
+i915_drm.h
+ - Missing PARAMS - HAS_POOLED_EU, MIN_EU_IN_POOL CONTEXT_PARAM_NO_ERROR_CAPTURE
+Status: Trivial.
+
+mga_drm.h
+ - Typo fix, use struct over typedef.
+Status: Trivial.
+
+nouveau_drm.h
+ - Missing macros NOUVEAU_GETPARAM*, NOUVEAU_DRM_HEADER_PATCHLEVEL, structs,
+enums, using stdint.h over the __u* types.
+Status: ?
+
+qxl_drm.h
+ - Using the stdint.h uint*_t over the respective __u* ones
+Status: Trivial.
+
+r128_drm.h
+ - Broken compat ioctls.
+
+radeon_drm.h
+ - Missing RADEON_TILING_R600_NO_SCANOUT, CIK_TILE_MODE_*, broken UMS ioctls,
+using stdint types.
+ - Both kernel and libdrm: missing padding -
+drm_radeon_gem_{create,{g,s}et_tiling,set_domain} others ?
+Status: ?
+
+savage_drm.h
+ - Renamed ioctls - DRM_IOCTL_SAVAGE_{,BCI}_EVENT_EMIT, compat ioctls are broken.
+Status: ?
+
+sis_drm.h
+ - Borken ioctls + libdrm uses int vs kernel long
+Status: ?
+
+via_drm.h
+ - Borken ioctls - libdrm int vs kernel long
+Status: ?
+
+
+omap_drm.h (living in $TOP/omap)
+ - License mismatch, missing DRM_IOCTL_OMAP_GEM_NEW and related struct
+Status: ?
+
+msm_drm.h (located in $TOP/freedreno/msm/)
+ - License mismatch, missing MSM_PIPE_*, MSM_SUBMIT_*. Renamed
+drm_msm_gem_submit::flags, missing drm_msm_gem_submit::fence_fd.
+Status: ?
+
+exynos_drm.h (living in $TOP/exynos)
+ - License mismatch, now using fixed size ints (but not everywhere). Lots of
+new stuff.
+Status: ?
diff --git a/include/drm/amdgpu_drm.h b/include/drm/amdgpu_drm.h
index fbdd118..d8f2497 100644
--- a/include/drm/amdgpu_drm.h
+++ b/include/drm/amdgpu_drm.h
@@ -34,6 +34,10 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define DRM_AMDGPU_GEM_CREATE		0x00
 #define DRM_AMDGPU_GEM_MMAP		0x01
 #define DRM_AMDGPU_CTX			0x02
@@ -73,6 +77,8 @@
 #define AMDGPU_GEM_CREATE_NO_CPU_ACCESS		(1 << 1)
 /* Flag that USWC attributes should be used for GTT */
 #define AMDGPU_GEM_CREATE_CPU_GTT_USWC		(1 << 2)
+/* Flag that the memory should be in VRAM and cleared */
+#define AMDGPU_GEM_CREATE_VRAM_CLEARED		(1 << 3)
 
 struct drm_amdgpu_gem_create_in  {
 	/** the requested memory size */
@@ -483,6 +489,22 @@
 #define AMDGPU_INFO_MMR_SH_INDEX_SHIFT	8
 #define AMDGPU_INFO_MMR_SH_INDEX_MASK	0xff
 
+struct drm_amdgpu_query_fw {
+	/** AMDGPU_INFO_FW_* */
+	uint32_t fw_type;
+	/**
+	 * Index of the IP if there are more IPs of
+	 * the same type.
+	 */
+	uint32_t ip_instance;
+	/**
+	 * Index of the engine. Whether this is used depends
+	 * on the firmware type. (e.g. MEC, SDMA)
+	 */
+	uint32_t index;
+	uint32_t _pad;
+};
+
 /* Input structure for the INFO ioctl */
 struct drm_amdgpu_info {
 	/* Where the return value will be stored */
@@ -518,21 +540,7 @@
 			uint32_t flags;
 		} read_mmr_reg;
 
-		struct {
-			/** AMDGPU_INFO_FW_* */
-			uint32_t fw_type;
-			/**
-			 * Index of the IP if there are more IPs of
-			 * the same type.
-			 */
-			uint32_t ip_instance;
-			/**
-			 * Index of the engine. Whether this is used depends
-			 * on the firmware type. (e.g. MEC, SDMA)
-			 */
-			uint32_t index;
-			uint32_t _pad;
-		} query_fw;
+		struct drm_amdgpu_query_fw query_fw;
 	};
 };
 
@@ -640,6 +648,10 @@
 #define AMDGPU_FAMILY_CI			120 /* Bonaire, Hawaii */
 #define AMDGPU_FAMILY_KV			125 /* Kaveri, Kabini, Mullins */
 #define AMDGPU_FAMILY_VI			130 /* Iceland, Tonga */
-#define AMDGPU_FAMILY_CZ			135 /* Carrizo */
+#define AMDGPU_FAMILY_CZ			135 /* Carrizo, Stoney */
+
+#if defined(__cplusplus)
+}
+#endif
 
 #endif
diff --git a/include/drm/drm.h b/include/drm/drm.h
index d36331a..f6fd5c2 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -36,7 +36,7 @@
 #ifndef _DRM_H_
 #define _DRM_H_
 
-#if defined(__linux__)
+#if   defined(__linux__)
 
 #include <linux/types.h>
 #include <asm/ioctl.h>
@@ -54,10 +54,15 @@
 typedef uint32_t __u32;
 typedef int64_t  __s64;
 typedef uint64_t __u64;
+typedef size_t   __kernel_size_t;
 typedef unsigned long drm_handle_t;
 
 #endif
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define DRM_NAME	"drm"	  /**< Name in kernel, /dev, and /proc */
 #define DRM_MIN_ORDER	5	  /**< At least 2^5 bytes = 32 bytes */
 #define DRM_MAX_ORDER	22	  /**< Up to 2^22 bytes = 4MB */
@@ -129,11 +134,11 @@
 	int version_major;	  /**< Major version */
 	int version_minor;	  /**< Minor version */
 	int version_patchlevel;	  /**< Patch level */
-	size_t name_len;	  /**< Length of name buffer */
+	__kernel_size_t name_len;	  /**< Length of name buffer */
 	char *name;	  /**< Name of driver */
-	size_t date_len;	  /**< Length of date buffer */
+	__kernel_size_t date_len;	  /**< Length of date buffer */
 	char *date;	  /**< User-space buffer to hold date */
-	size_t desc_len;	  /**< Length of desc buffer */
+	__kernel_size_t desc_len;	  /**< Length of desc buffer */
 	char *desc;	  /**< User-space buffer to hold desc */
 };
 
@@ -143,7 +148,7 @@
  * \sa drmGetBusid() and drmSetBusId().
  */
 struct drm_unique {
-	size_t unique_len;	  /**< Length of unique */
+	__kernel_size_t unique_len;	  /**< Length of unique */
 	char *unique;	  /**< Unique name for driver instantiation */
 };
 
@@ -180,8 +185,7 @@
 	_DRM_SHM = 2,		  /**< shared, cached */
 	_DRM_AGP = 3,		  /**< AGP/GART */
 	_DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
-	_DRM_CONSISTENT = 5,	  /**< Consistent memory for PCI DMA */
-	_DRM_GEM = 6		  /**< GEM object */
+	_DRM_CONSISTENT = 5	  /**< Consistent memory for PCI DMA */
 };
 
 /**
@@ -467,12 +471,15 @@
 enum drm_vblank_seq_type {
 	_DRM_VBLANK_ABSOLUTE = 0x0,	/**< Wait for specific vblank sequence number */
 	_DRM_VBLANK_RELATIVE = 0x1,	/**< Wait for given number of vblanks */
+	/* bits 1-6 are reserved for high crtcs */
+	_DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e,
 	_DRM_VBLANK_EVENT = 0x4000000,   /**< Send event instead of blocking */
 	_DRM_VBLANK_FLIP = 0x8000000,   /**< Scheduled buffer swap should flip */
 	_DRM_VBLANK_NEXTONMISS = 0x10000000,	/**< If missed, wait for next vblank */
 	_DRM_VBLANK_SECONDARY = 0x20000000,	/**< Secondary display controller */
 	_DRM_VBLANK_SIGNAL = 0x40000000	/**< Send signal instead of blocking, unsupported */
 };
+#define _DRM_VBLANK_HIGH_CRTC_SHIFT 1
 
 #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
 #define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \
@@ -612,6 +619,29 @@
 	__u64 size;
 };
 
+#define DRM_CAP_DUMB_BUFFER		0x1
+#define DRM_CAP_VBLANK_HIGH_CRTC	0x2
+#define DRM_CAP_DUMB_PREFERRED_DEPTH	0x3
+#define DRM_CAP_DUMB_PREFER_SHADOW	0x4
+#define DRM_CAP_PRIME			0x5
+#define  DRM_PRIME_CAP_IMPORT		0x1
+#define  DRM_PRIME_CAP_EXPORT		0x2
+#define DRM_CAP_TIMESTAMP_MONOTONIC	0x6
+#define DRM_CAP_ASYNC_PAGE_FLIP		0x7
+/*
+ * The CURSOR_WIDTH and CURSOR_HEIGHT capabilities return a valid widthxheight
+ * combination for the hardware cursor. The intention is that a hardware
+ * agnostic userspace can query a cursor plane size to use.
+ *
+ * Note that the cross-driver contract is to merely return a valid size;
+ * drivers are free to attach another meaning on top, eg. i915 returns the
+ * maximum plane size.
+ */
+#define DRM_CAP_CURSOR_WIDTH		0x8
+#define DRM_CAP_CURSOR_HEIGHT		0x9
+#define DRM_CAP_ADDFB2_MODIFIERS	0x10
+#define DRM_CAP_PAGE_FLIP_TARGET	0x11
+
 /** DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {
 	__u64 capability;
@@ -642,19 +672,13 @@
  */
 #define DRM_CLIENT_CAP_ATOMIC	3
 
-/**
- * DRM_CLIENT_CAP_ATOMIC
- *
- * If set to 1, the DRM core will allow atomic modesetting requests.
- */
-#define DRM_CLIENT_CAP_ATOMIC		3
-
 /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
 	__u64 capability;
 	__u64 value;
 };
 
+#define DRM_RDWR O_RDWR
 #define DRM_CLOEXEC O_CLOEXEC
 struct drm_prime_handle {
 	__u32 handle;
@@ -666,8 +690,16 @@
 	__s32 fd;
 };
 
+#if defined(__cplusplus)
+}
+#endif
+
 #include "drm_mode.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define DRM_IOCTL_BASE			'd'
 #define DRM_IO(nr)			_IO(DRM_IOCTL_BASE,nr)
 #define DRM_IOR(nr,type)		_IOR(DRM_IOCTL_BASE,nr,type)
@@ -750,8 +782,8 @@
 #define DRM_IOCTL_MODE_SETGAMMA		DRM_IOWR(0xA5, struct drm_mode_crtc_lut)
 #define DRM_IOCTL_MODE_GETENCODER	DRM_IOWR(0xA6, struct drm_mode_get_encoder)
 #define DRM_IOCTL_MODE_GETCONNECTOR	DRM_IOWR(0xA7, struct drm_mode_get_connector)
-#define DRM_IOCTL_MODE_ATTACHMODE	DRM_IOWR(0xA8, struct drm_mode_mode_cmd)
-#define DRM_IOCTL_MODE_DETACHMODE	DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
+#define DRM_IOCTL_MODE_ATTACHMODE	DRM_IOWR(0xA8, struct drm_mode_mode_cmd) /* deprecated (never worked) */
+#define DRM_IOCTL_MODE_DETACHMODE	DRM_IOWR(0xA9, struct drm_mode_mode_cmd) /* deprecated (never worked) */
 
 #define DRM_IOCTL_MODE_GETPROPERTY	DRM_IOWR(0xAA, struct drm_mode_get_property)
 #define DRM_IOCTL_MODE_SETPROPERTY	DRM_IOWR(0xAB, struct drm_mode_connector_set_property)
@@ -778,7 +810,7 @@
 
 /**
  * Device specific ioctls should only be in their respective headers
- * The device specific ioctl range is from 0x40 to 0x99.
+ * The device specific ioctl range is from 0x40 to 0x9f.
  * Generic IOCTLS restart at 0xA0.
  *
  * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
@@ -816,18 +848,6 @@
 	__u32 reserved;
 };
 
-#define DRM_CAP_DUMB_BUFFER 0x1
-#define DRM_CAP_VBLANK_HIGH_CRTC   0x2
-#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
-#define DRM_CAP_DUMB_PREFER_SHADOW 0x4
-#define DRM_CAP_PRIME 0x5
-#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
-#define DRM_CAP_ASYNC_PAGE_FLIP 0x7
-#define DRM_CAP_ADDFB2_MODIFIERS	0x10
-
-#define DRM_PRIME_CAP_IMPORT 0x1
-#define DRM_PRIME_CAP_EXPORT 0x2
-
 /* typedef area */
 typedef struct drm_clip_rect drm_clip_rect_t;
 typedef struct drm_drawable_info drm_drawable_info_t;
@@ -871,4 +891,8 @@
 typedef struct drm_scatter_gather drm_scatter_gather_t;
 typedef struct drm_set_version drm_set_version_t;
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
index e741b09..4d8da69 100644
--- a/include/drm/drm_fourcc.h
+++ b/include/drm/drm_fourcc.h
@@ -24,16 +24,23 @@
 #ifndef DRM_FOURCC_H
 #define DRM_FOURCC_H
 
-#include <inttypes.h>
+#include "drm.h"
 
-#define fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
-			      ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
+#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
+				 ((__u32)(c) << 16) | ((__u32)(d) << 24))
 
 #define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */
 
 /* color index */
 #define DRM_FORMAT_C8		fourcc_code('C', '8', ' ', ' ') /* [7:0] C */
 
+/* 8 bpp Red */
+#define DRM_FORMAT_R8		fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
+
+/* 16 bpp RG */
+#define DRM_FORMAT_RG88		fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
+#define DRM_FORMAT_GR88		fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
+
 /* 8 bpp RGB */
 #define DRM_FORMAT_RGB332	fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
 #define DRM_FORMAT_BGR233	fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */
@@ -106,6 +113,8 @@
 #define DRM_FORMAT_NV21		fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */
 #define DRM_FORMAT_NV16		fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
 #define DRM_FORMAT_NV61		fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
+#define DRM_FORMAT_NV24		fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV42		fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
 
 /*
  * 3 plane YCbCr
@@ -216,7 +225,7 @@
  * - multiple of 128 pixels for the width
  * - multiple of  32 pixels for the height
  *
- * For more information: see http://linuxtv.org/downloads/v4l-dvb-apis/re32.html
+ * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html
  */
 #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE	fourcc_mod_code(SAMSUNG, 1)
 
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 59e67b1..6708e2b 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -27,6 +27,12 @@
 #ifndef _DRM_MODE_H
 #define _DRM_MODE_H
 
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define DRM_DISPLAY_INFO_LEN	32
 #define DRM_CONNECTOR_NAME_LEN	32
 #define DRM_DISPLAY_MODE_LEN	32
@@ -56,6 +62,10 @@
 #define DRM_MODE_FLAG_PIXMUX			(1<<11)
 #define DRM_MODE_FLAG_DBLCLK			(1<<12)
 #define DRM_MODE_FLAG_CLKDIV2			(1<<13)
+ /*
+  * When adding a new stereo mode don't forget to adjust DRM_MODE_FLAGS_3D_MAX
+  * (define not exposed to user space).
+  */
 #define DRM_MODE_FLAG_3D_MASK			(0x1f<<14)
 #define  DRM_MODE_FLAG_3D_NONE			(0<<14)
 #define  DRM_MODE_FLAG_3D_FRAME_PACKING		(1<<14)
@@ -82,6 +92,11 @@
 #define DRM_MODE_SCALE_CENTER		2 /* Centered, no scaling */
 #define DRM_MODE_SCALE_ASPECT		3 /* Full screen, preserve aspect */
 
+/* Picture aspect ratio options */
+#define DRM_MODE_PICTURE_ASPECT_NONE	0
+#define DRM_MODE_PICTURE_ASPECT_4_3	1
+#define DRM_MODE_PICTURE_ASPECT_16_9	2
+
 /* Dithering mode options */
 #define DRM_MODE_DITHERING_OFF	0
 #define DRM_MODE_DITHERING_ON	1
@@ -102,8 +117,16 @@
 
 struct drm_mode_modeinfo {
 	__u32 clock;
-	__u16 hdisplay, hsync_start, hsync_end, htotal, hskew;
-	__u16 vdisplay, vsync_start, vsync_end, vtotal, vscan;
+	__u16 hdisplay;
+	__u16 hsync_start;
+	__u16 hsync_end;
+	__u16 htotal;
+	__u16 hskew;
+	__u16 vdisplay;
+	__u16 vsync_start;
+	__u16 vsync_end;
+	__u16 vtotal;
+	__u16 vscan;
 
 	__u32 vrefresh;
 
@@ -121,8 +144,10 @@
 	__u32 count_crtcs;
 	__u32 count_connectors;
 	__u32 count_encoders;
-	__u32 min_width, max_width;
-	__u32 min_height, max_height;
+	__u32 min_width;
+	__u32 max_width;
+	__u32 min_height;
+	__u32 max_height;
 };
 
 struct drm_mode_crtc {
@@ -132,30 +157,35 @@
 	__u32 crtc_id; /**< Id */
 	__u32 fb_id; /**< Id of framebuffer */
 
-	__u32 x, y; /**< Position on the frameuffer */
+	__u32 x; /**< x Position on the framebuffer */
+	__u32 y; /**< y Position on the framebuffer */
 
 	__u32 gamma_size;
 	__u32 mode_valid;
 	struct drm_mode_modeinfo mode;
 };
 
-#define DRM_MODE_PRESENT_TOP_FIELD     (1<<0)
-#define DRM_MODE_PRESENT_BOTTOM_FIELD  (1<<1)
+#define DRM_MODE_PRESENT_TOP_FIELD	(1<<0)
+#define DRM_MODE_PRESENT_BOTTOM_FIELD	(1<<1)
 
 /* Planes blend with or override other bits on the CRTC */
 struct drm_mode_set_plane {
 	__u32 plane_id;
 	__u32 crtc_id;
 	__u32 fb_id; /* fb object contains surface format type */
-	__u32 flags;
+	__u32 flags; /* see above flags */
 
 	/* Signed dest location allows it to be partially off screen */
-	__s32 crtc_x, crtc_y;
-	__u32 crtc_w, crtc_h;
+	__s32 crtc_x;
+	__s32 crtc_y;
+	__u32 crtc_w;
+	__u32 crtc_h;
 
 	/* Source values are 16.16 fixed point */
-	__u32 src_x, src_y;
-	__u32 src_h, src_w;
+	__u32 src_x;
+	__u32 src_y;
+	__u32 src_h;
+	__u32 src_w;
 };
 
 struct drm_mode_get_plane {
@@ -184,6 +214,7 @@
 #define DRM_MODE_ENCODER_VIRTUAL 5
 #define DRM_MODE_ENCODER_DSI	6
 #define DRM_MODE_ENCODER_DPMST	7
+#define DRM_MODE_ENCODER_DPI	8
 
 struct drm_mode_get_encoder {
 	__u32 encoder_id;
@@ -223,6 +254,7 @@
 #define DRM_MODE_CONNECTOR_eDP		14
 #define DRM_MODE_CONNECTOR_VIRTUAL      15
 #define DRM_MODE_CONNECTOR_DSI		16
+#define DRM_MODE_CONNECTOR_DPI		17
 
 struct drm_mode_get_connector {
 
@@ -241,8 +273,11 @@
 	__u32 connector_type_id;
 
 	__u32 connection;
-	__u32 mm_width, mm_height; /**< HxW in millimeters */
+	__u32 mm_width;  /**< width in millimeters */
+	__u32 mm_height; /**< height in millimeters */
 	__u32 subpixel;
+
+	__u32 pad;
 };
 
 #define DRM_MODE_PROP_PENDING	(1<<0)
@@ -288,6 +323,8 @@
 	char name[DRM_PROP_NAME_LEN];
 
 	__u32 count_values;
+	/* This is only used to count enum values, not blobs. The _blobs is
+	 * simply because of a historical reason, i.e. backwards compat. */
 	__u32 count_enum_blobs;
 };
 
@@ -305,6 +342,7 @@
 #define DRM_MODE_OBJECT_FB 0xfbfbfbfb
 #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
 #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
+#define DRM_MODE_OBJECT_ANY 0
 
 struct drm_mode_obj_get_properties {
 	__u64 props_ptr;
@@ -329,7 +367,8 @@
 
 struct drm_mode_fb_cmd {
 	__u32 fb_id;
-	__u32 width, height;
+	__u32 width;
+	__u32 height;
 	__u32 pitch;
 	__u32 bpp;
 	__u32 depth;
@@ -342,9 +381,10 @@
 
 struct drm_mode_fb_cmd2 {
 	__u32 fb_id;
-	__u32 width, height;
+	__u32 width;
+	__u32 height;
 	__u32 pixel_format; /* fourcc code from drm_fourcc.h */
-	__u32 flags;
+	__u32 flags; /* see above flags */
 
 	/*
 	 * In case of planar formats, this ioctl allows up to 4
@@ -356,9 +396,9 @@
 	 *   followed by an interleaved U/V plane containing
 	 *   8 bit 2x2 subsampled colour difference samples.
 	 *
-	 * So it would consist of Y as offset[0] and UV as
-	 * offset[1].  Note that offset[0] will generally
-	 * be 0.
+	 * So it would consist of Y as offsets[0] and UV as
+	 * offsets[1].  Note that offsets[0] will generally
+	 * be 0 (but this is not required).
 	 *
 	 * To accommodate tiled, compressed, etc formats, a per-plane
 	 * modifier can be specified.  The default value of zero
@@ -377,6 +417,8 @@
 #define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02
 #define DRM_MODE_FB_DIRTY_FLAGS         0x03
 
+#define DRM_MODE_FB_DIRTY_MAX_CLIPS     256
+
 /*
  * Mark a region of a framebuffer as dirty.
  *
@@ -417,20 +459,21 @@
 	struct drm_mode_modeinfo mode;
 };
 
-#define DRM_MODE_CURSOR_BO	(1<<0)
-#define DRM_MODE_CURSOR_MOVE	(1<<1)
+#define DRM_MODE_CURSOR_BO	0x01
+#define DRM_MODE_CURSOR_MOVE	0x02
+#define DRM_MODE_CURSOR_FLAGS	0x03
 
 /*
- * depending on the value in flags diffrent members are used.
+ * depending on the value in flags different members are used.
  *
  * CURSOR_BO uses
- *    crtc
+ *    crtc_id
  *    width
  *    height
- *    handle - if 0 turns the cursor of
+ *    handle - if 0 turns the cursor off
  *
  * CURSOR_MOVE uses
- *    crtc
+ *    crtc_id
  *    x
  *    y
  */
@@ -468,9 +511,30 @@
 	__u64 blue;
 };
 
+struct drm_color_ctm {
+	/* Conversion matrix in S31.32 format. */
+	__s64 matrix[9];
+};
+
+struct drm_color_lut {
+	/*
+	 * Data is U0.16 fixed point format.
+	 */
+	__u16 red;
+	__u16 green;
+	__u16 blue;
+	__u16 reserved;
+};
+
 #define DRM_MODE_PAGE_FLIP_EVENT 0x01
 #define DRM_MODE_PAGE_FLIP_ASYNC 0x02
-#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT|DRM_MODE_PAGE_FLIP_ASYNC)
+#define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4
+#define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8
+#define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \
+				   DRM_MODE_PAGE_FLIP_TARGET_RELATIVE)
+#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \
+				  DRM_MODE_PAGE_FLIP_ASYNC | \
+				  DRM_MODE_PAGE_FLIP_TARGET)
 
 /*
  * Request a page flip on the specified crtc.
@@ -484,14 +548,16 @@
  * flip is already pending as the ioctl is called, EBUSY will be
  * returned.
  *
- * The ioctl supports one flag, DRM_MODE_PAGE_FLIP_EVENT, which will
- * request that drm sends back a vblank event (see drm.h: struct
- * drm_event_vblank) when the page flip is done.  The user_data field
- * passed in with this ioctl will be returned as the user_data field
- * in the vblank event struct.
+ * Flag DRM_MODE_PAGE_FLIP_EVENT requests that drm sends back a vblank
+ * event (see drm.h: struct drm_event_vblank) when the page flip is
+ * done.  The user_data field passed in with this ioctl will be
+ * returned as the user_data field in the vblank event struct.
  *
- * The reserved field must be zero until we figure out something
- * clever to use it for.
+ * Flag DRM_MODE_PAGE_FLIP_ASYNC requests that the flip happen
+ * 'as soon as possible', meaning that it not delay waiting for vblank.
+ * This may cause tearing on the screen.
+ *
+ * The reserved field must be zero.
  */
 
 struct drm_mode_crtc_page_flip {
@@ -502,29 +568,57 @@
 	__u64 user_data;
 };
 
+/*
+ * Request a page flip on the specified crtc.
+ *
+ * Same as struct drm_mode_crtc_page_flip, but supports new flags and
+ * re-purposes the reserved field:
+ *
+ * The sequence field must be zero unless either of the
+ * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is specified. When
+ * the ABSOLUTE flag is specified, the sequence field denotes the absolute
+ * vblank sequence when the flip should take effect. When the RELATIVE
+ * flag is specified, the sequence field denotes the relative (to the
+ * current one when the ioctl is called) vblank sequence when the flip
+ * should take effect. NOTE: DRM_IOCTL_WAIT_VBLANK must still be used to
+ * make sure the vblank sequence before the target one has passed before
+ * calling this ioctl. The purpose of the
+ * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is merely to clarify
+ * the target for when code dealing with a page flip runs during a
+ * vertical blank period.
+ */
+
+struct drm_mode_crtc_page_flip_target {
+	__u32 crtc_id;
+	__u32 fb_id;
+	__u32 flags;
+	__u32 sequence;
+	__u64 user_data;
+};
+
 /* create a dumb scanout buffer */
 struct drm_mode_create_dumb {
-        __u32 height;
-        __u32 width;
-        __u32 bpp;
-        __u32 flags;
-        /* handle, pitch, size will be returned */
-        __u32 handle;
-        __u32 pitch;
-        __u64 size;
+	__u32 height;
+	__u32 width;
+	__u32 bpp;
+	__u32 flags;
+	/* handle, pitch, size will be returned */
+	__u32 handle;
+	__u32 pitch;
+	__u64 size;
 };
 
 /* set up for mmap of a dumb scanout buffer */
 struct drm_mode_map_dumb {
-        /** Handle for the object being mapped. */
-        __u32 handle;
-        __u32 pad;
-        /**
-         * Fake offset to use for subsequent mmap call
-         *
-         * This is a fixed-size type for 32/64 compatibility.
-         */
-        __u64 offset;
+	/** Handle for the object being mapped. */
+	__u32 handle;
+	__u32 pad;
+	/**
+	 * Fake offset to use for subsequent mmap call
+	 *
+	 * This is a fixed-size type for 32/64 compatibility.
+	 */
+	__u64 offset;
 };
 
 struct drm_mode_destroy_dumb {
@@ -532,9 +626,16 @@
 };
 
 /* page-flip flags are valid, plus: */
-#define DRM_MODE_ATOMIC_TEST_ONLY	0x0100
-#define DRM_MODE_ATOMIC_NONBLOCK	0x0200
-#define DRM_MODE_ATOMIC_ALLOW_MODESET	0x0400
+#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100
+#define DRM_MODE_ATOMIC_NONBLOCK  0x0200
+#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400
+
+#define DRM_MODE_ATOMIC_FLAGS (\
+		DRM_MODE_PAGE_FLIP_EVENT |\
+		DRM_MODE_PAGE_FLIP_ASYNC |\
+		DRM_MODE_ATOMIC_TEST_ONLY |\
+		DRM_MODE_ATOMIC_NONBLOCK |\
+		DRM_MODE_ATOMIC_ALLOW_MODESET)
 
 #define DRM_MODE_ATOMIC_FLAGS (\
 		DRM_MODE_PAGE_FLIP_EVENT |\
@@ -574,5 +675,8 @@
 	__u32 blob_id;
 };
 
+#if defined(__cplusplus)
+}
+#endif
 
 #endif
diff --git a/include/drm/drm_sarea.h b/include/drm/drm_sarea.h
index 7325558..502934e 100644
--- a/include/drm/drm_sarea.h
+++ b/include/drm/drm_sarea.h
@@ -37,6 +37,8 @@
 /* SAREA area needs to be at least a page */
 #if defined(__alpha__)
 #define SAREA_MAX                       0x2000U
+#elif defined(__mips__)
+#define SAREA_MAX                       0x4000U
 #elif defined(__ia64__)
 #define SAREA_MAX                       0x10000U	/* 64kB */
 #else
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 0e51d42..5ebe046 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -29,6 +29,10 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* Please note that modifications to all structs defined here are
  * subject to backwards-compatibility constraints.
  */
@@ -58,6 +62,30 @@
 #define I915_ERROR_UEVENT		"ERROR"
 #define I915_RESET_UEVENT		"RESET"
 
+/*
+ * MOCS indexes used for GPU surfaces, defining the cacheability of the
+ * surface data and the coherency for this data wrt. CPU vs. GPU accesses.
+ */
+enum i915_mocs_table_index {
+	/*
+	 * Not cached anywhere, coherency between CPU and GPU accesses is
+	 * guaranteed.
+	 */
+	I915_MOCS_UNCACHED,
+	/*
+	 * Cacheability and coherency controlled by the kernel automatically
+	 * based on the DRM_I915_GEM_SET_CACHING IOCTL setting and the current
+	 * usage of the surface (used for display scanout or not).
+	 */
+	I915_MOCS_PTE,
+	/*
+	 * Cached in all GPU caches available on the platform.
+	 * Coherency between CPU and GPU accesses to the surface is not
+	 * guaranteed without extra synchronization.
+	 */
+	I915_MOCS_CACHED,
+};
+
 /* Each region is a minimum of 16k, and there are at most 255 of them.
  */
 #define I915_NR_TEX_REGIONS 255	/* table size 2k - maximum due to use
@@ -218,6 +246,7 @@
 #define DRM_I915_OVERLAY_PUT_IMAGE	0x27
 #define DRM_I915_OVERLAY_ATTRS	0x28
 #define DRM_I915_GEM_EXECBUFFER2	0x29
+#define DRM_I915_GEM_EXECBUFFER2_WR	DRM_I915_GEM_EXECBUFFER2
 #define DRM_I915_GET_SPRITE_COLORKEY	0x2a
 #define DRM_I915_SET_SPRITE_COLORKEY	0x2b
 #define DRM_I915_GEM_WAIT	0x2c
@@ -230,6 +259,7 @@
 #define DRM_I915_GEM_USERPTR		0x33
 #define DRM_I915_GEM_CONTEXT_GETPARAM	0x34
 #define DRM_I915_GEM_CONTEXT_SETPARAM	0x35
+#define DRM_I915_PERF_OPEN		0x36
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -251,6 +281,7 @@
 #define DRM_IOCTL_I915_GEM_INIT		DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init)
 #define DRM_IOCTL_I915_GEM_EXECBUFFER	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
 #define DRM_IOCTL_I915_GEM_EXECBUFFER2	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2)
+#define DRM_IOCTL_I915_GEM_EXECBUFFER2_WR	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2_WR, struct drm_i915_gem_execbuffer2)
 #define DRM_IOCTL_I915_GEM_PIN		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
 #define DRM_IOCTL_I915_GEM_UNPIN	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
 #define DRM_IOCTL_I915_GEM_BUSY		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
@@ -283,6 +314,7 @@
 #define DRM_IOCTL_I915_GEM_USERPTR			DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr)
 #define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param)
 #define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param)
+#define DRM_IOCTL_I915_PERF_OPEN	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -357,6 +389,28 @@
 #define I915_PARAM_HAS_GPU_RESET	 35
 #define I915_PARAM_HAS_RESOURCE_STREAMER 36
 #define I915_PARAM_HAS_EXEC_SOFTPIN	 37
+#define I915_PARAM_HAS_POOLED_EU	 38
+#define I915_PARAM_MIN_EU_IN_POOL	 39
+#define I915_PARAM_MMAP_GTT_VERSION	 40
+
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports user defined execution
+ * priorities and the driver will attempt to execute batches in priority order.
+ */
+#define I915_PARAM_HAS_SCHEDULER	 41
+#define I915_PARAM_HUC_STATUS		 42
+
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to opt-out of
+ * synchronisation with implicit fencing on individual objects.
+ * See EXEC_OBJECT_ASYNC.
+ */
+#define I915_PARAM_HAS_EXEC_ASYNC	 43
+
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports explicit fence support -
+ * both being able to pass in a sync_file fd to wait upon before executing,
+ * and being able to return a new sync_file fd that is signaled when the
+ * current request is complete. See I915_EXEC_FENCE_IN and I915_EXEC_FENCE_OUT.
+ */
+#define I915_PARAM_HAS_EXEC_FENCE	 44
 
 typedef struct drm_i915_getparam {
 	__s32 param;
@@ -692,15 +746,41 @@
 	 */
 	__u64 offset;
 
-#define EXEC_OBJECT_NEEDS_FENCE (1<<0)
-#define EXEC_OBJECT_NEEDS_GTT	(1<<1)
-#define EXEC_OBJECT_WRITE	(1<<2)
+#define EXEC_OBJECT_NEEDS_FENCE		 (1<<0)
+#define EXEC_OBJECT_NEEDS_GTT		 (1<<1)
+#define EXEC_OBJECT_WRITE		 (1<<2)
 #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
-#define EXEC_OBJECT_PINNED	(1<<4)
-#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_PINNED<<1)
+#define EXEC_OBJECT_PINNED		 (1<<4)
+#define EXEC_OBJECT_PAD_TO_SIZE		 (1<<5)
+/* The kernel implicitly tracks GPU activity on all GEM objects, and
+ * synchronises operations with outstanding rendering. This includes
+ * rendering on other devices if exported via dma-buf. However, sometimes
+ * this tracking is too coarse and the user knows better. For example,
+ * if the object is split into non-overlapping ranges shared between different
+ * clients or engines (i.e. suballocating objects), the implicit tracking
+ * by kernel assumes that each operation affects the whole object rather
+ * than an individual range, causing needless synchronisation between clients.
+ * The kernel will also forgo any CPU cache flushes prior to rendering from
+ * the object as the client is expected to be also handling such domain
+ * tracking.
+ *
+ * The kernel maintains the implicit tracking in order to manage resources
+ * used by the GPU - this flag only disables the synchronisation prior to
+ * rendering with this object in this execbuf.
+ *
+ * Opting out of implicit synhronisation requires the user to do its own
+ * explicit tracking to avoid rendering corruption. See, for example,
+ * I915_PARAM_HAS_EXEC_FENCE to order execbufs and execute them asynchronously.
+ */
+#define EXEC_OBJECT_ASYNC		(1<<6)
+/* All remaining bits are MBZ and RESERVED FOR FUTURE USE */
+#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_ASYNC<<1)
 	__u64 flags;
 
-	__u64 rsvd1;
+	union {
+		__u64 rsvd1;
+		__u64 pad_to_size;
+	};
 	__u64 rsvd2;
 };
 
@@ -772,17 +852,44 @@
 #define I915_EXEC_HANDLE_LUT		(1<<12)
 
 /** Used for switching BSD rings on the platforms with two BSD rings */
-#define I915_EXEC_BSD_MASK		(3<<13)
-#define I915_EXEC_BSD_DEFAULT		(0<<13) /* default ping-pong mode */
-#define I915_EXEC_BSD_RING1		(1<<13)
-#define I915_EXEC_BSD_RING2		(2<<13)
+#define I915_EXEC_BSD_SHIFT	 (13)
+#define I915_EXEC_BSD_MASK	 (3 << I915_EXEC_BSD_SHIFT)
+/* default ping-pong mode */
+#define I915_EXEC_BSD_DEFAULT	 (0 << I915_EXEC_BSD_SHIFT)
+#define I915_EXEC_BSD_RING1	 (1 << I915_EXEC_BSD_SHIFT)
+#define I915_EXEC_BSD_RING2	 (2 << I915_EXEC_BSD_SHIFT)
 
 /** Tell the kernel that the batchbuffer is processed by
  *  the resource streamer.
  */
 #define I915_EXEC_RESOURCE_STREAMER     (1<<15)
 
-#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_RESOURCE_STREAMER<<1)
+/* Setting I915_EXEC_FENCE_IN implies that lower_32_bits(rsvd2) represent
+ * a sync_file fd to wait upon (in a nonblocking manner) prior to executing
+ * the batch.
+ *
+ * Returns -EINVAL if the sync_file fd cannot be found.
+ */
+#define I915_EXEC_FENCE_IN		(1<<16)
+
+/* Setting I915_EXEC_FENCE_OUT causes the ioctl to return a sync_file fd
+ * in the upper_32_bits(rsvd2) upon success. Ownership of the fd is given
+ * to the caller, and it should be close() after use. (The fd is a regular
+ * file descriptor and will be cleaned up on process termination. It holds
+ * a reference to the request, but nothing else.)
+ *
+ * The sync_file fd can be combined with other sync_file and passed either
+ * to execbuf using I915_EXEC_FENCE_IN, to atomic KMS ioctls (so that a flip
+ * will only occur after this request completes), or to other devices.
+ *
+ * Using I915_EXEC_FENCE_OUT requires use of
+ * DRM_IOCTL_I915_GEM_EXECBUFFER2_WR ioctl so that the result is written
+ * back to userspace. Failure to do so will cause the out-fence to always
+ * be reported as zero, and the real fence fd to be leaked.
+ */
+#define I915_EXEC_FENCE_OUT		(1<<17)
+
+#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_OUT<<1))
 
 #define I915_EXEC_CONTEXT_ID_MASK	(0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
@@ -812,10 +919,49 @@
 	/** Handle of the buffer to check for busy */
 	__u32 handle;
 
-	/** Return busy status (1 if busy, 0 if idle).
-	 * The high word is used to indicate on which rings the object
-	 * currently resides:
-	 *  16:31 - busy (r or r/w) rings (16 render, 17 bsd, 18 blt, etc)
+	/** Return busy status
+	 *
+	 * A return of 0 implies that the object is idle (after
+	 * having flushed any pending activity), and a non-zero return that
+	 * the object is still in-flight on the GPU. (The GPU has not yet
+	 * signaled completion for all pending requests that reference the
+	 * object.) An object is guaranteed to become idle eventually (so
+	 * long as no new GPU commands are executed upon it). Due to the
+	 * asynchronous nature of the hardware, an object reported
+	 * as busy may become idle before the ioctl is completed.
+	 *
+	 * Furthermore, if the object is busy, which engine is busy is only
+	 * provided as a guide. There are race conditions which prevent the
+	 * report of which engines are busy from being always accurate.
+	 * However, the converse is not true. If the object is idle, the
+	 * result of the ioctl, that all engines are idle, is accurate.
+	 *
+	 * The returned dword is split into two fields to indicate both
+	 * the engines on which the object is being read, and the
+	 * engine on which it is currently being written (if any).
+	 *
+	 * The low word (bits 0:15) indicate if the object is being written
+	 * to by any engine (there can only be one, as the GEM implicit
+	 * synchronisation rules force writes to be serialised). Only the
+	 * engine for the last write is reported.
+	 *
+	 * The high word (bits 16:31) are a bitmask of which engines are
+	 * currently reading from the object. Multiple engines may be
+	 * reading from the object simultaneously.
+	 *
+	 * The value of each engine is the same as specified in the
+	 * EXECBUFFER2 ioctl, i.e. I915_EXEC_RENDER, I915_EXEC_BSD etc.
+	 * Note I915_EXEC_DEFAULT is a symbolic value and is mapped to
+	 * the I915_EXEC_RENDER engine for execution, and so it is never
+	 * reported as active itself. Some hardware may have parallel
+	 * execution engines, e.g. multiple media engines, which are
+	 * mapped to the same identifier in the EXECBUFFER2 ioctl and
+	 * so are not separately reported for busyness.
+	 *
+	 * Caveat emptor:
+	 * Only the boolean result of this query is reliable; that is whether
+	 * the object is idle or busy. The report of which engines are busy
+	 * should be only used as a heuristic.
 	 */
 	__u32 busy;
 };
@@ -864,6 +1010,7 @@
 #define I915_TILING_NONE	0
 #define I915_TILING_X		1
 #define I915_TILING_Y		2
+#define I915_TILING_LAST	I915_TILING_Y
 
 #define I915_BIT_6_SWIZZLE_NONE		0
 #define I915_BIT_6_SWIZZLE_9		1
@@ -1140,7 +1287,145 @@
 #define I915_CONTEXT_PARAM_BAN_PERIOD	0x1
 #define I915_CONTEXT_PARAM_NO_ZEROMAP	0x2
 #define I915_CONTEXT_PARAM_GTT_SIZE	0x3
+#define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE	0x4
+#define I915_CONTEXT_PARAM_BANNABLE	0x5
 	__u64 value;
 };
 
+enum drm_i915_oa_format {
+	I915_OA_FORMAT_A13 = 1,
+	I915_OA_FORMAT_A29,
+	I915_OA_FORMAT_A13_B8_C8,
+	I915_OA_FORMAT_B4_C8,
+	I915_OA_FORMAT_A45_B8_C8,
+	I915_OA_FORMAT_B4_C8_A16,
+	I915_OA_FORMAT_C4_B8,
+
+	I915_OA_FORMAT_MAX	    /* non-ABI */
+};
+
+enum drm_i915_perf_property_id {
+	/**
+	 * Open the stream for a specific context handle (as used with
+	 * execbuffer2). A stream opened for a specific context this way
+	 * won't typically require root privileges.
+	 */
+	DRM_I915_PERF_PROP_CTX_HANDLE = 1,
+
+	/**
+	 * A value of 1 requests the inclusion of raw OA unit reports as
+	 * part of stream samples.
+	 */
+	DRM_I915_PERF_PROP_SAMPLE_OA,
+
+	/**
+	 * The value specifies which set of OA unit metrics should be
+	 * be configured, defining the contents of any OA unit reports.
+	 */
+	DRM_I915_PERF_PROP_OA_METRICS_SET,
+
+	/**
+	 * The value specifies the size and layout of OA unit reports.
+	 */
+	DRM_I915_PERF_PROP_OA_FORMAT,
+
+	/**
+	 * Specifying this property implicitly requests periodic OA unit
+	 * sampling and (at least on Haswell) the sampling frequency is derived
+	 * from this exponent as follows:
+	 *
+	 *   80ns * 2^(period_exponent + 1)
+	 */
+	DRM_I915_PERF_PROP_OA_EXPONENT,
+
+	DRM_I915_PERF_PROP_MAX /* non-ABI */
+};
+
+struct drm_i915_perf_open_param {
+	__u32 flags;
+#define I915_PERF_FLAG_FD_CLOEXEC	(1<<0)
+#define I915_PERF_FLAG_FD_NONBLOCK	(1<<1)
+#define I915_PERF_FLAG_DISABLED		(1<<2)
+
+	/** The number of u64 (id, value) pairs */
+	__u32 num_properties;
+
+	/**
+	 * Pointer to array of u64 (id, value) pairs configuring the stream
+	 * to open.
+	 */
+	__u64 properties_ptr;
+};
+
+/**
+ * Enable data capture for a stream that was either opened in a disabled state
+ * via I915_PERF_FLAG_DISABLED or was later disabled via
+ * I915_PERF_IOCTL_DISABLE.
+ *
+ * It is intended to be cheaper to disable and enable a stream than it may be
+ * to close and re-open a stream with the same configuration.
+ *
+ * It's undefined whether any pending data for the stream will be lost.
+ */
+#define I915_PERF_IOCTL_ENABLE	_IO('i', 0x0)
+
+/**
+ * Disable data capture for a stream.
+ *
+ * It is an error to try and read a stream that is disabled.
+ */
+#define I915_PERF_IOCTL_DISABLE	_IO('i', 0x1)
+
+/**
+ * Common to all i915 perf records
+ */
+struct drm_i915_perf_record_header {
+	__u32 type;
+	__u16 pad;
+	__u16 size;
+};
+
+enum drm_i915_perf_record_type {
+
+	/**
+	 * Samples are the work horse record type whose contents are extensible
+	 * and defined when opening an i915 perf stream based on the given
+	 * properties.
+	 *
+	 * Boolean properties following the naming convention
+	 * DRM_I915_PERF_SAMPLE_xyz_PROP request the inclusion of 'xyz' data in
+	 * every sample.
+	 *
+	 * The order of these sample properties given by userspace has no
+	 * affect on the ordering of data within a sample. The order is
+	 * documented here.
+	 *
+	 * struct {
+	 *     struct drm_i915_perf_record_header header;
+	 *
+	 *     { u32 oa_report[]; } && DRM_I915_PERF_PROP_SAMPLE_OA
+	 * };
+	 */
+	DRM_I915_PERF_RECORD_SAMPLE = 1,
+
+	/*
+	 * Indicates that one or more OA reports were not written by the
+	 * hardware. This can happen for example if an MI_REPORT_PERF_COUNT
+	 * command collides with periodic sampling - which would be more likely
+	 * at higher sampling frequencies.
+	 */
+	DRM_I915_PERF_RECORD_OA_REPORT_LOST = 2,
+
+	/**
+	 * An error occurred that resulted in all pending OA reports being lost.
+	 */
+	DRM_I915_PERF_RECORD_OA_BUFFER_LOST = 3,
+
+	DRM_I915_PERF_RECORD_MAX /* non-ABI */
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _I915_DRM_H_ */
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index cd31794..f09cc04 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -35,6 +35,10 @@
 
 #include "drm.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the X server file (radeon_sarea.h)
  */
@@ -511,6 +515,7 @@
 #define DRM_RADEON_GEM_BUSY		0x2a
 #define DRM_RADEON_GEM_VA		0x2b
 #define DRM_RADEON_GEM_OP		0x2c
+#define DRM_RADEON_GEM_USERPTR		0x2d
 
 #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
 #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
@@ -554,6 +559,7 @@
 #define DRM_IOCTL_RADEON_GEM_BUSY	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy)
 #define DRM_IOCTL_RADEON_GEM_VA		DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va)
 #define DRM_IOCTL_RADEON_GEM_OP		DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op)
+#define DRM_IOCTL_RADEON_GEM_USERPTR	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_USERPTR, struct drm_radeon_gem_userptr)
 
 typedef struct drm_radeon_init {
 	enum {
@@ -796,7 +802,13 @@
 	uint64_t	vram_visible;
 };
 
-#define RADEON_GEM_NO_BACKING_STORE 1
+#define RADEON_GEM_NO_BACKING_STORE	(1 << 0)
+#define RADEON_GEM_GTT_UC		(1 << 1)
+#define RADEON_GEM_GTT_WC		(1 << 2)
+/* BO is expected to be accessed by the CPU */
+#define RADEON_GEM_CPU_ACCESS		(1 << 3)
+/* CPU access is not expected to work for this BO */
+#define RADEON_GEM_NO_CPU_ACCESS	(1 << 4)
 
 struct drm_radeon_gem_create {
 	uint64_t	size;
@@ -806,6 +818,23 @@
 	uint32_t	flags;
 };
 
+/*
+ * This is not a reliable API and you should expect it to fail for any
+ * number of reasons and have fallback path that do not use userptr to
+ * perform any operation.
+ */
+#define RADEON_GEM_USERPTR_READONLY	(1 << 0)
+#define RADEON_GEM_USERPTR_ANONONLY	(1 << 1)
+#define RADEON_GEM_USERPTR_VALIDATE	(1 << 2)
+#define RADEON_GEM_USERPTR_REGISTER	(1 << 3)
+
+struct drm_radeon_gem_userptr {
+	uint64_t		addr;
+	uint64_t		size;
+	uint32_t		flags;
+	uint32_t		handle;
+};
+
 #define RADEON_TILING_MACRO				0x1
 #define RADEON_TILING_MICRO				0x2
 #define RADEON_TILING_SWAP_16BIT			0x4
@@ -943,6 +972,7 @@
 };
 
 /* drm_radeon_cs_reloc.flags */
+#define RADEON_RELOC_PRIO_MASK		(0xf << 0)
 
 struct drm_radeon_cs_reloc {
 	uint32_t		handle;
@@ -1008,7 +1038,13 @@
 #define RADEON_INFO_NUM_BYTES_MOVED	0x1d
 #define RADEON_INFO_VRAM_USAGE		0x1e
 #define RADEON_INFO_GTT_USAGE		0x1f
-
+#define RADEON_INFO_ACTIVE_CU_COUNT	0x20
+#define RADEON_INFO_CURRENT_GPU_TEMP	0x21
+#define RADEON_INFO_CURRENT_GPU_SCLK	0x22
+#define RADEON_INFO_CURRENT_GPU_MCLK	0x23
+#define RADEON_INFO_READ_REG		0x24
+#define RADEON_INFO_VA_UNMAP_WORKING	0x25
+#define RADEON_INFO_GPU_RESET_COUNTER	0x26
 
 struct drm_radeon_info {
 	uint32_t		request;
@@ -1034,13 +1070,10 @@
 #define SI_TILE_MODE_DEPTH_STENCIL_2D_4AA	3
 #define SI_TILE_MODE_DEPTH_STENCIL_2D_8AA	2
 
-#define CIK_TILE_MODE_COLOR_2D			14
-#define CIK_TILE_MODE_COLOR_2D_SCANOUT		10
-#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_64       0
-#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_128      1
-#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_256      2
-#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_512      3
-#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_ROW_SIZE 4
 #define CIK_TILE_MODE_DEPTH_STENCIL_1D		5
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/include/drm/vc4_drm.h b/include/drm/vc4_drm.h
new file mode 100644
index 0000000..319881d
--- /dev/null
+++ b/include/drm/vc4_drm.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2014-2015 Broadcom
+ *
+ * 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 _VC4_DRM_H_
+#define _VC4_DRM_H_
+
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define DRM_VC4_SUBMIT_CL                         0x00
+#define DRM_VC4_WAIT_SEQNO                        0x01
+#define DRM_VC4_WAIT_BO                           0x02
+#define DRM_VC4_CREATE_BO                         0x03
+#define DRM_VC4_MMAP_BO                           0x04
+#define DRM_VC4_CREATE_SHADER_BO                  0x05
+#define DRM_VC4_GET_HANG_STATE                    0x06
+#define DRM_VC4_GET_PARAM                         0x07
+
+#define DRM_IOCTL_VC4_SUBMIT_CL           DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
+#define DRM_IOCTL_VC4_WAIT_SEQNO          DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
+#define DRM_IOCTL_VC4_WAIT_BO             DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
+#define DRM_IOCTL_VC4_CREATE_BO           DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
+#define DRM_IOCTL_VC4_MMAP_BO             DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
+#define DRM_IOCTL_VC4_CREATE_SHADER_BO    DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
+#define DRM_IOCTL_VC4_GET_HANG_STATE      DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
+#define DRM_IOCTL_VC4_GET_PARAM           DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_PARAM, struct drm_vc4_get_param)
+
+struct drm_vc4_submit_rcl_surface {
+	__u32 hindex; /* Handle index, or ~0 if not present. */
+	__u32 offset; /* Offset to start of buffer. */
+	/*
+	 * Bits for either render config (color_write) or load/store packet.
+	 * Bits should all be 0 for MSAA load/stores.
+	 */
+	__u16 bits;
+
+#define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES		(1 << 0)
+	__u16 flags;
+};
+
+/**
+ * struct drm_vc4_submit_cl - ioctl argument for submitting commands to the 3D
+ * engine.
+ *
+ * Drivers typically use GPU BOs to store batchbuffers / command lists and
+ * their associated state.  However, because the VC4 lacks an MMU, we have to
+ * do validation of memory accesses by the GPU commands.  If we were to store
+ * our commands in BOs, we'd need to do uncached readback from them to do the
+ * validation process, which is too expensive.  Instead, userspace accumulates
+ * commands and associated state in plain memory, then the kernel copies the
+ * data to its own address space, and then validates and stores it in a GPU
+ * BO.
+ */
+struct drm_vc4_submit_cl {
+	/* Pointer to the binner command list.
+	 *
+	 * This is the first set of commands executed, which runs the
+	 * coordinate shader to determine where primitives land on the screen,
+	 * then writes out the state updates and draw calls necessary per tile
+	 * to the tile allocation BO.
+	 */
+	__u64 bin_cl;
+
+	/* Pointer to the shader records.
+	 *
+	 * Shader records are the structures read by the hardware that contain
+	 * pointers to uniforms, shaders, and vertex attributes.  The
+	 * reference to the shader record has enough information to determine
+	 * how many pointers are necessary (fixed number for shaders/uniforms,
+	 * and an attribute count), so those BO indices into bo_handles are
+	 * just stored as __u32s before each shader record passed in.
+	 */
+	__u64 shader_rec;
+
+	/* Pointer to uniform data and texture handles for the textures
+	 * referenced by the shader.
+	 *
+	 * For each shader state record, there is a set of uniform data in the
+	 * order referenced by the record (FS, VS, then CS).  Each set of
+	 * uniform data has a __u32 index into bo_handles per texture
+	 * sample operation, in the order the QPU_W_TMUn_S writes appear in
+	 * the program.  Following the texture BO handle indices is the actual
+	 * uniform data.
+	 *
+	 * The individual uniform state blocks don't have sizes passed in,
+	 * because the kernel has to determine the sizes anyway during shader
+	 * code validation.
+	 */
+	__u64 uniforms;
+	__u64 bo_handles;
+
+	/* Size in bytes of the binner command list. */
+	__u32 bin_cl_size;
+	/* Size in bytes of the set of shader records. */
+	__u32 shader_rec_size;
+	/* Number of shader records.
+	 *
+	 * This could just be computed from the contents of shader_records and
+	 * the address bits of references to them from the bin CL, but it
+	 * keeps the kernel from having to resize some allocations it makes.
+	 */
+	__u32 shader_rec_count;
+	/* Size in bytes of the uniform state. */
+	__u32 uniforms_size;
+
+	/* Number of BO handles passed in (size is that times 4). */
+	__u32 bo_handle_count;
+
+	/* RCL setup: */
+	__u16 width;
+	__u16 height;
+	__u8 min_x_tile;
+	__u8 min_y_tile;
+	__u8 max_x_tile;
+	__u8 max_y_tile;
+	struct drm_vc4_submit_rcl_surface color_read;
+	struct drm_vc4_submit_rcl_surface color_write;
+	struct drm_vc4_submit_rcl_surface zs_read;
+	struct drm_vc4_submit_rcl_surface zs_write;
+	struct drm_vc4_submit_rcl_surface msaa_color_write;
+	struct drm_vc4_submit_rcl_surface msaa_zs_write;
+	__u32 clear_color[2];
+	__u32 clear_z;
+	__u8 clear_s;
+
+	__u32 pad:24;
+
+#define VC4_SUBMIT_CL_USE_CLEAR_COLOR			(1 << 0)
+	__u32 flags;
+
+	/* Returned value of the seqno of this render job (for the
+	 * wait ioctl).
+	 */
+	__u64 seqno;
+};
+
+/**
+ * struct drm_vc4_wait_seqno - ioctl argument for waiting for
+ * DRM_VC4_SUBMIT_CL completion using its returned seqno.
+ *
+ * timeout_ns is the timeout in nanoseconds, where "0" means "don't
+ * block, just return the status."
+ */
+struct drm_vc4_wait_seqno {
+	__u64 seqno;
+	__u64 timeout_ns;
+};
+
+/**
+ * struct drm_vc4_wait_bo - ioctl argument for waiting for
+ * completion of the last DRM_VC4_SUBMIT_CL on a BO.
+ *
+ * This is useful for cases where multiple processes might be
+ * rendering to a BO and you want to wait for all rendering to be
+ * completed.
+ */
+struct drm_vc4_wait_bo {
+	__u32 handle;
+	__u32 pad;
+	__u64 timeout_ns;
+};
+
+/**
+ * struct drm_vc4_create_bo - ioctl argument for creating VC4 BOs.
+ *
+ * There are currently no values for the flags argument, but it may be
+ * used in a future extension.
+ */
+struct drm_vc4_create_bo {
+	__u32 size;
+	__u32 flags;
+	/** Returned GEM handle for the BO. */
+	__u32 handle;
+	__u32 pad;
+};
+
+/**
+ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
+ *
+ * This doesn't actually perform an mmap.  Instead, it returns the
+ * offset you need to use in an mmap on the DRM device node.  This
+ * means that tools like valgrind end up knowing about the mapped
+ * memory.
+ *
+ * There are currently no values for the flags argument, but it may be
+ * used in a future extension.
+ */
+struct drm_vc4_mmap_bo {
+	/** Handle for the object being mapped. */
+	__u32 handle;
+	__u32 flags;
+	/** offset into the drm node to use for subsequent mmap call. */
+	__u64 offset;
+};
+
+/**
+ * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4
+ * shader BOs.
+ *
+ * Since allowing a shader to be overwritten while it's also being
+ * executed from would allow privlege escalation, shaders must be
+ * created using this ioctl, and they can't be mmapped later.
+ */
+struct drm_vc4_create_shader_bo {
+	/* Size of the data argument. */
+	__u32 size;
+	/* Flags, currently must be 0. */
+	__u32 flags;
+
+	/* Pointer to the data. */
+	__u64 data;
+
+	/** Returned GEM handle for the BO. */
+	__u32 handle;
+	/* Pad, must be 0. */
+	__u32 pad;
+};
+
+struct drm_vc4_get_hang_state_bo {
+	__u32 handle;
+	__u32 paddr;
+	__u32 size;
+	__u32 pad;
+};
+
+/**
+ * struct drm_vc4_hang_state - ioctl argument for collecting state
+ * from a GPU hang for analysis.
+*/
+struct drm_vc4_get_hang_state {
+	/** Pointer to array of struct drm_vc4_get_hang_state_bo. */
+	__u64 bo;
+	/**
+	 * On input, the size of the bo array.  Output is the number
+	 * of bos to be returned.
+	 */
+	__u32 bo_count;
+
+	__u32 start_bin, start_render;
+
+	__u32 ct0ca, ct0ea;
+	__u32 ct1ca, ct1ea;
+	__u32 ct0cs, ct1cs;
+	__u32 ct0ra0, ct1ra0;
+
+	__u32 bpca, bpcs;
+	__u32 bpoa, bpos;
+
+	__u32 vpmbase;
+
+	__u32 dbge;
+	__u32 fdbgo;
+	__u32 fdbgb;
+	__u32 fdbgr;
+	__u32 fdbgs;
+	__u32 errstat;
+
+	/* Pad that we may save more registers into in the future. */
+	__u32 pad[16];
+};
+
+#define DRM_VC4_PARAM_V3D_IDENT0		0
+#define DRM_VC4_PARAM_V3D_IDENT1		1
+#define DRM_VC4_PARAM_V3D_IDENT2		2
+#define DRM_VC4_PARAM_SUPPORTS_BRANCHES		3
+#define DRM_VC4_PARAM_SUPPORTS_ETC1		4
+#define DRM_VC4_PARAM_SUPPORTS_THREADED_FS	5
+
+struct drm_vc4_get_param {
+	__u32 param;
+	__u32 pad;
+	__u64 value;
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _VC4_DRM_H_ */
diff --git a/include/drm/virtgpu_drm.h b/include/drm/virtgpu_drm.h
index abf11c5..91a31ff 100644
--- a/include/drm/virtgpu_drm.h
+++ b/include/drm/virtgpu_drm.h
@@ -24,13 +24,16 @@
 #ifndef VIRTGPU_DRM_H
 #define VIRTGPU_DRM_H
 
-#include <stddef.h>
-#include "drm/drm.h"
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
 
 /* Please note that modifications to all structs defined here are
  * subject to backwards-compatibility constraints.
  *
- * Do not use pointers, use uint64_t instead for 32 bit / 64 bit user/kernel
+ * Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel
  * compatibility Keep fields aligned to their size
  */
 
@@ -45,88 +48,88 @@
 #define DRM_VIRTGPU_GET_CAPS  0x09
 
 struct drm_virtgpu_map {
-	uint64_t offset; /* use for mmap system call */
-	uint32_t handle;
-	uint32_t pad;
+	__u64 offset; /* use for mmap system call */
+	__u32 handle;
+	__u32 pad;
 };
 
 struct drm_virtgpu_execbuffer {
-	uint32_t flags;		/* for future use */
-	uint32_t size;
-	uint64_t command; /* void* */
-	uint64_t bo_handles;
-	uint32_t num_bo_handles;
-	uint32_t pad;
+	__u32		flags;		/* for future use */
+	__u32 size;
+	__u64 command; /* void* */
+	__u64 bo_handles;
+	__u32 num_bo_handles;
+	__u32 pad;
 };
 
 #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
 
 struct drm_virtgpu_getparam {
-	uint64_t param;
-	uint64_t value;
+	__u64 param;
+	__u64 value;
 };
 
 /* NO_BO flags? NO resource flag? */
 /* resource flag for y_0_top */
 struct drm_virtgpu_resource_create {
-	uint32_t target;
-	uint32_t format;
-	uint32_t bind;
-	uint32_t width;
-	uint32_t height;
-	uint32_t depth;
-	uint32_t array_size;
-	uint32_t last_level;
-	uint32_t nr_samples;
-	uint32_t flags;
-	uint32_t bo_handle; /* if this is set - recreate a new resource attached to this bo ? */
-	uint32_t res_handle;  /* returned by kernel */
-	uint32_t size;        /* validate transfer in the host */
-	uint32_t stride;      /* validate transfer in the host */
+	__u32 target;
+	__u32 format;
+	__u32 bind;
+	__u32 width;
+	__u32 height;
+	__u32 depth;
+	__u32 array_size;
+	__u32 last_level;
+	__u32 nr_samples;
+	__u32 flags;
+	__u32 bo_handle; /* if this is set - recreate a new resource attached to this bo ? */
+	__u32 res_handle;  /* returned by kernel */
+	__u32 size;        /* validate transfer in the host */
+	__u32 stride;      /* validate transfer in the host */
 };
 
 struct drm_virtgpu_resource_info {
-	uint32_t bo_handle;
-	uint32_t res_handle;
-	uint32_t size;
-	uint32_t stride;
+	__u32 bo_handle;
+	__u32 res_handle;
+	__u32 size;
+	__u32 stride;
 };
 
 struct drm_virtgpu_3d_box {
-	uint32_t x;
-	uint32_t y;
-	uint32_t z;
-	uint32_t w;
-	uint32_t h;
-	uint32_t d;
+	__u32 x;
+	__u32 y;
+	__u32 z;
+	__u32 w;
+	__u32 h;
+	__u32 d;
 };
 
 struct drm_virtgpu_3d_transfer_to_host {
-	uint32_t bo_handle;
+	__u32 bo_handle;
 	struct drm_virtgpu_3d_box box;
-	uint32_t level;
-	uint32_t offset;
+	__u32 level;
+	__u32 offset;
 };
 
 struct drm_virtgpu_3d_transfer_from_host {
-	uint32_t bo_handle;
+	__u32 bo_handle;
 	struct drm_virtgpu_3d_box box;
-	uint32_t level;
-	uint32_t offset;
+	__u32 level;
+	__u32 offset;
 };
 
 #define VIRTGPU_WAIT_NOWAIT 1 /* like it */
 struct drm_virtgpu_3d_wait {
-	uint32_t handle; /* 0 is an invalid handle */
-	uint32_t flags;
+	__u32 handle; /* 0 is an invalid handle */
+	__u32 flags;
 };
 
 struct drm_virtgpu_get_caps {
-	uint32_t cap_set_id;
-	uint32_t cap_set_ver;
-	uint64_t addr;
-	uint32_t size;
-	uint32_t pad;
+	__u32 cap_set_id;
+	__u32 cap_set_ver;
+	__u64 addr;
+	__u32 size;
+	__u32 pad;
 };
 
 #define DRM_IOCTL_VIRTGPU_MAP \
@@ -164,4 +167,8 @@
 	DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GET_CAPS, \
 	struct drm_virtgpu_get_caps)
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h
index 4d08423..5b68b4d 100644
--- a/include/drm/vmwgfx_drm.h
+++ b/include/drm/vmwgfx_drm.h
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -28,10 +28,11 @@
 #ifndef __VMWGFX_DRM_H__
 #define __VMWGFX_DRM_H__
 
+#include "drm.h"
+
 #define DRM_VMW_MAX_SURFACE_FACES 6
 #define DRM_VMW_MAX_MIP_LEVELS 24
 
-#define DRM_VMW_EXT_NAME_LEN 128
 
 #define DRM_VMW_GET_PARAM            0
 #define DRM_VMW_ALLOC_DMABUF         1
@@ -48,11 +49,20 @@
 #define DRM_VMW_UNREF_SURFACE        10
 #define DRM_VMW_REF_SURFACE          11
 #define DRM_VMW_EXECBUF              12
-#define DRM_VMW_FIFO_DEBUG           13
+#define DRM_VMW_GET_3D_CAP           13
 #define DRM_VMW_FENCE_WAIT           14
-/* guarded by minor version >= 2 */
-#define DRM_VMW_UPDATE_LAYOUT        15
-
+#define DRM_VMW_FENCE_SIGNALED       15
+#define DRM_VMW_FENCE_UNREF          16
+#define DRM_VMW_FENCE_EVENT          17
+#define DRM_VMW_PRESENT              18
+#define DRM_VMW_PRESENT_READBACK     19
+#define DRM_VMW_UPDATE_LAYOUT        20
+#define DRM_VMW_CREATE_SHADER        21
+#define DRM_VMW_UNREF_SHADER         22
+#define DRM_VMW_GB_SURFACE_CREATE    23
+#define DRM_VMW_GB_SURFACE_REF       24
+#define DRM_VMW_SYNCCPU              25
+#define DRM_VMW_CREATE_EXTENDED_CONTEXT 26
 
 /*************************************************************************/
 /**
@@ -69,9 +79,25 @@
 #define DRM_VMW_PARAM_NUM_STREAMS      0
 #define DRM_VMW_PARAM_NUM_FREE_STREAMS 1
 #define DRM_VMW_PARAM_3D               2
-#define DRM_VMW_PARAM_FIFO_OFFSET      3
-#define DRM_VMW_PARAM_HW_CAPS          4
-#define DRM_VMW_PARAM_FIFO_CAPS        5
+#define DRM_VMW_PARAM_HW_CAPS          3
+#define DRM_VMW_PARAM_FIFO_CAPS        4
+#define DRM_VMW_PARAM_MAX_FB_SIZE      5
+#define DRM_VMW_PARAM_FIFO_HW_VERSION  6
+#define DRM_VMW_PARAM_MAX_SURF_MEMORY  7
+#define DRM_VMW_PARAM_3D_CAPS_SIZE     8
+#define DRM_VMW_PARAM_MAX_MOB_MEMORY   9
+#define DRM_VMW_PARAM_MAX_MOB_SIZE     10
+#define DRM_VMW_PARAM_SCREEN_TARGET    11
+#define DRM_VMW_PARAM_DX               12
+
+/**
+ * enum drm_vmw_handle_type - handle type for ref ioctls
+ *
+ */
+enum drm_vmw_handle_type {
+	DRM_VMW_HANDLE_LEGACY = 0,
+	DRM_VMW_HANDLE_PRIME = 1
+};
 
 /**
  * struct drm_vmw_getparam_arg
@@ -83,52 +109,9 @@
  */
 
 struct drm_vmw_getparam_arg {
-	uint64_t value;
-	uint32_t param;
-	uint32_t pad64;
-};
-
-/*************************************************************************/
-/**
- * DRM_VMW_EXTENSION - Query device extensions.
- */
-
-/**
- * struct drm_vmw_extension_rep
- *
- * @exists: The queried extension exists.
- * @driver_ioctl_offset: Ioctl number of the first ioctl in the extension.
- * @driver_sarea_offset: Offset to any space in the DRI SAREA
- * used by the extension.
- * @major: Major version number of the extension.
- * @minor: Minor version number of the extension.
- * @pl: Patch level version number of the extension.
- *
- * Output argument to the DRM_VMW_EXTENSION Ioctl.
- */
-
-struct drm_vmw_extension_rep {
-	int32_t exists;
-	uint32_t driver_ioctl_offset;
-	uint32_t driver_sarea_offset;
-	uint32_t major;
-	uint32_t minor;
-	uint32_t pl;
-	uint32_t pad64;
-};
-
-/**
- * union drm_vmw_extension_arg
- *
- * @extension - Ascii name of the extension to be queried. //In
- * @rep - Reply as defined above. //Out
- *
- * Argument to the DRM_VMW_EXTENSION Ioctl.
- */
-
-union drm_vmw_extension_arg {
-	char extension[DRM_VMW_EXT_NAME_LEN];
-	struct drm_vmw_extension_rep rep;
+	__u64 value;
+	__u32 param;
+	__u32 pad64;
 };
 
 /*************************************************************************/
@@ -149,8 +132,8 @@
  */
 
 struct drm_vmw_context_arg {
-	int32_t cid;
-	uint32_t pad64;
+	__s32 cid;
+	__u32 pad64;
 };
 
 /*************************************************************************/
@@ -180,7 +163,7 @@
  * @mip_levels: Number of mip levels for each face.
  * An unused face should have 0 encoded.
  * @size_addr: Address of a user-space array of sruct drm_vmw_size
- * cast to an uint64_t for 32-64 bit compatibility.
+ * cast to an __u64 for 32-64 bit compatibility.
  * The size of the array should equal the total number of mipmap levels.
  * @shareable: Boolean whether other clients (as identified by file descriptors)
  * may reference this surface.
@@ -192,18 +175,19 @@
  */
 
 struct drm_vmw_surface_create_req {
-	uint32_t flags;
-	uint32_t format;
-	uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES];
-	uint64_t size_addr;
-	int32_t shareable;
-	int32_t scanout;
+	__u32 flags;
+	__u32 format;
+	__u32 mip_levels[DRM_VMW_MAX_SURFACE_FACES];
+	__u64 size_addr;
+	__s32 shareable;
+	__s32 scanout;
 };
 
 /**
  * struct drm_wmv_surface_arg
  *
  * @sid: Surface id of created surface or surface to destroy or reference.
+ * @handle_type: Handle type for DRM_VMW_REF_SURFACE Ioctl.
  *
  * Output data from the DRM_VMW_CREATE_SURFACE Ioctl.
  * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl.
@@ -211,8 +195,8 @@
  */
 
 struct drm_vmw_surface_arg {
-	int32_t sid;
-	uint32_t pad64;
+	__s32 sid;
+	enum drm_vmw_handle_type handle_type;
 };
 
 /**
@@ -227,10 +211,10 @@
  */
 
 struct drm_vmw_size {
-	uint32_t width;
-	uint32_t height;
-	uint32_t depth;
-	uint32_t pad64;
+	__u32 width;
+	__u32 height;
+	__u32 depth;
+	__u32 pad64;
 };
 
 /**
@@ -291,20 +275,20 @@
  * DRM_VMW_EXECBUF
  *
  * Submit a command buffer for execution on the host, and return a
- * fence sequence that when signaled, indicates that the command buffer has
+ * fence seqno that when signaled, indicates that the command buffer has
  * executed.
  */
 
 /**
  * struct drm_vmw_execbuf_arg
  *
- * @commands: User-space address of a command buffer cast to an uint64_t.
+ * @commands: User-space address of a command buffer cast to an __u64.
  * @command-size: Size in bytes of the command buffer.
  * @throttle-us: Sleep until software is less than @throttle_us
  * microseconds ahead of hardware. The driver may round this value
  * to the nearest kernel tick.
  * @fence_rep: User-space address of a struct drm_vmw_fence_rep cast to an
- * uint64_t.
+ * __u64.
  * @version: Allows expanding the execbuf ioctl parameters without breaking
  * backwards compatibility, since user-space will always tell the kernel
  * which version it uses.
@@ -313,21 +297,32 @@
  * Argument to the DRM_VMW_EXECBUF Ioctl.
  */
 
-#define DRM_VMW_EXECBUF_VERSION 0
+#define DRM_VMW_EXECBUF_VERSION 2
 
 struct drm_vmw_execbuf_arg {
-	uint64_t commands;
-	uint32_t command_size;
-	uint32_t throttle_us;
-	uint64_t fence_rep;
-	 uint32_t version;
-	 uint32_t flags;
+	__u64 commands;
+	__u32 command_size;
+	__u32 throttle_us;
+	__u64 fence_rep;
+	__u32 version;
+	__u32 flags;
+	__u32 context_handle;
+	__u32 pad64;
 };
 
 /**
  * struct drm_vmw_fence_rep
  *
- * @fence_seq: Fence sequence associated with a command submission.
+ * @handle: Fence object handle for fence associated with a command submission.
+ * @mask: Fence flags relevant for this fence object.
+ * @seqno: Fence sequence number in fifo. A fence object with a lower
+ * seqno will signal the EXEC flag before a fence object with a higher
+ * seqno. This can be used by user-space to avoid kernel calls to determine
+ * whether a fence has signaled the EXEC flag. Note that @seqno will
+ * wrap at 32-bit.
+ * @passed_seqno: The highest seqno number processed by the hardware
+ * so far. This can be used to mark user-space fence objects as signaled, and
+ * to determine whether a fence seqno might be stale.
  * @error: This member should've been set to -EFAULT on submission.
  * The following actions should be take on completion:
  * error == -EFAULT: Fence communication failed. The host is synchronized.
@@ -341,9 +336,12 @@
  */
 
 struct drm_vmw_fence_rep {
-	uint64_t fence_seq;
-	int32_t error;
-	uint32_t pad64;
+	__u32 handle;
+	__u32 mask;
+	__u32 seqno;
+	__u32 passed_seqno;
+	__u32 pad64;
+	__s32 error;
 };
 
 /*************************************************************************/
@@ -373,8 +371,8 @@
  */
 
 struct drm_vmw_alloc_dmabuf_req {
-	uint32_t size;
-	uint32_t pad64;
+	__u32 size;
+	__u32 pad64;
 };
 
 /**
@@ -391,11 +389,11 @@
  */
 
 struct drm_vmw_dmabuf_rep {
-	uint64_t map_handle;
-	uint32_t handle;
-	uint32_t cur_gmr_id;
-	uint32_t cur_gmr_offset;
-	uint32_t pad64;
+	__u64 map_handle;
+	__u32 handle;
+	__u32 cur_gmr_id;
+	__u32 cur_gmr_offset;
+	__u32 pad64;
 };
 
 /**
@@ -428,41 +426,8 @@
  */
 
 struct drm_vmw_unref_dmabuf_arg {
-	uint32_t handle;
-	uint32_t pad64;
-};
-
-/*************************************************************************/
-/**
- * DRM_VMW_FIFO_DEBUG - Get last FIFO submission.
- *
- * This IOCTL copies the last FIFO submission directly out of the FIFO buffer.
- */
-
-/**
- * struct drm_vmw_fifo_debug_arg
- *
- * @debug_buffer: User space address of a debug_buffer cast to an uint64_t //In
- * @debug_buffer_size: Size in bytes of debug buffer //In
- * @used_size: Number of bytes copied to the buffer // Out
- * @did_not_fit: Boolean indicating that the fifo contents did not fit. //Out
- *
- * Argument to the DRM_VMW_FIFO_DEBUG Ioctl.
- */
-
-struct drm_vmw_fifo_debug_arg {
-	uint64_t debug_buffer;
-	uint32_t debug_buffer_size;
-	uint32_t used_size;
-	int32_t did_not_fit;
-	uint32_t pad64;
-};
-
-struct drm_vmw_fence_wait_arg {
-	uint64_t sequence;
-	uint64_t kernel_cookie;
-	int32_t cookie_valid;
-	int32_t pad64;
+	__u32 handle;
+	__u32 pad64;
 };
 
 /*************************************************************************/
@@ -485,10 +450,10 @@
  */
 
 struct drm_vmw_rect {
-	int32_t x;
-	int32_t y;
-	uint32_t w;
-	uint32_t h;
+	__s32 x;
+	__s32 y;
+	__u32 w;
+	__u32 h;
 };
 
 /**
@@ -510,21 +475,21 @@
  */
 
 struct drm_vmw_control_stream_arg {
-	uint32_t stream_id;
-	uint32_t enabled;
+	__u32 stream_id;
+	__u32 enabled;
 
-	uint32_t flags;
-	uint32_t color_key;
+	__u32 flags;
+	__u32 color_key;
 
-	uint32_t handle;
-	uint32_t offset;
-	int32_t format;
-	uint32_t size;
-	uint32_t width;
-	uint32_t height;
-	uint32_t pitch[3];
+	__u32 handle;
+	__u32 offset;
+	__s32 format;
+	__u32 size;
+	__u32 width;
+	__u32 height;
+	__u32 pitch[3];
 
-	uint32_t pad64;
+	__u32 pad64;
 	struct drm_vmw_rect src;
 	struct drm_vmw_rect dst;
 };
@@ -552,12 +517,12 @@
  */
 
 struct drm_vmw_cursor_bypass_arg {
-	uint32_t flags;
-	uint32_t crtc_id;
-	int32_t xpos;
-	int32_t ypos;
-	int32_t xhot;
-	int32_t yhot;
+	__u32 flags;
+	__u32 crtc_id;
+	__s32 xpos;
+	__s32 ypos;
+	__s32 xhot;
+	__s32 yhot;
 };
 
 /*************************************************************************/
@@ -575,8 +540,8 @@
  */
 
 struct drm_vmw_stream_arg {
-	uint32_t stream_id;
-	uint32_t pad64;
+	__u32 stream_id;
+	__u32 pad64;
 };
 
 /*************************************************************************/
@@ -589,26 +554,537 @@
 
 /*************************************************************************/
 /**
+ * DRM_VMW_GET_3D_CAP
+ *
+ * Read 3D capabilities from the FIFO
+ *
+ */
+
+/**
+ * struct drm_vmw_get_3d_cap_arg
+ *
+ * @buffer: Pointer to a buffer for capability data, cast to an __u64
+ * @size: Max size to copy
+ *
+ * Input argument to the DRM_VMW_GET_3D_CAP_IOCTL
+ * ioctls.
+ */
+
+struct drm_vmw_get_3d_cap_arg {
+	__u64 buffer;
+	__u32 max_size;
+	__u32 pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_WAIT
+ *
+ * Waits for a fence object to signal. The wait is interruptible, so that
+ * signals may be delivered during the interrupt. The wait may timeout,
+ * in which case the calls returns -EBUSY. If the wait is restarted,
+ * that is restarting without resetting @cookie_valid to zero,
+ * the timeout is computed from the first call.
+ *
+ * The flags argument to the DRM_VMW_FENCE_WAIT ioctl indicates what to wait
+ * on:
+ * DRM_VMW_FENCE_FLAG_EXEC: All commands ahead of the fence in the command
+ * stream
+ * have executed.
+ * DRM_VMW_FENCE_FLAG_QUERY: All query results resulting from query finish
+ * commands
+ * in the buffer given to the EXECBUF ioctl returning the fence object handle
+ * are available to user-space.
+ *
+ * DRM_VMW_WAIT_OPTION_UNREF: If this wait option is given, and the
+ * fenc wait ioctl returns 0, the fence object has been unreferenced after
+ * the wait.
+ */
+
+#define DRM_VMW_FENCE_FLAG_EXEC   (1 << 0)
+#define DRM_VMW_FENCE_FLAG_QUERY  (1 << 1)
+
+#define DRM_VMW_WAIT_OPTION_UNREF (1 << 0)
+
+/**
+ * struct drm_vmw_fence_wait_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ * @cookie_valid: Must be reset to 0 on first call. Left alone on restart.
+ * @kernel_cookie: Set to 0 on first call. Left alone on restart.
+ * @timeout_us: Wait timeout in microseconds. 0 for indefinite timeout.
+ * @lazy: Set to 1 if timing is not critical. Allow more than a kernel tick
+ * before returning.
+ * @flags: Fence flags to wait on.
+ * @wait_options: Options that control the behaviour of the wait ioctl.
+ *
+ * Input argument to the DRM_VMW_FENCE_WAIT ioctl.
+ */
+
+struct drm_vmw_fence_wait_arg {
+	__u32 handle;
+	__s32  cookie_valid;
+	__u64 kernel_cookie;
+	__u64 timeout_us;
+	__s32 lazy;
+	__s32 flags;
+	__s32 wait_options;
+	__s32 pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_SIGNALED
+ *
+ * Checks if a fence object is signaled..
+ */
+
+/**
+ * struct drm_vmw_fence_signaled_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ * @flags: Fence object flags input to DRM_VMW_FENCE_SIGNALED ioctl
+ * @signaled: Out: Flags signaled.
+ * @sequence: Out: Highest sequence passed so far. Can be used to signal the
+ * EXEC flag of user-space fence objects.
+ *
+ * Input/Output argument to the DRM_VMW_FENCE_SIGNALED and DRM_VMW_FENCE_UNREF
+ * ioctls.
+ */
+
+struct drm_vmw_fence_signaled_arg {
+	 __u32 handle;
+	 __u32 flags;
+	 __s32 signaled;
+	 __u32 passed_seqno;
+	 __u32 signaled_flags;
+	 __u32 pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_UNREF
+ *
+ * Unreferences a fence object, and causes it to be destroyed if there are no
+ * other references to it.
+ *
+ */
+
+/**
+ * struct drm_vmw_fence_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ *
+ * Input/Output argument to the DRM_VMW_FENCE_UNREF ioctl..
+ */
+
+struct drm_vmw_fence_arg {
+	 __u32 handle;
+	 __u32 pad64;
+};
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_EVENT
+ *
+ * Queues an event on a fence to be delivered on the drm character device
+ * when the fence has signaled the DRM_VMW_FENCE_FLAG_EXEC flag.
+ * Optionally the approximate time when the fence signaled is
+ * given by the event.
+ */
+
+/*
+ * The event type
+ */
+#define DRM_VMW_EVENT_FENCE_SIGNALED 0x80000000
+
+struct drm_vmw_event_fence {
+	struct drm_event base;
+	__u64 user_data;
+	__u32 tv_sec;
+	__u32 tv_usec;
+};
+
+/*
+ * Flags that may be given to the command.
+ */
+/* Request fence signaled time on the event. */
+#define DRM_VMW_FE_FLAG_REQ_TIME (1 << 0)
+
+/**
+ * struct drm_vmw_fence_event_arg
+ *
+ * @fence_rep: Pointer to fence_rep structure cast to __u64 or 0 if
+ * the fence is not supposed to be referenced by user-space.
+ * @user_info: Info to be delivered with the event.
+ * @handle: Attach the event to this fence only.
+ * @flags: A set of flags as defined above.
+ */
+struct drm_vmw_fence_event_arg {
+	__u64 fence_rep;
+	__u64 user_data;
+	__u32 handle;
+	__u32 flags;
+};
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_PRESENT
+ *
+ * Executes an SVGA present on a given fb for a given surface. The surface
+ * is placed on the framebuffer. Cliprects are given relative to the given
+ * point (the point disignated by dest_{x|y}).
+ *
+ */
+
+/**
+ * struct drm_vmw_present_arg
+ * @fb_id: framebuffer id to present / read back from.
+ * @sid: Surface id to present from.
+ * @dest_x: X placement coordinate for surface.
+ * @dest_y: Y placement coordinate for surface.
+ * @clips_ptr: Pointer to an array of clip rects cast to an __u64.
+ * @num_clips: Number of cliprects given relative to the framebuffer origin,
+ * in the same coordinate space as the frame buffer.
+ * @pad64: Unused 64-bit padding.
+ *
+ * Input argument to the DRM_VMW_PRESENT ioctl.
+ */
+
+struct drm_vmw_present_arg {
+	__u32 fb_id;
+	__u32 sid;
+	__s32 dest_x;
+	__s32 dest_y;
+	__u64 clips_ptr;
+	__u32 num_clips;
+	__u32 pad64;
+};
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_PRESENT_READBACK
+ *
+ * Executes an SVGA present readback from a given fb to the dma buffer
+ * currently bound as the fb. If there is no dma buffer bound to the fb,
+ * an error will be returned.
+ *
+ */
+
+/**
+ * struct drm_vmw_present_arg
+ * @fb_id: fb_id to present / read back from.
+ * @num_clips: Number of cliprects.
+ * @clips_ptr: Pointer to an array of clip rects cast to an __u64.
+ * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an __u64.
+ * If this member is NULL, then the ioctl should not return a fence.
+ */
+
+struct drm_vmw_present_readback_arg {
+	 __u32 fb_id;
+	 __u32 num_clips;
+	 __u64 clips_ptr;
+	 __u64 fence_rep;
+};
+
+/*************************************************************************/
+/**
  * DRM_VMW_UPDATE_LAYOUT - Update layout
  *
- * Updates the prefered modes and connection status for connectors. The
- * command conisits of one drm_vmw_update_layout_arg pointing out a array
+ * Updates the preferred modes and connection status for connectors. The
+ * command consists of one drm_vmw_update_layout_arg pointing to an array
  * of num_outputs drm_vmw_rect's.
  */
 
 /**
  * struct drm_vmw_update_layout_arg
  *
- * @num_outputs: number of active
- * @rects: pointer to array of drm_vmw_rect
+ * @num_outputs: number of active connectors
+ * @rects: pointer to array of drm_vmw_rect cast to an __u64
  *
  * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
  */
-
 struct drm_vmw_update_layout_arg {
-	uint32_t num_outputs;
-	uint32_t pad64;
-	uint64_t rects;
+	__u32 num_outputs;
+	__u32 pad64;
+	__u64 rects;
 };
 
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CREATE_SHADER - Create shader
+ *
+ * Creates a shader and optionally binds it to a dma buffer containing
+ * the shader byte-code.
+ */
+
+/**
+ * enum drm_vmw_shader_type - Shader types
+ */
+enum drm_vmw_shader_type {
+	drm_vmw_shader_type_vs = 0,
+	drm_vmw_shader_type_ps,
+};
+
+
+/**
+ * struct drm_vmw_shader_create_arg
+ *
+ * @shader_type: Shader type of the shader to create.
+ * @size: Size of the byte-code in bytes.
+ * where the shader byte-code starts
+ * @buffer_handle: Buffer handle identifying the buffer containing the
+ * shader byte-code
+ * @shader_handle: On successful completion contains a handle that
+ * can be used to subsequently identify the shader.
+ * @offset: Offset in bytes into the buffer given by @buffer_handle,
+ *
+ * Input / Output argument to the DRM_VMW_CREATE_SHADER Ioctl.
+ */
+struct drm_vmw_shader_create_arg {
+	enum drm_vmw_shader_type shader_type;
+	__u32 size;
+	__u32 buffer_handle;
+	__u32 shader_handle;
+	__u64 offset;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UNREF_SHADER - Unreferences a shader
+ *
+ * Destroys a user-space reference to a shader, optionally destroying
+ * it.
+ */
+
+/**
+ * struct drm_vmw_shader_arg
+ *
+ * @handle: Handle identifying the shader to destroy.
+ *
+ * Input argument to the DRM_VMW_UNREF_SHADER ioctl.
+ */
+struct drm_vmw_shader_arg {
+	__u32 handle;
+	__u32 pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_GB_SURFACE_CREATE - Create a host guest-backed surface.
+ *
+ * Allocates a surface handle and queues a create surface command
+ * for the host on the first use of the surface. The surface ID can
+ * be used as the surface ID in commands referencing the surface.
+ */
+
+/**
+ * enum drm_vmw_surface_flags
+ *
+ * @drm_vmw_surface_flag_shareable:     Whether the surface is shareable
+ * @drm_vmw_surface_flag_scanout:       Whether the surface is a scanout
+ *                                      surface.
+ * @drm_vmw_surface_flag_create_buffer: Create a backup buffer if none is
+ *                                      given.
+ */
+enum drm_vmw_surface_flags {
+	drm_vmw_surface_flag_shareable = (1 << 0),
+	drm_vmw_surface_flag_scanout = (1 << 1),
+	drm_vmw_surface_flag_create_buffer = (1 << 2)
+};
+
+/**
+ * struct drm_vmw_gb_surface_create_req
+ *
+ * @svga3d_flags:     SVGA3d surface flags for the device.
+ * @format:           SVGA3d format.
+ * @mip_level:        Number of mip levels for all faces.
+ * @drm_surface_flags Flags as described above.
+ * @multisample_count Future use. Set to 0.
+ * @autogen_filter    Future use. Set to 0.
+ * @buffer_handle     Buffer handle of backup buffer. SVGA3D_INVALID_ID
+ *                    if none.
+ * @base_size         Size of the base mip level for all faces.
+ * @array_size        Must be zero for non-DX hardware, and if non-zero
+ *                    svga3d_flags must have proper bind flags setup.
+ *
+ * Input argument to the  DRM_VMW_GB_SURFACE_CREATE Ioctl.
+ * Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl.
+ */
+struct drm_vmw_gb_surface_create_req {
+	__u32 svga3d_flags;
+	__u32 format;
+	__u32 mip_levels;
+	enum drm_vmw_surface_flags drm_surface_flags;
+	__u32 multisample_count;
+	__u32 autogen_filter;
+	__u32 buffer_handle;
+	__u32 array_size;
+	struct drm_vmw_size base_size;
+};
+
+/**
+ * struct drm_vmw_gb_surface_create_rep
+ *
+ * @handle:            Surface handle.
+ * @backup_size:       Size of backup buffers for this surface.
+ * @buffer_handle:     Handle of backup buffer. SVGA3D_INVALID_ID if none.
+ * @buffer_size:       Actual size of the buffer identified by
+ *                     @buffer_handle
+ * @buffer_map_handle: Offset into device address space for the buffer
+ *                     identified by @buffer_handle.
+ *
+ * Part of output argument for the DRM_VMW_GB_SURFACE_REF ioctl.
+ * Output argument for the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ */
+struct drm_vmw_gb_surface_create_rep {
+	__u32 handle;
+	__u32 backup_size;
+	__u32 buffer_handle;
+	__u32 buffer_size;
+	__u64 buffer_map_handle;
+};
+
+/**
+ * union drm_vmw_gb_surface_create_arg
+ *
+ * @req: Input argument as described above.
+ * @rep: Output argument as described above.
+ *
+ * Argument to the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ */
+union drm_vmw_gb_surface_create_arg {
+	struct drm_vmw_gb_surface_create_rep rep;
+	struct drm_vmw_gb_surface_create_req req;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_GB_SURFACE_REF - Reference a host surface.
+ *
+ * Puts a reference on a host surface with a given handle, as previously
+ * returned by the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ * A reference will make sure the surface isn't destroyed while we hold
+ * it and will allow the calling client to use the surface handle in
+ * the command stream.
+ *
+ * On successful return, the Ioctl returns the surface information given
+ * to and returned from the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ */
+
+/**
+ * struct drm_vmw_gb_surface_reference_arg
+ *
+ * @creq: The data used as input when the surface was created, as described
+ *        above at "struct drm_vmw_gb_surface_create_req"
+ * @crep: Additional data output when the surface was created, as described
+ *        above at "struct drm_vmw_gb_surface_create_rep"
+ *
+ * Output Argument to the DRM_VMW_GB_SURFACE_REF ioctl.
+ */
+struct drm_vmw_gb_surface_ref_rep {
+	struct drm_vmw_gb_surface_create_req creq;
+	struct drm_vmw_gb_surface_create_rep crep;
+};
+
+/**
+ * union drm_vmw_gb_surface_reference_arg
+ *
+ * @req: Input data as described above at "struct drm_vmw_surface_arg"
+ * @rep: Output data as described above at "struct drm_vmw_gb_surface_ref_rep"
+ *
+ * Argument to the DRM_VMW_GB_SURFACE_REF Ioctl.
+ */
+union drm_vmw_gb_surface_reference_arg {
+	struct drm_vmw_gb_surface_ref_rep rep;
+	struct drm_vmw_surface_arg req;
+};
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_SYNCCPU - Sync a DMA buffer / MOB for CPU access.
+ *
+ * Idles any previously submitted GPU operations on the buffer and
+ * by default blocks command submissions that reference the buffer.
+ * If the file descriptor used to grab a blocking CPU sync is closed, the
+ * cpu sync is released.
+ * The flags argument indicates how the grab / release operation should be
+ * performed:
+ */
+
+/**
+ * enum drm_vmw_synccpu_flags - Synccpu flags:
+ *
+ * @drm_vmw_synccpu_read: Sync for read. If sync is done for read only, it's a
+ * hint to the kernel to allow command submissions that references the buffer
+ * for read-only.
+ * @drm_vmw_synccpu_write: Sync for write. Block all command submissions
+ * referencing this buffer.
+ * @drm_vmw_synccpu_dontblock: Dont wait for GPU idle, but rather return
+ * -EBUSY should the buffer be busy.
+ * @drm_vmw_synccpu_allow_cs: Allow command submission that touches the buffer
+ * while the buffer is synced for CPU. This is similar to the GEM bo idle
+ * behavior.
+ */
+enum drm_vmw_synccpu_flags {
+	drm_vmw_synccpu_read = (1 << 0),
+	drm_vmw_synccpu_write = (1 << 1),
+	drm_vmw_synccpu_dontblock = (1 << 2),
+	drm_vmw_synccpu_allow_cs = (1 << 3)
+};
+
+/**
+ * enum drm_vmw_synccpu_op - Synccpu operations:
+ *
+ * @drm_vmw_synccpu_grab:    Grab the buffer for CPU operations
+ * @drm_vmw_synccpu_release: Release a previous grab.
+ */
+enum drm_vmw_synccpu_op {
+	drm_vmw_synccpu_grab,
+	drm_vmw_synccpu_release
+};
+
+/**
+ * struct drm_vmw_synccpu_arg
+ *
+ * @op:			     The synccpu operation as described above.
+ * @handle:		     Handle identifying the buffer object.
+ * @flags:		     Flags as described above.
+ */
+struct drm_vmw_synccpu_arg {
+	enum drm_vmw_synccpu_op op;
+	enum drm_vmw_synccpu_flags flags;
+	__u32 handle;
+	__u32 pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CREATE_EXTENDED_CONTEXT - Create a host context.
+ *
+ * Allocates a device unique context id, and queues a create context command
+ * for the host. Does not wait for host completion.
+ */
+enum drm_vmw_extended_context {
+	drm_vmw_context_legacy,
+	drm_vmw_context_dx
+};
+
+/**
+ * union drm_vmw_extended_context_arg
+ *
+ * @req: Context type.
+ * @rep: Context identifier.
+ *
+ * Argument to the DRM_VMW_CREATE_EXTENDED_CONTEXT Ioctl.
+ */
+union drm_vmw_extended_context_arg {
+	enum drm_vmw_extended_context req;
+	struct drm_vmw_context_arg rep;
+};
 #endif
diff --git a/intel/Android.mk b/intel/Android.mk
index 9084dc3..2a0dc4c 100644
--- a/intel/Android.mk
+++ b/intel/Android.mk
@@ -29,11 +29,10 @@
 
 LOCAL_MODULE := libdrm_intel
 
+# Removed dependency to libpciaccess: not used on Android
 LOCAL_SHARED_LIBRARIES := libdrm
 
-LOCAL_SRC_FILES := $(filter-out %.h,$(LIBDRM_INTEL_FILES))
+LOCAL_SRC_FILES := $(LIBDRM_INTEL_FILES)
 
-LOCAL_CFLAGS := \
-	-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
-
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_SHARED_LIBRARY)
diff --git a/intel/Makefile.am b/intel/Makefile.am
index d004568..c52e8c0 100644
--- a/intel/Makefile.am
+++ b/intel/Makefile.am
@@ -66,7 +66,6 @@
 	$(BATCHES:.batch=.batch-ref.txt) \
 	$(BATCHES:.batch=.batch-ref.txt) \
 	tests/test-batch.sh \
-	Android.mk \
 	$(TESTS)
 
 test_decode_LDADD = libdrm_intel.la ../libdrm.la
diff --git a/intel/Makefile.sources b/intel/Makefile.sources
index 7b2272c..6947ab7 100644
--- a/intel/Makefile.sources
+++ b/intel/Makefile.sources
@@ -6,7 +6,8 @@
 	intel_decode.c \
 	intel_chipset.h \
 	mm.c \
-	mm.h
+	mm.h \
+	uthash.h
 
 LIBDRM_INTEL_H_FILES := \
 	intel_bufmgr.h \
diff --git a/intel/intel-symbol-check b/intel/intel-symbol-check
index bde7634..2aa2d81 100755
--- a/intel/intel-symbol-check
+++ b/intel/intel-symbol-check
@@ -50,6 +50,7 @@
 drm_intel_bufmgr_fake_set_exec_callback
 drm_intel_bufmgr_fake_set_fence_callback
 drm_intel_bufmgr_fake_set_last_dispatch
+drm_intel_bufmgr_gem_can_disable_implicit_sync
 drm_intel_bufmgr_gem_enable_fenced_relocs
 drm_intel_bufmgr_gem_enable_reuse
 drm_intel_bufmgr_gem_get_devid
@@ -69,7 +70,13 @@
 drm_intel_gem_bo_aub_dump_bmp
 drm_intel_gem_bo_clear_relocs
 drm_intel_gem_bo_context_exec
+drm_intel_gem_bo_disable_implicit_sync
+drm_intel_gem_bo_enable_implicit_sync
+drm_intel_gem_bo_fence_exec
 drm_intel_gem_bo_get_reloc_count
+drm_intel_gem_bo_map__cpu
+drm_intel_gem_bo_map__gtt
+drm_intel_gem_bo_map__wc
 drm_intel_gem_bo_map_gtt
 drm_intel_gem_bo_map_unsynchronized
 drm_intel_gem_bo_start_gtt_access
@@ -77,9 +84,12 @@
 drm_intel_gem_bo_wait
 drm_intel_gem_context_create
 drm_intel_gem_context_destroy
+drm_intel_gem_context_get_id
 drm_intel_get_aperture_sizes
 drm_intel_get_eu_total
+drm_intel_get_min_eu_in_pool
 drm_intel_get_pipe_from_crtc_id
+drm_intel_get_pooled_eu
 drm_intel_get_reset_stats
 drm_intel_get_subslice_total
 drm_intel_reg_read
diff --git a/intel/intel_bufmgr.h b/intel/intel_bufmgr.h
index a1abbcd..693472a 100644
--- a/intel/intel_bufmgr.h
+++ b/intel/intel_bufmgr.h
@@ -184,6 +184,15 @@
 int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo);
 int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo);
 
+#define HAVE_DRM_INTEL_GEM_BO_DISABLE_IMPLICIT_SYNC 1
+int drm_intel_bufmgr_gem_can_disable_implicit_sync(drm_intel_bufmgr *bufmgr);
+void drm_intel_gem_bo_disable_implicit_sync(drm_intel_bo *bo);
+void drm_intel_gem_bo_enable_implicit_sync(drm_intel_bo *bo);
+
+void *drm_intel_gem_bo_map__cpu(drm_intel_bo *bo);
+void *drm_intel_gem_bo_map__gtt(drm_intel_bo *bo);
+void *drm_intel_gem_bo_map__wc(drm_intel_bo *bo);
+
 int drm_intel_gem_bo_get_reloc_count(drm_intel_bo *bo);
 void drm_intel_gem_bo_clear_relocs(drm_intel_bo *bo, int start);
 void drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable);
@@ -208,9 +217,17 @@
 int drm_intel_gem_bo_wait(drm_intel_bo *bo, int64_t timeout_ns);
 
 drm_intel_context *drm_intel_gem_context_create(drm_intel_bufmgr *bufmgr);
+int drm_intel_gem_context_get_id(drm_intel_context *ctx,
+                                 uint32_t *ctx_id);
 void drm_intel_gem_context_destroy(drm_intel_context *ctx);
 int drm_intel_gem_bo_context_exec(drm_intel_bo *bo, drm_intel_context *ctx,
 				  int used, unsigned int flags);
+int drm_intel_gem_bo_fence_exec(drm_intel_bo *bo,
+				drm_intel_context *ctx,
+				int used,
+				int in_fence,
+				int *out_fence,
+				unsigned int flags);
 
 int drm_intel_bo_gem_export_to_prime(drm_intel_bo *bo, int *prime_fd);
 drm_intel_bo *drm_intel_bo_gem_create_from_prime(drm_intel_bufmgr *bufmgr,
@@ -273,6 +290,9 @@
 int drm_intel_get_subslice_total(int fd, unsigned int *subslice_total);
 int drm_intel_get_eu_total(int fd, unsigned int *eu_total);
 
+int drm_intel_get_pooled_eu(int fd);
+int drm_intel_get_min_eu_in_pool(int fd);
+
 /** @{ Compatibility defines to keep old code building despite the symbol rename
  * from dri_* to drm_intel_*
  */
diff --git a/intel/intel_bufmgr_fake.c b/intel/intel_bufmgr_fake.c
index 7f4c7b9..641df6a 100644
--- a/intel/intel_bufmgr_fake.c
+++ b/intel/intel_bufmgr_fake.c
@@ -312,7 +312,7 @@
 	 *
 	 * Assume that in userland we treat sequence numbers as ints, which
 	 * makes some of the comparisons convenient, since the sequence
-	 * numbers are all postive signed integers.
+	 * numbers are all positive signed integers.
 	 *
 	 * From this we get several cases we need to handle.  Here's a timeline.
 	 * 0x2   0x7                                    0x7ffffff8   0x7ffffffd
@@ -737,7 +737,7 @@
 /**
  * Wait for rendering to a buffer to complete.
  *
- * It is assumed that the bathcbuffer which performed the rendering included
+ * It is assumed that the batchbuffer which performed the rendering included
  * the necessary flushing.
  */
 static void
@@ -1200,7 +1200,7 @@
 		assert(!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)));
 
 		/* Actually, should be able to just wait for a fence on the
-		 * mmory, hich we would be tracking when we free it.  Waiting
+		 * memory, which we would be tracking when we free it. Waiting
 		 * for idle is a sufficiently large hammer for now.
 		 */
 		drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
diff --git a/intel/intel_bufmgr_gem.c b/intel/intel_bufmgr_gem.c
index dc28200..a665600 100644
--- a/intel/intel_bufmgr_gem.c
+++ b/intel/intel_bufmgr_gem.c
@@ -64,6 +64,7 @@
 #include "string.h"
 
 #include "i915_drm.h"
+#include "uthash.h"
 
 #ifdef HAVE_VALGRIND
 #include <valgrind.h>
@@ -130,7 +131,9 @@
 
 	drmMMListHead managers;
 
-	drmMMListHead named;
+	drm_intel_bo_gem *name_table;
+	drm_intel_bo_gem *handle_table;
+
 	drmMMListHead vma_cache;
 	int vma_count, vma_open, vma_max;
 
@@ -146,6 +149,7 @@
 	unsigned int bo_reuse : 1;
 	unsigned int no_exec : 1;
 	unsigned int has_vebox : 1;
+	unsigned int has_exec_async : 1;
 	bool fenced_relocs;
 
 	struct {
@@ -175,7 +179,9 @@
          * List contains both flink named and prime fd'd objects
 	 */
 	unsigned int global_name;
-	drmMMListHead name_list;
+
+	UT_hash_handle handle_hh;
+	UT_hash_handle name_hh;
 
 	/**
 	 * Index of the buffer within the validation list while preparing a
@@ -190,6 +196,8 @@
 	uint32_t swizzle_mode;
 	unsigned long stride;
 
+	unsigned long kflags;
+
 	time_t free_time;
 
 	/** Array passed to the DRM containing relocation information. */
@@ -211,6 +219,8 @@
 	void *mem_virtual;
 	/** GTT virtual address for the buffer, saved across map/unmap cycles */
 	void *gtt_virtual;
+	/** WC CPU address for the buffer, saved across map/unmap cycles */
+	void *wc_virtual;
 	/**
 	 * Virtual address of the buffer allocated by user, used for userptr
 	 * objects only.
@@ -249,7 +259,7 @@
 	 * Boolean of whether the GPU is definitely not accessing the buffer.
 	 *
 	 * This is only valid when reusable, since non-reusable
-	 * buffers are those that have been shared wth other
+	 * buffers are those that have been shared with other
 	 * processes, so we don't know their state.
 	 */
 	bool idle;
@@ -287,7 +297,7 @@
 	 */
 	int reloc_tree_fences;
 
-	/** Flags that we may need to do the SW_FINSIH ioctl on unmap. */
+	/** Flags that we may need to do the SW_FINISH ioctl on unmap. */
 	bool mapped_cpu_write;
 };
 
@@ -568,12 +578,11 @@
 	bufmgr_gem->exec2_objects[index].relocation_count = bo_gem->reloc_count;
 	bufmgr_gem->exec2_objects[index].relocs_ptr = (uintptr_t)bo_gem->relocs;
 	bufmgr_gem->exec2_objects[index].alignment = bo->align;
-	bufmgr_gem->exec2_objects[index].offset = bo_gem->is_softpin ?
-		bo->offset64 : 0;
-	bufmgr_gem->exec_bos[index] = bo;
-	bufmgr_gem->exec2_objects[index].flags = flags;
+	bufmgr_gem->exec2_objects[index].offset = bo->offset64;
+	bufmgr_gem->exec2_objects[index].flags = flags | bo_gem->kflags;
 	bufmgr_gem->exec2_objects[index].rsvd1 = 0;
 	bufmgr_gem->exec2_objects[index].rsvd2 = 0;
+	bufmgr_gem->exec_bos[index] = bo;
 	bufmgr_gem->exec_count++;
 }
 
@@ -797,14 +806,17 @@
 			}
 		}
 	}
-	pthread_mutex_unlock(&bufmgr_gem->lock);
 
 	if (!alloc_from_cache) {
 		struct drm_i915_gem_create create;
 
 		bo_gem = calloc(1, sizeof(*bo_gem));
 		if (!bo_gem)
-			return NULL;
+			goto err;
+
+		/* drm_intel_gem_bo_free calls DRMLISTDEL() for an uninitialized
+		   list (vma_list), so better set the list head here */
+		DRMINITLISTHEAD(&bo_gem->vma_list);
 
 		bo_gem->bo.size = bo_size;
 
@@ -814,12 +826,13 @@
 		ret = drmIoctl(bufmgr_gem->fd,
 			       DRM_IOCTL_I915_GEM_CREATE,
 			       &create);
-		bo_gem->gem_handle = create.handle;
-		bo_gem->bo.handle = bo_gem->gem_handle;
 		if (ret != 0) {
 			free(bo_gem);
-			return NULL;
+			goto err;
 		}
+
+		bo_gem->gem_handle = create.handle;
+		bo_gem->bo.handle = bo_gem->gem_handle;
 		bo_gem->bo.bufmgr = bufmgr;
 		bo_gem->bo.align = alignment;
 
@@ -827,16 +840,14 @@
 		bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 		bo_gem->stride = 0;
 
-		/* drm_intel_gem_bo_free calls DRMLISTDEL() for an uninitialized
-		   list (vma_list), so better set the list head here */
-		DRMINITLISTHEAD(&bo_gem->name_list);
-		DRMINITLISTHEAD(&bo_gem->vma_list);
 		if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo,
 							 tiling_mode,
-							 stride)) {
-		    drm_intel_gem_bo_free(&bo_gem->bo);
-		    return NULL;
-		}
+							 stride))
+			goto err_free;
+
+		HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+			 gem_handle, sizeof(bo_gem->gem_handle),
+			 bo_gem);
 	}
 
 	bo_gem->name = name;
@@ -849,11 +860,18 @@
 	bo_gem->use_48b_address_range = false;
 
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, alignment);
+	pthread_mutex_unlock(&bufmgr_gem->lock);
 
 	DBG("bo_create: buf %d (%s) %ldb\n",
 	    bo_gem->gem_handle, bo_gem->name, size);
 
 	return &bo_gem->bo;
+
+err_free:
+	drm_intel_gem_bo_free(&bo_gem->bo);
+err:
+	pthread_mutex_unlock(&bufmgr_gem->lock);
+	return NULL;
 }
 
 static drm_intel_bo *
@@ -954,6 +972,9 @@
 	if (!bo_gem)
 		return NULL;
 
+	atomic_set(&bo_gem->refcount, 1);
+	DRMINITLISTHEAD(&bo_gem->vma_list);
+
 	bo_gem->bo.size = size;
 
 	memclear(userptr);
@@ -972,6 +993,8 @@
 		return NULL;
 	}
 
+	pthread_mutex_lock(&bufmgr_gem->lock);
+
 	bo_gem->gem_handle = userptr.handle;
 	bo_gem->bo.handle = bo_gem->gem_handle;
 	bo_gem->bo.bufmgr    = bufmgr;
@@ -983,11 +1006,11 @@
 	bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 	bo_gem->stride       = 0;
 
-	DRMINITLISTHEAD(&bo_gem->name_list);
-	DRMINITLISTHEAD(&bo_gem->vma_list);
+	HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+		 gem_handle, sizeof(bo_gem->gem_handle),
+		 bo_gem);
 
 	bo_gem->name = name;
-	atomic_set(&bo_gem->refcount, 1);
 	bo_gem->validate_index = -1;
 	bo_gem->reloc_tree_fences = 0;
 	bo_gem->used_as_reloc_target = false;
@@ -996,6 +1019,7 @@
 	bo_gem->use_48b_address_range = false;
 
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0);
+	pthread_mutex_unlock(&bufmgr_gem->lock);
 
 	DBG("bo_create_userptr: "
 	    "ptr %p buf %d (%s) size %ldb, stride 0x%x, tile mode %d\n",
@@ -1085,7 +1109,6 @@
 	int ret;
 	struct drm_gem_open open_arg;
 	struct drm_i915_gem_get_tiling get_tiling;
-	drmMMListHead *list;
 
 	/* At the moment most applications only have a few named bo.
 	 * For instance, in a DRI client only the render buffers passed
@@ -1094,15 +1117,11 @@
 	 * provides a sufficiently fast match.
 	 */
 	pthread_mutex_lock(&bufmgr_gem->lock);
-	for (list = bufmgr_gem->named.next;
-	     list != &bufmgr_gem->named;
-	     list = list->next) {
-		bo_gem = DRMLISTENTRY(drm_intel_bo_gem, list, name_list);
-		if (bo_gem->global_name == handle) {
-			drm_intel_gem_bo_reference(&bo_gem->bo);
-			pthread_mutex_unlock(&bufmgr_gem->lock);
-			return &bo_gem->bo;
-		}
+	HASH_FIND(name_hh, bufmgr_gem->name_table,
+		  &handle, sizeof(handle), bo_gem);
+	if (bo_gem) {
+		drm_intel_gem_bo_reference(&bo_gem->bo);
+		goto out;
 	}
 
 	memclear(open_arg);
@@ -1113,29 +1132,26 @@
 	if (ret != 0) {
 		DBG("Couldn't reference %s handle 0x%08x: %s\n",
 		    name, handle, strerror(errno));
-		pthread_mutex_unlock(&bufmgr_gem->lock);
-		return NULL;
+		bo_gem = NULL;
+		goto out;
 	}
         /* Now see if someone has used a prime handle to get this
          * object from the kernel before by looking through the list
          * again for a matching gem_handle
          */
-	for (list = bufmgr_gem->named.next;
-	     list != &bufmgr_gem->named;
-	     list = list->next) {
-		bo_gem = DRMLISTENTRY(drm_intel_bo_gem, list, name_list);
-		if (bo_gem->gem_handle == open_arg.handle) {
-			drm_intel_gem_bo_reference(&bo_gem->bo);
-			pthread_mutex_unlock(&bufmgr_gem->lock);
-			return &bo_gem->bo;
-		}
+	HASH_FIND(handle_hh, bufmgr_gem->handle_table,
+		  &open_arg.handle, sizeof(open_arg.handle), bo_gem);
+	if (bo_gem) {
+		drm_intel_gem_bo_reference(&bo_gem->bo);
+		goto out;
 	}
 
 	bo_gem = calloc(1, sizeof(*bo_gem));
-	if (!bo_gem) {
-		pthread_mutex_unlock(&bufmgr_gem->lock);
-		return NULL;
-	}
+	if (!bo_gem)
+		goto out;
+
+	atomic_set(&bo_gem->refcount, 1);
+	DRMINITLISTHEAD(&bo_gem->vma_list);
 
 	bo_gem->bo.size = open_arg.size;
 	bo_gem->bo.offset = 0;
@@ -1143,7 +1159,6 @@
 	bo_gem->bo.virtual = NULL;
 	bo_gem->bo.bufmgr = bufmgr;
 	bo_gem->name = name;
-	atomic_set(&bo_gem->refcount, 1);
 	bo_gem->validate_index = -1;
 	bo_gem->gem_handle = open_arg.handle;
 	bo_gem->bo.handle = open_arg.handle;
@@ -1151,27 +1166,33 @@
 	bo_gem->reusable = false;
 	bo_gem->use_48b_address_range = false;
 
+	HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+		 gem_handle, sizeof(bo_gem->gem_handle), bo_gem);
+	HASH_ADD(name_hh, bufmgr_gem->name_table,
+		 global_name, sizeof(bo_gem->global_name), bo_gem);
+
 	memclear(get_tiling);
 	get_tiling.handle = bo_gem->gem_handle;
 	ret = drmIoctl(bufmgr_gem->fd,
 		       DRM_IOCTL_I915_GEM_GET_TILING,
 		       &get_tiling);
-	if (ret != 0) {
-		drm_intel_gem_bo_unreference(&bo_gem->bo);
-		pthread_mutex_unlock(&bufmgr_gem->lock);
-		return NULL;
-	}
+	if (ret != 0)
+		goto err_unref;
+
 	bo_gem->tiling_mode = get_tiling.tiling_mode;
 	bo_gem->swizzle_mode = get_tiling.swizzle_mode;
 	/* XXX stride is unknown */
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0);
-
-	DRMINITLISTHEAD(&bo_gem->vma_list);
-	DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
-	pthread_mutex_unlock(&bufmgr_gem->lock);
 	DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
 
+out:
+	pthread_mutex_unlock(&bufmgr_gem->lock);
 	return &bo_gem->bo;
+
+err_unref:
+	drm_intel_gem_bo_free(&bo_gem->bo);
+	pthread_mutex_unlock(&bufmgr_gem->lock);
+	return NULL;
 }
 
 static void
@@ -1188,11 +1209,20 @@
 		drm_munmap(bo_gem->mem_virtual, bo_gem->bo.size);
 		bufmgr_gem->vma_count--;
 	}
+	if (bo_gem->wc_virtual) {
+		VG(VALGRIND_FREELIKE_BLOCK(bo_gem->wc_virtual, 0));
+		drm_munmap(bo_gem->wc_virtual, bo_gem->bo.size);
+		bufmgr_gem->vma_count--;
+	}
 	if (bo_gem->gtt_virtual) {
 		drm_munmap(bo_gem->gtt_virtual, bo_gem->bo.size);
 		bufmgr_gem->vma_count--;
 	}
 
+	if (bo_gem->global_name)
+		HASH_DELETE(name_hh, bufmgr_gem->name_table, bo_gem);
+	HASH_DELETE(handle_hh, bufmgr_gem->handle_table, bo_gem);
+
 	/* Close this object */
 	memclear(close);
 	close.handle = bo_gem->gem_handle;
@@ -1213,6 +1243,9 @@
 	if (bo_gem->mem_virtual)
 		VALGRIND_MAKE_MEM_NOACCESS(bo_gem->mem_virtual, bo->size);
 
+	if (bo_gem->wc_virtual)
+		VALGRIND_MAKE_MEM_NOACCESS(bo_gem->wc_virtual, bo->size);
+
 	if (bo_gem->gtt_virtual)
 		VALGRIND_MAKE_MEM_NOACCESS(bo_gem->gtt_virtual, bo->size);
 #endif
@@ -1277,6 +1310,11 @@
 			bo_gem->mem_virtual = NULL;
 			bufmgr_gem->vma_count--;
 		}
+		if (bo_gem->wc_virtual) {
+			drm_munmap(bo_gem->wc_virtual, bo_gem->bo.size);
+			bo_gem->wc_virtual = NULL;
+			bufmgr_gem->vma_count--;
+		}
 		if (bo_gem->gtt_virtual) {
 			drm_munmap(bo_gem->gtt_virtual, bo_gem->bo.size);
 			bo_gem->gtt_virtual = NULL;
@@ -1292,6 +1330,8 @@
 	DRMLISTADDTAIL(&bo_gem->vma_list, &bufmgr_gem->vma_cache);
 	if (bo_gem->mem_virtual)
 		bufmgr_gem->vma_count++;
+	if (bo_gem->wc_virtual)
+		bufmgr_gem->vma_count++;
 	if (bo_gem->gtt_virtual)
 		bufmgr_gem->vma_count++;
 	drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
@@ -1304,6 +1344,8 @@
 	DRMLISTDEL(&bo_gem->vma_list);
 	if (bo_gem->mem_virtual)
 		bufmgr_gem->vma_count--;
+	if (bo_gem->wc_virtual)
+		bufmgr_gem->vma_count--;
 	if (bo_gem->gtt_virtual)
 		bufmgr_gem->vma_count--;
 	drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
@@ -1328,6 +1370,7 @@
 	for (i = 0; i < bo_gem->softpin_target_count; i++)
 		drm_intel_gem_bo_unreference_locked_timed(bo_gem->softpin_target[i],
 								  time);
+	bo_gem->kflags = 0;
 	bo_gem->reloc_count = 0;
 	bo_gem->used_as_reloc_target = false;
 	bo_gem->softpin_target_count = 0;
@@ -1358,8 +1401,6 @@
 		drm_intel_gem_bo_mark_mmaps_incoherent(bo);
 	}
 
-	DRMLISTDEL(&bo_gem->name_list);
-
 	bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo->size);
 	/* Put the buffer into our internal cache for reuse if we can. */
 	if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL &&
@@ -1370,6 +1411,8 @@
 		bo_gem->name = NULL;
 		bo_gem->validate_index = -1;
 
+		bo_gem->kflags = 0;
+
 		DRMLISTADDTAIL(&bo_gem->head, &bucket->head);
 	} else {
 		drm_intel_gem_bo_free(bo);
@@ -1681,7 +1724,7 @@
 	}
 
 	/* We need to unmap after every innovation as we cannot track
-	 * an open vma for every bo as that will exhaasut the system
+	 * an open vma for every bo as that will exhaust the system
 	 * limits and cause later failures.
 	 */
 	if (--bo_gem->map_count == 0) {
@@ -2335,6 +2378,7 @@
 static int
 do_exec2(drm_intel_bo *bo, int used, drm_intel_context *ctx,
 	 drm_clip_rect_t *cliprects, int num_cliprects, int DR4,
+	 int in_fence, int *out_fence,
 	 unsigned int flags)
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
@@ -2389,12 +2433,20 @@
 	else
 		i915_execbuffer2_set_context_id(execbuf, ctx->ctx_id);
 	execbuf.rsvd2 = 0;
+	if (in_fence != -1) {
+		execbuf.rsvd2 = in_fence;
+		execbuf.flags |= I915_EXEC_FENCE_IN;
+	}
+	if (out_fence != NULL) {
+		*out_fence = -1;
+		execbuf.flags |= I915_EXEC_FENCE_OUT;
+	}
 
 	if (bufmgr_gem->no_exec)
 		goto skip_execution;
 
 	ret = drmIoctl(bufmgr_gem->fd,
-		       DRM_IOCTL_I915_GEM_EXECBUFFER2,
+		       DRM_IOCTL_I915_GEM_EXECBUFFER2_WR,
 		       &execbuf);
 	if (ret != 0) {
 		ret = -errno;
@@ -2410,6 +2462,9 @@
 	}
 	drm_intel_update_buffer_offsets2(bufmgr_gem);
 
+	if (ret == 0 && out_fence != NULL)
+		*out_fence = execbuf.rsvd2 >> 32;
+
 skip_execution:
 	if (bufmgr_gem->bufmgr.debug)
 		drm_intel_gem_dump_validation_list(bufmgr_gem);
@@ -2435,7 +2490,7 @@
 		       int DR4)
 {
 	return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4,
-			I915_EXEC_RENDER);
+			-1, NULL, I915_EXEC_RENDER);
 }
 
 static int
@@ -2444,14 +2499,25 @@
 			unsigned int flags)
 {
 	return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4,
-			flags);
+			-1, NULL, flags);
 }
 
 int
 drm_intel_gem_bo_context_exec(drm_intel_bo *bo, drm_intel_context *ctx,
 			      int used, unsigned int flags)
 {
-	return do_exec2(bo, used, ctx, NULL, 0, 0, flags);
+	return do_exec2(bo, used, ctx, NULL, 0, 0, -1, NULL, flags);
+}
+
+int
+drm_intel_gem_bo_fence_exec(drm_intel_bo *bo,
+			    drm_intel_context *ctx,
+			    int used,
+			    int in_fence,
+			    int *out_fence,
+			    unsigned int flags)
+{
+	return do_exec2(bo, used, ctx, NULL, 0, 0, in_fence, out_fence, flags);
 }
 
 static int
@@ -2591,7 +2657,6 @@
 	uint32_t handle;
 	drm_intel_bo_gem *bo_gem;
 	struct drm_i915_gem_get_tiling get_tiling;
-	drmMMListHead *list;
 
 	pthread_mutex_lock(&bufmgr_gem->lock);
 	ret = drmPrimeFDToHandle(bufmgr_gem->fd, prime_fd, &handle);
@@ -2606,22 +2671,20 @@
 	 * for named buffers, we must not create two bo's pointing at the same
 	 * kernel object
 	 */
-	for (list = bufmgr_gem->named.next;
-	     list != &bufmgr_gem->named;
-	     list = list->next) {
-		bo_gem = DRMLISTENTRY(drm_intel_bo_gem, list, name_list);
-		if (bo_gem->gem_handle == handle) {
-			drm_intel_gem_bo_reference(&bo_gem->bo);
-			pthread_mutex_unlock(&bufmgr_gem->lock);
-			return &bo_gem->bo;
-		}
+	HASH_FIND(handle_hh, bufmgr_gem->handle_table,
+		  &handle, sizeof(handle), bo_gem);
+	if (bo_gem) {
+		drm_intel_gem_bo_reference(&bo_gem->bo);
+		goto out;
 	}
 
 	bo_gem = calloc(1, sizeof(*bo_gem));
-	if (!bo_gem) {
-		pthread_mutex_unlock(&bufmgr_gem->lock);
-		return NULL;
-	}
+	if (!bo_gem)
+		goto out;
+
+	atomic_set(&bo_gem->refcount, 1);
+	DRMINITLISTHEAD(&bo_gem->vma_list);
+
 	/* Determine size of bo.  The fd-to-handle ioctl really should
 	 * return the size, but it doesn't.  If we have kernel 3.12 or
 	 * later, we can lseek on the prime fd to get the size.  Older
@@ -2637,8 +2700,8 @@
 	bo_gem->bo.bufmgr = bufmgr;
 
 	bo_gem->gem_handle = handle;
-
-	atomic_set(&bo_gem->refcount, 1);
+	HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+		 gem_handle, sizeof(bo_gem->gem_handle), bo_gem);
 
 	bo_gem->name = "prime";
 	bo_gem->validate_index = -1;
@@ -2648,26 +2711,26 @@
 	bo_gem->reusable = false;
 	bo_gem->use_48b_address_range = false;
 
-	DRMINITLISTHEAD(&bo_gem->vma_list);
-	DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
-	pthread_mutex_unlock(&bufmgr_gem->lock);
-
 	memclear(get_tiling);
 	get_tiling.handle = bo_gem->gem_handle;
-	ret = drmIoctl(bufmgr_gem->fd,
-		       DRM_IOCTL_I915_GEM_GET_TILING,
-		       &get_tiling);
-	if (ret != 0) {
-		DBG("create_from_prime: failed to get tiling: %s\n", strerror(errno));
-		drm_intel_gem_bo_unreference(&bo_gem->bo);
-		return NULL;
-	}
+	if (drmIoctl(bufmgr_gem->fd,
+		     DRM_IOCTL_I915_GEM_GET_TILING,
+		     &get_tiling))
+		goto err;
+
 	bo_gem->tiling_mode = get_tiling.tiling_mode;
 	bo_gem->swizzle_mode = get_tiling.swizzle_mode;
 	/* XXX stride is unknown */
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0);
 
+out:
+	pthread_mutex_unlock(&bufmgr_gem->lock);
 	return &bo_gem->bo;
+
+err:
+	drm_intel_gem_bo_free(&bo_gem->bo);
+	pthread_mutex_unlock(&bufmgr_gem->lock);
+	return NULL;
 }
 
 int
@@ -2676,11 +2739,6 @@
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
 
-	pthread_mutex_lock(&bufmgr_gem->lock);
-        if (DRMLISTEMPTY(&bo_gem->name_list))
-                DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
-	pthread_mutex_unlock(&bufmgr_gem->lock);
-
 	if (drmPrimeHandleToFD(bufmgr_gem->fd, bo_gem->gem_handle,
 			       DRM_CLOEXEC, prime_fd) != 0)
 		return -errno;
@@ -2695,27 +2753,24 @@
 {
 	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
-	int ret;
 
 	if (!bo_gem->global_name) {
 		struct drm_gem_flink flink;
 
 		memclear(flink);
 		flink.handle = bo_gem->gem_handle;
+		if (drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink))
+			return -errno;
 
 		pthread_mutex_lock(&bufmgr_gem->lock);
+		if (!bo_gem->global_name) {
+			bo_gem->global_name = flink.name;
+			bo_gem->reusable = false;
 
-		ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink);
-		if (ret != 0) {
-			pthread_mutex_unlock(&bufmgr_gem->lock);
-			return -errno;
+			HASH_ADD(name_hh, bufmgr_gem->name_table,
+				 global_name, sizeof(bo_gem->global_name),
+				 bo_gem);
 		}
-
-		bo_gem->global_name = flink.name;
-		bo_gem->reusable = false;
-
-                if (DRMLISTEMPTY(&bo_gem->name_list))
-                        DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
 		pthread_mutex_unlock(&bufmgr_gem->lock);
 	}
 
@@ -2739,6 +2794,59 @@
 }
 
 /**
+ * Disables implicit synchronisation before executing the bo
+ *
+ * This will cause rendering corruption unless you correctly manage explicit
+ * fences for all rendering involving this buffer - including use by others.
+ * Disabling the implicit serialisation is only required if that serialisation
+ * is too coarse (for example, you have split the buffer into many
+ * non-overlapping regions and are sharing the whole buffer between concurrent
+ * independent command streams).
+ *
+ * Note the kernel must advertise support via I915_PARAM_HAS_EXEC_ASYNC,
+ * which can be checked using drm_intel_bufmgr_can_disable_implicit_sync,
+ * or subsequent execbufs involving the bo will generate EINVAL.
+ */
+void
+drm_intel_gem_bo_disable_implicit_sync(drm_intel_bo *bo)
+{
+	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+	bo_gem->kflags |= EXEC_OBJECT_ASYNC;
+}
+
+/**
+ * Enables implicit synchronisation before executing the bo
+ *
+ * This is the default behaviour of the kernel, to wait upon prior writes
+ * completing on the object before rendering with it, or to wait for prior
+ * reads to complete before writing into the object.
+ * drm_intel_gem_bo_disable_implicit_sync() can stop this behaviour, telling
+ * the kernel never to insert a stall before using the object. Then this
+ * function can be used to restore the implicit sync before subsequent
+ * rendering.
+ */
+void
+drm_intel_gem_bo_enable_implicit_sync(drm_intel_bo *bo)
+{
+	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+	bo_gem->kflags &= ~EXEC_OBJECT_ASYNC;
+}
+
+/**
+ * Query whether the kernel supports disabling of its implicit synchronisation
+ * before execbuf. See drm_intel_gem_bo_disable_implicit_sync()
+ */
+int
+drm_intel_bufmgr_gem_can_disable_implicit_sync(drm_intel_bufmgr *bufmgr)
+{
+	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
+
+	return bufmgr_gem->has_exec_async;
+}
+
+/**
  * Enable use of fenced reloc type.
  *
  * New code should enable this to avoid unnecessary fence register
@@ -3034,6 +3142,34 @@
 	drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
 }
 
+static int
+parse_devid_override(const char *devid_override)
+{
+	static const struct {
+		const char *name;
+		int pci_id;
+	} name_map[] = {
+		{ "brw", PCI_CHIP_I965_GM },
+		{ "g4x", PCI_CHIP_GM45_GM },
+		{ "ilk", PCI_CHIP_ILD_G },
+		{ "snb", PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS },
+		{ "ivb", PCI_CHIP_IVYBRIDGE_S_GT2 },
+		{ "hsw", PCI_CHIP_HASWELL_CRW_E_GT3 },
+		{ "byt", PCI_CHIP_VALLEYVIEW_3 },
+		{ "bdw", 0x1620 | BDW_ULX },
+		{ "skl", PCI_CHIP_SKYLAKE_DT_GT2 },
+		{ "kbl", PCI_CHIP_KABYLAKE_DT_GT2 },
+	};
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(name_map); i++) {
+		if (!strcmp(name_map[i].name, devid_override))
+			return name_map[i].pci_id;
+	}
+
+	return strtod(devid_override, NULL);
+}
+
 /**
  * Get the PCI ID for the device.  This can be overridden by setting the
  * INTEL_DEVID_OVERRIDE environment variable to the desired ID.
@@ -3050,7 +3186,7 @@
 		devid_override = getenv("INTEL_DEVID_OVERRIDE");
 		if (devid_override) {
 			bufmgr_gem->no_exec = true;
-			return strtod(devid_override, NULL);
+			return parse_devid_override(devid_override);
 		}
 	}
 
@@ -3130,6 +3266,17 @@
 	return context;
 }
 
+int
+drm_intel_gem_context_get_id(drm_intel_context *ctx, uint32_t *ctx_id)
+{
+	if (ctx == NULL)
+		return -EINVAL;
+
+	*ctx_id = ctx->ctx_id;
+
+	return 0;
+}
+
 void
 drm_intel_gem_context_destroy(drm_intel_context *ctx)
 {
@@ -3237,6 +3384,36 @@
 	return 0;
 }
 
+int
+drm_intel_get_pooled_eu(int fd)
+{
+	drm_i915_getparam_t gp;
+	int ret = -1;
+
+	memclear(gp);
+	gp.param = I915_PARAM_HAS_POOLED_EU;
+	gp.value = &ret;
+	if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
+		return -errno;
+
+	return ret;
+}
+
+int
+drm_intel_get_min_eu_in_pool(int fd)
+{
+	drm_i915_getparam_t gp;
+	int ret = -1;
+
+	memclear(gp);
+	gp.param = I915_PARAM_MIN_EU_IN_POOL;
+	gp.value = &ret;
+	if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
+		return -errno;
+
+	return ret;
+}
+
 /**
  * Annotate the given bo for use in aub dumping.
  *
@@ -3300,6 +3477,141 @@
 	}
 }
 
+void *drm_intel_gem_bo_map__gtt(drm_intel_bo *bo)
+{
+	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+	if (bo_gem->gtt_virtual)
+		return bo_gem->gtt_virtual;
+
+	if (bo_gem->is_userptr)
+		return NULL;
+
+	pthread_mutex_lock(&bufmgr_gem->lock);
+	if (bo_gem->gtt_virtual == NULL) {
+		struct drm_i915_gem_mmap_gtt mmap_arg;
+		void *ptr;
+
+		DBG("bo_map_gtt: mmap %d (%s), map_count=%d\n",
+		    bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
+
+		if (bo_gem->map_count++ == 0)
+			drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
+		memclear(mmap_arg);
+		mmap_arg.handle = bo_gem->gem_handle;
+
+		/* Get the fake offset back... */
+		ptr = MAP_FAILED;
+		if (drmIoctl(bufmgr_gem->fd,
+			     DRM_IOCTL_I915_GEM_MMAP_GTT,
+			     &mmap_arg) == 0) {
+			/* and mmap it */
+			ptr = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
+				       MAP_SHARED, bufmgr_gem->fd,
+				       mmap_arg.offset);
+		}
+		if (ptr == MAP_FAILED) {
+			if (--bo_gem->map_count == 0)
+				drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+			ptr = NULL;
+		}
+
+		bo_gem->gtt_virtual = ptr;
+	}
+	pthread_mutex_unlock(&bufmgr_gem->lock);
+
+	return bo_gem->gtt_virtual;
+}
+
+void *drm_intel_gem_bo_map__cpu(drm_intel_bo *bo)
+{
+	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+	if (bo_gem->mem_virtual)
+		return bo_gem->mem_virtual;
+
+	if (bo_gem->is_userptr) {
+		/* Return the same user ptr */
+		return bo_gem->user_virtual;
+	}
+
+	pthread_mutex_lock(&bufmgr_gem->lock);
+	if (!bo_gem->mem_virtual) {
+		struct drm_i915_gem_mmap mmap_arg;
+
+		if (bo_gem->map_count++ == 0)
+			drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
+		DBG("bo_map: %d (%s), map_count=%d\n",
+		    bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
+
+		memclear(mmap_arg);
+		mmap_arg.handle = bo_gem->gem_handle;
+		mmap_arg.size = bo->size;
+		if (drmIoctl(bufmgr_gem->fd,
+			     DRM_IOCTL_I915_GEM_MMAP,
+			     &mmap_arg)) {
+			DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",
+			    __FILE__, __LINE__, bo_gem->gem_handle,
+			    bo_gem->name, strerror(errno));
+			if (--bo_gem->map_count == 0)
+				drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+		} else {
+			VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1));
+			bo_gem->mem_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr;
+		}
+	}
+	pthread_mutex_unlock(&bufmgr_gem->lock);
+
+	return bo_gem->mem_virtual;
+}
+
+void *drm_intel_gem_bo_map__wc(drm_intel_bo *bo)
+{
+	drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+	if (bo_gem->wc_virtual)
+		return bo_gem->wc_virtual;
+
+	if (bo_gem->is_userptr)
+		return NULL;
+
+	pthread_mutex_lock(&bufmgr_gem->lock);
+	if (!bo_gem->wc_virtual) {
+		struct drm_i915_gem_mmap mmap_arg;
+
+		if (bo_gem->map_count++ == 0)
+			drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
+		DBG("bo_map: %d (%s), map_count=%d\n",
+		    bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
+
+		memclear(mmap_arg);
+		mmap_arg.handle = bo_gem->gem_handle;
+		mmap_arg.size = bo->size;
+		mmap_arg.flags = I915_MMAP_WC;
+		if (drmIoctl(bufmgr_gem->fd,
+			     DRM_IOCTL_I915_GEM_MMAP,
+			     &mmap_arg)) {
+			DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",
+			    __FILE__, __LINE__, bo_gem->gem_handle,
+			    bo_gem->name, strerror(errno));
+			if (--bo_gem->map_count == 0)
+				drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+		} else {
+			VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1));
+			bo_gem->wc_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr;
+		}
+	}
+	pthread_mutex_unlock(&bufmgr_gem->lock);
+
+	return bo_gem->wc_virtual;
+}
+
 /**
  * Initializes the GEM buffer manager, which uses the kernel to allocate, map,
  * and manage map buffer objections.
@@ -3379,7 +3691,7 @@
 	    bufmgr_gem->gtt_size > 256*1024*1024) {
 		/* The unmappable part of gtt on gen 3 (i.e. above 256MB) can't
 		 * be used for tiled blits. To simplify the accounting, just
-		 * substract the unmappable part (fixed to 256MB on all known
+		 * subtract the unmappable part (fixed to 256MB on all known
 		 * gen3 devices) if the kernel advertises it. */
 		bufmgr_gem->gtt_size -= 256*1024*1024;
 	}
@@ -3404,6 +3716,10 @@
 	ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
 	bufmgr_gem->has_relaxed_fencing = ret == 0;
 
+	gp.param = I915_PARAM_HAS_EXEC_ASYNC;
+	ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+	bufmgr_gem->has_exec_async = ret == 0;
+
 	bufmgr_gem->bufmgr.bo_alloc_userptr = check_bo_alloc_userptr;
 
 	gp.param = I915_PARAM_HAS_WAIT_TIMEOUT;
@@ -3507,7 +3823,6 @@
 	    drm_intel_gem_get_pipe_from_crtc_id;
 	bufmgr_gem->bufmgr.bo_references = drm_intel_gem_bo_references;
 
-	DRMINITLISTHEAD(&bufmgr_gem->named);
 	init_cache_buckets(bufmgr_gem);
 
 	DRMINITLISTHEAD(&bufmgr_gem->vma_cache);
diff --git a/intel/intel_chipset.h b/intel/intel_chipset.h
index 26fbee4..41fc0da 100644
--- a/intel/intel_chipset.h
+++ b/intel/intel_chipset.h
@@ -168,6 +168,7 @@
 #define PCI_CHIP_SKYLAKE_DT_GT1		0x1902
 #define PCI_CHIP_SKYLAKE_ULT_GT1	0x1906
 #define PCI_CHIP_SKYLAKE_SRV_GT1	0x190A /* Reserved */
+#define PCI_CHIP_SKYLAKE_H_GT1		0x190B
 #define PCI_CHIP_SKYLAKE_ULX_GT1	0x190E /* Reserved */
 #define PCI_CHIP_SKYLAKE_DT_GT2		0x1912
 #define PCI_CHIP_SKYLAKE_FUSED0_GT2	0x1913 /* Reserved */
@@ -179,17 +180,46 @@
 #define PCI_CHIP_SKYLAKE_WKS_GT2 	0x191D
 #define PCI_CHIP_SKYLAKE_ULX_GT2	0x191E
 #define PCI_CHIP_SKYLAKE_MOBILE_GT2	0x1921 /* Reserved */
-#define PCI_CHIP_SKYLAKE_GT3		0x1926
-#define PCI_CHIP_SKYLAKE_HALO_GT3	0x192B /* Reserved */
+#define PCI_CHIP_SKYLAKE_ULT_GT3_0	0x1923
+#define PCI_CHIP_SKYLAKE_ULT_GT3_1	0x1926
+#define PCI_CHIP_SKYLAKE_ULT_GT3_2	0x1927
 #define PCI_CHIP_SKYLAKE_SRV_GT4	0x192A
+#define PCI_CHIP_SKYLAKE_HALO_GT3	0x192B /* Reserved */
+#define PCI_CHIP_SKYLAKE_SRV_GT3	0x192D
 #define PCI_CHIP_SKYLAKE_DT_GT4		0x1932
 #define PCI_CHIP_SKYLAKE_SRV_GT4X	0x193A
 #define PCI_CHIP_SKYLAKE_H_GT4		0x193B
 #define PCI_CHIP_SKYLAKE_WKS_GT4	0x193D
 
+#define PCI_CHIP_KABYLAKE_ULT_GT2	0x5916
+#define PCI_CHIP_KABYLAKE_ULT_GT1_5	0x5913
+#define PCI_CHIP_KABYLAKE_ULT_GT1	0x5906
+#define PCI_CHIP_KABYLAKE_ULT_GT3_0	0x5923
+#define PCI_CHIP_KABYLAKE_ULT_GT3_1	0x5926
+#define PCI_CHIP_KABYLAKE_ULT_GT3_2	0x5927
+#define PCI_CHIP_KABYLAKE_ULT_GT2F	0x5921
+#define PCI_CHIP_KABYLAKE_ULX_GT1_5	0x5915
+#define PCI_CHIP_KABYLAKE_ULX_GT1	0x590E
+#define PCI_CHIP_KABYLAKE_ULX_GT2	0x591E
+#define PCI_CHIP_KABYLAKE_DT_GT2	0x5912
+#define PCI_CHIP_KABYLAKE_DT_GT1_5	0x5917
+#define PCI_CHIP_KABYLAKE_DT_GT1	0x5902
+#define PCI_CHIP_KABYLAKE_HALO_GT2	0x591B
+#define PCI_CHIP_KABYLAKE_HALO_GT4	0x593B
+#define PCI_CHIP_KABYLAKE_HALO_GT1_0	0x5908
+#define PCI_CHIP_KABYLAKE_HALO_GT1_1	0x590B
+#define PCI_CHIP_KABYLAKE_SRV_GT2	0x591A
+#define PCI_CHIP_KABYLAKE_SRV_GT1	0x590A
+#define PCI_CHIP_KABYLAKE_WKS_GT2	0x591D
+
 #define PCI_CHIP_BROXTON_0		0x0A84
 #define PCI_CHIP_BROXTON_1		0x1A84
 #define PCI_CHIP_BROXTON_2		0x5A84
+#define PCI_CHIP_BROXTON_3		0x1A85
+#define PCI_CHIP_BROXTON_4		0x5A85
+
+#define PCI_CHIP_GLK			0x3184
+#define PCI_CHIP_GLK_2X6		0x3185
 
 #define IS_MOBILE(devid)	((devid) == PCI_CHIP_I855_GM || \
 				 (devid) == PCI_CHIP_I915_GM || \
@@ -350,10 +380,11 @@
 #define IS_GEN8(devid)		(IS_BROADWELL(devid) || \
 				 IS_CHERRYVIEW(devid))
 
-#define IS_SKL_GT1(devid)	((devid) == PCI_CHIP_SKYLAKE_ULT_GT1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_ULX_GT1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_DT_GT1	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_SRV_GT1)
+#define IS_SKL_GT1(devid)	((devid) == PCI_CHIP_SKYLAKE_DT_GT1	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_ULT_GT1	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_SRV_GT1	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_H_GT1	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_ULX_GT1)
 
 #define IS_SKL_GT2(devid)	((devid) == PCI_CHIP_SKYLAKE_DT_GT2	|| \
 				 (devid) == PCI_CHIP_SKYLAKE_FUSED0_GT2	|| \
@@ -366,8 +397,11 @@
 				 (devid) == PCI_CHIP_SKYLAKE_ULX_GT2	|| \
 				 (devid) == PCI_CHIP_SKYLAKE_MOBILE_GT2)
 
-#define IS_SKL_GT3(devid)	((devid) == PCI_CHIP_SKYLAKE_GT3	|| \
-				 (devid) == PCI_CHIP_SKYLAKE_HALO_GT3)
+#define IS_SKL_GT3(devid)	((devid) == PCI_CHIP_SKYLAKE_ULT_GT3_0	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_ULT_GT3_1	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_ULT_GT3_2	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_HALO_GT3	|| \
+				 (devid) == PCI_CHIP_SKYLAKE_SRV_GT3)
 
 #define IS_SKL_GT4(devid)	((devid) == PCI_CHIP_SKYLAKE_SRV_GT4	|| \
 				 (devid) == PCI_CHIP_SKYLAKE_DT_GT4	|| \
@@ -375,6 +409,35 @@
 				 (devid) == PCI_CHIP_SKYLAKE_H_GT4	|| \
 				 (devid) == PCI_CHIP_SKYLAKE_WKS_GT4)
 
+#define IS_KBL_GT1(devid)	((devid) == PCI_CHIP_KABYLAKE_ULT_GT1_5	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_ULX_GT1_5	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_DT_GT1_5	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT1	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_ULX_GT1	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_DT_GT1	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_HALO_GT1_0 || \
+				 (devid) == PCI_CHIP_KABYLAKE_HALO_GT1_1 || \
+				 (devid) == PCI_CHIP_KABYLAKE_SRV_GT1)
+
+#define IS_KBL_GT2(devid)	((devid) == PCI_CHIP_KABYLAKE_ULT_GT2	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT2F	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_ULX_GT2	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_DT_GT2	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_HALO_GT2	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_SRV_GT2	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_WKS_GT2)
+
+#define IS_KBL_GT3(devid)	((devid) == PCI_CHIP_KABYLAKE_ULT_GT3_0	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT3_1	|| \
+				 (devid) == PCI_CHIP_KABYLAKE_ULT_GT3_2)
+
+#define IS_KBL_GT4(devid)	((devid) == PCI_CHIP_KABYLAKE_HALO_GT4)
+
+#define IS_KABYLAKE(devid)	(IS_KBL_GT1(devid) || \
+				 IS_KBL_GT2(devid) || \
+				 IS_KBL_GT3(devid) || \
+				 IS_KBL_GT4(devid))
+
 #define IS_SKYLAKE(devid)	(IS_SKL_GT1(devid) || \
 				 IS_SKL_GT2(devid) || \
 				 IS_SKL_GT3(devid) || \
@@ -382,10 +445,17 @@
 
 #define IS_BROXTON(devid)	((devid) == PCI_CHIP_BROXTON_0	|| \
 				 (devid) == PCI_CHIP_BROXTON_1	|| \
-				 (devid) == PCI_CHIP_BROXTON_2)
+				 (devid) == PCI_CHIP_BROXTON_2	|| \
+				 (devid) == PCI_CHIP_BROXTON_3	|| \
+				 (devid) == PCI_CHIP_BROXTON_4)
 
-#define IS_GEN9(devid)		(IS_SKYLAKE(devid) || \
-				 IS_BROXTON(devid))
+#define IS_GEMINILAKE(devid)	((devid) == PCI_CHIP_GLK || \
+				 (devid) == PCI_CHIP_GLK_2X6)
+
+#define IS_GEN9(devid)		(IS_SKYLAKE(devid)  || \
+				 IS_BROXTON(devid)  || \
+				 IS_KABYLAKE(devid) || \
+				 IS_GEMINILAKE(devid))
 
 #define IS_9XX(dev)		(IS_GEN3(dev) || \
 				 IS_GEN4(dev) || \
diff --git a/intel/intel_decode.c b/intel/intel_decode.c
index e7aef74..803d202 100644
--- a/intel/intel_decode.c
+++ b/intel/intel_decode.c
@@ -38,8 +38,6 @@
 #include "intel_chipset.h"
 #include "intel_bufmgr.h"
 
-/* The compiler throws ~90 warnings. Do not spam the build, until we fix them. */
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 
 /* Struct for tracking drm_intel_decode state. */
 struct drm_intel_decode {
@@ -3600,7 +3598,7 @@
 		instr_out(ctx, 0, "3DSTATE_DEPTH_BUFFER\n");
 		if (IS_GEN5(devid) || IS_GEN6(devid))
 			instr_out(ctx, 1,
-				  "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
+				  "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
 				  get_965_surfacetype(data[1] >> 29),
 				  get_965_depthformat((data[1] >> 18) & 0x7),
 				  (data[1] & 0x0001ffff) + 1,
diff --git a/intel/tests/gen5-3d.batch-ref.txt b/intel/tests/gen5-3d.batch-ref.txt
index a0271ab..51dd85f 100644
--- a/intel/tests/gen5-3d.batch-ref.txt
+++ b/intel/tests/gen5-3d.batch-ref.txt
@@ -24,7 +24,7 @@
 0x1230005c:      0x00000000:    dword 3
 0x12300060:      0x00000000:    dword 4
 0x12300064:      0x79050004: 3DSTATE_DEPTH_BUFFER
-0x12300068:      0x2c0805ff:    2D, z24s8, pitch = 1536 bytes, tiled, HiZ 0, Seperate Stencil 0
+0x12300068:      0x2c0805ff:    2D, z24s8, pitch = 1536 bytes, tiled, HiZ 0, Separate Stencil 0
 0x1230006c:      0x00000000:    depth offset
 0x12300070:      0x09584ac0:    300x300
 0x12300074:      0x00000000:    volume depth
diff --git a/intel/tests/gen6-3d.batch-ref.txt b/intel/tests/gen6-3d.batch-ref.txt
index 9035663..04cbddc 100644
--- a/intel/tests/gen6-3d.batch-ref.txt
+++ b/intel/tests/gen6-3d.batch-ref.txt
@@ -140,7 +140,7 @@
 0x1230022c:      0x00000000:    
 0x12300230:      0x00000000:    
 0x12300234:      0x79050005: 3DSTATE_DEPTH_BUFFER
-0x12300238:      0x2c6c05ff:    2D, unknown, pitch = 1536 bytes, tiled, HiZ 1, Seperate Stencil 1
+0x12300238:      0x2c6c05ff:    2D, unknown, pitch = 1536 bytes, tiled, HiZ 1, Separate Stencil 1
 0x1230023c:      0x00000000:    depth offset
 0x12300240:      0x09584ac0:    300x300
 0x12300244:      0x00000000:    volume depth
diff --git a/intel/uthash.h b/intel/uthash.h
new file mode 100644
index 0000000..45d1f9f
--- /dev/null
+++ b/intel/uthash.h
@@ -0,0 +1,1074 @@
+/*
+Copyright (c) 2003-2016, Troy D. Hanson     http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#define UTHASH_VERSION 2.0.1
+
+#include <string.h>   /* memcmp,strlen */
+#include <stddef.h>   /* ptrdiff_t */
+#include <stdlib.h>   /* exit() */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ source) this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#if defined(_MSC_VER)   /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else                   /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#else                   /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  char **_da_dst = (char**)(&(dst));                                             \
+  *_da_dst = (char*)(src);                                                       \
+} while (0)
+#else
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  (dst) = DECLTYPE(dst)(src);                                                    \
+} while (0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1600
+#include <stdint.h>
+#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+#elif defined(__GNUC__) && !defined(__VXWORKS__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1)        /* fatal error (out of memory,etc) */
+#endif
+#ifndef uthash_malloc
+#define uthash_malloc(sz) malloc(sz)      /* malloc fcn                      */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) free(ptr)     /* free fcn                        */
+#endif
+#ifndef uthash_strlen
+#define uthash_strlen(s) strlen(s)
+#endif
+#ifndef uthash_memcmp
+#define uthash_memcmp(a,b,n) memcmp(a,b,n)
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl)          /* can be defined to log noexpand  */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl)            /* can be defined to log expands   */
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32U     /* initial number of buckets        */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10U     /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhp */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+/* calculate the hash handle from element address elp */
+#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho)))
+
+#define HASH_VALUE(keyptr,keylen,hashv)                                          \
+do {                                                                             \
+  HASH_FCN(keyptr, keylen, hashv);                                               \
+} while (0)
+
+#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out)                 \
+do {                                                                             \
+  (out) = NULL;                                                                  \
+  if (head) {                                                                    \
+    unsigned _hf_bkt;                                                            \
+    HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt);                  \
+    if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) {                         \
+      HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \
+    }                                                                            \
+  }                                                                              \
+} while (0)
+
+#define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
+do {                                                                             \
+  unsigned _hf_hashv;                                                            \
+  HASH_VALUE(keyptr, keylen, _hf_hashv);                                         \
+  HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out);               \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL)
+#define HASH_BLOOM_MAKE(tbl)                                                     \
+do {                                                                             \
+  (tbl)->bloom_nbits = HASH_BLOOM;                                               \
+  (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN);                 \
+  if (!((tbl)->bloom_bv))  { uthash_fatal( "out of memory"); }                   \
+  memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN);                                \
+  (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE;                                       \
+} while (0)
+
+#define HASH_BLOOM_FREE(tbl)                                                     \
+do {                                                                             \
+  uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN);                              \
+} while (0)
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U)))
+
+#define HASH_BLOOM_ADD(tbl,hashv)                                                \
+  HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U)))
+
+#define HASH_BLOOM_TEST(tbl,hashv)                                               \
+  HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0U
+#endif
+
+#define HASH_MAKE_TABLE(hh,head)                                                 \
+do {                                                                             \
+  (head)->hh.tbl = (UT_hash_table*)uthash_malloc(                                \
+                  sizeof(UT_hash_table));                                        \
+  if (!((head)->hh.tbl))  { uthash_fatal( "out of memory"); }                    \
+  memset((head)->hh.tbl, 0, sizeof(UT_hash_table));                              \
+  (head)->hh.tbl->tail = &((head)->hh);                                          \
+  (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS;                        \
+  (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2;              \
+  (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head);                    \
+  (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc(                      \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); }             \
+  memset((head)->hh.tbl->buckets, 0,                                             \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  HASH_BLOOM_MAKE((head)->hh.tbl);                                               \
+  (head)->hh.tbl->signature = HASH_SIGNATURE;                                    \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \
+do {                                                                             \
+  (replaced) = NULL;                                                             \
+  HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+  if (replaced) {                                                                \
+     HASH_DELETE(hh, head, replaced);                                            \
+  }                                                                              \
+  HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \
+do {                                                                             \
+  (replaced) = NULL;                                                             \
+  HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+  if (replaced) {                                                                \
+     HASH_DELETE(hh, head, replaced);                                            \
+  }                                                                              \
+  HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \
+} while (0)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced)                   \
+do {                                                                             \
+  unsigned _hr_hashv;                                                            \
+  HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv);                         \
+  HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \
+} while (0)
+
+#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn)    \
+do {                                                                             \
+  unsigned _hr_hashv;                                                            \
+  HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv);                         \
+  HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \
+} while (0)
+
+#define HASH_APPEND_LIST(hh, head, add)                                          \
+do {                                                                             \
+  (add)->hh.next = NULL;                                                         \
+  (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);           \
+  (head)->hh.tbl->tail->next = (add);                                            \
+  (head)->hh.tbl->tail = &((add)->hh);                                           \
+} while (0)
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \
+do {                                                                             \
+  unsigned _ha_bkt;                                                              \
+  (add)->hh.hashv = (hashval);                                                   \
+  (add)->hh.key = (char*) (keyptr);                                              \
+  (add)->hh.keylen = (unsigned) (keylen_in);                                     \
+  if (!(head)) {                                                                 \
+    (add)->hh.next = NULL;                                                       \
+    (add)->hh.prev = NULL;                                                       \
+    (head) = (add);                                                              \
+    HASH_MAKE_TABLE(hh, head);                                                   \
+  } else {                                                                       \
+    struct UT_hash_handle *_hs_iter = &(head)->hh;                               \
+    (add)->hh.tbl = (head)->hh.tbl;                                              \
+    do {                                                                         \
+      if (cmpfcn(DECLTYPE(head) ELMT_FROM_HH((head)->hh.tbl, _hs_iter), add) > 0) \
+        break;                                                                   \
+    } while ((_hs_iter = _hs_iter->next));                                       \
+    if (_hs_iter) {                                                              \
+      (add)->hh.next = _hs_iter;                                                 \
+      if (((add)->hh.prev = _hs_iter->prev)) {                                   \
+        HH_FROM_ELMT((head)->hh.tbl, _hs_iter->prev)->next = (add);              \
+      } else {                                                                   \
+        (head) = (add);                                                          \
+      }                                                                          \
+      _hs_iter->prev = (add);                                                    \
+    } else {                                                                     \
+      HASH_APPEND_LIST(hh, head, add);                                           \
+    }                                                                            \
+  }                                                                              \
+  (head)->hh.tbl->num_items++;                                                   \
+  HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt);                    \
+  HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh);                 \
+  HASH_BLOOM_ADD((head)->hh.tbl, hashval);                                       \
+  HASH_EMIT_KEY(hh, head, keyptr, keylen_in);                                    \
+  HASH_FSCK(hh, head);                                                           \
+} while (0)
+
+#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn)             \
+do {                                                                             \
+  unsigned _hs_hashv;                                                            \
+  HASH_VALUE(keyptr, keylen_in, _hs_hashv);                                      \
+  HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \
+  HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn)
+
+#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn)                 \
+  HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn)
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add)        \
+do {                                                                             \
+  unsigned _ha_bkt;                                                              \
+  (add)->hh.hashv = (hashval);                                                   \
+  (add)->hh.key = (char*) (keyptr);                                              \
+  (add)->hh.keylen = (unsigned) (keylen_in);                                     \
+  if (!(head)) {                                                                 \
+    (add)->hh.next = NULL;                                                       \
+    (add)->hh.prev = NULL;                                                       \
+    (head) = (add);                                                              \
+    HASH_MAKE_TABLE(hh, head);                                                   \
+  } else {                                                                       \
+    (add)->hh.tbl = (head)->hh.tbl;                                              \
+    HASH_APPEND_LIST(hh, head, add);                                             \
+  }                                                                              \
+  (head)->hh.tbl->num_items++;                                                   \
+  HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt);                    \
+  HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh);                 \
+  HASH_BLOOM_ADD((head)->hh.tbl, hashval);                                       \
+  HASH_EMIT_KEY(hh, head, keyptr, keylen_in);                                    \
+  HASH_FSCK(hh, head);                                                           \
+} while (0)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+do {                                                                             \
+  unsigned _ha_hashv;                                                            \
+  HASH_VALUE(keyptr, keylen_in, _ha_hashv);                                      \
+  HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add);      \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add)            \
+  HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
+  HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add)
+
+#define HASH_TO_BKT(hashv,num_bkts,bkt)                                          \
+do {                                                                             \
+  bkt = ((hashv) & ((num_bkts) - 1U));                                           \
+} while (0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ *  HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr)                                              \
+do {                                                                             \
+    struct UT_hash_handle *_hd_hh_del;                                           \
+    if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) )  {         \
+        uthash_free((head)->hh.tbl->buckets,                                     \
+                    (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+        HASH_BLOOM_FREE((head)->hh.tbl);                                         \
+        uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                      \
+        head = NULL;                                                             \
+    } else {                                                                     \
+        unsigned _hd_bkt;                                                        \
+        _hd_hh_del = &((delptr)->hh);                                            \
+        if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) {     \
+            (head)->hh.tbl->tail =                                               \
+                (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +               \
+                (head)->hh.tbl->hho);                                            \
+        }                                                                        \
+        if ((delptr)->hh.prev != NULL) {                                         \
+            ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +                  \
+                    (head)->hh.tbl->hho))->next = (delptr)->hh.next;             \
+        } else {                                                                 \
+            DECLTYPE_ASSIGN(head,(delptr)->hh.next);                             \
+        }                                                                        \
+        if (_hd_hh_del->next != NULL) {                                          \
+            ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next +                     \
+                    (head)->hh.tbl->hho))->prev =                                \
+                    _hd_hh_del->prev;                                            \
+        }                                                                        \
+        HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt);   \
+        HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del);        \
+        (head)->hh.tbl->num_items--;                                             \
+    }                                                                            \
+    HASH_FSCK(hh,head);                                                          \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out)                                          \
+    HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add)                                          \
+    HASH_ADD(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add)
+#define HASH_REPLACE_STR(head,strfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add,replaced)
+#define HASH_FIND_INT(head,findint,out)                                          \
+    HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add)                                          \
+    HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out)                                          \
+    HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add)                                          \
+    HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr)                                                    \
+    HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head)                                                       \
+do {                                                                             \
+    struct UT_hash_handle *_thh;                                                 \
+    if (head) {                                                                  \
+        unsigned _bkt_i;                                                         \
+        unsigned _count;                                                         \
+        char *_prev;                                                             \
+        _count = 0;                                                              \
+        for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) {       \
+            unsigned _bkt_count = 0;                                             \
+            _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head;                      \
+            _prev = NULL;                                                        \
+            while (_thh) {                                                       \
+               if (_prev != (char*)(_thh->hh_prev)) {                            \
+                   HASH_OOPS("invalid hh_prev %p, actual %p\n",                  \
+                    _thh->hh_prev, _prev );                                      \
+               }                                                                 \
+               _bkt_count++;                                                     \
+               _prev = (char*)(_thh);                                            \
+               _thh = _thh->hh_next;                                             \
+            }                                                                    \
+            _count += _bkt_count;                                                \
+            if ((head)->hh.tbl->buckets[_bkt_i].count !=  _bkt_count) {          \
+               HASH_OOPS("invalid bucket count %u, actual %u\n",                 \
+                (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count);              \
+            }                                                                    \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid hh item count %u, actual %u\n",                   \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+        /* traverse hh in app order; check next/prev integrity, count */         \
+        _count = 0;                                                              \
+        _prev = NULL;                                                            \
+        _thh =  &(head)->hh;                                                     \
+        while (_thh) {                                                           \
+           _count++;                                                             \
+           if (_prev !=(char*)(_thh->prev)) {                                    \
+              HASH_OOPS("invalid prev %p, actual %p\n",                          \
+                    _thh->prev, _prev );                                         \
+           }                                                                     \
+           _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh);                    \
+           _thh = ( _thh->next ?  (UT_hash_handle*)((char*)(_thh->next) +        \
+                                  (head)->hh.tbl->hho) : NULL );                 \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid app item count %u, actual %u\n",                  \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+    }                                                                            \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                                   \
+do {                                                                             \
+    unsigned _klen = fieldlen;                                                   \
+    write(HASH_EMIT_KEYS, &_klen, sizeof(_klen));                                \
+    write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen);                      \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
+#define HASH_BER(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _hb_keylen=(unsigned)keylen;                                          \
+  const unsigned char *_hb_key=(const unsigned char*)(key);                      \
+  (hashv) = 0;                                                                   \
+  while (_hb_keylen-- != 0U) {                                                   \
+      (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++;                         \
+  }                                                                              \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _sx_i;                                                                \
+  const unsigned char *_hs_key=(const unsigned char*)(key);                      \
+  hashv = 0;                                                                     \
+  for(_sx_i=0; _sx_i < keylen; _sx_i++) {                                        \
+      hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
+  }                                                                              \
+} while (0)
+/* FNV-1a variation */
+#define HASH_FNV(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _fn_i;                                                                \
+  const unsigned char *_hf_key=(const unsigned char*)(key);                      \
+  hashv = 2166136261U;                                                           \
+  for(_fn_i=0; _fn_i < keylen; _fn_i++) {                                        \
+      hashv = hashv ^ _hf_key[_fn_i];                                            \
+      hashv = hashv * 16777619U;                                                 \
+  }                                                                              \
+} while (0)
+
+#define HASH_OAT(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _ho_i;                                                                \
+  const unsigned char *_ho_key=(const unsigned char*)(key);                      \
+  hashv = 0;                                                                     \
+  for(_ho_i=0; _ho_i < keylen; _ho_i++) {                                        \
+      hashv += _ho_key[_ho_i];                                                   \
+      hashv += (hashv << 10);                                                    \
+      hashv ^= (hashv >> 6);                                                     \
+  }                                                                              \
+  hashv += (hashv << 3);                                                         \
+  hashv ^= (hashv >> 11);                                                        \
+  hashv += (hashv << 15);                                                        \
+} while (0)
+
+#define HASH_JEN_MIX(a,b,c)                                                      \
+do {                                                                             \
+  a -= b; a -= c; a ^= ( c >> 13 );                                              \
+  b -= c; b -= a; b ^= ( a << 8 );                                               \
+  c -= a; c -= b; c ^= ( b >> 13 );                                              \
+  a -= b; a -= c; a ^= ( c >> 12 );                                              \
+  b -= c; b -= a; b ^= ( a << 16 );                                              \
+  c -= a; c -= b; c ^= ( b >> 5 );                                               \
+  a -= b; a -= c; a ^= ( c >> 3 );                                               \
+  b -= c; b -= a; b ^= ( a << 10 );                                              \
+  c -= a; c -= b; c ^= ( b >> 15 );                                              \
+} while (0)
+
+#define HASH_JEN(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned _hj_i,_hj_j,_hj_k;                                                    \
+  unsigned const char *_hj_key=(unsigned const char*)(key);                      \
+  hashv = 0xfeedbeefu;                                                           \
+  _hj_i = _hj_j = 0x9e3779b9u;                                                   \
+  _hj_k = (unsigned)(keylen);                                                    \
+  while (_hj_k >= 12U) {                                                         \
+    _hj_i +=    (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 )                      \
+        + ( (unsigned)_hj_key[2] << 16 )                                         \
+        + ( (unsigned)_hj_key[3] << 24 ) );                                      \
+    _hj_j +=    (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 )                      \
+        + ( (unsigned)_hj_key[6] << 16 )                                         \
+        + ( (unsigned)_hj_key[7] << 24 ) );                                      \
+    hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 )                         \
+        + ( (unsigned)_hj_key[10] << 16 )                                        \
+        + ( (unsigned)_hj_key[11] << 24 ) );                                     \
+                                                                                 \
+     HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                          \
+                                                                                 \
+     _hj_key += 12;                                                              \
+     _hj_k -= 12U;                                                               \
+  }                                                                              \
+  hashv += (unsigned)(keylen);                                                   \
+  switch ( _hj_k ) {                                                             \
+     case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */        \
+     case 10: hashv += ( (unsigned)_hj_key[9] << 16 );  /* FALLTHROUGH */        \
+     case 9:  hashv += ( (unsigned)_hj_key[8] << 8 );   /* FALLTHROUGH */        \
+     case 8:  _hj_j += ( (unsigned)_hj_key[7] << 24 );  /* FALLTHROUGH */        \
+     case 7:  _hj_j += ( (unsigned)_hj_key[6] << 16 );  /* FALLTHROUGH */        \
+     case 6:  _hj_j += ( (unsigned)_hj_key[5] << 8 );   /* FALLTHROUGH */        \
+     case 5:  _hj_j += _hj_key[4];                      /* FALLTHROUGH */        \
+     case 4:  _hj_i += ( (unsigned)_hj_key[3] << 24 );  /* FALLTHROUGH */        \
+     case 3:  _hj_i += ( (unsigned)_hj_key[2] << 16 );  /* FALLTHROUGH */        \
+     case 2:  _hj_i += ( (unsigned)_hj_key[1] << 8 );   /* FALLTHROUGH */        \
+     case 1:  _hj_i += _hj_key[0];                                               \
+  }                                                                              \
+  HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
+} while (0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)             \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,hashv)                                               \
+do {                                                                             \
+  unsigned const char *_sfh_key=(unsigned const char*)(key);                     \
+  uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen;                                \
+                                                                                 \
+  unsigned _sfh_rem = _sfh_len & 3U;                                             \
+  _sfh_len >>= 2;                                                                \
+  hashv = 0xcafebabeu;                                                           \
+                                                                                 \
+  /* Main loop */                                                                \
+  for (;_sfh_len > 0U; _sfh_len--) {                                             \
+    hashv    += get16bits (_sfh_key);                                            \
+    _sfh_tmp  = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv;              \
+    hashv     = (hashv << 16) ^ _sfh_tmp;                                        \
+    _sfh_key += 2U*sizeof (uint16_t);                                            \
+    hashv    += hashv >> 11;                                                     \
+  }                                                                              \
+                                                                                 \
+  /* Handle end cases */                                                         \
+  switch (_sfh_rem) {                                                            \
+    case 3: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 16;                                                \
+            hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18;              \
+            hashv += hashv >> 11;                                                \
+            break;                                                               \
+    case 2: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 11;                                                \
+            hashv += hashv >> 17;                                                \
+            break;                                                               \
+    case 1: hashv += *_sfh_key;                                                  \
+            hashv ^= hashv << 10;                                                \
+            hashv += hashv >> 1;                                                 \
+  }                                                                              \
+                                                                                 \
+    /* Force "avalanching" of final 127 bits */                                  \
+    hashv ^= hashv << 3;                                                         \
+    hashv += hashv >> 5;                                                         \
+    hashv ^= hashv << 4;                                                         \
+    hashv += hashv >> 17;                                                        \
+    hashv ^= hashv << 25;                                                        \
+    hashv += hashv >> 6;                                                         \
+} while (0)
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ *   gcc -m64 -dM -E - < /dev/null                  (on gcc)
+ *   cc -## a.c (where a.c is a simple test file)   (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__)  || defined(_M_IX86))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >>  8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) <<  8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) :           \
+                            (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+                             (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) :  \
+                                                      MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do {                 \
+  _h ^= _h >> 16;    \
+  _h *= 0x85ebca6bu; \
+  _h ^= _h >> 13;    \
+  _h *= 0xc2b2ae35u; \
+  _h ^= _h >> 16;    \
+} while (0)
+
+#define HASH_MUR(key,keylen,hashv)                                     \
+do {                                                                   \
+  const uint8_t *_mur_data = (const uint8_t*)(key);                    \
+  const int _mur_nblocks = (int)(keylen) / 4;                          \
+  uint32_t _mur_h1 = 0xf88D5353u;                                      \
+  uint32_t _mur_c1 = 0xcc9e2d51u;                                      \
+  uint32_t _mur_c2 = 0x1b873593u;                                      \
+  uint32_t _mur_k1 = 0;                                                \
+  const uint8_t *_mur_tail;                                            \
+  const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \
+  int _mur_i;                                                          \
+  for(_mur_i = -_mur_nblocks; _mur_i!=0; _mur_i++) {                   \
+    _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i);                        \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+                                                                       \
+    _mur_h1 ^= _mur_k1;                                                \
+    _mur_h1 = MUR_ROTL32(_mur_h1,13);                                  \
+    _mur_h1 = (_mur_h1*5U) + 0xe6546b64u;                              \
+  }                                                                    \
+  _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4));          \
+  _mur_k1=0;                                                           \
+  switch((keylen) & 3U) {                                              \
+    case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \
+    case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8;  /* FALLTHROUGH */ \
+    case 1: _mur_k1 ^= (uint32_t)_mur_tail[0];                         \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+    _mur_h1 ^= _mur_k1;                                                \
+  }                                                                    \
+  _mur_h1 ^= (uint32_t)(keylen);                                       \
+  MUR_FMIX(_mur_h1);                                                   \
+  hashv = _mur_h1;                                                     \
+} while (0)
+#endif  /* HASH_USING_NO_STRICT_ALIASING */
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out)               \
+do {                                                                             \
+  if ((head).hh_head != NULL) {                                                  \
+    DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head));                     \
+  } else {                                                                       \
+    (out) = NULL;                                                                \
+  }                                                                              \
+  while ((out) != NULL) {                                                        \
+    if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) {       \
+      if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) {                \
+        break;                                                                   \
+      }                                                                          \
+    }                                                                            \
+    if ((out)->hh.hh_next != NULL) {                                             \
+      DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next));                \
+    } else {                                                                     \
+      (out) = NULL;                                                              \
+    }                                                                            \
+  }                                                                              \
+} while (0)
+
+/* add an item to a bucket  */
+#define HASH_ADD_TO_BKT(head,addhh)                                              \
+do {                                                                             \
+ head.count++;                                                                   \
+ (addhh)->hh_next = head.hh_head;                                                \
+ (addhh)->hh_prev = NULL;                                                        \
+ if (head.hh_head != NULL) { (head).hh_head->hh_prev = (addhh); }                \
+ (head).hh_head=addhh;                                                           \
+ if ((head.count >= ((head.expand_mult+1U) * HASH_BKT_CAPACITY_THRESH))          \
+     && ((addhh)->tbl->noexpand != 1U)) {                                        \
+       HASH_EXPAND_BUCKETS((addhh)->tbl);                                        \
+ }                                                                               \
+} while (0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del)                                          \
+    (head).count--;                                                              \
+    if ((head).hh_head == hh_del) {                                              \
+      (head).hh_head = hh_del->hh_next;                                          \
+    }                                                                            \
+    if (hh_del->hh_prev) {                                                       \
+        hh_del->hh_prev->hh_next = hh_del->hh_next;                              \
+    }                                                                            \
+    if (hh_del->hh_next) {                                                       \
+        hh_del->hh_next->hh_prev = hh_del->hh_prev;                              \
+    }
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ *      ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ *      ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(tbl)                                                 \
+do {                                                                             \
+    unsigned _he_bkt;                                                            \
+    unsigned _he_bkt_i;                                                          \
+    struct UT_hash_handle *_he_thh, *_he_hh_nxt;                                 \
+    UT_hash_bucket *_he_new_buckets, *_he_newbkt;                                \
+    _he_new_buckets = (UT_hash_bucket*)uthash_malloc(                            \
+             2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket));            \
+    if (!_he_new_buckets) { uthash_fatal( "out of memory"); }                    \
+    memset(_he_new_buckets, 0,                                                   \
+            2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket));             \
+    tbl->ideal_chain_maxlen =                                                    \
+       (tbl->num_items >> (tbl->log2_num_buckets+1U)) +                          \
+       (((tbl->num_items & ((tbl->num_buckets*2U)-1U)) != 0U) ? 1U : 0U);        \
+    tbl->nonideal_items = 0;                                                     \
+    for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++)                \
+    {                                                                            \
+        _he_thh = tbl->buckets[ _he_bkt_i ].hh_head;                             \
+        while (_he_thh != NULL) {                                                \
+           _he_hh_nxt = _he_thh->hh_next;                                        \
+           HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2U, _he_bkt);           \
+           _he_newbkt = &(_he_new_buckets[ _he_bkt ]);                           \
+           if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) {                \
+             tbl->nonideal_items++;                                              \
+             _he_newbkt->expand_mult = _he_newbkt->count /                       \
+                                        tbl->ideal_chain_maxlen;                 \
+           }                                                                     \
+           _he_thh->hh_prev = NULL;                                              \
+           _he_thh->hh_next = _he_newbkt->hh_head;                               \
+           if (_he_newbkt->hh_head != NULL) { _he_newbkt->hh_head->hh_prev =     \
+                _he_thh; }                                                       \
+           _he_newbkt->hh_head = _he_thh;                                        \
+           _he_thh = _he_hh_nxt;                                                 \
+        }                                                                        \
+    }                                                                            \
+    uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+    tbl->num_buckets *= 2U;                                                      \
+    tbl->log2_num_buckets++;                                                     \
+    tbl->buckets = _he_new_buckets;                                              \
+    tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ?         \
+        (tbl->ineff_expands+1U) : 0U;                                            \
+    if (tbl->ineff_expands > 1U) {                                               \
+        tbl->noexpand=1;                                                         \
+        uthash_noexpand_fyi(tbl);                                                \
+    }                                                                            \
+    uthash_expand_fyi(tbl);                                                      \
+} while (0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn)                                                 \
+do {                                                                             \
+  unsigned _hs_i;                                                                \
+  unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize;               \
+  struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail;            \
+  if (head != NULL) {                                                            \
+      _hs_insize = 1;                                                            \
+      _hs_looping = 1;                                                           \
+      _hs_list = &((head)->hh);                                                  \
+      while (_hs_looping != 0U) {                                                \
+          _hs_p = _hs_list;                                                      \
+          _hs_list = NULL;                                                       \
+          _hs_tail = NULL;                                                       \
+          _hs_nmerges = 0;                                                       \
+          while (_hs_p != NULL) {                                                \
+              _hs_nmerges++;                                                     \
+              _hs_q = _hs_p;                                                     \
+              _hs_psize = 0;                                                     \
+              for ( _hs_i = 0; _hs_i  < _hs_insize; _hs_i++ ) {                  \
+                  _hs_psize++;                                                   \
+                  _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ?              \
+                          ((void*)((char*)(_hs_q->next) +                        \
+                          (head)->hh.tbl->hho)) : NULL);                         \
+                  if (! (_hs_q) ) { break; }                                     \
+              }                                                                  \
+              _hs_qsize = _hs_insize;                                            \
+              while ((_hs_psize > 0U) || ((_hs_qsize > 0U) && (_hs_q != NULL))) {\
+                  if (_hs_psize == 0U) {                                         \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ?          \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  } else if ( (_hs_qsize == 0U) || (_hs_q == NULL) ) {           \
+                      _hs_e = _hs_p;                                             \
+                      if (_hs_p != NULL){                                        \
+                        _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ?        \
+                                ((void*)((char*)(_hs_p->next) +                  \
+                                (head)->hh.tbl->hho)) : NULL);                   \
+                       }                                                         \
+                      _hs_psize--;                                               \
+                  } else if ((                                                   \
+                      cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+                             DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+                             ) <= 0) {                                           \
+                      _hs_e = _hs_p;                                             \
+                      if (_hs_p != NULL){                                        \
+                        _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ?        \
+                               ((void*)((char*)(_hs_p->next) +                   \
+                               (head)->hh.tbl->hho)) : NULL);                    \
+                       }                                                         \
+                      _hs_psize--;                                               \
+                  } else {                                                       \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ?          \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  }                                                              \
+                  if ( _hs_tail != NULL ) {                                      \
+                      _hs_tail->next = ((_hs_e != NULL) ?                        \
+                            ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL);          \
+                  } else {                                                       \
+                      _hs_list = _hs_e;                                          \
+                  }                                                              \
+                  if (_hs_e != NULL) {                                           \
+                  _hs_e->prev = ((_hs_tail != NULL) ?                            \
+                     ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL);              \
+                  }                                                              \
+                  _hs_tail = _hs_e;                                              \
+              }                                                                  \
+              _hs_p = _hs_q;                                                     \
+          }                                                                      \
+          if (_hs_tail != NULL){                                                 \
+            _hs_tail->next = NULL;                                               \
+          }                                                                      \
+          if ( _hs_nmerges <= 1U ) {                                             \
+              _hs_looping=0;                                                     \
+              (head)->hh.tbl->tail = _hs_tail;                                   \
+              DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list));      \
+          }                                                                      \
+          _hs_insize *= 2U;                                                      \
+      }                                                                          \
+      HASH_FSCK(hh,head);                                                        \
+ }                                                                               \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond)                              \
+do {                                                                             \
+  unsigned _src_bkt, _dst_bkt;                                                   \
+  void *_last_elt=NULL, *_elt;                                                   \
+  UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL;                         \
+  ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst));                 \
+  if (src != NULL) {                                                             \
+    for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) {     \
+      for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head;                \
+          _src_hh != NULL;                                                       \
+          _src_hh = _src_hh->hh_next) {                                          \
+          _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh);                       \
+          if (cond(_elt)) {                                                      \
+            _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho);               \
+            _dst_hh->key = _src_hh->key;                                         \
+            _dst_hh->keylen = _src_hh->keylen;                                   \
+            _dst_hh->hashv = _src_hh->hashv;                                     \
+            _dst_hh->prev = _last_elt;                                           \
+            _dst_hh->next = NULL;                                                \
+            if (_last_elt_hh != NULL) { _last_elt_hh->next = _elt; }             \
+            if (dst == NULL) {                                                   \
+              DECLTYPE_ASSIGN(dst,_elt);                                         \
+              HASH_MAKE_TABLE(hh_dst,dst);                                       \
+            } else {                                                             \
+              _dst_hh->tbl = (dst)->hh_dst.tbl;                                  \
+            }                                                                    \
+            HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt);    \
+            HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh);            \
+            (dst)->hh_dst.tbl->num_items++;                                      \
+            _last_elt = _elt;                                                    \
+            _last_elt_hh = _dst_hh;                                              \
+          }                                                                      \
+      }                                                                          \
+    }                                                                            \
+  }                                                                              \
+  HASH_FSCK(hh_dst,dst);                                                         \
+} while (0)
+
+#define HASH_CLEAR(hh,head)                                                      \
+do {                                                                             \
+  if (head != NULL) {                                                            \
+    uthash_free((head)->hh.tbl->buckets,                                         \
+                (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket));      \
+    HASH_BLOOM_FREE((head)->hh.tbl);                                             \
+    uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                          \
+    (head)=NULL;                                                                 \
+  }                                                                              \
+} while (0)
+
+#define HASH_OVERHEAD(hh,head)                                                   \
+ ((head != NULL) ? (                                                             \
+ (size_t)(((head)->hh.tbl->num_items   * sizeof(UT_hash_handle))   +             \
+          ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket))   +             \
+           sizeof(UT_hash_table)                                   +             \
+           (HASH_BLOOM_BYTELEN))) : 0U)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \
+  (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#else
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL));      \
+  (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U)
+
+typedef struct UT_hash_bucket {
+   struct UT_hash_handle *hh_head;
+   unsigned count;
+
+   /* expand_mult is normally set to 0. In this situation, the max chain length
+    * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+    * the bucket's chain exceeds this length, bucket expansion is triggered).
+    * However, setting expand_mult to a non-zero value delays bucket expansion
+    * (that would be triggered by additions to this particular bucket)
+    * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+    * (The multiplier is simply expand_mult+1). The whole idea of this
+    * multiplier is to reduce bucket expansions, since they are expensive, in
+    * situations where we know that a particular bucket tends to be overused.
+    * It is better to let its chain length grow to a longer yet-still-bounded
+    * value, than to do an O(n) bucket expansion too often.
+    */
+   unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1u
+#define HASH_BLOOM_SIGNATURE 0xb12220f2u
+
+typedef struct UT_hash_table {
+   UT_hash_bucket *buckets;
+   unsigned num_buckets, log2_num_buckets;
+   unsigned num_items;
+   struct UT_hash_handle *tail; /* tail hh in app order, for fast append    */
+   ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+   /* in an ideal situation (all buckets used equally), no bucket would have
+    * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+   unsigned ideal_chain_maxlen;
+
+   /* nonideal_items is the number of items in the hash whose chain position
+    * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+    * hash distribution; reaching them in a chain traversal takes >ideal steps */
+   unsigned nonideal_items;
+
+   /* ineffective expands occur when a bucket doubling was performed, but
+    * afterward, more than half the items in the hash had nonideal chain
+    * positions. If this happens on two consecutive expansions we inhibit any
+    * further expansion, as it's not helping; this happens when the hash
+    * function isn't a good fit for the key domain. When expansion is inhibited
+    * the hash will still work, albeit no longer in constant time. */
+   unsigned ineff_expands, noexpand;
+
+   uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+   uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+   uint8_t *bloom_bv;
+   uint8_t bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+   struct UT_hash_table *tbl;
+   void *prev;                       /* prev element in app order      */
+   void *next;                       /* next element in app order      */
+   struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */
+   struct UT_hash_handle *hh_next;   /* next hh in bucket order        */
+   void *key;                        /* ptr to enclosing struct's key  */
+   unsigned keylen;                  /* enclosing struct's key len     */
+   unsigned hashv;                   /* result of hash-fcn(key)        */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/libkms/Android.mk b/libkms/Android.mk
index aafebb6..9f81d8e 100644
--- a/libkms/Android.mk
+++ b/libkms/Android.mk
@@ -4,6 +4,7 @@
 radeon_drivers := r300g r600g radeonsi
 rockchip_drivers := rockchip
 nouveau_drivers := nouveau
+virgl_drivers := virgl
 vmwgfx_drivers := vmwgfx
 tegra_drivers := tegra
 
@@ -12,6 +13,7 @@
 	$(radeon_drivers) \
 	$(rockchip_drivers) \
 	$(nouveau_drivers) \
+	$(virgl_drivers) \
 	$(vmwgfx_drivers) \
 	$(tegra_drivers)
 
@@ -46,10 +48,8 @@
 LOCAL_SRC_FILES += $(LIBKMS_RADEON_FILES)
 endif
 
-LOCAL_SRC_FILES := $(filter-out %.h,$(LOCAL_SRC_FILES))
-
 LOCAL_MODULE := libkms
-LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES := libdrm
 
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libkms/Makefile.am b/libkms/Makefile.am
index 6c0ab7a..461fc35 100644
--- a/libkms/Makefile.am
+++ b/libkms/Makefile.am
@@ -10,10 +10,6 @@
 libkms_la_LDFLAGS = -version-number 1:0:0 -no-undefined
 libkms_la_LIBADD = ../libdrm.la
 
-#if HAVE_LIBUDEV
-#libkms_la_LIBADD += $(LIBUDEV_LIBS)
-#endif
-
 libkms_la_SOURCES = $(LIBKMS_FILES)
 
 if HAVE_VMWGFX
@@ -44,4 +40,4 @@
 pkgconfig_DATA = libkms.pc
 
 TESTS = kms-symbol-check
-EXTRA_DIST = Android.mk $(TESTS)
+EXTRA_DIST = $(TESTS)
diff --git a/libkms/exynos.c b/libkms/exynos.c
index 5de2e5a..0e97fb5 100644
--- a/libkms/exynos.c
+++ b/libkms/exynos.c
@@ -88,7 +88,8 @@
 		pitch = (pitch + 512 - 1) & ~(512 - 1);
 		size = pitch * ((height + 4 - 1) & ~(4 - 1));
 	} else {
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_free;
 	}
 
 	memset(&arg, 0, sizeof(arg));
diff --git a/libkms/libkms.pc.in b/libkms/libkms.pc.in
index 511535a..1421b3e 100644
--- a/libkms/libkms.pc.in
+++ b/libkms/libkms.pc.in
@@ -8,3 +8,4 @@
 Version: 1.0.0
 Libs: -L${libdir} -lkms
 Cflags: -I${includedir}/libkms
+Requires.private: libdrm
diff --git a/libkms/linux.c b/libkms/linux.c
index 6e0da83..0b50777 100644
--- a/libkms/linux.c
+++ b/libkms/linux.c
@@ -41,9 +41,12 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#ifdef HAVE_SYS_MKDEV_H
+#ifdef MAJOR_IN_MKDEV
 #include <sys/mkdev.h>
 #endif
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
 
 #include "libdrm_macros.h"
 #include "internal.h"
@@ -138,105 +141,11 @@
 	return ret;
 }
 
-#if 0
-#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
-#include <libudev.h>
-
-struct create_record
-{
-	unsigned vendor;
-	unsigned chip;
-	int (*func)(int fd, struct kms_driver **out);
-};
-
-static const struct create_record table[] = {
-	{ 0x8086, 0x2a42, intel_create }, /* i965 */
-#ifdef HAVE_VMWGFX
-	{ 0x15ad, 0x0405, vmwgfx_create }, /* VMware vGPU */
-#endif
-	{ 0, 0, NULL },
-};
-
-static int
-linux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id)
-{
-	struct udev *udev;
-	struct udev_device *device;
-	struct udev_device *parent;
-	const char *pci_id;
-	struct stat buffer;
-	int ret;
-
-	ret = fstat(fd, &buffer);
-	if (ret)
-		return -EINVAL;
-
-	if (!S_ISCHR(buffer.st_mode))
-		return -EINVAL;
-
-	udev = udev_new();
-	if (!udev)
-		return -ENOMEM;
-
-	device = udev_device_new_from_devnum(udev, 'c', buffer.st_rdev);
-	if (!device)
-		goto err_free_udev;
-
-	parent = udev_device_get_parent(device);
-	if (!parent)
-		goto err_free_device;
-
-	pci_id = udev_device_get_property_value(parent, "PCI_ID");
-	if (!pci_id)
-		goto err_free_device;
-
-	if (sscanf(pci_id, "%x:%x", vendor_id, chip_id) != 2)
-		goto err_free_device;
-
-	udev_device_unref(device);
-	udev_unref(udev);
-
-	return 0;
-
-err_free_device:
-	udev_device_unref(device);
-err_free_udev:
-	udev_unref(udev);
-	return -EINVAL;
-}
-
-static int
-linux_from_udev(int fd, struct kms_driver **out)
-{
-	unsigned vendor_id, chip_id;
-	int ret, i;
-
-	ret = linux_get_pciid_from_fd(fd, &vendor_id, &chip_id);
-	if (ret)
-		return ret;
-
-	for (i = 0; table[i].func; i++)
-		if (table[i].vendor == vendor_id && table[i].chip == chip_id)
-			return table[i].func(fd, out);
-
-	return -ENOSYS;
-}
-#else
-static int
-linux_from_udev(int fd, struct kms_driver **out)
-{
-	return -ENOSYS;
-}
-#endif
-
 drm_private int
 linux_create(int fd, struct kms_driver **out)
 {
 	if (!dumb_create(fd, out))
 		return 0;
 
-	if (!linux_from_udev(fd, out))
-		return 0;
-
 	return linux_from_sysfs(fd, out);
 }
diff --git a/libsync.h b/libsync.h
new file mode 100644
index 0000000..f1a2f96
--- /dev/null
+++ b/libsync.h
@@ -0,0 +1,148 @@
+/*
+ *  sync abstraction
+ *  Copyright 2015-2016 Collabora Ltd.
+ *
+ *  Based on the implementation from the Android Open Source Project,
+ *
+ *  Copyright 2012 Google, 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 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 _LIBSYNC_H
+#define _LIBSYNC_H
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <unistd.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef SYNC_IOC_MERGE
+/* duplicated from linux/sync_file.h to avoid build-time dependency
+ * on new (v4.7) kernel headers.  Once distro's are mostly using
+ * something newer than v4.7 drop this and #include <linux/sync_file.h>
+ * instead.
+ */
+struct sync_merge_data {
+	char	name[32];
+	int32_t	fd2;
+	int32_t	fence;
+	uint32_t	flags;
+	uint32_t	pad;
+};
+#define SYNC_IOC_MAGIC		'>'
+#define SYNC_IOC_MERGE		_IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
+#endif
+
+
+static inline int sync_wait(int fd, int timeout)
+{
+	struct pollfd fds = {0};
+	int ret;
+
+	fds.fd = fd;
+	fds.events = POLLIN;
+
+	do {
+		ret = poll(&fds, 1, timeout);
+		if (ret > 0) {
+			if (fds.revents & (POLLERR | POLLNVAL)) {
+				errno = EINVAL;
+				return -1;
+			}
+			return 0;
+		} else if (ret == 0) {
+			errno = ETIME;
+			return -1;
+		}
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+	return ret;
+}
+
+static inline int sync_merge(const char *name, int fd1, int fd2)
+{
+	struct sync_merge_data data = {0};
+	int ret;
+
+	data.fd2 = fd2;
+	strncpy(data.name, name, sizeof(data.name));
+
+	do {
+		ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+	if (ret < 0)
+		return ret;
+
+	return data.fence;
+}
+
+/* accumulate fd2 into fd1.  If *fd1 is not a valid fd then dup fd2,
+ * otherwise sync_merge() and close the old *fd1.  This can be used
+ * to implement the pattern:
+ *
+ *    init()
+ *    {
+ *       batch.fence_fd = -1;
+ *    }
+ *
+ *    // does *NOT* take ownership of fd
+ *    server_sync(int fd)
+ *    {
+ *       if (sync_accumulate("foo", &batch.fence_fd, fd)) {
+ *          ... error ...
+ *       }
+ *    }
+ */
+static inline int sync_accumulate(const char *name, int *fd1, int fd2)
+{
+	int ret;
+
+	assert(fd2 >= 0);
+
+	if (*fd1 < 0) {
+		*fd1 = dup(fd2);
+		return 0;
+	}
+
+	ret = sync_merge(name, *fd1, fd2);
+	if (ret < 0) {
+		/* leave *fd1 as it is */
+		return ret;
+	}
+
+	close(*fd1);
+	*fd1 = ret;
+
+	return 0;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/man/drm-kms.xml b/man/drm-kms.xml
index 5f04157..ae38dc8 100644
--- a/man/drm-kms.xml
+++ b/man/drm-kms.xml
@@ -126,7 +126,7 @@
           <listitem>
             <para><emphasis>Framebuffers</emphasis> are abstract memory objects
                   that provide a source of pixel data to scanout to a CRTC.
-                  Applications explicitely request the creation of framebuffers
+                  Applications explicitly request the creation of framebuffers
                   and can control their behavior. Framebuffers rely on the
                   underneath memory manager for low-level memory operations.
                   When creating a framebuffer, applications pass a memory handle
diff --git a/nouveau/Android.mk b/nouveau/Android.mk
index 1992797..b430af4 100644
--- a/nouveau/Android.mk
+++ b/nouveau/Android.mk
@@ -8,9 +8,7 @@
 
 LOCAL_SHARED_LIBRARIES := libdrm
 
-LOCAL_SRC_FILES := $(filter-out %.h,$(LIBDRM_NOUVEAU_FILES))
+LOCAL_SRC_FILES := $(LIBDRM_NOUVEAU_FILES)
 
-LOCAL_CFLAGS := \
-	-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
-
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_SHARED_LIBRARY)
diff --git a/nouveau/Makefile.am b/nouveau/Makefile.am
index 76cdeca..344a844 100644
--- a/nouveau/Makefile.am
+++ b/nouveau/Makefile.am
@@ -30,4 +30,4 @@
 pkgconfig_DATA = libdrm_nouveau.pc
 
 TESTS = nouveau-symbol-check
-EXTRA_DIST = Android.mk $(TESTS)
+EXTRA_DIST = $(TESTS)
diff --git a/radeon/Android.mk b/radeon/Android.mk
index 890bf54..71040da 100644
--- a/radeon/Android.mk
+++ b/radeon/Android.mk
@@ -8,9 +8,7 @@
 
 LOCAL_SHARED_LIBRARIES := libdrm
 
-LOCAL_SRC_FILES := $(filter-out %.h,$(LIBDRM_RADEON_FILES))
+LOCAL_SRC_FILES := $(LIBDRM_RADEON_FILES)
 
-LOCAL_CFLAGS := \
-	-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
-
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_SHARED_LIBRARY)
diff --git a/radeon/Makefile.am b/radeon/Makefile.am
index 25c03d3..e241531 100644
--- a/radeon/Makefile.am
+++ b/radeon/Makefile.am
@@ -43,4 +43,5 @@
 pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = libdrm_radeon.pc
 
-EXTRA_DIST = Android.mk $(LIBDRM_RADEON_BOF_FILES) $(TESTS)
+TESTS = radeon-symbol-check
+EXTRA_DIST = $(LIBDRM_RADEON_BOF_FILES) $(TESTS)
diff --git a/radeon/libdrm_radeon.pc.in b/radeon/libdrm_radeon.pc.in
index 68ef0ab..432993a 100644
--- a/radeon/libdrm_radeon.pc.in
+++ b/radeon/libdrm_radeon.pc.in
@@ -8,3 +8,4 @@
 Version: @PACKAGE_VERSION@
 Libs: -L${libdir} -ldrm_radeon
 Cflags: -I${includedir} -I${includedir}/libdrm
+Requires.private: libdrm
diff --git a/radeon/radeon_bo_gem.c b/radeon/radeon_bo_gem.c
index c9fe19f..fbd453d 100644
--- a/radeon/radeon_bo_gem.c
+++ b/radeon/radeon_bo_gem.c
@@ -103,7 +103,7 @@
         args.size = size;
         args.alignment = alignment;
         args.initial_domain = bo->base.domains;
-        args.flags = 0;
+        args.flags = flags;
         args.handle = 0;
         r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE,
                                 &args, sizeof(args));
diff --git a/radeon/radeon_cs_gem.c b/radeon/radeon_cs_gem.c
index cdec64e..f3dccb6 100644
--- a/radeon/radeon_cs_gem.c
+++ b/radeon/radeon_cs_gem.c
@@ -189,7 +189,7 @@
     /* check domains */
     if ((read_domain && write_domain) || (!read_domain && !write_domain)) {
         /* in one CS a bo can only be in read or write domain but not
-         * in read & write domain at the same sime
+         * in read & write domain at the same time
          */
         return -EINVAL;
     }
@@ -242,7 +242,7 @@
     }
     /* new relocation */
     if (csg->base.crelocs >= csg->nrelocs) {
-        /* allocate more memory (TODO: should use a slab allocatore maybe) */
+        /* allocate more memory (TODO: should use a slab allocator maybe) */
         uint32_t *tmp, size;
         size = ((csg->nrelocs + 1) * sizeof(struct radeon_bo*));
         tmp = (uint32_t*)realloc(csg->relocs_bo, size);
@@ -268,7 +268,7 @@
     reloc->flags = flags;
     csg->chunks[1].length_dw += RELOC_SIZE;
     radeon_bo_ref(bo);
-    /* bo might be referenced from another context so have to use atomic opertions */
+    /* bo might be referenced from another context so have to use atomic operations */
     atomic_add((atomic_t *)radeon_gem_get_reloc_in_cs(bo), cs->id);
     cs->relocs_total_size += boi->size;
     radeon_cs_write_dword((struct radeon_cs *)cs, 0xc0001000);
@@ -323,7 +323,7 @@
         return -EPIPE;
     }
     if (cs->section_ndw != cs->section_cdw) {
-        fprintf(stderr, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n",
+        fprintf(stderr, "CS section size mismatch start at (%s,%s,%d) %d vs %d\n",
                 cs->section_file, cs->section_func, cs->section_line, cs->section_ndw, cs->section_cdw);
         fprintf(stderr, "CS section end at (%s,%s,%d)\n",
                 file, func, line);
@@ -449,7 +449,7 @@
                             &csg->cs, sizeof(struct drm_radeon_cs));
     for (i = 0; i < csg->base.crelocs; i++) {
         csg->relocs_bo[i]->space_accounted = 0;
-        /* bo might be referenced from another context so have to use atomic opertions */
+        /* bo might be referenced from another context so have to use atomic operations */
         atomic_dec((atomic_t *)radeon_gem_get_reloc_in_cs((struct radeon_bo*)csg->relocs_bo[i]), cs->id);
         radeon_bo_unref((struct radeon_bo *)csg->relocs_bo[i]);
         csg->relocs_bo[i] = NULL;
@@ -481,7 +481,7 @@
     if (csg->relocs_bo) {
         for (i = 0; i < csg->base.crelocs; i++) {
             if (csg->relocs_bo[i]) {
-                /* bo might be referenced from another context so have to use atomic opertions */
+                /* bo might be referenced from another context so have to use atomic operations */
                 atomic_dec((atomic_t *)radeon_gem_get_reloc_in_cs((struct radeon_bo*)csg->relocs_bo[i]), cs->id);
                 radeon_bo_unref((struct radeon_bo *)csg->relocs_bo[i]);
                 csg->relocs_bo[i] = NULL;
diff --git a/radeon/radeon_surface.c b/radeon/radeon_surface.c
index 5ec9745..965be24 100644
--- a/radeon/radeon_surface.c
+++ b/radeon/radeon_surface.c
@@ -42,6 +42,14 @@
 #include "radeon_drm.h"
 #include "radeon_surface.h"
 
+#define CIK_TILE_MODE_COLOR_2D			14
+#define CIK_TILE_MODE_COLOR_2D_SCANOUT		10
+#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_64       0
+#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_128      1
+#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_256      2
+#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_512      3
+#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_ROW_SIZE 4
+
 #define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
 #define MAX2(A, B)              ((A) > (B) ? (A) : (B))
 #define MIN2(A, B)              ((A) < (B) ? (A) : (B))
@@ -957,8 +965,10 @@
             }
             surf->stencil_tile_split = 64;
         } else {
-            /* tile split must be >= 256 for colorbuffer surfaces */
-            surf->tile_split = MAX2(surf->nsamples * surf->bpe * 64, 256);
+            /* tile split must be >= 256 for colorbuffer surfaces,
+             * SAMPLE_SPLIT = tile_split / (bpe * 64), the optimal value is 2
+             */
+            surf->tile_split = MAX2(2 * surf->bpe * 64, 256);
             if (surf->tile_split > 4096)
                 surf->tile_split = 4096;
         }
@@ -971,7 +981,7 @@
     /* bankw or bankh greater than 1 increase alignment requirement, not
      * sure if it's worth using smaller bankw & bankh to stick with 2D
      * tiling on small surface rather than falling back to 1D tiling.
-     * Use recommanded value based on tile size for now.
+     * Use recommended value based on tile size for now.
      *
      * fmask buffer has different optimal value figure them out once we
      * use it.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d892576..f2bb4d4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -22,6 +22,14 @@
 SUBDIRS += tegra
 endif
 
+if HAVE_ETNAVIV
+SUBDIRS += etnaviv
+endif
+
+if HAVE_NOUVEAU
+SUBDIRS += nouveau
+endif
+
 AM_CFLAGS = \
 	$(WARN_CFLAGS)\
 	-I $(top_srcdir)/include/drm \
@@ -29,47 +37,11 @@
 
 LDADD = $(top_builddir)/libdrm.la
 
-check_PROGRAMS = \
-	dristat \
-	drmdevice \
-	drmstat
-
-dristat_LDADD = -lm
-
-if HAVE_NOUVEAU
-SUBDIRS += nouveau
-endif
-
 TESTS = \
 	drmsl \
 	hash \
 	random
 
-if HAVE_LIBUDEV
-
-check_LTLIBRARIES = libdrmtest.la
-
-libdrmtest_la_SOURCES = \
-	drmtest.c \
-	drmtest.h
-
-LDADD += \
-	libdrmtest.la \
-	$(LIBUDEV_LIBS)
-
-
-XFAIL_TESTS =					\
-	auth					\
-	lock
-
-TESTS +=					\
-	openclose				\
-	getversion				\
-	getclient				\
-	getstats				\
-	setversion				\
-	updatedraw				\
-	name_from_fd
-endif
-
-check_PROGRAMS += $(TESTS)
+check_PROGRAMS = \
+	$(TESTS) \
+	drmdevice
diff --git a/tests/amdgpu/amdgpu_test.c b/tests/amdgpu/amdgpu_test.c
index 71f357c..3fd6820 100644
--- a/tests/amdgpu/amdgpu_test.c
+++ b/tests/amdgpu/amdgpu_test.c
@@ -56,6 +56,9 @@
  */
 int drm_amdgpu[MAX_CARDS_SUPPORTED];
 
+/** Open render node to test */
+int open_render_node = 0;	/* By default run most tests on primary node */
+
 /** The table of all known test suites to run */
 static CU_SuiteInfo suites[] = {
 	{
@@ -108,12 +111,181 @@
 
 
 /** Help string for command line parameters */
-static const char usage[] = "Usage: %s [-hl] [<-s <suite id>> [-t <test id>]]\n"
-				"where:\n"
-				"       l - Display all suites and their tests\n"
-				"       h - Display this help\n";
+static const char usage[] =
+	"Usage: %s [-hlpr] [<-s <suite id>> [-t <test id>]] "
+	"[-b <pci_bus_id> [-d <pci_device_id>]]\n"
+	"where:\n"
+	"       l - Display all suites and their tests\n"
+	"       r - Run the tests on render node\n"
+	"       b - Specify device's PCI bus id to run tests\n"
+	"       d - Specify device's PCI device id to run tests (optional)\n"
+	"       p - Display information of AMDGPU devices in system\n"
+	"       h - Display this help\n";
 /** Specified options strings for getopt */
-static const char options[]   = "hls:t:";
+static const char options[]   = "hlrps:t:b:d:";
+
+/* Open AMD devices.
+ * Return the number of AMD device openned.
+ */
+static int amdgpu_open_devices(int open_render_node)
+{
+	drmDevicePtr devices[MAX_CARDS_SUPPORTED];
+	int ret;
+	int i;
+	int drm_node;
+	int amd_index = 0;
+	int drm_count;
+	int fd;
+	drmVersionPtr version;
+
+	drm_count = drmGetDevices2(0, devices, MAX_CARDS_SUPPORTED);
+
+	if (drm_count < 0) {
+		fprintf(stderr,
+			"drmGetDevices2() returned an error %d\n",
+			drm_count);
+		return 0;
+	}
+
+	for (i = 0; i < drm_count; i++) {
+		/* If this is not PCI device, skip*/
+		if (devices[i]->bustype != DRM_BUS_PCI)
+			continue;
+
+		/* If this is not AMD GPU vender ID, skip*/
+		if (devices[i]->deviceinfo.pci->vendor_id != 0x1002)
+			continue;
+
+		if (open_render_node)
+			drm_node = DRM_NODE_RENDER;
+		else
+			drm_node = DRM_NODE_PRIMARY;
+
+		fd = -1;
+		if (devices[i]->available_nodes & 1 << drm_node)
+			fd = open(
+				devices[i]->nodes[drm_node],
+				O_RDWR | O_CLOEXEC);
+
+		/* This node is not available. */
+		if (fd < 0) continue;
+
+		version = drmGetVersion(fd);
+		if (!version) {
+			fprintf(stderr,
+				"Warning: Cannot get version for %s."
+				"Error is %s\n",
+				devices[i]->nodes[drm_node],
+				strerror(errno));
+			close(fd);
+			continue;
+		}
+
+		if (strcmp(version->name, "amdgpu")) {
+			/* This is not AMDGPU driver, skip.*/
+			drmFreeVersion(version);
+			close(fd);
+			continue;
+		}
+
+		drmFreeVersion(version);
+
+		drm_amdgpu[amd_index] = fd;
+		amd_index++;
+	}
+
+	drmFreeDevices(devices, drm_count);
+	return amd_index;
+}
+
+/* Close AMD devices.
+ */
+static void amdgpu_close_devices()
+{
+	int i;
+	for (i = 0; i < MAX_CARDS_SUPPORTED; i++)
+		if (drm_amdgpu[i] >=0)
+			close(drm_amdgpu[i]);
+}
+
+/* Print AMD devices information */
+static void amdgpu_print_devices()
+{
+	int i;
+	drmDevicePtr device;
+
+	/* Open the first AMD devcie to print driver information. */
+	if (drm_amdgpu[0] >=0) {
+		/* Display AMD driver version information.*/
+		drmVersionPtr retval = drmGetVersion(drm_amdgpu[0]);
+
+		if (retval == NULL) {
+			perror("Cannot get version for AMDGPU device");
+			return;
+		}
+
+		printf("Driver name: %s, Date: %s, Description: %s.\n",
+			retval->name, retval->date, retval->desc);
+		drmFreeVersion(retval);
+	}
+
+	/* Display information of AMD devices */
+	printf("Devices:\n");
+	for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >=0; i++)
+		if (drmGetDevice2(drm_amdgpu[i],
+			DRM_DEVICE_GET_PCI_REVISION,
+			&device) == 0) {
+			if (device->bustype == DRM_BUS_PCI) {
+				printf("PCI ");
+				printf(" domain:%04x",
+					device->businfo.pci->domain);
+				printf(" bus:%02x",
+					device->businfo.pci->bus);
+				printf(" device:%02x",
+					device->businfo.pci->dev);
+				printf(" function:%01x",
+					device->businfo.pci->func);
+				printf(" vendor_id:%04x",
+					device->deviceinfo.pci->vendor_id);
+				printf(" device_id:%04x",
+					device->deviceinfo.pci->device_id);
+				printf(" subvendor_id:%04x",
+					device->deviceinfo.pci->subvendor_id);
+				printf(" subdevice_id:%04x",
+					device->deviceinfo.pci->subdevice_id);
+				printf(" revision_id:%02x",
+					device->deviceinfo.pci->revision_id);
+				printf("\n");
+			}
+			drmFreeDevice(&device);
+		}
+}
+
+/* Find a match AMD device in PCI bus
+ * Return the index of the device or -1 if not found
+ */
+static int amdgpu_find_device(uint8_t bus, uint8_t dev)
+{
+	int i;
+	drmDevicePtr device;
+
+	for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >=0; i++)
+		if (drmGetDevice2(drm_amdgpu[i],
+			DRM_DEVICE_GET_PCI_REVISION,
+			&device) == 0) {
+			if (device->bustype == DRM_BUS_PCI)
+				if (device->businfo.pci->bus == bus &&
+					device->businfo.pci->dev == dev) {
+
+					drmFreeDevice(&device);
+					return i;
+				}
+
+			drmFreeDevice(&device);
+		}
+
+	return -1;
+}
 
 /* The main() function for setting up and running the tests.
  * Returns a CUE_SUCCESS on successful running, another
@@ -125,16 +297,12 @@
 	int i = 0;
 	int suite_id = -1;	/* By default run everything */
 	int test_id  = -1;	/* By default run all tests in the suite */
+	int pci_bus_id = -1;    /* By default PC bus ID is not specified */
+	int pci_device_id = 0;  /* By default PC device ID is zero */
+	int display_devices = 0;/* By default not to display devices' info */
 	CU_pSuite pSuite = NULL;
 	CU_pTest  pTest  = NULL;
-
-	int aval = drmAvailable();
-
-	if (aval == 0) {
-		fprintf(stderr, "DRM driver is not available\n");
-		exit(EXIT_FAILURE);
-	}
-
+	int test_device_index;
 
 	for (i = 0; i < MAX_CARDS_SUPPORTED; i++)
 		drm_amdgpu[i] = -1;
@@ -153,6 +321,18 @@
 		case 't':
 			test_id = atoi(optarg);
 			break;
+		case 'b':
+			pci_bus_id = atoi(optarg);
+			break;
+		case 'd':
+			pci_device_id = atoi(optarg);
+			break;
+		case 'p':
+			display_devices = 1;
+			break;
+		case 'r':
+			open_render_node = 1;
+			break;
 		case '?':
 		case 'h':
 			fprintf(stderr, usage, argv[0]);
@@ -163,35 +343,46 @@
 		}
 	}
 
-	/* Try to open all possible radeon connections
-	 * Right now: Open only the 0.
-	 */
-	printf("Try to open the card 0..\n");
-	drm_amdgpu[0] = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
+	if (amdgpu_open_devices(open_render_node) <= 0) {
+		perror("Cannot open AMDGPU device");
+		exit(EXIT_FAILURE);
+	}
 
 	if (drm_amdgpu[0] < 0) {
-		perror("Cannot open /dev/dri/card0\n");
+		perror("Cannot open AMDGPU device");
 		exit(EXIT_FAILURE);
 	}
 
-	/** Display version of DRM driver */
-	drmVersionPtr retval = drmGetVersion(drm_amdgpu[0]);
-
-	if (retval == NULL) {
-		perror("Could not get information about DRM driver");
-		exit(EXIT_FAILURE);
+	if (display_devices) {
+		amdgpu_print_devices();
+		amdgpu_close_devices();
+		exit(EXIT_SUCCESS);
 	}
 
-	printf("DRM Driver: Name: [%s] : Date [%s] : Description [%s]\n",
-	       retval->name, retval->date, retval->desc);
+	if (pci_bus_id > 0) {
+		/* A device was specified to run the test */
+		test_device_index = amdgpu_find_device((uint8_t)pci_bus_id,
+							(uint8_t)pci_device_id);
 
-	drmFreeVersion(retval);
+		if (test_device_index >= 0) {
+			/* Most tests run on device of drm_amdgpu[0].
+			 * Swap the chosen device to drm_amdgpu[0].
+			 */
+			i = drm_amdgpu[0];
+			drm_amdgpu[0] = drm_amdgpu[test_device_index];
+			drm_amdgpu[test_device_index] = i;
+		} else {
+			fprintf(stderr,
+				"The specified GPU device does not exist.\n");
+			exit(EXIT_FAILURE);
+		}
+	}
 
 	/* Initialize test suites to run */
 
 	/* initialize the CUnit test registry */
 	if (CUE_SUCCESS != CU_initialize_registry()) {
-		close(drm_amdgpu[0]);
+		amdgpu_close_devices();
 		return CU_get_error();
 	}
 
@@ -200,7 +391,7 @@
 		fprintf(stderr, "suite registration failed - %s\n",
 				CU_get_error_msg());
 		CU_cleanup_registry();
-		close(drm_amdgpu[0]);
+		amdgpu_close_devices();
 		exit(EXIT_FAILURE);
 	}
 
@@ -222,7 +413,7 @@
 					fprintf(stderr, "Invalid test id: %d\n",
 								test_id);
 					CU_cleanup_registry();
-					close(drm_amdgpu[0]);
+					amdgpu_close_devices();
 					exit(EXIT_FAILURE);
 				}
 			} else
@@ -231,13 +422,13 @@
 			fprintf(stderr, "Invalid suite id : %d\n",
 					suite_id);
 			CU_cleanup_registry();
-			close(drm_amdgpu[0]);
+			amdgpu_close_devices();
 			exit(EXIT_FAILURE);
 		}
 	} else
 		CU_basic_run_tests();
 
 	CU_cleanup_registry();
-	close(drm_amdgpu[0]);
+	amdgpu_close_devices();
 	return CU_get_error();
 }
diff --git a/tests/amdgpu/amdgpu_test.h b/tests/amdgpu/amdgpu_test.h
index fca92ad..e30e231 100644
--- a/tests/amdgpu/amdgpu_test.h
+++ b/tests/amdgpu/amdgpu_test.h
@@ -35,6 +35,9 @@
 /* Forward reference for array to keep "drm" handles */
 extern int drm_amdgpu[MAX_CARDS_SUPPORTED];
 
+/* Global variables */
+extern int open_render_node;
+
 /*************************  Basic test suite ********************************/
 
 /*
diff --git a/tests/amdgpu/basic_tests.c b/tests/amdgpu/basic_tests.c
index e489e6e..bfda21b 100644
--- a/tests/amdgpu/basic_tests.c
+++ b/tests/amdgpu/basic_tests.c
@@ -47,6 +47,11 @@
 static void amdgpu_command_submission_compute(void);
 static void amdgpu_command_submission_sdma(void);
 static void amdgpu_userptr_test(void);
+static void amdgpu_semaphore_test(void);
+
+static void amdgpu_command_submission_write_linear_helper(unsigned ip_type);
+static void amdgpu_command_submission_const_fill_helper(unsigned ip_type);
+static void amdgpu_command_submission_copy_linear_helper(unsigned ip_type);
 
 CU_TestInfo basic_tests[] = {
 	{ "Query Info Test",  amdgpu_query_info_test },
@@ -55,6 +60,7 @@
 	{ "Command submission Test (GFX)",  amdgpu_command_submission_gfx },
 	{ "Command submission Test (Compute)", amdgpu_command_submission_compute },
 	{ "Command submission Test (SDMA)", amdgpu_command_submission_sdma },
+	{ "SW semaphore Test",  amdgpu_semaphore_test },
 	CU_TEST_INFO_NULL,
 };
 #define BUFFER_SIZE (8 * 1024)
@@ -77,6 +83,120 @@
 #define	SDMA_OPCODE_COPY				  1
 #       define SDMA_COPY_SUB_OPCODE_LINEAR                0
 
+#define GFX_COMPUTE_NOP  0xffff1000
+#define SDMA_NOP  0x0
+
+/* PM4 */
+#define	PACKET_TYPE0	0
+#define	PACKET_TYPE1	1
+#define	PACKET_TYPE2	2
+#define	PACKET_TYPE3	3
+
+#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3)
+#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF)
+#define CP_PACKET0_GET_REG(h) ((h) & 0xFFFF)
+#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
+#define PACKET0(reg, n)	((PACKET_TYPE0 << 30) |				\
+			 ((reg) & 0xFFFF) |			\
+			 ((n) & 0x3FFF) << 16)
+#define CP_PACKET2			0x80000000
+#define		PACKET2_PAD_SHIFT		0
+#define		PACKET2_PAD_MASK		(0x3fffffff << 0)
+
+#define PACKET2(v)	(CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
+
+#define PACKET3(op, n)	((PACKET_TYPE3 << 30) |				\
+			 (((op) & 0xFF) << 8) |				\
+			 ((n) & 0x3FFF) << 16)
+
+/* Packet 3 types */
+#define	PACKET3_NOP					0x10
+
+#define	PACKET3_WRITE_DATA				0x37
+#define		WRITE_DATA_DST_SEL(x)                   ((x) << 8)
+		/* 0 - register
+		 * 1 - memory (sync - via GRBM)
+		 * 2 - gl2
+		 * 3 - gds
+		 * 4 - reserved
+		 * 5 - memory (async - direct)
+		 */
+#define		WR_ONE_ADDR                             (1 << 16)
+#define		WR_CONFIRM                              (1 << 20)
+#define		WRITE_DATA_CACHE_POLICY(x)              ((x) << 25)
+		/* 0 - LRU
+		 * 1 - Stream
+		 */
+#define		WRITE_DATA_ENGINE_SEL(x)                ((x) << 30)
+		/* 0 - me
+		 * 1 - pfp
+		 * 2 - ce
+		 */
+
+#define	PACKET3_DMA_DATA				0x50
+/* 1. header
+ * 2. CONTROL
+ * 3. SRC_ADDR_LO or DATA [31:0]
+ * 4. SRC_ADDR_HI [31:0]
+ * 5. DST_ADDR_LO [31:0]
+ * 6. DST_ADDR_HI [7:0]
+ * 7. COMMAND [30:21] | BYTE_COUNT [20:0]
+ */
+/* CONTROL */
+#              define PACKET3_DMA_DATA_ENGINE(x)     ((x) << 0)
+		/* 0 - ME
+		 * 1 - PFP
+		 */
+#              define PACKET3_DMA_DATA_SRC_CACHE_POLICY(x) ((x) << 13)
+		/* 0 - LRU
+		 * 1 - Stream
+		 * 2 - Bypass
+		 */
+#              define PACKET3_DMA_DATA_SRC_VOLATILE (1 << 15)
+#              define PACKET3_DMA_DATA_DST_SEL(x)  ((x) << 20)
+		/* 0 - DST_ADDR using DAS
+		 * 1 - GDS
+		 * 3 - DST_ADDR using L2
+		 */
+#              define PACKET3_DMA_DATA_DST_CACHE_POLICY(x) ((x) << 25)
+		/* 0 - LRU
+		 * 1 - Stream
+		 * 2 - Bypass
+		 */
+#              define PACKET3_DMA_DATA_DST_VOLATILE (1 << 27)
+#              define PACKET3_DMA_DATA_SRC_SEL(x)  ((x) << 29)
+		/* 0 - SRC_ADDR using SAS
+		 * 1 - GDS
+		 * 2 - DATA
+		 * 3 - SRC_ADDR using L2
+		 */
+#              define PACKET3_DMA_DATA_CP_SYNC     (1 << 31)
+/* COMMAND */
+#              define PACKET3_DMA_DATA_DIS_WC      (1 << 21)
+#              define PACKET3_DMA_DATA_CMD_SRC_SWAP(x) ((x) << 22)
+		/* 0 - none
+		 * 1 - 8 in 16
+		 * 2 - 8 in 32
+		 * 3 - 8 in 64
+		 */
+#              define PACKET3_DMA_DATA_CMD_DST_SWAP(x) ((x) << 24)
+		/* 0 - none
+		 * 1 - 8 in 16
+		 * 2 - 8 in 32
+		 * 3 - 8 in 64
+		 */
+#              define PACKET3_DMA_DATA_CMD_SAS     (1 << 26)
+		/* 0 - memory
+		 * 1 - register
+		 */
+#              define PACKET3_DMA_DATA_CMD_DAS     (1 << 27)
+		/* 0 - memory
+		 * 1 - register
+		 */
+#              define PACKET3_DMA_DATA_CMD_SAIC    (1 << 28)
+#              define PACKET3_DMA_DATA_CMD_DAIC    (1 << 29)
+#              define PACKET3_DMA_DATA_CMD_RAW_WAIT  (1 << 30)
+
 int suite_basic_tests_init(void)
 {
 	int r;
@@ -86,8 +206,13 @@
 
 	if (r == 0)
 		return CUE_SUCCESS;
-	else
+	else {
+		if ((r == -EACCES) && (errno == EACCES))
+			printf("\n\nError:%s. "
+				"Hint:Try to run this test program as root.",
+				strerror(errno));
 		return CUE_SINIT_FAILED;
+	}
 }
 
 int suite_basic_tests_clean(void)
@@ -226,6 +351,7 @@
 
 	fence_status.context = context_handle;
 	fence_status.ip_type = AMDGPU_HW_IP_GFX;
+	fence_status.ip_instance = 0;
 	fence_status.fence = ibs_request.seq_no;
 
 	r = amdgpu_cs_query_fence_status(&fence_status,
@@ -307,6 +433,7 @@
 
 	fence_status.context = context_handle;
 	fence_status.ip_type = AMDGPU_HW_IP_GFX;
+	fence_status.ip_instance = 0;
 	fence_status.fence = ibs_request.seq_no;
 
 	r = amdgpu_cs_query_fence_status(&fence_status,
@@ -325,15 +452,166 @@
 	CU_ASSERT_EQUAL(r, 0);
 }
 
+static void amdgpu_command_submission_gfx_cp_write_data(void)
+{
+	amdgpu_command_submission_write_linear_helper(AMDGPU_HW_IP_GFX);
+}
+
+static void amdgpu_command_submission_gfx_cp_const_fill(void)
+{
+	amdgpu_command_submission_const_fill_helper(AMDGPU_HW_IP_GFX);
+}
+
+static void amdgpu_command_submission_gfx_cp_copy_data(void)
+{
+	amdgpu_command_submission_copy_linear_helper(AMDGPU_HW_IP_GFX);
+}
+
 static void amdgpu_command_submission_gfx(void)
 {
+	/* write data using the CP */
+	amdgpu_command_submission_gfx_cp_write_data();
+	/* const fill using the CP */
+	amdgpu_command_submission_gfx_cp_const_fill();
+	/* copy data using the CP */
+	amdgpu_command_submission_gfx_cp_copy_data();
 	/* separate IB buffers for multi-IB submission */
 	amdgpu_command_submission_gfx_separate_ibs();
 	/* shared IB buffer for multi-IB submission */
 	amdgpu_command_submission_gfx_shared_ib();
 }
 
-static void amdgpu_command_submission_compute(void)
+static void amdgpu_semaphore_test(void)
+{
+	amdgpu_context_handle context_handle[2];
+	amdgpu_semaphore_handle sem;
+	amdgpu_bo_handle ib_result_handle[2];
+	void *ib_result_cpu[2];
+	uint64_t ib_result_mc_address[2];
+	struct amdgpu_cs_request ibs_request[2] = {0};
+	struct amdgpu_cs_ib_info ib_info[2] = {0};
+	struct amdgpu_cs_fence fence_status = {0};
+	uint32_t *ptr;
+	uint32_t expired;
+	amdgpu_bo_list_handle bo_list[2];
+	amdgpu_va_handle va_handle[2];
+	int r, i;
+
+	r = amdgpu_cs_create_semaphore(&sem);
+	CU_ASSERT_EQUAL(r, 0);
+	for (i = 0; i < 2; i++) {
+		r = amdgpu_cs_ctx_create(device_handle, &context_handle[i]);
+		CU_ASSERT_EQUAL(r, 0);
+
+		r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096,
+					    AMDGPU_GEM_DOMAIN_GTT, 0,
+					    &ib_result_handle[i], &ib_result_cpu[i],
+					    &ib_result_mc_address[i], &va_handle[i]);
+		CU_ASSERT_EQUAL(r, 0);
+
+		r = amdgpu_get_bo_list(device_handle, ib_result_handle[i],
+				       NULL, &bo_list[i]);
+		CU_ASSERT_EQUAL(r, 0);
+	}
+
+	/* 1. same context different engine */
+	ptr = ib_result_cpu[0];
+	ptr[0] = SDMA_NOP;
+	ib_info[0].ib_mc_address = ib_result_mc_address[0];
+	ib_info[0].size = 1;
+
+	ibs_request[0].ip_type = AMDGPU_HW_IP_DMA;
+	ibs_request[0].number_of_ibs = 1;
+	ibs_request[0].ibs = &ib_info[0];
+	ibs_request[0].resources = bo_list[0];
+	ibs_request[0].fence_info.handle = NULL;
+	r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request[0], 1);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_cs_signal_semaphore(context_handle[0], AMDGPU_HW_IP_DMA, 0, 0, sem);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_cs_wait_semaphore(context_handle[0], AMDGPU_HW_IP_GFX, 0, 0, sem);
+	CU_ASSERT_EQUAL(r, 0);
+	ptr = ib_result_cpu[1];
+	ptr[0] = GFX_COMPUTE_NOP;
+	ib_info[1].ib_mc_address = ib_result_mc_address[1];
+	ib_info[1].size = 1;
+
+	ibs_request[1].ip_type = AMDGPU_HW_IP_GFX;
+	ibs_request[1].number_of_ibs = 1;
+	ibs_request[1].ibs = &ib_info[1];
+	ibs_request[1].resources = bo_list[1];
+	ibs_request[1].fence_info.handle = NULL;
+
+	r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request[1], 1);
+	CU_ASSERT_EQUAL(r, 0);
+
+	fence_status.context = context_handle[0];
+	fence_status.ip_type = AMDGPU_HW_IP_GFX;
+	fence_status.ip_instance = 0;
+	fence_status.fence = ibs_request[1].seq_no;
+	r = amdgpu_cs_query_fence_status(&fence_status,
+					 500000000, 0, &expired);
+	CU_ASSERT_EQUAL(r, 0);
+	CU_ASSERT_EQUAL(expired, true);
+
+	/* 2. same engine different context */
+	ptr = ib_result_cpu[0];
+	ptr[0] = GFX_COMPUTE_NOP;
+	ib_info[0].ib_mc_address = ib_result_mc_address[0];
+	ib_info[0].size = 1;
+
+	ibs_request[0].ip_type = AMDGPU_HW_IP_GFX;
+	ibs_request[0].number_of_ibs = 1;
+	ibs_request[0].ibs = &ib_info[0];
+	ibs_request[0].resources = bo_list[0];
+	ibs_request[0].fence_info.handle = NULL;
+	r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request[0], 1);
+	CU_ASSERT_EQUAL(r, 0);
+	r = amdgpu_cs_signal_semaphore(context_handle[0], AMDGPU_HW_IP_GFX, 0, 0, sem);
+	CU_ASSERT_EQUAL(r, 0);
+
+	r = amdgpu_cs_wait_semaphore(context_handle[1], AMDGPU_HW_IP_GFX, 0, 0, sem);
+	CU_ASSERT_EQUAL(r, 0);
+	ptr = ib_result_cpu[1];
+	ptr[0] = GFX_COMPUTE_NOP;
+	ib_info[1].ib_mc_address = ib_result_mc_address[1];
+	ib_info[1].size = 1;
+
+	ibs_request[1].ip_type = AMDGPU_HW_IP_GFX;
+	ibs_request[1].number_of_ibs = 1;
+	ibs_request[1].ibs = &ib_info[1];
+	ibs_request[1].resources = bo_list[1];
+	ibs_request[1].fence_info.handle = NULL;
+	r = amdgpu_cs_submit(context_handle[1], 0,&ibs_request[1], 1);
+
+	CU_ASSERT_EQUAL(r, 0);
+
+	fence_status.context = context_handle[1];
+	fence_status.ip_type = AMDGPU_HW_IP_GFX;
+	fence_status.ip_instance = 0;
+	fence_status.fence = ibs_request[1].seq_no;
+	r = amdgpu_cs_query_fence_status(&fence_status,
+					 500000000, 0, &expired);
+	CU_ASSERT_EQUAL(r, 0);
+	CU_ASSERT_EQUAL(expired, true);
+	for (i = 0; i < 2; i++) {
+		r = amdgpu_bo_unmap_and_free(ib_result_handle[i], va_handle[i],
+					     ib_result_mc_address[i], 4096);
+		CU_ASSERT_EQUAL(r, 0);
+
+		r = amdgpu_bo_list_destroy(bo_list[i]);
+		CU_ASSERT_EQUAL(r, 0);
+
+		r = amdgpu_cs_ctx_free(context_handle[i]);
+		CU_ASSERT_EQUAL(r, 0);
+	}
+
+	r = amdgpu_cs_destroy_semaphore(sem);
+	CU_ASSERT_EQUAL(r, 0);
+}
+
+static void amdgpu_command_submission_compute_nop(void)
 {
 	amdgpu_context_handle context_handle;
 	amdgpu_bo_handle ib_result_handle;
@@ -384,6 +662,7 @@
 
 		fence_status.context = context_handle;
 		fence_status.ip_type = AMDGPU_HW_IP_COMPUTE;
+		fence_status.ip_instance = 0;
 		fence_status.ring = instance;
 		fence_status.fence = ibs_request.seq_no;
 
@@ -404,16 +683,44 @@
 	CU_ASSERT_EQUAL(r, 0);
 }
 
+static void amdgpu_command_submission_compute_cp_write_data(void)
+{
+	amdgpu_command_submission_write_linear_helper(AMDGPU_HW_IP_COMPUTE);
+}
+
+static void amdgpu_command_submission_compute_cp_const_fill(void)
+{
+	amdgpu_command_submission_const_fill_helper(AMDGPU_HW_IP_COMPUTE);
+}
+
+static void amdgpu_command_submission_compute_cp_copy_data(void)
+{
+	amdgpu_command_submission_copy_linear_helper(AMDGPU_HW_IP_COMPUTE);
+}
+
+static void amdgpu_command_submission_compute(void)
+{
+	/* write data using the CP */
+	amdgpu_command_submission_compute_cp_write_data();
+	/* const fill using the CP */
+	amdgpu_command_submission_compute_cp_const_fill();
+	/* copy data using the CP */
+	amdgpu_command_submission_compute_cp_copy_data();
+	/* nop test */
+	amdgpu_command_submission_compute_nop();
+}
+
 /*
  * caller need create/release:
  * pm4_src, resources, ib_info, and ibs_request
  * submit command stream described in ibs_request and wait for this IB accomplished
  */
-static void amdgpu_sdma_test_exec_cs(amdgpu_context_handle context_handle,
-				 int instance, int pm4_dw, uint32_t *pm4_src,
-				 int res_cnt, amdgpu_bo_handle *resources,
-				 struct amdgpu_cs_ib_info *ib_info,
-				 struct amdgpu_cs_request *ibs_request)
+static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle,
+				       unsigned ip_type,
+				       int instance, int pm4_dw, uint32_t *pm4_src,
+				       int res_cnt, amdgpu_bo_handle *resources,
+				       struct amdgpu_cs_ib_info *ib_info,
+				       struct amdgpu_cs_request *ibs_request)
 {
 	int r;
 	uint32_t expired;
@@ -446,7 +753,7 @@
 	ib_info->ib_mc_address = ib_result_mc_address;
 	ib_info->size = pm4_dw;
 
-	ibs_request->ip_type = AMDGPU_HW_IP_DMA;
+	ibs_request->ip_type = ip_type;
 	ibs_request->ring = instance;
 	ibs_request->number_of_ibs = 1;
 	ibs_request->ibs = ib_info;
@@ -468,7 +775,8 @@
 	r = amdgpu_bo_list_destroy(ibs_request->resources);
 	CU_ASSERT_EQUAL(r, 0);
 
-	fence_status.ip_type = AMDGPU_HW_IP_DMA;
+	fence_status.ip_type = ip_type;
+	fence_status.ip_instance = 0;
 	fence_status.ring = ibs_request->ring;
 	fence_status.context = context_handle;
 	fence_status.fence = ibs_request->seq_no;
@@ -485,7 +793,7 @@
 	CU_ASSERT_EQUAL(r, 0);
 }
 
-static void amdgpu_command_submission_sdma_write_linear(void)
+static void amdgpu_command_submission_write_linear_helper(unsigned ip_type)
 {
 	const int sdma_write_length = 128;
 	const int pm4_dw = 256;
@@ -533,20 +841,31 @@
 
 		resources[0] = bo;
 
-		/* fullfill PM4: test DMA write-linear */
+		/* fulfill PM4: test DMA write-linear */
 		i = j = 0;
-		pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
-				SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
-		pm4[i++] = 0xffffffff & bo_mc;
-		pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
-		pm4[i++] = sdma_write_length;
-		while(j++ < sdma_write_length)
-			pm4[i++] = 0xdeadbeaf;
+		if (ip_type == AMDGPU_HW_IP_DMA) {
+			pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
+					       SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+			pm4[i++] = 0xffffffff & bo_mc;
+			pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+			pm4[i++] = sdma_write_length;
+			while(j++ < sdma_write_length)
+				pm4[i++] = 0xdeadbeaf;
+		} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
+			   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
+			pm4[i++] = PACKET3(PACKET3_WRITE_DATA, 2 + sdma_write_length);
+			pm4[i++] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
+			pm4[i++] = 0xfffffffc & bo_mc;
+			pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+			while(j++ < sdma_write_length)
+				pm4[i++] = 0xdeadbeaf;
+		}
 
-		amdgpu_sdma_test_exec_cs(context_handle, 0,
-					i, pm4,
-					1, resources,
-					ib_info, ibs_request);
+		amdgpu_test_exec_cs_helper(context_handle,
+					   ip_type, 0,
+					   i, pm4,
+					   1, resources,
+					   ib_info, ibs_request);
 
 		/* verify if SDMA test result meets with expected */
 		i = 0;
@@ -570,7 +889,12 @@
 	CU_ASSERT_EQUAL(r, 0);
 }
 
-static void amdgpu_command_submission_sdma_const_fill(void)
+static void amdgpu_command_submission_sdma_write_linear(void)
+{
+	amdgpu_command_submission_write_linear_helper(AMDGPU_HW_IP_DMA);
+}
+
+static void amdgpu_command_submission_const_fill_helper(unsigned ip_type)
 {
 	const int sdma_write_length = 1024 * 1024;
 	const int pm4_dw = 256;
@@ -617,19 +941,34 @@
 
 		resources[0] = bo;
 
-		/* fullfill PM4: test DMA const fill */
+		/* fulfill PM4: test DMA const fill */
 		i = j = 0;
-		pm4[i++] = SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0,
-				   SDMA_CONSTANT_FILL_EXTRA_SIZE(2));
-		pm4[i++] = 0xffffffff & bo_mc;
-		pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
-		pm4[i++] = 0xdeadbeaf;
-		pm4[i++] = sdma_write_length;
+		if (ip_type == AMDGPU_HW_IP_DMA) {
+			pm4[i++] = SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0,
+					       SDMA_CONSTANT_FILL_EXTRA_SIZE(2));
+			pm4[i++] = 0xffffffff & bo_mc;
+			pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+			pm4[i++] = 0xdeadbeaf;
+			pm4[i++] = sdma_write_length;
+		} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
+			   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
+			pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5);
+			pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) |
+				PACKET3_DMA_DATA_DST_SEL(0) |
+				PACKET3_DMA_DATA_SRC_SEL(2) |
+				PACKET3_DMA_DATA_CP_SYNC;
+			pm4[i++] = 0xdeadbeaf;
+			pm4[i++] = 0;
+			pm4[i++] = 0xfffffffc & bo_mc;
+			pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32;
+			pm4[i++] = sdma_write_length;
+		}
 
-		amdgpu_sdma_test_exec_cs(context_handle, 0,
-					i, pm4,
-					1, resources,
-					ib_info, ibs_request);
+		amdgpu_test_exec_cs_helper(context_handle,
+					   ip_type, 0,
+					   i, pm4,
+					   1, resources,
+					   ib_info, ibs_request);
 
 		/* verify if SDMA test result meets with expected */
 		i = 0;
@@ -653,7 +992,12 @@
 	CU_ASSERT_EQUAL(r, 0);
 }
 
-static void amdgpu_command_submission_sdma_copy_linear(void)
+static void amdgpu_command_submission_sdma_const_fill(void)
+{
+	amdgpu_command_submission_const_fill_helper(AMDGPU_HW_IP_DMA);
+}
+
+static void amdgpu_command_submission_copy_linear_helper(unsigned ip_type)
 {
 	const int sdma_write_length = 1024;
 	const int pm4_dw = 256;
@@ -716,21 +1060,35 @@
 			resources[0] = bo1;
 			resources[1] = bo2;
 
-			/* fullfill PM4: test DMA copy linear */
+			/* fulfill PM4: test DMA copy linear */
 			i = j = 0;
-			pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0);
-			pm4[i++] = sdma_write_length;
-			pm4[i++] = 0;
-			pm4[i++] = 0xffffffff & bo1_mc;
-			pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
-			pm4[i++] = 0xffffffff & bo2_mc;
-			pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+			if (ip_type == AMDGPU_HW_IP_DMA) {
+				pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0);
+				pm4[i++] = sdma_write_length;
+				pm4[i++] = 0;
+				pm4[i++] = 0xffffffff & bo1_mc;
+				pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
+				pm4[i++] = 0xffffffff & bo2_mc;
+				pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+			} else if ((ip_type == AMDGPU_HW_IP_GFX) ||
+				   (ip_type == AMDGPU_HW_IP_COMPUTE)) {
+				pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5);
+				pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) |
+					PACKET3_DMA_DATA_DST_SEL(0) |
+					PACKET3_DMA_DATA_SRC_SEL(0) |
+					PACKET3_DMA_DATA_CP_SYNC;
+				pm4[i++] = 0xfffffffc & bo1_mc;
+				pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32;
+				pm4[i++] = 0xfffffffc & bo2_mc;
+				pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32;
+				pm4[i++] = sdma_write_length;
+			}
 
-
-			amdgpu_sdma_test_exec_cs(context_handle, 0,
-						i, pm4,
-						2, resources,
-						ib_info, ibs_request);
+			amdgpu_test_exec_cs_helper(context_handle,
+						   ip_type, 0,
+						   i, pm4,
+						   2, resources,
+						   ib_info, ibs_request);
 
 			/* verify if SDMA test result meets with expected */
 			i = 0;
@@ -758,6 +1116,11 @@
 	CU_ASSERT_EQUAL(r, 0);
 }
 
+static void amdgpu_command_submission_sdma_copy_linear(void)
+{
+	amdgpu_command_submission_copy_linear_helper(AMDGPU_HW_IP_DMA);
+}
+
 static void amdgpu_command_submission_sdma(void)
 {
 	amdgpu_command_submission_sdma_write_linear();
@@ -821,10 +1184,11 @@
 	while (j++ < sdma_write_length)
 		pm4[i++] = 0xdeadbeaf;
 
-	amdgpu_sdma_test_exec_cs(context_handle, 0,
-				 i, pm4,
-				 1, &handle,
-				 ib_info, ibs_request);
+	amdgpu_test_exec_cs_helper(context_handle,
+				   AMDGPU_HW_IP_DMA, 0,
+				   i, pm4,
+				   1, &handle,
+				   ib_info, ibs_request);
 	i = 0;
 	while (i < sdma_write_length) {
 		CU_ASSERT_EQUAL(((int*)ptr)[i++], 0xdeadbeaf);
diff --git a/tests/amdgpu/bo_tests.c b/tests/amdgpu/bo_tests.c
index 993895d..74b5e77 100644
--- a/tests/amdgpu/bo_tests.c
+++ b/tests/amdgpu/bo_tests.c
@@ -65,8 +65,14 @@
 
 	r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
 				  &minor_version, &device_handle);
-	if (r)
+	if (r) {
+		if ((r == -EACCES) && (errno == EACCES))
+			printf("\n\nError:%s. "
+				"Hint:Try to run this test program as root.",
+				strerror(errno));
+
 		return CUE_SINIT_FAILED;
+	}
 
 	req.alloc_size = BUFFER_SIZE;
 	req.phys_alignment = BUFFER_ALIGN;
@@ -146,6 +152,11 @@
 
 static void amdgpu_bo_export_import(void)
 {
+	if (open_render_node) {
+		printf("(DRM render node is used. Skip export/Import test) ");
+		return;
+	}
+
 	amdgpu_bo_export_import_do_type(amdgpu_bo_handle_type_gem_flink_name);
 	amdgpu_bo_export_import_do_type(amdgpu_bo_handle_type_dma_buf_fd);
 }
diff --git a/tests/amdgpu/cs_tests.c b/tests/amdgpu/cs_tests.c
index dfbf5af..82c55aa 100644
--- a/tests/amdgpu/cs_tests.c
+++ b/tests/amdgpu/cs_tests.c
@@ -43,6 +43,8 @@
 static uint32_t major_version;
 static uint32_t minor_version;
 static uint32_t family_id;
+static uint32_t chip_rev;
+static uint32_t chip_id;
 
 static amdgpu_context_handle context_handle;
 static amdgpu_bo_handle ib_handle;
@@ -74,10 +76,19 @@
 
 	r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
 				     &minor_version, &device_handle);
-	if (r)
+	if (r) {
+		if ((r == -EACCES) && (errno == EACCES))
+			printf("\n\nError:%s. "
+				"Hint:Try to run this test program as root.",
+				strerror(errno));
+
 		return CUE_SINIT_FAILED;
+	}
 
 	family_id = device_handle->info.family_id;
+	/* VI asic POLARIS10/11 have specific external_rev_id */
+	chip_rev = device_handle->info.chip_rev;
+	chip_id = device_handle->info.chip_external_rev;
 
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	if (r)
@@ -200,8 +211,17 @@
 	CU_ASSERT_EQUAL(r, 0);
 
 	memcpy(msg, uvd_create_msg, sizeof(uvd_create_msg));
-	if (family_id >= AMDGPU_FAMILY_VI)
+	if (family_id >= AMDGPU_FAMILY_VI) {
 		((uint8_t*)msg)[0x10] = 7;
+		/* chip polaris 10/11 */
+		if (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A) {
+			/* dpb size */
+			((uint8_t*)msg)[0x28] = 0x00;
+			((uint8_t*)msg)[0x29] = 0x94;
+			((uint8_t*)msg)[0x2A] = 0x6B;
+			((uint8_t*)msg)[0x2B] = 0x00;
+		}
+	}
 
 	r = amdgpu_bo_cpu_unmap(buf_handle);
 	CU_ASSERT_EQUAL(r, 0);
@@ -230,8 +250,8 @@
 
 static void amdgpu_cs_uvd_decode(void)
 {
-	const unsigned dpb_size = 15923584, dt_size = 737280;
-	uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, dt_addr, it_addr;
+	const unsigned dpb_size = 15923584, ctx_size = 5287680, dt_size = 737280;
+	uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, ctx_addr, dt_addr, it_addr;
 	struct amdgpu_bo_alloc_request req = {0};
 	amdgpu_bo_handle buf_handle;
 	amdgpu_va_handle va_handle;
@@ -266,9 +286,25 @@
 	r = amdgpu_bo_cpu_map(buf_handle, (void **)&ptr);
 	CU_ASSERT_EQUAL(r, 0);
 
-	memcpy(ptr, uvd_decode_msg, sizeof(uvd_decode_msg));
-	if (family_id >= AMDGPU_FAMILY_VI)
+	memcpy(ptr, uvd_decode_msg, sizeof(uvd_create_msg));
+	if (family_id >= AMDGPU_FAMILY_VI) {
 		ptr[0x10] = 7;
+		ptr[0x98] = 0x00;
+		ptr[0x99] = 0x02;
+		/* chip polaris10/11 */
+		if (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A) {
+			/*dpb size */
+			ptr[0x24] = 0x00;
+			ptr[0x25] = 0x94;
+			ptr[0x26] = 0x6B;
+			ptr[0x27] = 0x00;
+			/*ctx size */
+			ptr[0x2C] = 0x00;
+			ptr[0x2D] = 0xAF;
+			ptr[0x2E] = 0x50;
+			ptr[0x2F] = 0x00;
+		}
+	}
 
 	ptr += 4*1024;
 	memset(ptr, 0, 4*1024);
@@ -298,6 +334,12 @@
 	} else
 		bs_addr = fb_addr + 4*1024;
 	dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024);
+
+	if ((family_id >= AMDGPU_FAMILY_VI) &&
+		(chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A)) {
+		ctx_addr = ALIGN(dpb_addr + 0x006B9400, 4*1024);
+	}
+
 	dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024);
 
 	i = 0;
@@ -306,8 +348,11 @@
 	uvd_cmd(dt_addr, 0x2, &i);
 	uvd_cmd(fb_addr, 0x3, &i);
 	uvd_cmd(bs_addr, 0x100, &i);
-	if (family_id >= AMDGPU_FAMILY_VI)
+	if (family_id >= AMDGPU_FAMILY_VI) {
 		uvd_cmd(it_addr, 0x204, &i);
+		if (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A)
+			uvd_cmd(ctx_addr, 0x206, &i);
+}
 	ib_cpu[i++] = 0x3BC6;
 	ib_cpu[i++] = 0x1;
 	for (; i % 16; ++i)
diff --git a/tests/amdgpu/vce_ib.h b/tests/amdgpu/vce_ib.h
index bd0bf94..80ab179 100644
--- a/tests/amdgpu/vce_ib.h
+++ b/tests/amdgpu/vce_ib.h
@@ -53,7 +53,7 @@
 	0x000000a0,
 	0x000000a0,
 	0x00000010,
-	0x00000000,
+	0x00000201,
 };
 
 static const uint32_t vce_rate_ctrl[] = {
diff --git a/tests/amdgpu/vce_tests.c b/tests/amdgpu/vce_tests.c
index 32fc001..de63aa1 100644
--- a/tests/amdgpu/vce_tests.c
+++ b/tests/amdgpu/vce_tests.c
@@ -65,6 +65,7 @@
 static uint32_t major_version;
 static uint32_t minor_version;
 static uint32_t family_id;
+static uint32_t vce_harvest_config;
 
 static amdgpu_context_handle context_handle;
 static amdgpu_bo_handle ib_handle;
@@ -93,10 +94,17 @@
 
 	r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
 				     &minor_version, &device_handle);
-	if (r)
+	if (r) {
+		if ((r == -EACCES) && (errno == EACCES))
+			printf("\n\nError:%s. "
+				"Hint:Try to run this test program as root.",
+				strerror(errno));
+
 		return CUE_SINIT_FAILED;
+	}
 
 	family_id = device_handle->info.family_id;
+	vce_harvest_config = device_handle->info.vce_harvest_config;
 
 	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
 	if (r)
@@ -440,14 +448,16 @@
 		check_result(&enc);
 
 		/* two instances */
-		enc.two_instance = true;
-		vce_taskinfo[2] = 0x83;
-		vce_taskinfo[4] = 1;
-		amdgpu_cs_vce_encode_idr(&enc);
-		vce_taskinfo[2] = 0xffffffff;
-		vce_taskinfo[4] = 2;
-		amdgpu_cs_vce_encode_p(&enc);
-		check_result(&enc);
+		if (vce_harvest_config == 0) {
+			enc.two_instance = true;
+			vce_taskinfo[2] = 0x83;
+			vce_taskinfo[4] = 1;
+			amdgpu_cs_vce_encode_idr(&enc);
+			vce_taskinfo[2] = 0xffffffff;
+			vce_taskinfo[4] = 2;
+			amdgpu_cs_vce_encode_p(&enc);
+			check_result(&enc);
+		}
 	} else {
 		vce_taskinfo[3] = 3;
 		vce_encode[16] = 0;
diff --git a/tests/auth.c b/tests/auth.c
deleted file mode 100644
index 9147b11..0000000
--- a/tests/auth.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <limits.h>
-#include <sys/ioctl.h>
-#include "drmtest.h"
-
-enum auth_event {
-	SERVER_READY,
-	CLIENT_MAGIC,
-	CLIENT_DONE,
-};
-
-int commfd[2];
-
-static void wait_event(int pipe, enum auth_event expected_event)
-{
-	int ret;
-	enum auth_event event;
-	unsigned char in;
-
-	ret = read(commfd[pipe], &in, 1);
-	if (ret == -1)
-		err(1, "read error");
-	event = in;
-
-	if (event != expected_event)
-		errx(1, "unexpected event: %d\n", event);
-}
-
-static void
-send_event(int pipe, enum auth_event send_event)
-{
-	int ret;
-	unsigned char event;
-
-	event = send_event;
-	ret = write(commfd[pipe], &event, 1);
-	if (ret == -1)
-		err(1, "failed to send event %d", event);
-}
-
-static void client()
-{
-	struct drm_auth auth;
-	int drmfd, ret;
-
-	/* XXX: Should make sure we open the same DRM as the master */
-	wait_event(0, SERVER_READY);
-
-	drmfd = drm_open_any();
-
-	/* Get a client magic number and pass it to the master for auth. */
-	auth.magic = 0; /* Quiet valgrind */
-	ret = ioctl(drmfd, DRM_IOCTL_GET_MAGIC, &auth);
-	if (ret == -1)
-		err(1, "Couldn't get client magic");
-	send_event(0, CLIENT_MAGIC);
-	ret = write(commfd[0], &auth.magic, sizeof(auth.magic));
-	if (ret == -1)
-		err(1, "Couldn't write auth data");
-
-	/* Signal that the client is completely done. */
-	send_event(0, CLIENT_DONE);
-}
-
-static void server()
-{
-	int drmfd, ret;
-	struct drm_auth auth;
-
-	drmfd = drm_open_any_master();
-
-	auth.magic = 0xd0d0d0d0;
-	ret = ioctl(drmfd, DRM_IOCTL_AUTH_MAGIC, &auth);
-	if (ret != -1 || errno != EINVAL)
-		errx(1, "Authenticating bad magic succeeded\n");
-
-	send_event(1, SERVER_READY);
-
-	wait_event(1, CLIENT_MAGIC);
-	ret = read(commfd[1], &auth.magic, sizeof(auth.magic));
-	if (ret == -1)
-		err(1, "Failure to read client magic");
-
-	ret = ioctl(drmfd, DRM_IOCTL_AUTH_MAGIC, &auth);
-	if (ret == -1)
-		err(1, "Failure to authenticate client magic\n");
-
-	wait_event(1, CLIENT_DONE);
-}
-
-/**
- * Checks DRM authentication mechanisms.
- */
-int main(int argc, char **argv)
-{
-	int ret;
-
-	ret = pipe(commfd);
-	if (ret == -1)
-		err(1, "Couldn't create pipe");
-
-	ret = fork();
-	if (ret == -1)
-		err(1, "failure to fork client");
-	if (ret == 0)
-		client();
-	else
-		server();
-
-	return 0;
-}
-
diff --git a/tests/dristat.c b/tests/dristat.c
deleted file mode 100644
index cca4b03..0000000
--- a/tests/dristat.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/* dristat.c -- 
- * Created: Mon Jan 15 05:05:07 2001 by faith@acm.org
- *
- * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
- * All Rights Reserved.
- *
- * 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- * 
- * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
- * 
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "xf86drm.h"
-#include "xf86drmRandom.c"
-#include "xf86drmHash.c"
-#include "xf86drm.c"
-
-#define DRM_VERSION 0x00000001
-#define DRM_MEMORY  0x00000002
-#define DRM_CLIENTS 0x00000004
-#define DRM_STATS   0x00000008
-#define DRM_BUSID   0x00000010
-
-static void getversion(int fd)
-{
-    drmVersionPtr version;
-    
-    version = drmGetVersion(fd);
-    if (version) {
-	printf("  Version information:\n");
-	printf("    Name: %s\n", version->name ? version->name : "?");
-	printf("    Version: %d.%d.%d\n",
-	       version->version_major,
-	       version->version_minor,
-	       version->version_patchlevel);
-	printf("    Date: %s\n", version->date ? version->date : "?");
-	printf("    Desc: %s\n", version->desc ? version->desc : "?");
-	drmFreeVersion(version);
-    } else {
-	printf("  No version information available\n");
-    }
-}
-
-static void getbusid(int fd)
-{
-    const char *busid = drmGetBusid(fd);
-    
-    printf("  Busid: %s\n", *busid ? busid : "(not set)");
-    drmFreeBusid(busid);
-}
-
-
-static void getvm(int fd)
-{
-    int             i;
-    const char      *typename;
-    char            flagname[33];
-    drm_handle_t    offset;
-    drmSize         size;
-    drmMapType      type;
-    drmMapFlags     flags;
-    drm_handle_t    handle;
-    int             mtrr;
-
-    printf("  VM map information:\n");
-    printf("  flags: (R)estricted (r)ead/(w)rite (l)ocked (k)ernel (W)rite-combine (L)ock:\n");
-    printf("    slot     offset       size type flags    address mtrr\n");
-
-    for (i = 0;
-	 !drmGetMap(fd, i, &offset, &size, &type, &flags, &handle, &mtrr);
-	 i++) {
-	
-	switch (type) {
-	case DRM_FRAME_BUFFER:   typename = "FB";  break;
-	case DRM_REGISTERS:      typename = "REG"; break;
-	case DRM_SHM:            typename = "SHM"; break;
-	case DRM_AGP:            typename = "AGP"; break;
-	case DRM_SCATTER_GATHER: typename = "SG";  break;
-	case DRM_CONSISTENT:     typename = "CON"; break;
-	default:                 typename = "???"; break;
-	}
-
-	flagname[0] = (flags & DRM_RESTRICTED)      ? 'R' : ' ';
-	flagname[1] = (flags & DRM_READ_ONLY)       ? 'r' : 'w';
-	flagname[2] = (flags & DRM_LOCKED)          ? 'l' : ' ';
-	flagname[3] = (flags & DRM_KERNEL)          ? 'k' : ' ';
-	flagname[4] = (flags & DRM_WRITE_COMBINING) ? 'W' : ' ';
-	flagname[5] = (flags & DRM_CONTAINS_LOCK)   ? 'L' : ' ';
-	flagname[6] = '\0';
-	
-	printf("    %4d 0x%08lx 0x%08lx %3.3s %6.6s 0x%08lx ",
-	       i, (unsigned long)offset, (unsigned long)size,
-	       typename, flagname, (unsigned long)handle);
-	if (mtrr < 0) printf("none\n");
-	else          printf("%4d\n", mtrr);
-    }
-}
-
-static void getclients(int fd)
-{
-    int           i;
-    int           auth;
-    int           pid;
-    int           uid;
-    unsigned long magic;
-    unsigned long iocs;
-    char          buf[64];
-    char          cmd[40];
-    int           procfd;
-    
-    printf("  DRI client information:\n");
-    printf("    a   pid   uid      magic     ioctls   prog\n");
-
-    for (i = 0; !drmGetClient(fd, i, &auth, &pid, &uid, &magic, &iocs); i++) {
-	sprintf(buf, "/proc/%d/cmdline", pid);
-	memset(cmd, 0, sizeof(cmd));
-	if ((procfd = open(buf, O_RDONLY, 0)) >= 0) {
-	    read(procfd, cmd, sizeof(cmd)-1);
-	    close(procfd);
-	}
-	if (*cmd) {
-	    char *pt;
-
-	    for (pt = cmd; *pt; pt++) if (!isprint(*pt)) *pt = ' ';
-	    printf("    %c %5d %5d %10lu %10lu   %s\n",
-		   auth ? 'y' : 'n', pid, uid, magic, iocs, cmd);
-	} else {
-	    printf("    %c %5d %5d %10lu %10lu\n",
-		   auth ? 'y' : 'n', pid, uid, magic, iocs);
-	}
-    }
-}
-
-static void printhuman(unsigned long value, const char *name, int mult)
-{
-    const char *p;
-    double     f;
-				/* Print width 5 number in width 6 space */
-    if (value < 100000) {
-	printf(" %5lu", value);
-	return;
-    }
-
-    p = name;
-    f = (double)value / (double)mult;
-    if (f < 10.0) {
-	printf(" %4.2f%c", f, *p);
-	return;
-    }
-
-    p++;
-    f = (double)value / (double)mult;
-    if (f < 10.0) {
-	printf(" %4.2f%c", f, *p);
-	return;
-    }
-    
-    p++;
-    f = (double)value / (double)mult;
-    if (f < 10.0) {
-	printf(" %4.2f%c", f, *p);
-	return;
-    }
-}
-
-static void getstats(int fd, int i)
-{
-    drmStatsT prev, curr;
-    unsigned  j;
-    double    rate;
-
-    printf("  System statistics:\n");
-
-    if (drmGetStats(fd, &prev)) return;
-    if (!i) {
-	for (j = 0; j < prev.count; j++) {
-	    printf("    ");
-	    printf(prev.data[j].long_format, prev.data[j].long_name);
-	    if (prev.data[j].isvalue) printf(" 0x%08lx\n", prev.data[j].value);
-	    else                      printf(" %10lu\n", prev.data[j].value);
-	}
-	return;
-    }
-
-    printf("    ");
-    for (j = 0; j < prev.count; j++)
-	if (!prev.data[j].verbose) {
-	    printf(" ");
-	    printf(prev.data[j].rate_format, prev.data[j].rate_name);
-	}
-    printf("\n");
-    
-    for (;;) {
-	sleep(i);
-	if (drmGetStats(fd, &curr)) return;
-	printf("    ");
-	for (j = 0; j < curr.count; j++) {
-	    if (curr.data[j].verbose) continue;
-	    if (curr.data[j].isvalue) {
-		printf(" %08lx", curr.data[j].value);
-	    } else {
-		rate = (curr.data[j].value - prev.data[j].value) / (double)i;
-		printhuman(rate, curr.data[j].mult_names, curr.data[j].mult);
-	    }
-	}
-	printf("\n");
-	memcpy(&prev, &curr, sizeof(prev));
-    }
-    
-}
-
-int main(int argc, char **argv)
-{
-    int  c;
-    int  mask     = 0;
-    int  minor    = 0;
-    int  interval = 0;
-    int  fd;
-    char buf[64];
-    int  i;
-
-    while ((c = getopt(argc, argv, "avmcsbM:i:")) != EOF)
-	switch (c) {
-	case 'a': mask = ~0;                          break;
-	case 'v': mask |= DRM_VERSION;                break;
-	case 'm': mask |= DRM_MEMORY;                 break;
-	case 'c': mask |= DRM_CLIENTS;                break;
-	case 's': mask |= DRM_STATS;                  break;
-	case 'b': mask |= DRM_BUSID;                  break;
-	case 'i': interval = strtol(optarg, NULL, 0); break;
-	case 'M': minor = strtol(optarg, NULL, 0);    break;
-	default:
-	    fprintf( stderr, "Usage: dristat [options]\n\n" );
-	    fprintf( stderr, "Displays DRM information. Use with no arguments to display available cards.\n\n" );
-	    fprintf( stderr, "  -a            Show all available information\n" );
-	    fprintf( stderr, "  -b            Show DRM bus ID's\n" );
-	    fprintf( stderr, "  -c            Display information about DRM clients\n" );
-	    fprintf( stderr, "  -i [interval] Continuously display statistics every [interval] seconds\n" );
-	    fprintf( stderr, "  -v            Display DRM module and card version information\n" );
-	    fprintf( stderr, "  -m            Display memory use information\n" );
-	    fprintf( stderr, "  -s            Display DRM statistics\n" );
-	    fprintf( stderr, "  -M [minor]    Select card by minor number\n" );
-	    return 1;
-	}
-
-    for (i = 0; i < 16; i++) if (!minor || i == minor) {
-	sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i);
-	fd = drmOpenMinor(i, 1, DRM_NODE_PRIMARY);
-	if (fd >= 0) {
-	    printf("%s\n", buf);
-	    if (mask & DRM_BUSID)   getbusid(fd);
-	    if (mask & DRM_VERSION) getversion(fd);
-	    if (mask & DRM_MEMORY)  getvm(fd);
-	    if (mask & DRM_CLIENTS) getclients(fd);
-	    if (mask & DRM_STATS)   getstats(fd, interval);
-	    close(fd);
-	}
-    }
-
-    return 0; 
-}
diff --git a/tests/drmdevice.c b/tests/drmdevice.c
index c336327..9dd5098 100644
--- a/tests/drmdevice.c
+++ b/tests/drmdevice.c
@@ -21,8 +21,11 @@
  *
  */
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -30,7 +33,7 @@
 
 
 static void
-print_device_info(drmDevicePtr device, int i)
+print_device_info(drmDevicePtr device, int i, bool print_revision)
 {
     printf("device[%i]\n", i);
     printf("\tavailable_nodes %04x\n", device->available_nodes);
@@ -44,8 +47,8 @@
     if (device->bustype == DRM_BUS_PCI) {
         printf("\t\tpci\n");
         printf("\t\t\tdomain\t%04x\n",device->businfo.pci->domain);
-        printf("\t\t\tbu\t%02x\n", device->businfo.pci->bus);
-        printf("\t\t\tde\t%02x\n", device->businfo.pci->dev);
+        printf("\t\t\tbus\t%02x\n", device->businfo.pci->bus);
+        printf("\t\t\tdev\t%02x\n", device->businfo.pci->dev);
         printf("\t\t\tfunc\t%1u\n", device->businfo.pci->func);
 
         printf("\tdeviceinfo\n");
@@ -54,7 +57,48 @@
         printf("\t\t\tdevice_id\t%04x\n", device->deviceinfo.pci->device_id);
         printf("\t\t\tsubvendor_id\t%04x\n", device->deviceinfo.pci->subvendor_id);
         printf("\t\t\tsubdevice_id\t%04x\n", device->deviceinfo.pci->subdevice_id);
-        printf("\t\t\trevision_id\t%02x\n", device->deviceinfo.pci->revision_id);
+        if (print_revision)
+            printf("\t\t\trevision_id\t%02x\n", device->deviceinfo.pci->revision_id);
+        else
+            printf("\t\t\trevision_id\tIGNORED\n");
+
+    } else if (device->bustype == DRM_BUS_USB) {
+        printf("\t\tusb\n");
+        printf("\t\t\tbus\t%03u\n", device->businfo.usb->bus);
+        printf("\t\t\tdev\t%03u\n", device->businfo.usb->dev);
+
+        printf("\tdeviceinfo\n");
+        printf("\t\tusb\n");
+        printf("\t\t\tvendor\t%04x\n", device->deviceinfo.usb->vendor);
+        printf("\t\t\tproduct\t%04x\n", device->deviceinfo.usb->product);
+    } else if (device->bustype == DRM_BUS_PLATFORM) {
+        char **compatible = device->deviceinfo.platform->compatible;
+
+        printf("\t\tplatform\n");
+        printf("\t\t\tfullname\t%s\n", device->businfo.platform->fullname);
+
+        printf("\tdeviceinfo\n");
+        printf("\t\tplatform\n");
+        printf("\t\t\tcompatible\n");
+
+        while (*compatible) {
+            printf("\t\t\t\t%s\n", *compatible);
+            compatible++;
+        }
+    } else if (device->bustype == DRM_BUS_HOST1X) {
+        char **compatible = device->deviceinfo.platform->compatible;
+
+        printf("\t\thost1x\n");
+        printf("\t\t\tfullname\t%s\n", device->businfo.host1x->fullname);
+
+        printf("\tdeviceinfo\n");
+        printf("\t\tplatform\n");
+        printf("\t\t\tcompatible\n");
+
+        while (*compatible) {
+            printf("\t\t\t\t%s\n", *compatible);
+            compatible++;
+        }
     } else {
         printf("Unknown/unhandled bustype\n");
     }
@@ -68,10 +112,10 @@
     drmDevicePtr device;
     int fd, ret, max_devices;
 
-    max_devices = drmGetDevices(NULL, 0);
+    max_devices = drmGetDevices2(0, NULL, 0);
 
     if (max_devices <= 0) {
-        printf("drmGetDevices() has returned %d\n", max_devices);
+        printf("drmGetDevices2() has returned %d\n", max_devices);
         return -1;
     }
 
@@ -81,24 +125,27 @@
         return -1;
     }
 
-    ret = drmGetDevices(devices, max_devices);
+    ret = drmGetDevices2(0, devices, max_devices);
     if (ret < 0) {
-        printf("drmGetDevices() returned an error %d\n", ret);
+        printf("drmGetDevices2() returned an error %d\n", ret);
         free(devices);
         return -1;
     }
 
     for (int i = 0; i < ret; i++) {
-        print_device_info(devices[i], i);
+        print_device_info(devices[i], i, false);
 
         for (int j = 0; j < DRM_NODE_MAX; j++) {
             if (devices[i]->available_nodes & 1 << j) {
+                printf("Opening device %d node %s\n", i, devices[i]->nodes[j]);
                 fd = open(devices[i]->nodes[j], O_RDONLY | O_CLOEXEC, 0);
-                if (fd < 0)
+                if (fd < 0) {
+                    printf("Failed - %s (%d)\n", strerror(errno), errno);
                     continue;
+                }
 
-                if (drmGetDevice(fd, &device) == 0) {
-                    print_device_info(device, -1);
+                if (drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, &device) == 0) {
+                    print_device_info(device, i, true);
                     drmFreeDevice(&device);
                 }
                 close(fd);
diff --git a/tests/drmtest.c b/tests/drmtest.c
deleted file mode 100644
index 022994a..0000000
--- a/tests/drmtest.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <string.h>
-#include <fcntl.h>
-#include <fnmatch.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include "drmtest.h"
-
-#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
-#include <libudev.h>
-
-static int is_master(int fd)
-{
-	drm_client_t client;
-	int ret;
-
-	/* Check that we're the only opener and authed. */
-	client.idx = 0;
-	ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
-	assert (ret == 0);
-	if (!client.auth)
-		return 0;
-	client.idx = 1;
-	ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
-	if (ret != -1 || errno != EINVAL)
-		return 0;
-
-	return 1;
-}
-
-/** Open the first DRM device matching the criteria */
-int drm_open_matching(const char *pci_glob, int flags)
-{
-	struct udev *udev;
-	struct udev_enumerate *e;
-	struct udev_device *device, *parent;
-        struct udev_list_entry *entry;
-	const char *pci_id, *path;
-	const char *usub, *dnode;
-	int fd;
-
-	udev = udev_new();
-	if (udev == NULL) {
-		fprintf(stderr, "failed to initialize udev context\n");
-		abort();
-	}
-
-	fd = -1;
-	e = udev_enumerate_new(udev);
-	udev_enumerate_add_match_subsystem(e, "drm");
-        udev_enumerate_scan_devices(e);
-        udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
-		path = udev_list_entry_get_name(entry);
-		device = udev_device_new_from_syspath(udev, path);
-		parent = udev_device_get_parent(device);
-		usub = udev_device_get_subsystem(parent);
-		/* Filter out KMS output devices. */
-		if (!usub || (strcmp(usub, "pci") != 0))
-			continue;
-		pci_id = udev_device_get_property_value(parent, "PCI_ID");
-		if (fnmatch(pci_glob, pci_id, 0) != 0)
-			continue;
-		dnode = udev_device_get_devnode(device);
-		if (strstr(dnode, "control"))
-			continue;
-		fd = open(dnode, O_RDWR);
-		if (fd < 0)
-			continue;
-		if ((flags & DRM_TEST_MASTER) && !is_master(fd)) {
-			close(fd);
-			fd = -1;
-			continue;
-		}
-
-		break;
-	}
-        udev_enumerate_unref(e);
-	udev_unref(udev);
-
-	return fd;
-}
-
-int drm_open_any(void)
-{
-	int fd = drm_open_matching("*:*", 0);
-
-	if (fd < 0) {
-		fprintf(stderr, "failed to open any drm device\n");
-		exit(0);
-	}
-
-	return fd;
-}
-
-/**
- * Open the first DRM device we can find where we end up being the master.
- */
-int drm_open_any_master(void)
-{
-	int fd = drm_open_matching("*:*", DRM_TEST_MASTER);
-
-	if (fd < 0) {
-		fprintf(stderr, "failed to open any drm device\n");
-		exit(0);
-	}
-
-	return fd;
-
-}
diff --git a/tests/drmtest.h b/tests/drmtest.h
deleted file mode 100644
index 55bb446..0000000
--- a/tests/drmtest.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-
-#include "xf86drm.h"
-
-#define DRM_TEST_MASTER 0x01
-
-int drm_open_any(void);
-int drm_open_any_master(void);
-int drm_open_matching(const char *pci_glob, int flags);
diff --git a/tests/etnaviv/Makefile.am b/tests/etnaviv/Makefile.am
new file mode 100644
index 0000000..0631864
--- /dev/null
+++ b/tests/etnaviv/Makefile.am
@@ -0,0 +1,41 @@
+AM_CFLAGS = \
+	-I $(top_srcdir)/include/drm \
+	-I $(top_srcdir)/etnaviv \
+	-I $(top_srcdir)
+
+if HAVE_INSTALL_TESTS
+bin_PROGRAMS = \
+	etnaviv_2d_test \
+	etnaviv_cmd_stream_test \
+	etnaviv_bo_cache_test
+else
+noinst_PROGRAMS = \
+	etnaviv_2d_test \
+	etnaviv_cmd_stream_test \
+	etnaviv_bo_cache_test
+endif
+
+etnaviv_2d_test_LDADD = \
+	$(top_builddir)/libdrm.la \
+	$(top_builddir)/etnaviv/libdrm_etnaviv.la
+
+etnaviv_2d_test_SOURCES = \
+	cmdstream.xml.h \
+	etnaviv_2d_test.c \
+	state.xml.h \
+	state_2d.xml.h \
+	write_bmp.c \
+	write_bmp.h
+
+etnaviv_cmd_stream_test_LDADD = \
+	$(top_builddir)/etnaviv/libdrm_etnaviv.la
+
+etnaviv_cmd_stream_test_SOURCES = \
+	etnaviv_cmd_stream_test.c
+
+etnaviv_bo_cache_test_LDADD = \
+	$(top_builddir)/libdrm.la \
+	$(top_builddir)/etnaviv/libdrm_etnaviv.la
+
+etnaviv_bo_cache_test_SOURCES = \
+	etnaviv_bo_cache_test.c
diff --git a/tests/etnaviv/cmdstream.xml.h b/tests/etnaviv/cmdstream.xml.h
new file mode 100644
index 0000000..109285c
--- /dev/null
+++ b/tests/etnaviv/cmdstream.xml.h
@@ -0,0 +1,242 @@
+#ifndef CMDSTREAM_XML
+#define CMDSTREAM_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- cmdstream.xml (  12621 bytes, from 2016-09-06 14:44:16)
+- copyright.xml (   1597 bytes, from 2016-09-06 14:44:16)
+- common.xml    (  20583 bytes, from 2016-09-06 14:14:12)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@arm.linux.org.uk>
+
+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, sub license,
+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 NON-INFRINGEMENT. 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.
+*/
+
+
+#define FE_OPCODE_LOAD_STATE					0x00000001
+#define FE_OPCODE_END						0x00000002
+#define FE_OPCODE_NOP						0x00000003
+#define FE_OPCODE_DRAW_2D					0x00000004
+#define FE_OPCODE_DRAW_PRIMITIVES				0x00000005
+#define FE_OPCODE_DRAW_INDEXED_PRIMITIVES			0x00000006
+#define FE_OPCODE_WAIT						0x00000007
+#define FE_OPCODE_LINK						0x00000008
+#define FE_OPCODE_STALL						0x00000009
+#define FE_OPCODE_CALL						0x0000000a
+#define FE_OPCODE_RETURN					0x0000000b
+#define FE_OPCODE_CHIP_SELECT					0x0000000d
+#define PRIMITIVE_TYPE_POINTS					0x00000001
+#define PRIMITIVE_TYPE_LINES					0x00000002
+#define PRIMITIVE_TYPE_LINE_STRIP				0x00000003
+#define PRIMITIVE_TYPE_TRIANGLES				0x00000004
+#define PRIMITIVE_TYPE_TRIANGLE_STRIP				0x00000005
+#define PRIMITIVE_TYPE_TRIANGLE_FAN				0x00000006
+#define PRIMITIVE_TYPE_LINE_LOOP				0x00000007
+#define PRIMITIVE_TYPE_QUADS					0x00000008
+#define VIV_FE_LOAD_STATE					0x00000000
+
+#define VIV_FE_LOAD_STATE_HEADER				0x00000000
+#define VIV_FE_LOAD_STATE_HEADER_OP__MASK			0xf8000000
+#define VIV_FE_LOAD_STATE_HEADER_OP__SHIFT			27
+#define VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE			0x08000000
+#define VIV_FE_LOAD_STATE_HEADER_FIXP				0x04000000
+#define VIV_FE_LOAD_STATE_HEADER_COUNT__MASK			0x03ff0000
+#define VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT			16
+#define VIV_FE_LOAD_STATE_HEADER_COUNT(x)			(((x) << VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK)
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK			0x0000ffff
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT			0
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET(x)			(((x) << VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT) & VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK)
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR			2
+
+#define VIV_FE_END						0x00000000
+
+#define VIV_FE_END_HEADER					0x00000000
+#define VIV_FE_END_HEADER_EVENT_ID__MASK			0x0000001f
+#define VIV_FE_END_HEADER_EVENT_ID__SHIFT			0
+#define VIV_FE_END_HEADER_EVENT_ID(x)				(((x) << VIV_FE_END_HEADER_EVENT_ID__SHIFT) & VIV_FE_END_HEADER_EVENT_ID__MASK)
+#define VIV_FE_END_HEADER_EVENT_ENABLE				0x00000100
+#define VIV_FE_END_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_END_HEADER_OP__SHIFT				27
+#define VIV_FE_END_HEADER_OP_END				0x10000000
+
+#define VIV_FE_NOP						0x00000000
+
+#define VIV_FE_NOP_HEADER					0x00000000
+#define VIV_FE_NOP_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_NOP_HEADER_OP__SHIFT				27
+#define VIV_FE_NOP_HEADER_OP_NOP				0x18000000
+
+#define VIV_FE_DRAW_2D						0x00000000
+
+#define VIV_FE_DRAW_2D_HEADER					0x00000000
+#define VIV_FE_DRAW_2D_HEADER_COUNT__MASK			0x0000ff00
+#define VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT			8
+#define VIV_FE_DRAW_2D_HEADER_COUNT(x)				(((x) << VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_COUNT__MASK)
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK			0x07ff0000
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT			16
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT(x)			(((x) << VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK)
+#define VIV_FE_DRAW_2D_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_DRAW_2D_HEADER_OP__SHIFT				27
+#define VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D			0x20000000
+
+#define VIV_FE_DRAW_2D_TOP_LEFT					0x00000008
+#define VIV_FE_DRAW_2D_TOP_LEFT_X__MASK				0x0000ffff
+#define VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT			0
+#define VIV_FE_DRAW_2D_TOP_LEFT_X(x)				(((x) << VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_X__MASK)
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK				0xffff0000
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT			16
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y(x)				(((x) << VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK)
+
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT				0x0000000c
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK			0x0000ffff
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT			0
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x)			(((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK)
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK			0xffff0000
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT			16
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(x)			(((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK)
+
+#define VIV_FE_DRAW_PRIMITIVES					0x00000000
+
+#define VIV_FE_DRAW_PRIMITIVES_HEADER				0x00000000
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__MASK			0xf8000000
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__SHIFT			27
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES	0x28000000
+
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND				0x00000004
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK		0x000000ff
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT		0
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE(x)			(((x) << VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK)
+
+#define VIV_FE_DRAW_PRIMITIVES_START				0x00000008
+
+#define VIV_FE_DRAW_PRIMITIVES_COUNT				0x0000000c
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES				0x00000000
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER			0x00000000
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__MASK		0xf8000000
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__SHIFT		27
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES	0x30000000
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND			0x00000004
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK	0x000000ff
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT	0
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE(x)		(((x) << VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK)
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_START			0x00000008
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COUNT			0x0000000c
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_OFFSET			0x00000010
+
+#define VIV_FE_WAIT						0x00000000
+
+#define VIV_FE_WAIT_HEADER					0x00000000
+#define VIV_FE_WAIT_HEADER_DELAY__MASK				0x0000ffff
+#define VIV_FE_WAIT_HEADER_DELAY__SHIFT				0
+#define VIV_FE_WAIT_HEADER_DELAY(x)				(((x) << VIV_FE_WAIT_HEADER_DELAY__SHIFT) & VIV_FE_WAIT_HEADER_DELAY__MASK)
+#define VIV_FE_WAIT_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_WAIT_HEADER_OP__SHIFT				27
+#define VIV_FE_WAIT_HEADER_OP_WAIT				0x38000000
+
+#define VIV_FE_LINK						0x00000000
+
+#define VIV_FE_LINK_HEADER					0x00000000
+#define VIV_FE_LINK_HEADER_PREFETCH__MASK			0x0000ffff
+#define VIV_FE_LINK_HEADER_PREFETCH__SHIFT			0
+#define VIV_FE_LINK_HEADER_PREFETCH(x)				(((x) << VIV_FE_LINK_HEADER_PREFETCH__SHIFT) & VIV_FE_LINK_HEADER_PREFETCH__MASK)
+#define VIV_FE_LINK_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_LINK_HEADER_OP__SHIFT				27
+#define VIV_FE_LINK_HEADER_OP_LINK				0x40000000
+
+#define VIV_FE_LINK_ADDRESS					0x00000004
+
+#define VIV_FE_STALL						0x00000000
+
+#define VIV_FE_STALL_HEADER					0x00000000
+#define VIV_FE_STALL_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_STALL_HEADER_OP__SHIFT				27
+#define VIV_FE_STALL_HEADER_OP_STALL				0x48000000
+
+#define VIV_FE_STALL_TOKEN					0x00000004
+#define VIV_FE_STALL_TOKEN_FROM__MASK				0x0000001f
+#define VIV_FE_STALL_TOKEN_FROM__SHIFT				0
+#define VIV_FE_STALL_TOKEN_FROM(x)				(((x) << VIV_FE_STALL_TOKEN_FROM__SHIFT) & VIV_FE_STALL_TOKEN_FROM__MASK)
+#define VIV_FE_STALL_TOKEN_TO__MASK				0x00001f00
+#define VIV_FE_STALL_TOKEN_TO__SHIFT				8
+#define VIV_FE_STALL_TOKEN_TO(x)				(((x) << VIV_FE_STALL_TOKEN_TO__SHIFT) & VIV_FE_STALL_TOKEN_TO__MASK)
+
+#define VIV_FE_CALL						0x00000000
+
+#define VIV_FE_CALL_HEADER					0x00000000
+#define VIV_FE_CALL_HEADER_PREFETCH__MASK			0x0000ffff
+#define VIV_FE_CALL_HEADER_PREFETCH__SHIFT			0
+#define VIV_FE_CALL_HEADER_PREFETCH(x)				(((x) << VIV_FE_CALL_HEADER_PREFETCH__SHIFT) & VIV_FE_CALL_HEADER_PREFETCH__MASK)
+#define VIV_FE_CALL_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_CALL_HEADER_OP__SHIFT				27
+#define VIV_FE_CALL_HEADER_OP_CALL				0x50000000
+
+#define VIV_FE_CALL_ADDRESS					0x00000004
+
+#define VIV_FE_CALL_RETURN_PREFETCH				0x00000008
+
+#define VIV_FE_CALL_RETURN_ADDRESS				0x0000000c
+
+#define VIV_FE_RETURN						0x00000000
+
+#define VIV_FE_RETURN_HEADER					0x00000000
+#define VIV_FE_RETURN_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_RETURN_HEADER_OP__SHIFT				27
+#define VIV_FE_RETURN_HEADER_OP_RETURN				0x58000000
+
+#define VIV_FE_CHIP_SELECT					0x00000000
+
+#define VIV_FE_CHIP_SELECT_HEADER				0x00000000
+#define VIV_FE_CHIP_SELECT_HEADER_OP__MASK			0xf8000000
+#define VIV_FE_CHIP_SELECT_HEADER_OP__SHIFT			27
+#define VIV_FE_CHIP_SELECT_HEADER_OP_CHIP_SELECT		0x68000000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP15			0x00008000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP14			0x00004000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP13			0x00002000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP12			0x00001000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP11			0x00000800
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP10			0x00000400
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP9			0x00000200
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP8			0x00000100
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP7			0x00000080
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP6			0x00000040
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP5			0x00000020
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP4			0x00000010
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP3			0x00000008
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP2			0x00000004
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP1			0x00000002
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP0			0x00000001
+
+
+#endif /* CMDSTREAM_XML */
diff --git a/tests/etnaviv/etnaviv_2d_test.c b/tests/etnaviv/etnaviv_2d_test.c
new file mode 100644
index 0000000..10751c7
--- /dev/null
+++ b/tests/etnaviv/etnaviv_2d_test.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2014-2015 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xf86drm.h"
+#include "etnaviv_drmif.h"
+#include "etnaviv_drm.h"
+
+#include "state.xml.h"
+#include "state_2d.xml.h"
+#include "cmdstream.xml.h"
+
+#include "write_bmp.h"
+
+static inline void etna_emit_load_state(struct etna_cmd_stream *stream,
+		const uint16_t offset, const uint16_t count)
+{
+	uint32_t v;
+
+	v = 	(VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | VIV_FE_LOAD_STATE_HEADER_OFFSET(offset) |
+			(VIV_FE_LOAD_STATE_HEADER_COUNT(count) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK));
+
+	etna_cmd_stream_emit(stream, v);
+}
+
+static inline void etna_set_state(struct etna_cmd_stream *stream, uint32_t address, uint32_t value)
+{
+	etna_cmd_stream_reserve(stream, 2);
+	etna_emit_load_state(stream, address >> 2, 1);
+	etna_cmd_stream_emit(stream, value);
+}
+
+static inline void etna_set_state_from_bo(struct etna_cmd_stream *stream,
+		uint32_t address, struct etna_bo *bo)
+{
+	etna_cmd_stream_reserve(stream, 2);
+	etna_emit_load_state(stream, address >> 2, 1);
+
+	etna_cmd_stream_reloc(stream, &(struct etna_reloc){
+		.bo = bo,
+		.flags = ETNA_RELOC_READ,
+		.offset = 0,
+	});
+}
+
+static void gen_cmd_stream(struct etna_cmd_stream *stream, struct etna_bo *bmp, const int width, const int height)
+{
+	int rec;
+	static int num_rects = 256;
+
+	etna_set_state(stream, VIVS_DE_SRC_STRIDE, 0);
+	etna_set_state(stream, VIVS_DE_SRC_ROTATION_CONFIG, 0);
+	etna_set_state(stream, VIVS_DE_SRC_CONFIG, 0);
+	etna_set_state(stream, VIVS_DE_SRC_ORIGIN, 0);
+	etna_set_state(stream, VIVS_DE_SRC_SIZE, 0);
+	etna_set_state(stream, VIVS_DE_SRC_COLOR_BG, 0);
+	etna_set_state(stream, VIVS_DE_SRC_COLOR_FG, 0);
+	etna_set_state(stream, VIVS_DE_STRETCH_FACTOR_LOW, 0);
+	etna_set_state(stream, VIVS_DE_STRETCH_FACTOR_HIGH, 0);
+	etna_set_state_from_bo(stream, VIVS_DE_DEST_ADDRESS, bmp);
+	etna_set_state(stream, VIVS_DE_DEST_STRIDE, width*4);
+	etna_set_state(stream, VIVS_DE_DEST_ROTATION_CONFIG, 0);
+	etna_set_state(stream, VIVS_DE_DEST_CONFIG,
+			VIVS_DE_DEST_CONFIG_FORMAT(DE_FORMAT_A8R8G8B8) |
+			VIVS_DE_DEST_CONFIG_COMMAND_CLEAR |
+			VIVS_DE_DEST_CONFIG_SWIZZLE(DE_SWIZZLE_ARGB) |
+			VIVS_DE_DEST_CONFIG_TILED_DISABLE |
+			VIVS_DE_DEST_CONFIG_MINOR_TILED_DISABLE
+			);
+	etna_set_state(stream, VIVS_DE_ROP,
+			VIVS_DE_ROP_ROP_FG(0xcc) | VIVS_DE_ROP_ROP_BG(0xcc) | VIVS_DE_ROP_TYPE_ROP4);
+	etna_set_state(stream, VIVS_DE_CLIP_TOP_LEFT,
+			VIVS_DE_CLIP_TOP_LEFT_X(0) |
+			VIVS_DE_CLIP_TOP_LEFT_Y(0)
+			);
+	etna_set_state(stream, VIVS_DE_CLIP_BOTTOM_RIGHT,
+			VIVS_DE_CLIP_BOTTOM_RIGHT_X(width) |
+			VIVS_DE_CLIP_BOTTOM_RIGHT_Y(height)
+			);
+	etna_set_state(stream, VIVS_DE_CONFIG, 0); /* TODO */
+	etna_set_state(stream, VIVS_DE_SRC_ORIGIN_FRACTION, 0);
+	etna_set_state(stream, VIVS_DE_ALPHA_CONTROL, 0);
+	etna_set_state(stream, VIVS_DE_ALPHA_MODES, 0);
+	etna_set_state(stream, VIVS_DE_DEST_ROTATION_HEIGHT, 0);
+	etna_set_state(stream, VIVS_DE_SRC_ROTATION_HEIGHT, 0);
+	etna_set_state(stream, VIVS_DE_ROT_ANGLE, 0);
+
+	/* Clear color PE20 */
+	etna_set_state(stream, VIVS_DE_CLEAR_PIXEL_VALUE32, 0xff40ff40);
+	/* Clear color PE10 */
+	etna_set_state(stream, VIVS_DE_CLEAR_BYTE_MASK, 0xff);
+	etna_set_state(stream, VIVS_DE_CLEAR_PIXEL_VALUE_LOW, 0xff40ff40);
+	etna_set_state(stream, VIVS_DE_CLEAR_PIXEL_VALUE_HIGH, 0xff40ff40);
+
+	etna_set_state(stream, VIVS_DE_DEST_COLOR_KEY, 0);
+	etna_set_state(stream, VIVS_DE_GLOBAL_SRC_COLOR, 0);
+	etna_set_state(stream, VIVS_DE_GLOBAL_DEST_COLOR, 0);
+	etna_set_state(stream, VIVS_DE_COLOR_MULTIPLY_MODES, 0);
+	etna_set_state(stream, VIVS_DE_PE_TRANSPARENCY, 0);
+	etna_set_state(stream, VIVS_DE_PE_CONTROL, 0);
+	etna_set_state(stream, VIVS_DE_PE_DITHER_LOW, 0xffffffff);
+	etna_set_state(stream, VIVS_DE_PE_DITHER_HIGH, 0xffffffff);
+
+	/* Queue DE command */
+	etna_cmd_stream_emit(stream,
+			VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D | VIV_FE_DRAW_2D_HEADER_COUNT(num_rects) /* render one rectangle */
+		);
+	etna_cmd_stream_emit(stream, 0x0); /* rectangles start aligned */
+
+	for(rec=0; rec < num_rects; ++rec) {
+		int x = rec%16;
+		int y = rec/16;
+		etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_TOP_LEFT_X(x*8) | VIV_FE_DRAW_2D_TOP_LEFT_Y(y*8));
+		etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x*8+4) | VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(y*8+4));
+	}
+	etna_set_state(stream, 1, 0);
+	etna_set_state(stream, 1, 0);
+	etna_set_state(stream, 1, 0);
+
+	etna_set_state(stream, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_PE2D);
+}
+
+int main(int argc, char *argv[])
+{
+	const int width = 256;
+	const int height = 256;
+	const size_t bmp_size = width * height * 4;
+
+	struct etna_device *dev;
+	struct etna_gpu *gpu;
+	struct etna_pipe *pipe;
+	struct etna_bo *bmp;
+	struct etna_cmd_stream *stream;
+
+	drmVersionPtr version;
+	int fd, ret = 0;
+
+	fd = open(argv[1], O_RDWR);
+	if (fd < 0)
+		return 1;
+
+	version = drmGetVersion(fd);
+	if (version) {
+		printf("Version: %d.%d.%d\n", version->version_major,
+		       version->version_minor, version->version_patchlevel);
+		printf("  Name: %s\n", version->name);
+		printf("  Date: %s\n", version->date);
+		printf("  Description: %s\n", version->desc);
+		drmFreeVersion(version);
+	}
+
+	dev = etna_device_new(fd);
+	if (!dev) {
+		ret = 2;
+		goto out;
+	}
+
+	/* TODO: we assume that core 0 is a 2D capable one */
+	gpu = etna_gpu_new(dev, 0);
+	if (!gpu) {
+		ret = 3;
+		goto out_device;
+	}
+
+	pipe = etna_pipe_new(gpu, ETNA_PIPE_2D);
+	if (!pipe) {
+		ret = 4;
+		goto out_gpu;
+	}
+
+	bmp = etna_bo_new(dev, bmp_size, ETNA_BO_UNCACHED);
+	if (!bmp) {
+		ret = 5;
+		goto out_pipe;
+	}
+	memset(etna_bo_map(bmp), 0, bmp_size);
+
+	stream = etna_cmd_stream_new(pipe, 0x300, NULL, NULL);
+	if (!stream) {
+		ret = 6;
+		goto out_bo;
+	}
+
+	/* generate command sequence */
+	gen_cmd_stream(stream, bmp, width, height);
+
+	etna_cmd_stream_finish(stream);
+
+	bmp_dump32(etna_bo_map(bmp), width, height, false, "/tmp/etna.bmp");
+
+	etna_cmd_stream_del(stream);
+
+out_bo:
+    etna_bo_del(bmp);
+
+out_pipe:
+	etna_pipe_del(pipe);
+
+out_gpu:
+	etna_gpu_del(gpu);
+
+out_device:
+	etna_device_del(dev);
+
+out:
+	close(fd);
+
+	return ret;
+}
diff --git a/tests/etnaviv/etnaviv_bo_cache_test.c b/tests/etnaviv/etnaviv_bo_cache_test.c
new file mode 100644
index 0000000..fb01f8d
--- /dev/null
+++ b/tests/etnaviv/etnaviv_bo_cache_test.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xf86drm.h"
+#include "etnaviv_drmif.h"
+#include "etnaviv_drm.h"
+
+static void test_cache(struct etna_device *dev)
+{
+	struct etna_bo *bo, *tmp;
+
+	/* allocate and free some bo's with same size - we must
+	 * get the same bo over and over. */
+	printf("testing bo cache ... ");
+
+	bo = tmp = etna_bo_new(dev, 0x100, ETNA_BO_UNCACHED);
+	assert(bo);
+	etna_bo_del(bo);
+
+	for (unsigned i = 0; i < 100; i++) {
+		tmp = etna_bo_new(dev, 0x100, ETNA_BO_UNCACHED);
+		etna_bo_del(tmp);
+		assert(tmp == bo);
+	}
+
+	printf("ok\n");
+}
+
+static void test_size_rounding(struct etna_device *dev)
+{
+	struct etna_bo *bo;
+
+	printf("testing size rounding ... ");
+
+	bo = etna_bo_new(dev, 15, ETNA_BO_UNCACHED);
+	assert(etna_bo_size(bo) == 4096);
+	etna_bo_del(bo);
+
+	bo = etna_bo_new(dev, 4096, ETNA_BO_UNCACHED);
+	assert(etna_bo_size(bo) == 4096);
+	etna_bo_del(bo);
+
+	bo = etna_bo_new(dev, 4100, ETNA_BO_UNCACHED);
+	assert(etna_bo_size(bo) == 8192);
+	etna_bo_del(bo);
+
+	printf("ok\n");
+}
+
+int main(int argc, char *argv[])
+{
+	struct etna_device *dev;
+
+	drmVersionPtr version;
+	int fd, ret = 0;
+
+	fd = open(argv[1], O_RDWR);
+	if (fd < 0)
+		return 1;
+
+	version = drmGetVersion(fd);
+	if (version) {
+		printf("Version: %d.%d.%d\n", version->version_major,
+		       version->version_minor, version->version_patchlevel);
+		printf("  Name: %s\n", version->name);
+		printf("  Date: %s\n", version->date);
+		printf("  Description: %s\n", version->desc);
+		drmFreeVersion(version);
+	}
+
+	dev = etna_device_new(fd);
+	if (!dev) {
+		ret = 2;
+		goto out;
+	}
+
+	test_cache(dev);
+	test_size_rounding(dev);
+
+	etna_device_del(dev);
+
+out:
+	close(fd);
+
+	return ret;
+}
diff --git a/tests/etnaviv/etnaviv_cmd_stream_test.c b/tests/etnaviv/etnaviv_cmd_stream_test.c
new file mode 100644
index 0000000..b650aae
--- /dev/null
+++ b/tests/etnaviv/etnaviv_cmd_stream_test.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#undef NDEBUG
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "etnaviv_drmif.h"
+
+static void test_avail()
+{
+	struct etna_cmd_stream *stream;
+
+	printf("testing etna_cmd_stream_avail ... ");
+
+	/* invalid size */
+	stream = etna_cmd_stream_new(NULL, 0, NULL, NULL);
+	assert(stream == NULL);
+
+	stream = etna_cmd_stream_new(NULL, 4, NULL, NULL);
+	assert(stream);
+	assert(etna_cmd_stream_avail(stream) == 2);
+	etna_cmd_stream_del(stream);
+
+	stream = etna_cmd_stream_new(NULL, 20, NULL, NULL);
+	assert(stream);
+	assert(etna_cmd_stream_avail(stream) == 18);
+	etna_cmd_stream_del(stream);
+
+	/* odd number of 32 bit words */
+	stream = etna_cmd_stream_new(NULL, 1, NULL, NULL);
+	assert(stream);
+	assert(etna_cmd_stream_avail(stream) == 0);
+	etna_cmd_stream_del(stream);
+
+	stream = etna_cmd_stream_new(NULL, 23, NULL, NULL);
+	assert(stream);
+	assert(etna_cmd_stream_avail(stream) == 22);
+	etna_cmd_stream_del(stream);
+
+	printf("ok\n");
+}
+
+static void test_emit()
+{
+	struct etna_cmd_stream *stream;
+
+	printf("testing etna_cmd_stream_emit ... ");
+
+	stream = etna_cmd_stream_new(NULL, 6, NULL, NULL);
+	assert(stream);
+	assert(etna_cmd_stream_avail(stream) == 4);
+
+	etna_cmd_stream_emit(stream, 0x1);
+	assert(etna_cmd_stream_avail(stream) == 3);
+
+	etna_cmd_stream_emit(stream, 0x2);
+	assert(etna_cmd_stream_avail(stream) == 2);
+
+	etna_cmd_stream_emit(stream, 0x3);
+	assert(etna_cmd_stream_avail(stream) == 1);
+
+	etna_cmd_stream_del(stream);
+
+	printf("ok\n");
+}
+
+static void test_offset()
+{
+	struct etna_cmd_stream *stream;
+
+	printf("testing etna_cmd_stream_offset ... ");
+
+	stream = etna_cmd_stream_new(NULL, 6, NULL, NULL);
+	assert(etna_cmd_stream_offset(stream) == 0);
+
+	etna_cmd_stream_emit(stream, 0x1);
+	assert(etna_cmd_stream_offset(stream) == 1);
+
+	etna_cmd_stream_emit(stream, 0x2);
+	assert(etna_cmd_stream_offset(stream) == 2);
+
+	etna_cmd_stream_emit(stream, 0x3);
+	etna_cmd_stream_emit(stream, 0x4);
+	assert(etna_cmd_stream_offset(stream) == 4);
+
+	etna_cmd_stream_del(stream);
+
+	printf("ok\n");
+}
+
+int main(int argc, char *argv[])
+{
+	test_avail();
+	test_emit();
+	test_offset();
+
+	return 0;
+}
diff --git a/tests/etnaviv/state.xml.h b/tests/etnaviv/state.xml.h
new file mode 100644
index 0000000..e1ecbf3
--- /dev/null
+++ b/tests/etnaviv/state.xml.h
@@ -0,0 +1,375 @@
+#ifndef STATE_XML
+#define STATE_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state.xml     (  18940 bytes, from 2016-09-06 14:14:12)
+- common.xml    (  20583 bytes, from 2016-09-06 14:14:12)
+- state_hi.xml  (  25653 bytes, from 2016-09-06 14:45:17)
+- copyright.xml (   1597 bytes, from 2016-09-06 14:44:16)
+- state_2d.xml  (  51552 bytes, from 2016-09-06 14:44:16)
+- state_3d.xml  (  54603 bytes, from 2016-09-06 14:44:16)
+- state_vg.xml  (   5975 bytes, from 2016-09-06 14:44:16)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@arm.linux.org.uk>
+
+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, sub license,
+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 NON-INFRINGEMENT. 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.
+*/
+
+
+#define VARYING_COMPONENT_USE_UNUSED				0x00000000
+#define VARYING_COMPONENT_USE_USED				0x00000001
+#define VARYING_COMPONENT_USE_POINTCOORD_X			0x00000002
+#define VARYING_COMPONENT_USE_POINTCOORD_Y			0x00000003
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK		0x000000ff
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT		0
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x)		(((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK)
+#define VIVS_FE							0x00000000
+
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0)		       (0x00000600 + 0x4*(i0))
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE			0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN			0x00000010
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK		0x0000000f
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT		0
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE			0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE	0x00000001
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT		0x00000002
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT	0x00000003
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT			0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT		0x00000005
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT		0x00000008
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT		0x00000009
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED		0x0000000b
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2	0x0000000c
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2	0x0000000d
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK		0x00000030
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT		4
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE		0x00000080
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK		0x00000700
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT		8
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK			0x00003000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT		12
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK		0x0000c000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT		14
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF		0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON		0x00008000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK		0x00ff0000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT		16
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK			0xff000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT		24
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK)
+
+#define VIVS_FE_CMD_STREAM_BASE_ADDR				0x00000640
+
+#define VIVS_FE_INDEX_STREAM_BASE_ADDR				0x00000644
+
+#define VIVS_FE_INDEX_STREAM_CONTROL				0x00000648
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK			0x00000003
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT		0
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR		0x00000000
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT	0x00000001
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT		0x00000002
+
+#define VIVS_FE_VERTEX_STREAM_BASE_ADDR				0x0000064c
+
+#define VIVS_FE_VERTEX_STREAM_CONTROL				0x00000650
+
+#define VIVS_FE_COMMAND_ADDRESS					0x00000654
+
+#define VIVS_FE_COMMAND_CONTROL					0x00000658
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK			0x0000ffff
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT			0
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x)			(((x) << VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK)
+#define VIVS_FE_COMMAND_CONTROL_ENABLE				0x00010000
+
+#define VIVS_FE_DMA_STATUS					0x0000065c
+
+#define VIVS_FE_DMA_DEBUG_STATE					0x00000660
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK			0x0000001f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT		0
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE			0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC			0x00000001
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0			0x00000002
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0			0x00000003
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1			0x00000004
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1			0x00000005
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR			0x00000006
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD			0x00000007
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL		0x00000008
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL		0x00000009
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA		0x0000000a
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX		0x0000000b
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW			0x0000000c
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0		0x0000000d
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1		0x0000000e
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0		0x0000000f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1		0x00000010
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO		0x00000011
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT			0x00000012
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK			0x00000013
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END			0x00000014
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL			0x00000015
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK		0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT		8
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START		0x00000100
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ		0x00000200
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END		0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK		0x00000c00
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT		10
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID	0x00000400
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID		0x00000800
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK		0x00003000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT		12
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX		0x00001000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL		0x00002000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK			0x0000c000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT		14
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE			0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR			0x00004000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC		0x00008000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK		0x00030000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT		16
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE		0x00010000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS		0x00020000
+
+#define VIVS_FE_DMA_ADDRESS					0x00000664
+
+#define VIVS_FE_DMA_LOW						0x00000668
+
+#define VIVS_FE_DMA_HIGH					0x0000066c
+
+#define VIVS_FE_AUTO_FLUSH					0x00000670
+
+#define VIVS_FE_UNK00678					0x00000678
+
+#define VIVS_FE_UNK0067C					0x0000067c
+
+#define VIVS_FE_VERTEX_STREAMS(i0)			       (0x00000000 + 0x4*(i0))
+#define VIVS_FE_VERTEX_STREAMS__ESIZE				0x00000004
+#define VIVS_FE_VERTEX_STREAMS__LEN				0x00000008
+
+#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0)		       (0x00000680 + 0x4*(i0))
+
+#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0)		       (0x000006a0 + 0x4*(i0))
+
+#define VIVS_FE_UNK00700(i0)				       (0x00000700 + 0x4*(i0))
+#define VIVS_FE_UNK00700__ESIZE					0x00000004
+#define VIVS_FE_UNK00700__LEN					0x00000010
+
+#define VIVS_FE_UNK00740(i0)				       (0x00000740 + 0x4*(i0))
+#define VIVS_FE_UNK00740__ESIZE					0x00000004
+#define VIVS_FE_UNK00740__LEN					0x00000010
+
+#define VIVS_FE_UNK00780(i0)				       (0x00000780 + 0x4*(i0))
+#define VIVS_FE_UNK00780__ESIZE					0x00000004
+#define VIVS_FE_UNK00780__LEN					0x00000010
+
+#define VIVS_GL							0x00000000
+
+#define VIVS_GL_PIPE_SELECT					0x00003800
+#define VIVS_GL_PIPE_SELECT_PIPE__MASK				0x00000001
+#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT				0
+#define VIVS_GL_PIPE_SELECT_PIPE(x)				(((x) << VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK)
+
+#define VIVS_GL_EVENT						0x00003804
+#define VIVS_GL_EVENT_EVENT_ID__MASK				0x0000001f
+#define VIVS_GL_EVENT_EVENT_ID__SHIFT				0
+#define VIVS_GL_EVENT_EVENT_ID(x)				(((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK)
+#define VIVS_GL_EVENT_FROM_FE					0x00000020
+#define VIVS_GL_EVENT_FROM_PE					0x00000040
+#define VIVS_GL_EVENT_SOURCE__MASK				0x00001f00
+#define VIVS_GL_EVENT_SOURCE__SHIFT				8
+#define VIVS_GL_EVENT_SOURCE(x)					(((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK)
+
+#define VIVS_GL_SEMAPHORE_TOKEN					0x00003808
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK			0x0000001f
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT			0
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x)				(((x) << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK)
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK			0x00001f00
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT			8
+#define VIVS_GL_SEMAPHORE_TOKEN_TO(x)				(((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK)
+
+#define VIVS_GL_FLUSH_CACHE					0x0000380c
+#define VIVS_GL_FLUSH_CACHE_DEPTH				0x00000001
+#define VIVS_GL_FLUSH_CACHE_COLOR				0x00000002
+#define VIVS_GL_FLUSH_CACHE_TEXTURE				0x00000004
+#define VIVS_GL_FLUSH_CACHE_PE2D				0x00000008
+#define VIVS_GL_FLUSH_CACHE_TEXTUREVS				0x00000010
+#define VIVS_GL_FLUSH_CACHE_SHADER_L1				0x00000020
+#define VIVS_GL_FLUSH_CACHE_SHADER_L2				0x00000040
+
+#define VIVS_GL_FLUSH_MMU					0x00003810
+#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU				0x00000001
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1				0x00000002
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2				0x00000004
+#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU				0x00000008
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4				0x00000010
+
+#define VIVS_GL_VERTEX_ELEMENT_CONFIG				0x00003814
+
+#define VIVS_GL_MULTI_SAMPLE_CONFIG				0x00003818
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK		0x00000003
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT		0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE		0x00000000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X		0x00000001
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X		0x00000002
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK		0x00000008
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK		0x000000f0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT		4
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x)		(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK		0x00000100
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK			0x00007000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT		12
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x)			(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK			0x00008000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK			0x00030000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT		16
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x)			(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK			0x00080000
+
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS			0x0000381c
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK		0x000000ff
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT		0
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x)			(((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK)
+
+#define VIVS_GL_VARYING_NUM_COMPONENTS				0x00003820
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK		0x00000007
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT		0
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK		0x00000070
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT		4
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK		0x00000700
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT		8
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK		0x00007000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT		12
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK		0x00070000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT		16
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK		0x00700000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT		20
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK		0x07000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT		24
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK		0x70000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT		28
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK)
+
+#define VIVS_GL_VARYING_COMPONENT_USE(i0)		       (0x00003828 + 0x4*(i0))
+#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE			0x00000004
+#define VIVS_GL_VARYING_COMPONENT_USE__LEN			0x00000002
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK		0x00000003
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT		0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK		0x0000000c
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT		2
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK		0x00000030
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT		4
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK		0x000000c0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT		6
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK		0x00000300
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT		8
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK		0x00000c00
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT		10
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK		0x00003000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT		12
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK		0x0000c000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT		14
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK		0x00030000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT		16
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK		0x000c0000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT		18
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK		0x00300000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT		20
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK		0x00c00000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT		22
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK		0x03000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT		24
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK		0x0c000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT		26
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK		0x30000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT		28
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK		0xc0000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT		30
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK)
+
+#define VIVS_GL_UNK03834					0x00003834
+
+#define VIVS_GL_UNK03838					0x00003838
+
+#define VIVS_GL_API_MODE					0x0000384c
+#define VIVS_GL_API_MODE_OPENGL					0x00000000
+#define VIVS_GL_API_MODE_OPENVG					0x00000001
+#define VIVS_GL_API_MODE_OPENCL					0x00000002
+
+#define VIVS_GL_CONTEXT_POINTER					0x00003850
+
+#define VIVS_GL_UNK03A00					0x00003a00
+
+#define VIVS_GL_STALL_TOKEN					0x00003c00
+#define VIVS_GL_STALL_TOKEN_FROM__MASK				0x0000001f
+#define VIVS_GL_STALL_TOKEN_FROM__SHIFT				0
+#define VIVS_GL_STALL_TOKEN_FROM(x)				(((x) << VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK)
+#define VIVS_GL_STALL_TOKEN_TO__MASK				0x00001f00
+#define VIVS_GL_STALL_TOKEN_TO__SHIFT				8
+#define VIVS_GL_STALL_TOKEN_TO(x)				(((x) << VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK)
+#define VIVS_GL_STALL_TOKEN_FLIP0				0x40000000
+#define VIVS_GL_STALL_TOKEN_FLIP1				0x80000000
+
+#define VIVS_DUMMY						0x00000000
+
+#define VIVS_DUMMY_DUMMY					0x0003fffc
+
+
+#endif /* STATE_XML */
diff --git a/tests/etnaviv/state_2d.xml.h b/tests/etnaviv/state_2d.xml.h
new file mode 100644
index 0000000..715eed4
--- /dev/null
+++ b/tests/etnaviv/state_2d.xml.h
@@ -0,0 +1,1497 @@
+#ifndef STATE_2D_XML
+#define STATE_2D_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state.xml     (  18940 bytes, from 2016-09-06 14:14:12)
+- common.xml    (  20583 bytes, from 2016-09-06 14:14:12)
+- state_hi.xml  (  25653 bytes, from 2016-09-06 14:45:17)
+- copyright.xml (   1597 bytes, from 2016-09-06 14:44:16)
+- state_2d.xml  (  51552 bytes, from 2016-09-06 14:44:16)
+- state_3d.xml  (  54603 bytes, from 2016-09-06 14:44:16)
+- state_vg.xml  (   5975 bytes, from 2016-09-06 14:44:16)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@arm.linux.org.uk>
+
+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, sub license,
+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 NON-INFRINGEMENT. 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.
+*/
+
+
+#define DE_FORMAT_X4R4G4B4					0x00000000
+#define DE_FORMAT_A4R4G4B4					0x00000001
+#define DE_FORMAT_X1R5G5B5					0x00000002
+#define DE_FORMAT_A1R5G5B5					0x00000003
+#define DE_FORMAT_R5G6B5					0x00000004
+#define DE_FORMAT_X8R8G8B8					0x00000005
+#define DE_FORMAT_A8R8G8B8					0x00000006
+#define DE_FORMAT_YUY2						0x00000007
+#define DE_FORMAT_UYVY						0x00000008
+#define DE_FORMAT_INDEX8					0x00000009
+#define DE_FORMAT_MONOCHROME					0x0000000a
+#define DE_FORMAT_YV12						0x0000000f
+#define DE_FORMAT_A8						0x00000010
+#define DE_FORMAT_NV12						0x00000011
+#define DE_FORMAT_NV16						0x00000012
+#define DE_FORMAT_RG16						0x00000013
+#define DE_SWIZZLE_ARGB						0x00000000
+#define DE_SWIZZLE_RGBA						0x00000001
+#define DE_SWIZZLE_ABGR						0x00000002
+#define DE_SWIZZLE_BGRA						0x00000003
+#define DE_BLENDMODE_ZERO					0x00000000
+#define DE_BLENDMODE_ONE					0x00000001
+#define DE_BLENDMODE_NORMAL					0x00000002
+#define DE_BLENDMODE_INVERSED					0x00000003
+#define DE_BLENDMODE_COLOR					0x00000004
+#define DE_BLENDMODE_COLOR_INVERSED				0x00000005
+#define DE_BLENDMODE_SATURATED_ALPHA				0x00000006
+#define DE_BLENDMODE_SATURATED_DEST_ALPHA			0x00000007
+#define DE_COMPONENT_BLUE					0x00000000
+#define DE_COMPONENT_GREEN					0x00000001
+#define DE_COMPONENT_RED					0x00000002
+#define DE_COMPONENT_ALPHA					0x00000003
+#define DE_ROT_MODE_ROT0					0x00000000
+#define DE_ROT_MODE_FLIP_X					0x00000001
+#define DE_ROT_MODE_FLIP_Y					0x00000002
+#define DE_ROT_MODE_ROT90					0x00000004
+#define DE_ROT_MODE_ROT180					0x00000005
+#define DE_ROT_MODE_ROT270					0x00000006
+#define DE_MIRROR_MODE_NONE					0x00000000
+#define DE_MIRROR_MODE_MIRROR_X					0x00000001
+#define DE_MIRROR_MODE_MIRROR_Y					0x00000002
+#define DE_MIRROR_MODE_MIRROR_XY				0x00000003
+#define DE_COLOR_BLUE__MASK					0x000000ff
+#define DE_COLOR_BLUE__SHIFT					0
+#define DE_COLOR_BLUE(x)					(((x) << DE_COLOR_BLUE__SHIFT) & DE_COLOR_BLUE__MASK)
+#define DE_COLOR_GREEN__MASK					0x0000ff00
+#define DE_COLOR_GREEN__SHIFT					8
+#define DE_COLOR_GREEN(x)					(((x) << DE_COLOR_GREEN__SHIFT) & DE_COLOR_GREEN__MASK)
+#define DE_COLOR_RED__MASK					0x00ff0000
+#define DE_COLOR_RED__SHIFT					16
+#define DE_COLOR_RED(x)						(((x) << DE_COLOR_RED__SHIFT) & DE_COLOR_RED__MASK)
+#define DE_COLOR_ALPHA__MASK					0xff000000
+#define DE_COLOR_ALPHA__SHIFT					24
+#define DE_COLOR_ALPHA(x)					(((x) << DE_COLOR_ALPHA__SHIFT) & DE_COLOR_ALPHA__MASK)
+#define VIVS_DE							0x00000000
+
+#define VIVS_DE_SRC_ADDRESS					0x00001200
+
+#define VIVS_DE_SRC_STRIDE					0x00001204
+#define VIVS_DE_SRC_STRIDE_STRIDE__MASK				0x0003ffff
+#define VIVS_DE_SRC_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_SRC_STRIDE_STRIDE(x)				(((x) << VIVS_DE_SRC_STRIDE_STRIDE__SHIFT) & VIVS_DE_SRC_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_SRC_ROTATION_CONFIG				0x00001208
+#define VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__MASK			0x0000ffff
+#define VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__SHIFT		0
+#define VIVS_DE_SRC_ROTATION_CONFIG_WIDTH(x)			(((x) << VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__MASK)
+#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION__MASK		0x00010000
+#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION__SHIFT		16
+#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION_DISABLE		0x00000000
+#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION_ENABLE		0x00010000
+
+#define VIVS_DE_SRC_CONFIG					0x0000120c
+#define VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK		0x0000000f
+#define VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT		0
+#define VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT(x)		(((x) << VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT) & VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK)
+#define VIVS_DE_SRC_CONFIG_TRANSPARENCY__MASK			0x00000030
+#define VIVS_DE_SRC_CONFIG_TRANSPARENCY__SHIFT			4
+#define VIVS_DE_SRC_CONFIG_TRANSPARENCY(x)			(((x) << VIVS_DE_SRC_CONFIG_TRANSPARENCY__SHIFT) & VIVS_DE_SRC_CONFIG_TRANSPARENCY__MASK)
+#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE__MASK			0x00000040
+#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE__SHIFT			6
+#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE_ABSOLUTE		0x00000000
+#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE_RELATIVE		0x00000040
+#define VIVS_DE_SRC_CONFIG_TILED__MASK				0x00000080
+#define VIVS_DE_SRC_CONFIG_TILED__SHIFT				7
+#define VIVS_DE_SRC_CONFIG_TILED_DISABLE			0x00000000
+#define VIVS_DE_SRC_CONFIG_TILED_ENABLE				0x00000080
+#define VIVS_DE_SRC_CONFIG_LOCATION__MASK			0x00000100
+#define VIVS_DE_SRC_CONFIG_LOCATION__SHIFT			8
+#define VIVS_DE_SRC_CONFIG_LOCATION_MEMORY			0x00000000
+#define VIVS_DE_SRC_CONFIG_LOCATION_STREAM			0x00000100
+#define VIVS_DE_SRC_CONFIG_PACK__MASK				0x00003000
+#define VIVS_DE_SRC_CONFIG_PACK__SHIFT				12
+#define VIVS_DE_SRC_CONFIG_PACK_PACKED8				0x00000000
+#define VIVS_DE_SRC_CONFIG_PACK_PACKED16			0x00001000
+#define VIVS_DE_SRC_CONFIG_PACK_PACKED32			0x00002000
+#define VIVS_DE_SRC_CONFIG_PACK_UNPACKED			0x00003000
+#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY__MASK		0x00008000
+#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY__SHIFT		15
+#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY_BACKGROUND		0x00000000
+#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY_FOREGROUND		0x00008000
+#define VIVS_DE_SRC_CONFIG_UNK16				0x00010000
+#define VIVS_DE_SRC_CONFIG_SWIZZLE__MASK			0x00300000
+#define VIVS_DE_SRC_CONFIG_SWIZZLE__SHIFT			20
+#define VIVS_DE_SRC_CONFIG_SWIZZLE(x)				(((x) << VIVS_DE_SRC_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_SRC_CONFIG_SWIZZLE__MASK)
+#define VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__MASK			0x1f000000
+#define VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__SHIFT			24
+#define VIVS_DE_SRC_CONFIG_SOURCE_FORMAT(x)			(((x) << VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__SHIFT) & VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__MASK)
+#define VIVS_DE_SRC_CONFIG_DISABLE420_L2_CACHE			0x20000000
+#define VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__MASK			0xc0000000
+#define VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__SHIFT		30
+#define VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL(x)			(((x) << VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__MASK)
+
+#define VIVS_DE_SRC_ORIGIN					0x00001210
+#define VIVS_DE_SRC_ORIGIN_X__MASK				0x0000ffff
+#define VIVS_DE_SRC_ORIGIN_X__SHIFT				0
+#define VIVS_DE_SRC_ORIGIN_X(x)					(((x) << VIVS_DE_SRC_ORIGIN_X__SHIFT) & VIVS_DE_SRC_ORIGIN_X__MASK)
+#define VIVS_DE_SRC_ORIGIN_Y__MASK				0xffff0000
+#define VIVS_DE_SRC_ORIGIN_Y__SHIFT				16
+#define VIVS_DE_SRC_ORIGIN_Y(x)					(((x) << VIVS_DE_SRC_ORIGIN_Y__SHIFT) & VIVS_DE_SRC_ORIGIN_Y__MASK)
+
+#define VIVS_DE_SRC_SIZE					0x00001214
+#define VIVS_DE_SRC_SIZE_X__MASK				0x0000ffff
+#define VIVS_DE_SRC_SIZE_X__SHIFT				0
+#define VIVS_DE_SRC_SIZE_X(x)					(((x) << VIVS_DE_SRC_SIZE_X__SHIFT) & VIVS_DE_SRC_SIZE_X__MASK)
+#define VIVS_DE_SRC_SIZE_Y__MASK				0xffff0000
+#define VIVS_DE_SRC_SIZE_Y__SHIFT				16
+#define VIVS_DE_SRC_SIZE_Y(x)					(((x) << VIVS_DE_SRC_SIZE_Y__SHIFT) & VIVS_DE_SRC_SIZE_Y__MASK)
+
+#define VIVS_DE_SRC_COLOR_BG					0x00001218
+
+#define VIVS_DE_SRC_COLOR_FG					0x0000121c
+
+#define VIVS_DE_STRETCH_FACTOR_LOW				0x00001220
+#define VIVS_DE_STRETCH_FACTOR_LOW_X__MASK			0x7fffffff
+#define VIVS_DE_STRETCH_FACTOR_LOW_X__SHIFT			0
+#define VIVS_DE_STRETCH_FACTOR_LOW_X(x)				(((x) << VIVS_DE_STRETCH_FACTOR_LOW_X__SHIFT) & VIVS_DE_STRETCH_FACTOR_LOW_X__MASK)
+
+#define VIVS_DE_STRETCH_FACTOR_HIGH				0x00001224
+#define VIVS_DE_STRETCH_FACTOR_HIGH_Y__MASK			0x7fffffff
+#define VIVS_DE_STRETCH_FACTOR_HIGH_Y__SHIFT			0
+#define VIVS_DE_STRETCH_FACTOR_HIGH_Y(x)			(((x) << VIVS_DE_STRETCH_FACTOR_HIGH_Y__SHIFT) & VIVS_DE_STRETCH_FACTOR_HIGH_Y__MASK)
+
+#define VIVS_DE_DEST_ADDRESS					0x00001228
+
+#define VIVS_DE_DEST_STRIDE					0x0000122c
+#define VIVS_DE_DEST_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_DEST_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_DEST_STRIDE_STRIDE(x)				(((x) << VIVS_DE_DEST_STRIDE_STRIDE__SHIFT) & VIVS_DE_DEST_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_DEST_ROTATION_CONFIG				0x00001230
+#define VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__MASK		0x0000ffff
+#define VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__SHIFT		0
+#define VIVS_DE_DEST_ROTATION_CONFIG_WIDTH(x)			(((x) << VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__MASK)
+#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION__MASK		0x00010000
+#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION__SHIFT		16
+#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION_DISABLE		0x00000000
+#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION_ENABLE		0x00010000
+
+#define VIVS_DE_DEST_CONFIG					0x00001234
+#define VIVS_DE_DEST_CONFIG_FORMAT__MASK			0x0000001f
+#define VIVS_DE_DEST_CONFIG_FORMAT__SHIFT			0
+#define VIVS_DE_DEST_CONFIG_FORMAT(x)				(((x) << VIVS_DE_DEST_CONFIG_FORMAT__SHIFT) & VIVS_DE_DEST_CONFIG_FORMAT__MASK)
+#define VIVS_DE_DEST_CONFIG_TILED__MASK				0x00000100
+#define VIVS_DE_DEST_CONFIG_TILED__SHIFT			8
+#define VIVS_DE_DEST_CONFIG_TILED_DISABLE			0x00000000
+#define VIVS_DE_DEST_CONFIG_TILED_ENABLE			0x00000100
+#define VIVS_DE_DEST_CONFIG_COMMAND__MASK			0x0000f000
+#define VIVS_DE_DEST_CONFIG_COMMAND__SHIFT			12
+#define VIVS_DE_DEST_CONFIG_COMMAND_CLEAR			0x00000000
+#define VIVS_DE_DEST_CONFIG_COMMAND_LINE			0x00001000
+#define VIVS_DE_DEST_CONFIG_COMMAND_BIT_BLT			0x00002000
+#define VIVS_DE_DEST_CONFIG_COMMAND_BIT_BLT_REVERSED		0x00003000
+#define VIVS_DE_DEST_CONFIG_COMMAND_STRETCH_BLT			0x00004000
+#define VIVS_DE_DEST_CONFIG_COMMAND_HOR_FILTER_BLT		0x00005000
+#define VIVS_DE_DEST_CONFIG_COMMAND_VER_FILTER_BLT		0x00006000
+#define VIVS_DE_DEST_CONFIG_COMMAND_ONE_PASS_FILTER_BLT		0x00007000
+#define VIVS_DE_DEST_CONFIG_COMMAND_MULTI_SOURCE_BLT		0x00008000
+#define VIVS_DE_DEST_CONFIG_SWIZZLE__MASK			0x00030000
+#define VIVS_DE_DEST_CONFIG_SWIZZLE__SHIFT			16
+#define VIVS_DE_DEST_CONFIG_SWIZZLE(x)				(((x) << VIVS_DE_DEST_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_DEST_CONFIG_SWIZZLE__MASK)
+#define VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__MASK		0x00300000
+#define VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__SHIFT		20
+#define VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL(x)			(((x) << VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__MASK)
+#define VIVS_DE_DEST_CONFIG_GDI_STRE__MASK			0x01000000
+#define VIVS_DE_DEST_CONFIG_GDI_STRE__SHIFT			24
+#define VIVS_DE_DEST_CONFIG_GDI_STRE_DISABLE			0x00000000
+#define VIVS_DE_DEST_CONFIG_GDI_STRE_ENABLE			0x01000000
+#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX__MASK		0x02000000
+#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX__SHIFT		25
+#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX_DISABLED		0x02000000
+#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX_ENABLED		0x00000000
+#define VIVS_DE_DEST_CONFIG_MINOR_TILED__MASK			0x04000000
+#define VIVS_DE_DEST_CONFIG_MINOR_TILED__SHIFT			26
+#define VIVS_DE_DEST_CONFIG_MINOR_TILED_DISABLE			0x00000000
+#define VIVS_DE_DEST_CONFIG_MINOR_TILED_ENABLE			0x04000000
+
+#define VIVS_DE_PATTERN_ADDRESS					0x00001238
+
+#define VIVS_DE_PATTERN_CONFIG					0x0000123c
+#define VIVS_DE_PATTERN_CONFIG_FORMAT__MASK			0x0000000f
+#define VIVS_DE_PATTERN_CONFIG_FORMAT__SHIFT			0
+#define VIVS_DE_PATTERN_CONFIG_FORMAT(x)			(((x) << VIVS_DE_PATTERN_CONFIG_FORMAT__SHIFT) & VIVS_DE_PATTERN_CONFIG_FORMAT__MASK)
+#define VIVS_DE_PATTERN_CONFIG_TYPE__MASK			0x00000010
+#define VIVS_DE_PATTERN_CONFIG_TYPE__SHIFT			4
+#define VIVS_DE_PATTERN_CONFIG_TYPE_SOLID_COLOR			0x00000000
+#define VIVS_DE_PATTERN_CONFIG_TYPE_PATTERN			0x00000010
+#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT__MASK		0x00000020
+#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT__SHIFT		5
+#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT_DISABLE		0x00000000
+#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT_ENABLE		0x00000020
+#define VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__MASK		0x000000c0
+#define VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__SHIFT		6
+#define VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER(x)			(((x) << VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__SHIFT) & VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__MASK)
+#define VIVS_DE_PATTERN_CONFIG_ORIGIN_X__MASK			0x00070000
+#define VIVS_DE_PATTERN_CONFIG_ORIGIN_X__SHIFT			16
+#define VIVS_DE_PATTERN_CONFIG_ORIGIN_X(x)			(((x) << VIVS_DE_PATTERN_CONFIG_ORIGIN_X__SHIFT) & VIVS_DE_PATTERN_CONFIG_ORIGIN_X__MASK)
+#define VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__MASK			0x00700000
+#define VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__SHIFT			20
+#define VIVS_DE_PATTERN_CONFIG_ORIGIN_Y(x)			(((x) << VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__SHIFT) & VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__MASK)
+
+#define VIVS_DE_PATTERN_LOW					0x00001240
+
+#define VIVS_DE_PATTERN_HIGH					0x00001244
+
+#define VIVS_DE_PATTERN_MASK_LOW				0x00001248
+
+#define VIVS_DE_PATTERN_MASK_HIGH				0x0000124c
+
+#define VIVS_DE_PATTERN_BG_COLOR				0x00001250
+
+#define VIVS_DE_PATTERN_FG_COLOR				0x00001254
+
+#define VIVS_DE_ROP						0x0000125c
+#define VIVS_DE_ROP_ROP_FG__MASK				0x000000ff
+#define VIVS_DE_ROP_ROP_FG__SHIFT				0
+#define VIVS_DE_ROP_ROP_FG(x)					(((x) << VIVS_DE_ROP_ROP_FG__SHIFT) & VIVS_DE_ROP_ROP_FG__MASK)
+#define VIVS_DE_ROP_ROP_BG__MASK				0x0000ff00
+#define VIVS_DE_ROP_ROP_BG__SHIFT				8
+#define VIVS_DE_ROP_ROP_BG(x)					(((x) << VIVS_DE_ROP_ROP_BG__SHIFT) & VIVS_DE_ROP_ROP_BG__MASK)
+#define VIVS_DE_ROP_TYPE__MASK					0x00300000
+#define VIVS_DE_ROP_TYPE__SHIFT					20
+#define VIVS_DE_ROP_TYPE_ROP2_PATTERN				0x00000000
+#define VIVS_DE_ROP_TYPE_ROP2_SOURCE				0x00100000
+#define VIVS_DE_ROP_TYPE_ROP3					0x00200000
+#define VIVS_DE_ROP_TYPE_ROP4					0x00300000
+
+#define VIVS_DE_CLIP_TOP_LEFT					0x00001260
+#define VIVS_DE_CLIP_TOP_LEFT_X__MASK				0x00007fff
+#define VIVS_DE_CLIP_TOP_LEFT_X__SHIFT				0
+#define VIVS_DE_CLIP_TOP_LEFT_X(x)				(((x) << VIVS_DE_CLIP_TOP_LEFT_X__SHIFT) & VIVS_DE_CLIP_TOP_LEFT_X__MASK)
+#define VIVS_DE_CLIP_TOP_LEFT_Y__MASK				0x7fff0000
+#define VIVS_DE_CLIP_TOP_LEFT_Y__SHIFT				16
+#define VIVS_DE_CLIP_TOP_LEFT_Y(x)				(((x) << VIVS_DE_CLIP_TOP_LEFT_Y__SHIFT) & VIVS_DE_CLIP_TOP_LEFT_Y__MASK)
+
+#define VIVS_DE_CLIP_BOTTOM_RIGHT				0x00001264
+#define VIVS_DE_CLIP_BOTTOM_RIGHT_X__MASK			0x00007fff
+#define VIVS_DE_CLIP_BOTTOM_RIGHT_X__SHIFT			0
+#define VIVS_DE_CLIP_BOTTOM_RIGHT_X(x)				(((x) << VIVS_DE_CLIP_BOTTOM_RIGHT_X__SHIFT) & VIVS_DE_CLIP_BOTTOM_RIGHT_X__MASK)
+#define VIVS_DE_CLIP_BOTTOM_RIGHT_Y__MASK			0x7fff0000
+#define VIVS_DE_CLIP_BOTTOM_RIGHT_Y__SHIFT			16
+#define VIVS_DE_CLIP_BOTTOM_RIGHT_Y(x)				(((x) << VIVS_DE_CLIP_BOTTOM_RIGHT_Y__SHIFT) & VIVS_DE_CLIP_BOTTOM_RIGHT_Y__MASK)
+
+#define VIVS_DE_CLEAR_BYTE_MASK					0x00001268
+
+#define VIVS_DE_CONFIG						0x0000126c
+#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE__MASK			0x00000001
+#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE__SHIFT			0
+#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE_OFF			0x00000000
+#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE_ON			0x00000001
+#define VIVS_DE_CONFIG_MIRROR_BLT_MODE__MASK			0x00000030
+#define VIVS_DE_CONFIG_MIRROR_BLT_MODE__SHIFT			4
+#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_NORMAL			0x00000000
+#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_HMIRROR			0x00000010
+#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_VMIRROR			0x00000020
+#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_FULL_MIRROR		0x00000030
+#define VIVS_DE_CONFIG_SOURCE_SELECT__MASK			0x00070000
+#define VIVS_DE_CONFIG_SOURCE_SELECT__SHIFT			16
+#define VIVS_DE_CONFIG_SOURCE_SELECT(x)				(((x) << VIVS_DE_CONFIG_SOURCE_SELECT__SHIFT) & VIVS_DE_CONFIG_SOURCE_SELECT__MASK)
+#define VIVS_DE_CONFIG_DESTINATION_SELECT__MASK			0x00300000
+#define VIVS_DE_CONFIG_DESTINATION_SELECT__SHIFT		20
+#define VIVS_DE_CONFIG_DESTINATION_SELECT(x)			(((x) << VIVS_DE_CONFIG_DESTINATION_SELECT__SHIFT) & VIVS_DE_CONFIG_DESTINATION_SELECT__MASK)
+
+#define VIVS_DE_CLEAR_PIXEL_VALUE_LOW				0x00001270
+
+#define VIVS_DE_CLEAR_PIXEL_VALUE_HIGH				0x00001274
+
+#define VIVS_DE_SRC_ORIGIN_FRACTION				0x00001278
+#define VIVS_DE_SRC_ORIGIN_FRACTION_X__MASK			0x0000ffff
+#define VIVS_DE_SRC_ORIGIN_FRACTION_X__SHIFT			0
+#define VIVS_DE_SRC_ORIGIN_FRACTION_X(x)			(((x) << VIVS_DE_SRC_ORIGIN_FRACTION_X__SHIFT) & VIVS_DE_SRC_ORIGIN_FRACTION_X__MASK)
+#define VIVS_DE_SRC_ORIGIN_FRACTION_Y__MASK			0xffff0000
+#define VIVS_DE_SRC_ORIGIN_FRACTION_Y__SHIFT			16
+#define VIVS_DE_SRC_ORIGIN_FRACTION_Y(x)			(((x) << VIVS_DE_SRC_ORIGIN_FRACTION_Y__SHIFT) & VIVS_DE_SRC_ORIGIN_FRACTION_Y__MASK)
+
+#define VIVS_DE_ALPHA_CONTROL					0x0000127c
+#define VIVS_DE_ALPHA_CONTROL_ENABLE__MASK			0x00000001
+#define VIVS_DE_ALPHA_CONTROL_ENABLE__SHIFT			0
+#define VIVS_DE_ALPHA_CONTROL_ENABLE_OFF			0x00000000
+#define VIVS_DE_ALPHA_CONTROL_ENABLE_ON				0x00000001
+#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK	0x00ff0000
+#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT	16
+#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA(x)		(((x) << VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT) & VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK)
+#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK	0xff000000
+#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT	24
+#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA(x)		(((x) << VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT) & VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK)
+
+#define VIVS_DE_ALPHA_MODES					0x00001280
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE__MASK		0x00000001
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE__SHIFT		0
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE_NORMAL		0x00000000
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE_INVERSED		0x00000001
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE__MASK		0x00000010
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE__SHIFT		4
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE_NORMAL		0x00000000
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE_INVERSED		0x00000010
+#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__MASK		0x00000300
+#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__SHIFT	8
+#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_GLOBAL	0x00000100
+#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_SCALED	0x00000200
+#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__MASK		0x00003000
+#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__SHIFT	12
+#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_GLOBAL	0x00001000
+#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_SCALED	0x00002000
+#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__MASK	0x00010000
+#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__SHIFT	16
+#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_ENABLE	0x00010000
+#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__MASK	0x00100000
+#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__SHIFT	20
+#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_ENABLE	0x00100000
+#define VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__MASK		0x07000000
+#define VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT		24
+#define VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE(x)		(((x) << VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT) & VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__MASK)
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR__MASK		0x08000000
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR__SHIFT		27
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR_DISABLE		0x00000000
+#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR_ENABLE		0x08000000
+#define VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__MASK		0x70000000
+#define VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__SHIFT		28
+#define VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE(x)		(((x) << VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__SHIFT) & VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__MASK)
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR__MASK		0x80000000
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR__SHIFT		31
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR_DISABLE		0x00000000
+#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR_ENABLE		0x80000000
+
+#define VIVS_DE_UPLANE_ADDRESS					0x00001284
+
+#define VIVS_DE_UPLANE_STRIDE					0x00001288
+#define VIVS_DE_UPLANE_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_UPLANE_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_UPLANE_STRIDE_STRIDE(x)				(((x) << VIVS_DE_UPLANE_STRIDE_STRIDE__SHIFT) & VIVS_DE_UPLANE_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_VPLANE_ADDRESS					0x0000128c
+
+#define VIVS_DE_VPLANE_STRIDE					0x00001290
+#define VIVS_DE_VPLANE_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_VPLANE_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_VPLANE_STRIDE_STRIDE(x)				(((x) << VIVS_DE_VPLANE_STRIDE_STRIDE__SHIFT) & VIVS_DE_VPLANE_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_VR_CONFIG					0x00001294
+#define VIVS_DE_VR_CONFIG_START__MASK				0x00000003
+#define VIVS_DE_VR_CONFIG_START__SHIFT				0
+#define VIVS_DE_VR_CONFIG_START_HORIZONTAL_BLIT			0x00000000
+#define VIVS_DE_VR_CONFIG_START_VERTICAL_BLIT			0x00000001
+#define VIVS_DE_VR_CONFIG_START_ONE_PASS_BLIT			0x00000002
+#define VIVS_DE_VR_CONFIG_START_MASK				0x00000008
+
+#define VIVS_DE_VR_SOURCE_IMAGE_LOW				0x00001298
+#define VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__MASK			0x0000ffff
+#define VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__SHIFT			0
+#define VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT(x)			(((x) << VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__MASK)
+#define VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__MASK			0xffff0000
+#define VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__SHIFT			16
+#define VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP(x)			(((x) << VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__MASK)
+
+#define VIVS_DE_VR_SOURCE_IMAGE_HIGH				0x0000129c
+#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__MASK		0x0000ffff
+#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__SHIFT		0
+#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT(x)			(((x) << VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__MASK)
+#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__MASK		0xffff0000
+#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__SHIFT		16
+#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM(x)			(((x) << VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__MASK)
+
+#define VIVS_DE_VR_SOURCE_ORIGIN_LOW				0x000012a0
+#define VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__MASK			0xffffffff
+#define VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__SHIFT			0
+#define VIVS_DE_VR_SOURCE_ORIGIN_LOW_X(x)			(((x) << VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__SHIFT) & VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__MASK)
+
+#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH				0x000012a4
+#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__MASK			0xffffffff
+#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__SHIFT			0
+#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y(x)			(((x) << VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__SHIFT) & VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__MASK)
+
+#define VIVS_DE_VR_TARGET_WINDOW_LOW				0x000012a8
+#define VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__MASK			0x0000ffff
+#define VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__SHIFT		0
+#define VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT(x)			(((x) << VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__MASK)
+#define VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__MASK			0xffff0000
+#define VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__SHIFT			16
+#define VIVS_DE_VR_TARGET_WINDOW_LOW_TOP(x)			(((x) << VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__MASK)
+
+#define VIVS_DE_VR_TARGET_WINDOW_HIGH				0x000012ac
+#define VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__MASK		0x0000ffff
+#define VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__SHIFT		0
+#define VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT(x)			(((x) << VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__MASK)
+#define VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__MASK		0xffff0000
+#define VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__SHIFT		16
+#define VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM(x)			(((x) << VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__MASK)
+
+#define VIVS_DE_PE_CONFIG					0x000012b0
+#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH__MASK		0x00000003
+#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH__SHIFT		0
+#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_DISABLE		0x00000000
+#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_DEFAULT		0x00000001
+#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_ALWAYS		0x00000002
+#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_MASK		0x00000008
+
+#define VIVS_DE_DEST_ROTATION_HEIGHT				0x000012b4
+#define VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__MASK		0x0000ffff
+#define VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__SHIFT		0
+#define VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT(x)			(((x) << VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__MASK)
+
+#define VIVS_DE_SRC_ROTATION_HEIGHT				0x000012b8
+#define VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__MASK		0x0000ffff
+#define VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT		0
+#define VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT(x)			(((x) << VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__MASK)
+
+#define VIVS_DE_ROT_ANGLE					0x000012bc
+#define VIVS_DE_ROT_ANGLE_SRC__MASK				0x00000007
+#define VIVS_DE_ROT_ANGLE_SRC__SHIFT				0
+#define VIVS_DE_ROT_ANGLE_SRC(x)				(((x) << VIVS_DE_ROT_ANGLE_SRC__SHIFT) & VIVS_DE_ROT_ANGLE_SRC__MASK)
+#define VIVS_DE_ROT_ANGLE_DST__MASK				0x00000038
+#define VIVS_DE_ROT_ANGLE_DST__SHIFT				3
+#define VIVS_DE_ROT_ANGLE_DST(x)				(((x) << VIVS_DE_ROT_ANGLE_DST__SHIFT) & VIVS_DE_ROT_ANGLE_DST__MASK)
+#define VIVS_DE_ROT_ANGLE_SRC_MASK				0x00000100
+#define VIVS_DE_ROT_ANGLE_DST_MASK				0x00000200
+#define VIVS_DE_ROT_ANGLE_SRC_MIRROR__MASK			0x00003000
+#define VIVS_DE_ROT_ANGLE_SRC_MIRROR__SHIFT			12
+#define VIVS_DE_ROT_ANGLE_SRC_MIRROR(x)				(((x) << VIVS_DE_ROT_ANGLE_SRC_MIRROR__SHIFT) & VIVS_DE_ROT_ANGLE_SRC_MIRROR__MASK)
+#define VIVS_DE_ROT_ANGLE_SRC_MIRROR_MASK			0x00008000
+#define VIVS_DE_ROT_ANGLE_DST_MIRROR__MASK			0x00030000
+#define VIVS_DE_ROT_ANGLE_DST_MIRROR__SHIFT			16
+#define VIVS_DE_ROT_ANGLE_DST_MIRROR(x)				(((x) << VIVS_DE_ROT_ANGLE_DST_MIRROR__SHIFT) & VIVS_DE_ROT_ANGLE_DST_MIRROR__MASK)
+#define VIVS_DE_ROT_ANGLE_DST_MIRROR_MASK			0x00080000
+
+#define VIVS_DE_CLEAR_PIXEL_VALUE32				0x000012c0
+
+#define VIVS_DE_DEST_COLOR_KEY					0x000012c4
+
+#define VIVS_DE_GLOBAL_SRC_COLOR				0x000012c8
+
+#define VIVS_DE_GLOBAL_DEST_COLOR				0x000012cc
+
+#define VIVS_DE_COLOR_MULTIPLY_MODES				0x000012d0
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__MASK	0x00000001
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__SHIFT	0
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE	0x00000001
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__MASK	0x00000010
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__SHIFT	4
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_ENABLE	0x00000010
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__MASK	0x00000300
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__SHIFT	8
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_ALPHA	0x00000100
+#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_COLOR	0x00000200
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__MASK	0x00100000
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__SHIFT	20
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE	0x00100000
+
+#define VIVS_DE_PE_TRANSPARENCY					0x000012d4
+#define VIVS_DE_PE_TRANSPARENCY_SOURCE__MASK			0x00000003
+#define VIVS_DE_PE_TRANSPARENCY_SOURCE__SHIFT			0
+#define VIVS_DE_PE_TRANSPARENCY_SOURCE_OPAQUE			0x00000000
+#define VIVS_DE_PE_TRANSPARENCY_SOURCE_MASK			0x00000001
+#define VIVS_DE_PE_TRANSPARENCY_SOURCE_KEY			0x00000002
+#define VIVS_DE_PE_TRANSPARENCY_PATTERN__MASK			0x00000030
+#define VIVS_DE_PE_TRANSPARENCY_PATTERN__SHIFT			4
+#define VIVS_DE_PE_TRANSPARENCY_PATTERN_OPAQUE			0x00000000
+#define VIVS_DE_PE_TRANSPARENCY_PATTERN_MASK			0x00000010
+#define VIVS_DE_PE_TRANSPARENCY_PATTERN_KEY			0x00000020
+#define VIVS_DE_PE_TRANSPARENCY_DESTINATION__MASK		0x00000300
+#define VIVS_DE_PE_TRANSPARENCY_DESTINATION__SHIFT		8
+#define VIVS_DE_PE_TRANSPARENCY_DESTINATION_OPAQUE		0x00000000
+#define VIVS_DE_PE_TRANSPARENCY_DESTINATION_MASK		0x00000100
+#define VIVS_DE_PE_TRANSPARENCY_DESTINATION_KEY			0x00000200
+#define VIVS_DE_PE_TRANSPARENCY_TRANSPARENCY_MASK		0x00001000
+#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE__MASK		0x00030000
+#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE__SHIFT		16
+#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE_USE_ENABLE	0x00010000
+#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE_USE_DISABLE	0x00020000
+#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE__MASK		0x00300000
+#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE__SHIFT		20
+#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE_USE_ENABLE	0x00100000
+#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE_USE_DISABLE	0x00200000
+#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE__MASK		0x03000000
+#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE__SHIFT		24
+#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE_USE_ENABLE	0x01000000
+#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE_USE_DISABLE	0x02000000
+#define VIVS_DE_PE_TRANSPARENCY_RESOURCE_OVERRIDE_MASK		0x10000000
+#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY__MASK		0x20000000
+#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY__SHIFT		29
+#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY_DISABLE		0x00000000
+#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY_ENABLE		0x20000000
+#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY_MASK		0x80000000
+
+#define VIVS_DE_PE_CONTROL					0x000012d8
+#define VIVS_DE_PE_CONTROL_YUV__MASK				0x00000001
+#define VIVS_DE_PE_CONTROL_YUV__SHIFT				0
+#define VIVS_DE_PE_CONTROL_YUV_601				0x00000000
+#define VIVS_DE_PE_CONTROL_YUV_709				0x00000001
+#define VIVS_DE_PE_CONTROL_YUV_MASK				0x00000008
+#define VIVS_DE_PE_CONTROL_UV_SWIZZLE__MASK			0x00000010
+#define VIVS_DE_PE_CONTROL_UV_SWIZZLE__SHIFT			4
+#define VIVS_DE_PE_CONTROL_UV_SWIZZLE_UV			0x00000000
+#define VIVS_DE_PE_CONTROL_UV_SWIZZLE_VU			0x00000010
+#define VIVS_DE_PE_CONTROL_UV_SWIZZLE_MASK			0x00000080
+#define VIVS_DE_PE_CONTROL_YUVRGB__MASK				0x00000100
+#define VIVS_DE_PE_CONTROL_YUVRGB__SHIFT			8
+#define VIVS_DE_PE_CONTROL_YUVRGB_DISABLE			0x00000000
+#define VIVS_DE_PE_CONTROL_YUVRGB_ENABLE			0x00000100
+#define VIVS_DE_PE_CONTROL_YUVRGB_MASK				0x00000800
+
+#define VIVS_DE_SRC_COLOR_KEY_HIGH				0x000012dc
+
+#define VIVS_DE_DEST_COLOR_KEY_HIGH				0x000012e0
+
+#define VIVS_DE_VR_CONFIG_EX					0x000012e4
+#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH__MASK		0x00000003
+#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH__SHIFT		0
+#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_AUTO		0x00000000
+#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_PIXELS16	0x00000001
+#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_PIXELS32	0x00000002
+#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_MASK		0x00000008
+#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP__MASK			0x000000f0
+#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP__SHIFT			4
+#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP(x)			(((x) << VIVS_DE_VR_CONFIG_EX_FILTER_TAP__SHIFT) & VIVS_DE_VR_CONFIG_EX_FILTER_TAP__MASK)
+#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP_MASK			0x00000100
+
+#define VIVS_DE_PE_DITHER_LOW					0x000012e8
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__MASK			0x0000000f
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__SHIFT		0
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__MASK)
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__MASK			0x000000f0
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__SHIFT		4
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__MASK)
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__MASK			0x00000f00
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__SHIFT		8
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__MASK)
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__MASK			0x0000f000
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__SHIFT		12
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__MASK)
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__MASK			0x000f0000
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__SHIFT		16
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__MASK)
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__MASK			0x00f00000
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__SHIFT		20
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__MASK)
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__MASK			0x0f000000
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__SHIFT		24
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__MASK)
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__MASK			0xf0000000
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__SHIFT		28
+#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1(x)			(((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__MASK)
+
+#define VIVS_DE_PE_DITHER_HIGH					0x000012ec
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__MASK		0x0000000f
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__SHIFT		0
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__MASK)
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__MASK		0x000000f0
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__SHIFT		4
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__MASK)
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__MASK		0x00000f00
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__SHIFT		8
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__MASK)
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__MASK		0x0000f000
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__SHIFT		12
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__MASK)
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__MASK		0x000f0000
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__SHIFT		16
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__MASK)
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__MASK		0x00f00000
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__SHIFT		20
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__MASK)
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__MASK		0x0f000000
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__SHIFT		24
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__MASK)
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__MASK		0xf0000000
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__SHIFT		28
+#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3(x)			(((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__MASK)
+
+#define VIVS_DE_BW_CONFIG					0x000012f0
+#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG__MASK			0x00000001
+#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG__SHIFT			0
+#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG_AUTO			0x00000000
+#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG_CUSTOMIZE		0x00000001
+#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG_MASK			0x00000008
+#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION__MASK		0x00000010
+#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION__SHIFT		4
+#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION_RIGHT_BOTTOM	0x00000000
+#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION_BOTTOM_RIGHT	0x00000010
+#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION_MASK		0x00000080
+#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION__MASK		0x00000100
+#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION__SHIFT		8
+#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION_RIGHT_BOTTOM	0x00000000
+#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION_BOTTOM_RIGHT	0x00000100
+#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION_MASK		0x00000800
+#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION__MASK		0x00001000
+#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION__SHIFT		12
+#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION_RIGHT_BOTTOM	0x00000000
+#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION_BOTTOM_RIGHT	0x00001000
+#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION_MASK		0x00008000
+
+#define VIVS_DE_BW_BLOCK_SIZE					0x000012f4
+#define VIVS_DE_BW_BLOCK_SIZE_WIDTH__MASK			0x0000ffff
+#define VIVS_DE_BW_BLOCK_SIZE_WIDTH__SHIFT			0
+#define VIVS_DE_BW_BLOCK_SIZE_WIDTH(x)				(((x) << VIVS_DE_BW_BLOCK_SIZE_WIDTH__SHIFT) & VIVS_DE_BW_BLOCK_SIZE_WIDTH__MASK)
+#define VIVS_DE_BW_BLOCK_SIZE_HEIGHT__MASK			0xffff0000
+#define VIVS_DE_BW_BLOCK_SIZE_HEIGHT__SHIFT			16
+#define VIVS_DE_BW_BLOCK_SIZE_HEIGHT(x)				(((x) << VIVS_DE_BW_BLOCK_SIZE_HEIGHT__SHIFT) & VIVS_DE_BW_BLOCK_SIZE_HEIGHT__MASK)
+
+#define VIVS_DE_BW_TILE_SIZE					0x000012f8
+#define VIVS_DE_BW_TILE_SIZE_WIDTH__MASK			0x0000ffff
+#define VIVS_DE_BW_TILE_SIZE_WIDTH__SHIFT			0
+#define VIVS_DE_BW_TILE_SIZE_WIDTH(x)				(((x) << VIVS_DE_BW_TILE_SIZE_WIDTH__SHIFT) & VIVS_DE_BW_TILE_SIZE_WIDTH__MASK)
+#define VIVS_DE_BW_TILE_SIZE_HEIGHT__MASK			0xffff0000
+#define VIVS_DE_BW_TILE_SIZE_HEIGHT__SHIFT			16
+#define VIVS_DE_BW_TILE_SIZE_HEIGHT(x)				(((x) << VIVS_DE_BW_TILE_SIZE_HEIGHT__SHIFT) & VIVS_DE_BW_TILE_SIZE_HEIGHT__MASK)
+
+#define VIVS_DE_BW_BLOCK_MASK					0x000012fc
+#define VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__MASK			0x0000ffff
+#define VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__SHIFT			0
+#define VIVS_DE_BW_BLOCK_MASK_HORIZONTAL(x)			(((x) << VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__SHIFT) & VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__MASK)
+#define VIVS_DE_BW_BLOCK_MASK_VERTICAL__MASK			0xffff0000
+#define VIVS_DE_BW_BLOCK_MASK_VERTICAL__SHIFT			16
+#define VIVS_DE_BW_BLOCK_MASK_VERTICAL(x)			(((x) << VIVS_DE_BW_BLOCK_MASK_VERTICAL__SHIFT) & VIVS_DE_BW_BLOCK_MASK_VERTICAL__MASK)
+
+#define VIVS_DE_SRC_EX_CONFIG					0x00001300
+#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED__MASK			0x00000001
+#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED__SHIFT		0
+#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED_DISABLE		0x00000000
+#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED_ENABLE		0x00000001
+#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED__MASK			0x00000008
+#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED__SHIFT		3
+#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED_DISABLE		0x00000000
+#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED_ENABLE		0x00000008
+#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED__MASK			0x00000100
+#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED__SHIFT		8
+#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED_DISABLE		0x00000000
+#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED_ENABLE		0x00000100
+
+#define VIVS_DE_SRC_EX_ADDRESS					0x00001304
+
+#define VIVS_DE_DE_MULTI_SOURCE					0x00001308
+#define VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__MASK		0x00000007
+#define VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__SHIFT		0
+#define VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE(x)			(((x) << VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__SHIFT) & VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__MASK)
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK__MASK		0x00000700
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK__SHIFT		8
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL16	0x00000000
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL32	0x00000100
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL64	0x00000200
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL128	0x00000300
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL256	0x00000400
+#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL512	0x00000500
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK__MASK		0x00070000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK__SHIFT		16
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE1		0x00000000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE2		0x00010000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE4		0x00020000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE8		0x00030000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE16		0x00040000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE32		0x00050000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE64		0x00060000
+#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE128		0x00070000
+
+#define VIVS_DE_DEYUV_CONVERSION				0x0000130c
+#define VIVS_DE_DEYUV_CONVERSION_ENABLE__MASK			0x00000003
+#define VIVS_DE_DEYUV_CONVERSION_ENABLE__SHIFT			0
+#define VIVS_DE_DEYUV_CONVERSION_ENABLE_OFF			0x00000000
+#define VIVS_DE_DEYUV_CONVERSION_ENABLE_PLANE1			0x00000001
+#define VIVS_DE_DEYUV_CONVERSION_ENABLE_PLANE2			0x00000002
+#define VIVS_DE_DEYUV_CONVERSION_ENABLE_PLANE3			0x00000003
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__MASK		0x0000000c
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__SHIFT		2
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__MASK		0x00000030
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__SHIFT		4
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__MASK		0x000000c0
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__SHIFT		6
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__MASK		0x00000300
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__SHIFT	8
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__MASK		0x00000c00
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__SHIFT	10
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__MASK		0x00003000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__SHIFT	12
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__MASK		0x0000c000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__SHIFT	14
+#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__MASK		0x00030000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__SHIFT	16
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__MASK		0x000c0000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__SHIFT	18
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__MASK		0x00300000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__SHIFT	20
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__MASK		0x00c00000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__SHIFT	22
+#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__MASK		0x03000000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__SHIFT	24
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__MASK		0x0c000000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__SHIFT	26
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__MASK		0x30000000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__SHIFT	28
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__MASK)
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__MASK		0xc0000000
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__SHIFT	30
+#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A(x)		(((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__MASK)
+
+#define VIVS_DE_DE_PLANE2_ADDRESS				0x00001310
+
+#define VIVS_DE_DE_PLANE2_STRIDE				0x00001314
+#define VIVS_DE_DE_PLANE2_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_DE_PLANE2_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_DE_PLANE2_STRIDE_STRIDE(x)			(((x) << VIVS_DE_DE_PLANE2_STRIDE_STRIDE__SHIFT) & VIVS_DE_DE_PLANE2_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_DE_PLANE3_ADDRESS				0x00001318
+
+#define VIVS_DE_DE_PLANE3_STRIDE				0x0000131c
+#define VIVS_DE_DE_PLANE3_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_DE_PLANE3_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_DE_PLANE3_STRIDE_STRIDE(x)			(((x) << VIVS_DE_DE_PLANE3_STRIDE_STRIDE__SHIFT) & VIVS_DE_DE_PLANE3_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_DE_STALL_DE					0x00001320
+#define VIVS_DE_DE_STALL_DE_ENABLE__MASK			0x00000001
+#define VIVS_DE_DE_STALL_DE_ENABLE__SHIFT			0
+#define VIVS_DE_DE_STALL_DE_ENABLE_DISABLE			0x00000000
+#define VIVS_DE_DE_STALL_DE_ENABLE_ENABLE			0x00000001
+
+#define VIVS_DE_FILTER_KERNEL(i0)			       (0x00001800 + 0x4*(i0))
+#define VIVS_DE_FILTER_KERNEL__ESIZE				0x00000004
+#define VIVS_DE_FILTER_KERNEL__LEN				0x00000080
+#define VIVS_DE_FILTER_KERNEL_COEFFICIENT0__MASK		0x0000ffff
+#define VIVS_DE_FILTER_KERNEL_COEFFICIENT0__SHIFT		0
+#define VIVS_DE_FILTER_KERNEL_COEFFICIENT0(x)			(((x) << VIVS_DE_FILTER_KERNEL_COEFFICIENT0__SHIFT) & VIVS_DE_FILTER_KERNEL_COEFFICIENT0__MASK)
+#define VIVS_DE_FILTER_KERNEL_COEFFICIENT1__MASK		0xffff0000
+#define VIVS_DE_FILTER_KERNEL_COEFFICIENT1__SHIFT		16
+#define VIVS_DE_FILTER_KERNEL_COEFFICIENT1(x)			(((x) << VIVS_DE_FILTER_KERNEL_COEFFICIENT1__SHIFT) & VIVS_DE_FILTER_KERNEL_COEFFICIENT1__MASK)
+
+#define VIVS_DE_INDEX_COLOR_TABLE(i0)			       (0x00001c00 + 0x4*(i0))
+#define VIVS_DE_INDEX_COLOR_TABLE__ESIZE			0x00000004
+#define VIVS_DE_INDEX_COLOR_TABLE__LEN				0x00000100
+
+#define VIVS_DE_HORI_FILTER_KERNEL(i0)			       (0x00002800 + 0x4*(i0))
+#define VIVS_DE_HORI_FILTER_KERNEL__ESIZE			0x00000004
+#define VIVS_DE_HORI_FILTER_KERNEL__LEN				0x00000080
+#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__MASK		0x0000ffff
+#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__SHIFT		0
+#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0(x)		(((x) << VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__SHIFT) & VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__MASK)
+#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__MASK		0xffff0000
+#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__SHIFT		16
+#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1(x)		(((x) << VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__SHIFT) & VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__MASK)
+
+#define VIVS_DE_VERTI_FILTER_KERNEL(i0)			       (0x00002a00 + 0x4*(i0))
+#define VIVS_DE_VERTI_FILTER_KERNEL__ESIZE			0x00000004
+#define VIVS_DE_VERTI_FILTER_KERNEL__LEN			0x00000080
+#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__MASK		0x0000ffff
+#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__SHIFT		0
+#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0(x)		(((x) << VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__SHIFT) & VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__MASK)
+#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__MASK		0xffff0000
+#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__SHIFT		16
+#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1(x)		(((x) << VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__SHIFT) & VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__MASK)
+
+#define VIVS_DE_INDEX_COLOR_TABLE32(i0)			       (0x00003400 + 0x4*(i0))
+#define VIVS_DE_INDEX_COLOR_TABLE32__ESIZE			0x00000004
+#define VIVS_DE_INDEX_COLOR_TABLE32__LEN			0x00000100
+
+#define VIVS_DE_BLOCK4						0x00000000
+
+#define VIVS_DE_BLOCK4_SRC_ADDRESS(i0)			       (0x00012800 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_ADDRESS__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_SRC_ADDRESS__LEN				0x00000004
+
+#define VIVS_DE_BLOCK4_SRC_STRIDE(i0)			       (0x00012810 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_STRIDE__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_SRC_STRIDE__LEN				0x00000004
+#define VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE(x)			(((x) << VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__SHIFT) & VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG(i0)		       (0x00012820 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG__ESIZE		0x00000004
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG__LEN			0x00000004
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__MASK		0x0000ffff
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__SHIFT		0
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH(x)		(((x) << VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__MASK)
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION__MASK	0x00010000
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION__SHIFT	16
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION_ENABLE	0x00010000
+
+#define VIVS_DE_BLOCK4_SRC_CONFIG(i0)			       (0x00012830 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_CONFIG__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_SRC_CONFIG__LEN				0x00000004
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK	0x0000000f
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT	0
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT(x)		(((x) << VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK)
+#define VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__MASK		0x00000030
+#define VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__SHIFT		4
+#define VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY(x)		(((x) << VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__MASK)
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE__MASK		0x00000040
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE__SHIFT		6
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE_ABSOLUTE		0x00000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE_RELATIVE		0x00000040
+#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED__MASK			0x00000080
+#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED__SHIFT			7
+#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED_DISABLE			0x00000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED_ENABLE			0x00000080
+#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION__MASK		0x00000100
+#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION__SHIFT		8
+#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION_MEMORY		0x00000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION_STREAM		0x00000100
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK__MASK			0x00003000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK__SHIFT			12
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_PACKED8			0x00000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_PACKED16			0x00001000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_PACKED32			0x00002000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_UNPACKED			0x00003000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY__MASK	0x00008000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY__SHIFT	15
+#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY_BACKGROUND	0x00000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY_FOREGROUND	0x00008000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_UNK16				0x00010000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__MASK			0x00300000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__SHIFT		20
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE(x)			(((x) << VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__MASK)
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__MASK		0x1f000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__SHIFT		24
+#define VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT(x)		(((x) << VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__MASK)
+#define VIVS_DE_BLOCK4_SRC_CONFIG_DISABLE420_L2_CACHE		0x20000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__MASK		0xc0000000
+#define VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__SHIFT		30
+#define VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL(x)		(((x) << VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__MASK)
+
+#define VIVS_DE_BLOCK4_SRC_ORIGIN(i0)			       (0x00012840 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_ORIGIN__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_SRC_ORIGIN__LEN				0x00000004
+#define VIVS_DE_BLOCK4_SRC_ORIGIN_X__MASK			0x0000ffff
+#define VIVS_DE_BLOCK4_SRC_ORIGIN_X__SHIFT			0
+#define VIVS_DE_BLOCK4_SRC_ORIGIN_X(x)				(((x) << VIVS_DE_BLOCK4_SRC_ORIGIN_X__SHIFT) & VIVS_DE_BLOCK4_SRC_ORIGIN_X__MASK)
+#define VIVS_DE_BLOCK4_SRC_ORIGIN_Y__MASK			0xffff0000
+#define VIVS_DE_BLOCK4_SRC_ORIGIN_Y__SHIFT			16
+#define VIVS_DE_BLOCK4_SRC_ORIGIN_Y(x)				(((x) << VIVS_DE_BLOCK4_SRC_ORIGIN_Y__SHIFT) & VIVS_DE_BLOCK4_SRC_ORIGIN_Y__MASK)
+
+#define VIVS_DE_BLOCK4_SRC_SIZE(i0)			       (0x00012850 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_SIZE__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_SRC_SIZE__LEN				0x00000004
+#define VIVS_DE_BLOCK4_SRC_SIZE_X__MASK				0x0000ffff
+#define VIVS_DE_BLOCK4_SRC_SIZE_X__SHIFT			0
+#define VIVS_DE_BLOCK4_SRC_SIZE_X(x)				(((x) << VIVS_DE_BLOCK4_SRC_SIZE_X__SHIFT) & VIVS_DE_BLOCK4_SRC_SIZE_X__MASK)
+#define VIVS_DE_BLOCK4_SRC_SIZE_Y__MASK				0xffff0000
+#define VIVS_DE_BLOCK4_SRC_SIZE_Y__SHIFT			16
+#define VIVS_DE_BLOCK4_SRC_SIZE_Y(x)				(((x) << VIVS_DE_BLOCK4_SRC_SIZE_Y__SHIFT) & VIVS_DE_BLOCK4_SRC_SIZE_Y__MASK)
+
+#define VIVS_DE_BLOCK4_SRC_COLOR_BG(i0)			       (0x00012860 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_COLOR_BG__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_SRC_COLOR_BG__LEN			0x00000004
+
+#define VIVS_DE_BLOCK4_ROP(i0)				       (0x00012870 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_ROP__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_ROP__LEN					0x00000004
+#define VIVS_DE_BLOCK4_ROP_ROP_FG__MASK				0x000000ff
+#define VIVS_DE_BLOCK4_ROP_ROP_FG__SHIFT			0
+#define VIVS_DE_BLOCK4_ROP_ROP_FG(x)				(((x) << VIVS_DE_BLOCK4_ROP_ROP_FG__SHIFT) & VIVS_DE_BLOCK4_ROP_ROP_FG__MASK)
+#define VIVS_DE_BLOCK4_ROP_ROP_BG__MASK				0x0000ff00
+#define VIVS_DE_BLOCK4_ROP_ROP_BG__SHIFT			8
+#define VIVS_DE_BLOCK4_ROP_ROP_BG(x)				(((x) << VIVS_DE_BLOCK4_ROP_ROP_BG__SHIFT) & VIVS_DE_BLOCK4_ROP_ROP_BG__MASK)
+#define VIVS_DE_BLOCK4_ROP_TYPE__MASK				0x00300000
+#define VIVS_DE_BLOCK4_ROP_TYPE__SHIFT				20
+#define VIVS_DE_BLOCK4_ROP_TYPE_ROP2_PATTERN			0x00000000
+#define VIVS_DE_BLOCK4_ROP_TYPE_ROP2_SOURCE			0x00100000
+#define VIVS_DE_BLOCK4_ROP_TYPE_ROP3				0x00200000
+#define VIVS_DE_BLOCK4_ROP_TYPE_ROP4				0x00300000
+
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL(i0)		       (0x00012880 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL__LEN			0x00000004
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE__MASK		0x00000001
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE__SHIFT		0
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE_OFF			0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE_ON			0x00000001
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK	0x00ff0000
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT	16
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA(x)	(((x) << VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT) & VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK)
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK	0xff000000
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT	24
+#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA(x)	(((x) << VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT) & VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK)
+
+#define VIVS_DE_BLOCK4_ALPHA_MODES(i0)			       (0x00012890 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_ALPHA_MODES__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_ALPHA_MODES__LEN				0x00000004
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE__MASK		0x00000001
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE__SHIFT	0
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE_INVERSED	0x00000001
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE__MASK		0x00000010
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE__SHIFT	4
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE_INVERSED	0x00000010
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__MASK	0x00000300
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__SHIFT	8
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_GLOBAL	0x00000100
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_SCALED	0x00000200
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__MASK	0x00003000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__SHIFT	12
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_GLOBAL	0x00001000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_SCALED	0x00002000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__MASK	0x00010000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__SHIFT	16
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_ENABLE	0x00010000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__MASK	0x00100000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__SHIFT	20
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_ENABLE	0x00100000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__MASK	0x07000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT	24
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE(x)		(((x) << VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__MASK)
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR__MASK	0x08000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR__SHIFT	27
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR_ENABLE	0x08000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__MASK	0x70000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__SHIFT	28
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE(x)		(((x) << VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__MASK)
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR__MASK	0x80000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR__SHIFT	31
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR_ENABLE	0x80000000
+
+#define VIVS_DE_BLOCK4_ADDRESS_U(i0)			       (0x000128a0 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_ADDRESS_U__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_ADDRESS_U__LEN				0x00000004
+
+#define VIVS_DE_BLOCK4_STRIDE_U(i0)			       (0x000128b0 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_STRIDE_U__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_STRIDE_U__LEN				0x00000004
+#define VIVS_DE_BLOCK4_STRIDE_U_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_BLOCK4_STRIDE_U_STRIDE__SHIFT			0
+#define VIVS_DE_BLOCK4_STRIDE_U_STRIDE(x)			(((x) << VIVS_DE_BLOCK4_STRIDE_U_STRIDE__SHIFT) & VIVS_DE_BLOCK4_STRIDE_U_STRIDE__MASK)
+
+#define VIVS_DE_BLOCK4_ADDRESS_V(i0)			       (0x000128c0 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_ADDRESS_V__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_ADDRESS_V__LEN				0x00000004
+
+#define VIVS_DE_BLOCK4_STRIDE_V(i0)			       (0x000128d0 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_STRIDE_V__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_STRIDE_V__LEN				0x00000004
+#define VIVS_DE_BLOCK4_STRIDE_V_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_BLOCK4_STRIDE_V_STRIDE__SHIFT			0
+#define VIVS_DE_BLOCK4_STRIDE_V_STRIDE(x)			(((x) << VIVS_DE_BLOCK4_STRIDE_V_STRIDE__SHIFT) & VIVS_DE_BLOCK4_STRIDE_V_STRIDE__MASK)
+
+#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT(i0)		       (0x000128e0 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT__ESIZE		0x00000004
+#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT__LEN			0x00000004
+#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__MASK		0x0000ffff
+#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT	0
+#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT(x)		(((x) << VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__MASK)
+
+#define VIVS_DE_BLOCK4_ROT_ANGLE(i0)			       (0x000128f0 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_ROT_ANGLE__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_ROT_ANGLE__LEN				0x00000004
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC__MASK			0x00000007
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC__SHIFT			0
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC(x)				(((x) << VIVS_DE_BLOCK4_ROT_ANGLE_SRC__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_SRC__MASK)
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST__MASK			0x00000038
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST__SHIFT			3
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST(x)				(((x) << VIVS_DE_BLOCK4_ROT_ANGLE_DST__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_DST__MASK)
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MASK			0x00000100
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MASK			0x00000200
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__MASK		0x00003000
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__SHIFT		12
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR(x)			(((x) << VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__MASK)
+#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR_MASK		0x00008000
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__MASK		0x00030000
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__SHIFT		16
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR(x)			(((x) << VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__MASK)
+#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR_MASK		0x00080000
+
+#define VIVS_DE_BLOCK4_GLOBAL_SRC_COLOR(i0)		       (0x00012900 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_GLOBAL_SRC_COLOR__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_GLOBAL_SRC_COLOR__LEN			0x00000004
+
+#define VIVS_DE_BLOCK4_GLOBAL_DEST_COLOR(i0)		       (0x00012910 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_GLOBAL_DEST_COLOR__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_GLOBAL_DEST_COLOR__LEN			0x00000004
+
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES(i0)		       (0x00012920 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES__ESIZE		0x00000004
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES__LEN		0x00000004
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__MASK	0x00000001
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__SHIFT	0
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE	0x00000001
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__MASK	0x00000010
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__SHIFT	4
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_ENABLE	0x00000010
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__MASK	0x00000300
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__SHIFT	8
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_ALPHA	0x00000100
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_COLOR	0x00000200
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__MASK	0x00100000
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__SHIFT	20
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE	0x00100000
+
+#define VIVS_DE_BLOCK4_TRANSPARENCY(i0)			       (0x00012930 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_TRANSPARENCY__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_TRANSPARENCY__LEN			0x00000004
+#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE__MASK		0x00000003
+#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE__SHIFT		0
+#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE_OPAQUE		0x00000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE_MASK			0x00000001
+#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE_KEY			0x00000002
+#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN__MASK		0x00000030
+#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN__SHIFT		4
+#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN_OPAQUE		0x00000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN_MASK		0x00000010
+#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN_KEY			0x00000020
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION__MASK		0x00000300
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION__SHIFT		8
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION_OPAQUE		0x00000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION_MASK		0x00000100
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION_KEY		0x00000200
+#define VIVS_DE_BLOCK4_TRANSPARENCY_TRANSPARENCY_MASK		0x00001000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE__MASK	0x00030000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE__SHIFT	16
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE_USE_ENABLE	0x00010000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE_USE_DISABLE	0x00020000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE__MASK	0x00300000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE__SHIFT	20
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE_USE_ENABLE	0x00100000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE_USE_DISABLE	0x00200000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE__MASK	0x03000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE__SHIFT	24
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE_USE_ENABLE	0x01000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE_USE_DISABLE	0x02000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_RESOURCE_OVERRIDE_MASK	0x10000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY__MASK		0x20000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY__SHIFT	29
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY_ENABLE	0x20000000
+#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY_MASK		0x80000000
+
+#define VIVS_DE_BLOCK4_CONTROL(i0)			       (0x00012940 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_CONTROL__ESIZE				0x00000004
+#define VIVS_DE_BLOCK4_CONTROL__LEN				0x00000004
+#define VIVS_DE_BLOCK4_CONTROL_YUV__MASK			0x00000001
+#define VIVS_DE_BLOCK4_CONTROL_YUV__SHIFT			0
+#define VIVS_DE_BLOCK4_CONTROL_YUV_601				0x00000000
+#define VIVS_DE_BLOCK4_CONTROL_YUV_709				0x00000001
+#define VIVS_DE_BLOCK4_CONTROL_YUV_MASK				0x00000008
+#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE__MASK			0x00000010
+#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE__SHIFT		4
+#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE_UV			0x00000000
+#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE_VU			0x00000010
+#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE_MASK			0x00000080
+#define VIVS_DE_BLOCK4_CONTROL_YUVRGB__MASK			0x00000100
+#define VIVS_DE_BLOCK4_CONTROL_YUVRGB__SHIFT			8
+#define VIVS_DE_BLOCK4_CONTROL_YUVRGB_DISABLE			0x00000000
+#define VIVS_DE_BLOCK4_CONTROL_YUVRGB_ENABLE			0x00000100
+#define VIVS_DE_BLOCK4_CONTROL_YUVRGB_MASK			0x00000800
+
+#define VIVS_DE_BLOCK4_SRC_COLOR_KEY_HIGH(i0)		       (0x00012950 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_COLOR_KEY_HIGH__ESIZE		0x00000004
+#define VIVS_DE_BLOCK4_SRC_COLOR_KEY_HIGH__LEN			0x00000004
+
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG(i0)		       (0x00012960 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG__LEN			0x00000004
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED__MASK		0x00000001
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED__SHIFT		0
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED_ENABLE		0x00000001
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED__MASK		0x00000008
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED__SHIFT		3
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED_ENABLE		0x00000008
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED__MASK		0x00000100
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED__SHIFT		8
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED_DISABLE	0x00000000
+#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED_ENABLE		0x00000100
+
+#define VIVS_DE_BLOCK4_SRC_EX_ADDRESS(i0)		       (0x00012970 + 0x4*(i0))
+#define VIVS_DE_BLOCK4_SRC_EX_ADDRESS__ESIZE			0x00000004
+#define VIVS_DE_BLOCK4_SRC_EX_ADDRESS__LEN			0x00000004
+
+#define VIVS_DE_BLOCK8						0x00000000
+
+#define VIVS_DE_BLOCK8_SRC_ADDRESS(i0)			       (0x00012a00 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_ADDRESS__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_SRC_ADDRESS__LEN				0x00000008
+
+#define VIVS_DE_BLOCK8_SRC_STRIDE(i0)			       (0x00012a20 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_STRIDE__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_SRC_STRIDE__LEN				0x00000008
+#define VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__SHIFT			0
+#define VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE(x)			(((x) << VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__SHIFT) & VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__MASK)
+
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG(i0)		       (0x00012a40 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG__ESIZE		0x00000004
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG__LEN			0x00000008
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__MASK		0x0000ffff
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__SHIFT		0
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH(x)		(((x) << VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__MASK)
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION__MASK	0x00010000
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION__SHIFT	16
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION_ENABLE	0x00010000
+
+#define VIVS_DE_BLOCK8_SRC_CONFIG(i0)			       (0x00012a60 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_CONFIG__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_SRC_CONFIG__LEN				0x00000008
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK	0x0000000f
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT	0
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT(x)		(((x) << VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK)
+#define VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__MASK		0x00000030
+#define VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__SHIFT		4
+#define VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY(x)		(((x) << VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__MASK)
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE__MASK		0x00000040
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE__SHIFT		6
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE_ABSOLUTE		0x00000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE_RELATIVE		0x00000040
+#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED__MASK			0x00000080
+#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED__SHIFT			7
+#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED_DISABLE			0x00000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED_ENABLE			0x00000080
+#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION__MASK		0x00000100
+#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION__SHIFT		8
+#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION_MEMORY		0x00000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION_STREAM		0x00000100
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK__MASK			0x00003000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK__SHIFT			12
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_PACKED8			0x00000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_PACKED16			0x00001000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_PACKED32			0x00002000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_UNPACKED			0x00003000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY__MASK	0x00008000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY__SHIFT	15
+#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY_BACKGROUND	0x00000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY_FOREGROUND	0x00008000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_UNK16				0x00010000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__MASK			0x00300000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__SHIFT		20
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE(x)			(((x) << VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__MASK)
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__MASK		0x1f000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__SHIFT		24
+#define VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT(x)		(((x) << VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__MASK)
+#define VIVS_DE_BLOCK8_SRC_CONFIG_DISABLE420_L2_CACHE		0x20000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__MASK		0xc0000000
+#define VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__SHIFT		30
+#define VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL(x)		(((x) << VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__MASK)
+
+#define VIVS_DE_BLOCK8_SRC_ORIGIN(i0)			       (0x00012a80 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_ORIGIN__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_SRC_ORIGIN__LEN				0x00000008
+#define VIVS_DE_BLOCK8_SRC_ORIGIN_X__MASK			0x0000ffff
+#define VIVS_DE_BLOCK8_SRC_ORIGIN_X__SHIFT			0
+#define VIVS_DE_BLOCK8_SRC_ORIGIN_X(x)				(((x) << VIVS_DE_BLOCK8_SRC_ORIGIN_X__SHIFT) & VIVS_DE_BLOCK8_SRC_ORIGIN_X__MASK)
+#define VIVS_DE_BLOCK8_SRC_ORIGIN_Y__MASK			0xffff0000
+#define VIVS_DE_BLOCK8_SRC_ORIGIN_Y__SHIFT			16
+#define VIVS_DE_BLOCK8_SRC_ORIGIN_Y(x)				(((x) << VIVS_DE_BLOCK8_SRC_ORIGIN_Y__SHIFT) & VIVS_DE_BLOCK8_SRC_ORIGIN_Y__MASK)
+
+#define VIVS_DE_BLOCK8_SRC_SIZE(i0)			       (0x00012aa0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_SIZE__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_SRC_SIZE__LEN				0x00000008
+#define VIVS_DE_BLOCK8_SRC_SIZE_X__MASK				0x0000ffff
+#define VIVS_DE_BLOCK8_SRC_SIZE_X__SHIFT			0
+#define VIVS_DE_BLOCK8_SRC_SIZE_X(x)				(((x) << VIVS_DE_BLOCK8_SRC_SIZE_X__SHIFT) & VIVS_DE_BLOCK8_SRC_SIZE_X__MASK)
+#define VIVS_DE_BLOCK8_SRC_SIZE_Y__MASK				0xffff0000
+#define VIVS_DE_BLOCK8_SRC_SIZE_Y__SHIFT			16
+#define VIVS_DE_BLOCK8_SRC_SIZE_Y(x)				(((x) << VIVS_DE_BLOCK8_SRC_SIZE_Y__SHIFT) & VIVS_DE_BLOCK8_SRC_SIZE_Y__MASK)
+
+#define VIVS_DE_BLOCK8_SRC_COLOR_BG(i0)			       (0x00012ac0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_COLOR_BG__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_SRC_COLOR_BG__LEN			0x00000008
+
+#define VIVS_DE_BLOCK8_ROP(i0)				       (0x00012ae0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_ROP__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_ROP__LEN					0x00000008
+#define VIVS_DE_BLOCK8_ROP_ROP_FG__MASK				0x000000ff
+#define VIVS_DE_BLOCK8_ROP_ROP_FG__SHIFT			0
+#define VIVS_DE_BLOCK8_ROP_ROP_FG(x)				(((x) << VIVS_DE_BLOCK8_ROP_ROP_FG__SHIFT) & VIVS_DE_BLOCK8_ROP_ROP_FG__MASK)
+#define VIVS_DE_BLOCK8_ROP_ROP_BG__MASK				0x0000ff00
+#define VIVS_DE_BLOCK8_ROP_ROP_BG__SHIFT			8
+#define VIVS_DE_BLOCK8_ROP_ROP_BG(x)				(((x) << VIVS_DE_BLOCK8_ROP_ROP_BG__SHIFT) & VIVS_DE_BLOCK8_ROP_ROP_BG__MASK)
+#define VIVS_DE_BLOCK8_ROP_TYPE__MASK				0x00300000
+#define VIVS_DE_BLOCK8_ROP_TYPE__SHIFT				20
+#define VIVS_DE_BLOCK8_ROP_TYPE_ROP2_PATTERN			0x00000000
+#define VIVS_DE_BLOCK8_ROP_TYPE_ROP2_SOURCE			0x00100000
+#define VIVS_DE_BLOCK8_ROP_TYPE_ROP3				0x00200000
+#define VIVS_DE_BLOCK8_ROP_TYPE_ROP4				0x00300000
+
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL(i0)		       (0x00012b00 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL__LEN			0x00000008
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE__MASK		0x00000001
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE__SHIFT		0
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE_OFF			0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE_ON			0x00000001
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK	0x00ff0000
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT	16
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA(x)	(((x) << VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT) & VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK)
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK	0xff000000
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT	24
+#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA(x)	(((x) << VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT) & VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK)
+
+#define VIVS_DE_BLOCK8_ALPHA_MODES(i0)			       (0x00012b20 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_ALPHA_MODES__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_ALPHA_MODES__LEN				0x00000008
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE__MASK		0x00000001
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE__SHIFT	0
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE_INVERSED	0x00000001
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE__MASK		0x00000010
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE__SHIFT	4
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE_INVERSED	0x00000010
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__MASK	0x00000300
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__SHIFT	8
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_GLOBAL	0x00000100
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_SCALED	0x00000200
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__MASK	0x00003000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__SHIFT	12
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_NORMAL	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_GLOBAL	0x00001000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_SCALED	0x00002000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__MASK	0x00010000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__SHIFT	16
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_ENABLE	0x00010000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__MASK	0x00100000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__SHIFT	20
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_ENABLE	0x00100000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__MASK	0x07000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT	24
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE(x)		(((x) << VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__MASK)
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR__MASK	0x08000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR__SHIFT	27
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR_ENABLE	0x08000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__MASK	0x70000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__SHIFT	28
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE(x)		(((x) << VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__MASK)
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR__MASK	0x80000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR__SHIFT	31
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR_ENABLE	0x80000000
+
+#define VIVS_DE_BLOCK8_ADDRESS_U(i0)			       (0x00012b40 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_ADDRESS_U__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_ADDRESS_U__LEN				0x00000008
+
+#define VIVS_DE_BLOCK8_STRIDE_U(i0)			       (0x00012b60 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_STRIDE_U__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_STRIDE_U__LEN				0x00000008
+#define VIVS_DE_BLOCK8_STRIDE_U_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_BLOCK8_STRIDE_U_STRIDE__SHIFT			0
+#define VIVS_DE_BLOCK8_STRIDE_U_STRIDE(x)			(((x) << VIVS_DE_BLOCK8_STRIDE_U_STRIDE__SHIFT) & VIVS_DE_BLOCK8_STRIDE_U_STRIDE__MASK)
+
+#define VIVS_DE_BLOCK8_ADDRESS_V(i0)			       (0x00012b80 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_ADDRESS_V__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_ADDRESS_V__LEN				0x00000008
+
+#define VIVS_DE_BLOCK8_STRIDE_V(i0)			       (0x00012ba0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_STRIDE_V__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_STRIDE_V__LEN				0x00000008
+#define VIVS_DE_BLOCK8_STRIDE_V_STRIDE__MASK			0x0003ffff
+#define VIVS_DE_BLOCK8_STRIDE_V_STRIDE__SHIFT			0
+#define VIVS_DE_BLOCK8_STRIDE_V_STRIDE(x)			(((x) << VIVS_DE_BLOCK8_STRIDE_V_STRIDE__SHIFT) & VIVS_DE_BLOCK8_STRIDE_V_STRIDE__MASK)
+
+#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT(i0)		       (0x00012bc0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT__ESIZE		0x00000004
+#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT__LEN			0x00000008
+#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__MASK		0x0000ffff
+#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT	0
+#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT(x)		(((x) << VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__MASK)
+
+#define VIVS_DE_BLOCK8_ROT_ANGLE(i0)			       (0x00012be0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_ROT_ANGLE__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_ROT_ANGLE__LEN				0x00000008
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC__MASK			0x00000007
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC__SHIFT			0
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC(x)				(((x) << VIVS_DE_BLOCK8_ROT_ANGLE_SRC__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_SRC__MASK)
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST__MASK			0x00000038
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST__SHIFT			3
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST(x)				(((x) << VIVS_DE_BLOCK8_ROT_ANGLE_DST__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_DST__MASK)
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MASK			0x00000100
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MASK			0x00000200
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__MASK		0x00003000
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__SHIFT		12
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR(x)			(((x) << VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__MASK)
+#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR_MASK		0x00008000
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__MASK		0x00030000
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__SHIFT		16
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR(x)			(((x) << VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__MASK)
+#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR_MASK		0x00080000
+
+#define VIVS_DE_BLOCK8_GLOBAL_SRC_COLOR(i0)		       (0x00012c00 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_GLOBAL_SRC_COLOR__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_GLOBAL_SRC_COLOR__LEN			0x00000008
+
+#define VIVS_DE_BLOCK8_GLOBAL_DEST_COLOR(i0)		       (0x00012c20 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_GLOBAL_DEST_COLOR__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_GLOBAL_DEST_COLOR__LEN			0x00000008
+
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES(i0)		       (0x00012c40 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES__ESIZE		0x00000004
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES__LEN		0x00000008
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__MASK	0x00000001
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__SHIFT	0
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE	0x00000001
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__MASK	0x00000010
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__SHIFT	4
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_ENABLE	0x00000010
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__MASK	0x00000300
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__SHIFT	8
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_ALPHA	0x00000100
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_COLOR	0x00000200
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__MASK	0x00100000
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__SHIFT	20
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE	0x00100000
+
+#define VIVS_DE_BLOCK8_TRANSPARENCY(i0)			       (0x00012c60 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_TRANSPARENCY__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_TRANSPARENCY__LEN			0x00000008
+#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE__MASK		0x00000003
+#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE__SHIFT		0
+#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE_OPAQUE		0x00000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE_MASK			0x00000001
+#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE_KEY			0x00000002
+#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN__MASK		0x00000030
+#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN__SHIFT		4
+#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN_OPAQUE		0x00000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN_MASK		0x00000010
+#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN_KEY			0x00000020
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION__MASK		0x00000300
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION__SHIFT		8
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION_OPAQUE		0x00000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION_MASK		0x00000100
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION_KEY		0x00000200
+#define VIVS_DE_BLOCK8_TRANSPARENCY_TRANSPARENCY_MASK		0x00001000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE__MASK	0x00030000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE__SHIFT	16
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE_USE_ENABLE	0x00010000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE_USE_DISABLE	0x00020000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE__MASK	0x00300000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE__SHIFT	20
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE_USE_ENABLE	0x00100000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE_USE_DISABLE	0x00200000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE__MASK	0x03000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE__SHIFT	24
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE_DEFAULT	0x00000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE_USE_ENABLE	0x01000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE_USE_DISABLE	0x02000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_RESOURCE_OVERRIDE_MASK	0x10000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY__MASK		0x20000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY__SHIFT	29
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY_ENABLE	0x20000000
+#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY_MASK		0x80000000
+
+#define VIVS_DE_BLOCK8_CONTROL(i0)			       (0x00012c80 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_CONTROL__ESIZE				0x00000004
+#define VIVS_DE_BLOCK8_CONTROL__LEN				0x00000008
+#define VIVS_DE_BLOCK8_CONTROL_YUV__MASK			0x00000001
+#define VIVS_DE_BLOCK8_CONTROL_YUV__SHIFT			0
+#define VIVS_DE_BLOCK8_CONTROL_YUV_601				0x00000000
+#define VIVS_DE_BLOCK8_CONTROL_YUV_709				0x00000001
+#define VIVS_DE_BLOCK8_CONTROL_YUV_MASK				0x00000008
+#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE__MASK			0x00000010
+#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE__SHIFT		4
+#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE_UV			0x00000000
+#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE_VU			0x00000010
+#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE_MASK			0x00000080
+#define VIVS_DE_BLOCK8_CONTROL_YUVRGB__MASK			0x00000100
+#define VIVS_DE_BLOCK8_CONTROL_YUVRGB__SHIFT			8
+#define VIVS_DE_BLOCK8_CONTROL_YUVRGB_DISABLE			0x00000000
+#define VIVS_DE_BLOCK8_CONTROL_YUVRGB_ENABLE			0x00000100
+#define VIVS_DE_BLOCK8_CONTROL_YUVRGB_MASK			0x00000800
+
+#define VIVS_DE_BLOCK8_SRC_COLOR_KEY_HIGH(i0)		       (0x00012ca0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_COLOR_KEY_HIGH__ESIZE		0x00000004
+#define VIVS_DE_BLOCK8_SRC_COLOR_KEY_HIGH__LEN			0x00000008
+
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG(i0)		       (0x00012cc0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG__LEN			0x00000008
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED__MASK		0x00000001
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED__SHIFT		0
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED_ENABLE		0x00000001
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED__MASK		0x00000008
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED__SHIFT		3
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED_ENABLE		0x00000008
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED__MASK		0x00000100
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED__SHIFT		8
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED_DISABLE	0x00000000
+#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED_ENABLE		0x00000100
+
+#define VIVS_DE_BLOCK8_SRC_EX_ADDRESS(i0)		       (0x00012ce0 + 0x4*(i0))
+#define VIVS_DE_BLOCK8_SRC_EX_ADDRESS__ESIZE			0x00000004
+#define VIVS_DE_BLOCK8_SRC_EX_ADDRESS__LEN			0x00000008
+
+
+#endif /* STATE_2D_XML */
diff --git a/tests/etnaviv/write_bmp.c b/tests/etnaviv/write_bmp.c
new file mode 100644
index 0000000..7ae0646
--- /dev/null
+++ b/tests/etnaviv/write_bmp.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2011      Luc Verhaegen <libv@codethink.co.uk>
+ *
+ * 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, sub license,
+ * 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 NON-INFRINGEMENT. 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.
+ *
+ */
+/*
+ * Quick 'n Dirty bitmap dumper.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "write_bmp.h"
+
+#define FILENAME_SIZE 1024
+
+struct bmp_header {
+	unsigned short magic;
+	unsigned int size;
+	unsigned int unused;
+	unsigned int start;
+} __attribute__((__packed__));
+
+struct dib_header {
+	unsigned int size;
+	unsigned int width;
+	unsigned int height;
+	unsigned short planes;
+	unsigned short bpp;
+	unsigned int compression;
+	unsigned int data_size;
+	unsigned int h_res;
+	unsigned int v_res;
+	unsigned int colours;
+	unsigned int important_colours;
+	unsigned int red_mask;
+	unsigned int green_mask;
+	unsigned int blue_mask;
+	unsigned int alpha_mask;
+	unsigned int colour_space;
+	unsigned int unused[12];
+} __attribute__((__packed__));
+
+static int
+bmp_header_write(int fd, int width, int height, int bgra, int noflip, int alpha)
+{
+	struct bmp_header bmp_header = {
+		.magic = 0x4d42,
+		.size = (width * height * 4) +
+		sizeof(struct bmp_header) + sizeof(struct dib_header),
+		.start = sizeof(struct bmp_header) + sizeof(struct dib_header),
+	};
+	struct dib_header dib_header = {
+		.size = sizeof(struct dib_header),
+		.width = width,
+		.height = noflip ? -height : height,
+		.planes = 1,
+		.bpp = 32,
+		.compression = 3,
+		.data_size = 4 * width * height,
+		.h_res = 0xB13,
+		.v_res = 0xB13,
+		.colours = 0,
+		.important_colours = 0,
+		.red_mask = 0x000000FF,
+		.green_mask = 0x0000FF00,
+		.blue_mask = 0x00FF0000,
+		.alpha_mask = alpha ? 0xFF000000 : 0x00000000,
+		.colour_space = 0x57696E20,
+	};
+
+	if (bgra) {
+		dib_header.red_mask = 0x00FF0000;
+		dib_header.blue_mask = 0x000000FF;
+	}
+
+	write(fd, &bmp_header, sizeof(struct bmp_header));
+	write(fd, &dib_header, sizeof(struct dib_header));
+
+	return 0;
+}
+
+void
+bmp_dump32(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename)
+{
+	int fd;
+
+	fd = open(filename, O_WRONLY| O_TRUNC | O_CREAT, 0666);
+	if (fd == -1) {
+		printf("Failed to open %s: %s\n", filename, strerror(errno));
+		return;
+	}
+
+	bmp_header_write(fd, width, height, bgra, false, true);
+
+	write(fd, buffer, width * height * 4);
+}
+
+void
+bmp_dump32_noflip(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename)
+{
+	int fd;
+
+	fd = open(filename, O_WRONLY| O_TRUNC | O_CREAT, 0666);
+	if (fd == -1) {
+		printf("Failed to open %s: %s\n", filename, strerror(errno));
+		return;
+	}
+
+	bmp_header_write(fd, width, height, bgra, true, true);
+
+	write(fd, buffer, width * height * 4);
+}
+
+void
+bmp_dump32_ex(char *buffer, unsigned width, unsigned height, bool flip, bool bgra, bool alpha, const char *filename)
+{
+	int fd;
+
+	fd = open(filename, O_WRONLY| O_TRUNC | O_CREAT, 0666);
+	if (fd == -1) {
+		printf("Failed to open %s: %s\n", filename, strerror(errno));
+		return;
+	}
+
+	bmp_header_write(fd, width, height, bgra, flip, alpha);
+
+	write(fd, buffer, width * height * 4);
+}
diff --git a/tests/etnaviv/write_bmp.h b/tests/etnaviv/write_bmp.h
new file mode 100644
index 0000000..667fa87
--- /dev/null
+++ b/tests/etnaviv/write_bmp.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011      Luc Verhaegen <libv@codethink.co.uk>
+ *
+ * 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, sub license,
+ * 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 NON-INFRINGEMENT. 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 BMP_DUMP_H
+#define BMP_DUMP_H 1
+#include <stdbool.h>
+/* write 32-bit image (y axis upwards) */
+void bmp_dump32(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename);
+/* write 32-bit image (y axis downwards) */
+void bmp_dump32_noflip(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename);
+/* write 32-bit image */
+void bmp_dump32_ex(char *buffer, unsigned width, unsigned height, bool flip, bool bgra, bool alpha, const char *filename);
+
+#endif /* BMP_DUMP_H */
diff --git a/tests/exynos/Makefile.am b/tests/exynos/Makefile.am
index 357d6b8..b636172 100644
--- a/tests/exynos/Makefile.am
+++ b/tests/exynos/Makefile.am
@@ -1,4 +1,5 @@
 AM_CFLAGS = \
+	-pthread \
 	$(WARN_CFLAGS)\
 	-I $(top_srcdir)/include/drm \
 	-I $(top_srcdir)/libkms/ \
@@ -34,8 +35,7 @@
 
 exynos_fimg2d_event_LDADD = \
 	$(top_builddir)/libdrm.la \
-	$(top_builddir)/exynos/libdrm_exynos.la \
-	-lpthread
+	$(top_builddir)/exynos/libdrm_exynos.la
 
 exynos_fimg2d_test_LDADD = \
 	$(top_builddir)/libdrm.la \
diff --git a/tests/getclient.c b/tests/getclient.c
deleted file mode 100644
index 481ce11..0000000
--- a/tests/getclient.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <limits.h>
-#include <sys/ioctl.h>
-#include "drmtest.h"
-
-/**
- * Checks DRM_IOCTL_GET_CLIENT.
- */
-int main(int argc, char **argv)
-{
-	int fd, ret;
-	drm_client_t client;
-
-	fd = drm_open_any();
-
-	/* Look for client index 0.  This should exist whether we're operating
-	 * on an otherwise unused drm device, or the X Server is running on
-	 * the device.
-	 */
-	client.idx = 0;
-	ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
-	assert(ret == 0);
-
-	/* Look for some absurd client index and make sure it's invalid.
-	 * The DRM drivers currently always return data, so the user has
-	 * no real way to detect when the list has terminated.  That's bad,
-	 * and this test is XFAIL as a result.
-	 */
-	client.idx = 0x7fffffff;
-	ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
-	assert(ret == -1 && errno == EINVAL);
-
-	close(fd);
-	return 0;
-}
diff --git a/tests/getstats.c b/tests/getstats.c
deleted file mode 100644
index 8a7d299..0000000
--- a/tests/getstats.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <limits.h>
-#include <sys/ioctl.h>
-#include "drmtest.h"
-
-/**
- * Checks DRM_IOCTL_GET_STATS.
- *
- * I don't care too much about the actual contents, just that the kernel
- * doesn't crash.
- */
-int main(int argc, char **argv)
-{
-	int fd, ret;
-	drm_stats_t stats;
-
-	fd = drm_open_any();
-
-	ret = ioctl(fd, DRM_IOCTL_GET_STATS, &stats);
-	assert(ret == 0);
-
-	close(fd);
-	return 0;
-}
diff --git a/tests/getversion.c b/tests/getversion.c
deleted file mode 100644
index bcec469..0000000
--- a/tests/getversion.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <string.h>
-#include "drmtest.h"
-
-/**
- * Checks DRM_IOCTL_GET_VERSION and libdrm's drmGetVersion() interface to it.
- */
-int main(int argc, char **argv)
-{
-	int fd;
-	drmVersionPtr v;
-
-	fd = drm_open_any();
-	v = drmGetVersion(fd);
-	assert(strlen(v->name) != 0);
-	assert(strlen(v->date) != 0);
-	assert(strlen(v->desc) != 0);
-	if (strcmp(v->name, "i915") == 0)
-		assert(v->version_major >= 1);
-	drmFreeVersion(v);
-	close(fd);
-	return 0;
-}
diff --git a/tests/kms/kms-steal-crtc.c b/tests/kms/kms-steal-crtc.c
index 2f7f327..4b830d2 100644
--- a/tests/kms/kms-steal-crtc.c
+++ b/tests/kms/kms-steal-crtc.c
@@ -29,8 +29,12 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <string.h>
 #include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
 
 #include <drm_fourcc.h>
 
diff --git a/tests/kms/kms-universal-planes.c b/tests/kms/kms-universal-planes.c
index 9151231..89057bb 100644
--- a/tests/kms/kms-universal-planes.c
+++ b/tests/kms/kms-universal-planes.c
@@ -32,6 +32,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
 
 #include <drm_fourcc.h>
 #include "xf86drm.h"
@@ -209,9 +212,9 @@
 		printf("Planes: %u\n", device->num_planes);
 
 		for (i = 0; i < device->num_planes; i++) {
-			struct kms_plane *plane = device->planes[i];
 			const char *type = NULL;
 
+			plane = device->planes[i];
 			switch (plane->type) {
 			case DRM_PLANE_TYPE_OVERLAY:
 				type = "overlay";
diff --git a/tests/kmstest/Makefile.am b/tests/kmstest/Makefile.am
index fd21e61..ced541b 100644
--- a/tests/kmstest/Makefile.am
+++ b/tests/kmstest/Makefile.am
@@ -2,6 +2,7 @@
 	$(WARN_CFLAGS)\
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/libkms/ \
+	-I$(top_srcdir)/tests/ \
 	-I$(top_srcdir)
 
 if HAVE_INSTALL_TESTS
@@ -16,8 +17,9 @@
 	main.c
 
 kmstest_LDADD = \
-	$(top_builddir)/libdrm.la \
-	$(top_builddir)/libkms/libkms.la
+	$(top_builddir)/tests/util/libutil.la \
+	$(top_builddir)/libkms/libkms.la \
+	$(top_builddir)/libdrm.la
 
 run: kmstest
 	./kmstest
diff --git a/tests/kmstest/main.c b/tests/kmstest/main.c
index 120bc0f..a0e4ebb 100644
--- a/tests/kmstest/main.c
+++ b/tests/kmstest/main.c
@@ -25,12 +25,14 @@
  *
  **************************************************************************/
 
-
+#include <getopt.h>
 #include <stdio.h>
 #include <string.h>
 #include "xf86drm.h"
 #include "libkms.h"
 
+#include "util/kms.h"
+
 #define CHECK_RET_RETURN(ret, str) \
 	if (ret < 0) { \
 		printf("%s: %s (%s)\n", __func__, str, strerror(-ret)); \
@@ -56,26 +58,37 @@
 	return 0;
 }
 
-static const char *drivers[] = {
-	"i915",
-	"radeon",
-	"nouveau",
-	"vmwgfx",
-	"exynos",
-	"amdgpu",
-	"imx-drm",
-	"rockchip",
-	"atmel-hlcdc",
-	NULL
-};
+static void usage(const char *program)
+{
+	fprintf(stderr, "Usage: %s [options]\n", program);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "  -D DEVICE  open the given device\n");
+	fprintf(stderr, "  -M MODULE  open the given module\n");
+}
 
 int main(int argc, char** argv)
 {
+	static const char optstr[] = "D:M:";
 	struct kms_driver *kms;
-	int ret, fd, i;
+	int c, fd, ret;
+	char *device = NULL;
+	char *module = NULL;
 
-	for (i = 0, fd = -1; fd < 0 && drivers[i]; i++)
-		fd = drmOpen(drivers[i], NULL);
+	while ((c = getopt(argc, argv, optstr)) != -1) {
+		switch (c) {
+		case 'D':
+			device = optarg;
+			break;
+		case 'M':
+			module = optarg;
+			break;
+		default:
+			usage(argv[0]);
+			return 0;
+		}
+	}
+
+	fd = util_open(device, module);
 	CHECK_RET_RETURN(fd, "Could not open device");
 
 	ret = kms_create(fd, &kms);
diff --git a/tests/lock.c b/tests/lock.c
deleted file mode 100644
index 365681b..0000000
--- a/tests/lock.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-/** @file lock.c
- * Tests various potential failures of the DRM locking mechanisms
- */
-
-#include <limits.h>
-#include <sys/ioctl.h>
-#include "drmtest.h"
-
-enum auth_event {
-	SERVER_READY,
-	CLIENT_MAGIC,
-	SERVER_LOCKED,
-	CLIENT_LOCKED,
-};
-
-int commfd[2];
-unsigned int lock1 = 0x00001111;
-unsigned int lock2 = 0x00002222;
-
-/* return time in milliseconds */
-static unsigned int
-get_millis()
-{
-	struct timeval tv;
-
-	gettimeofday(&tv, NULL);
-	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-static void
-wait_event(int pipe, enum auth_event expected_event)
-{
-	int ret;
-	enum auth_event event;
-	unsigned char in;
-
-	ret = read(commfd[pipe], &in, 1);
-	if (ret == -1)
-		err(1, "read error");
-	event = in;
-
-	if (event != expected_event)
-		errx(1, "unexpected event: %d\n", event);
-}
-
-static void
-send_event(int pipe, enum auth_event send_event)
-{
-	int ret;
-	unsigned char event;
-
-	event = send_event;
-	ret = write(commfd[pipe], &event, 1);
-	if (ret == -1)
-		err(1, "failed to send event %d", event);
-}
-
-static void
-client_auth(int drmfd)
-{
-	struct drm_auth auth;
-	int ret;
-
-	/* Get a client magic number and pass it to the master for auth. */
-	ret = ioctl(drmfd, DRM_IOCTL_GET_MAGIC, &auth);
-	if (ret == -1)
-		err(1, "Couldn't get client magic");
-	send_event(0, CLIENT_MAGIC);
-	ret = write(commfd[0], &auth.magic, sizeof(auth.magic));
-	if (ret == -1)
-		err(1, "Couldn't write auth data");
-}
-
-static void
-server_auth(int drmfd)
-{
-	struct drm_auth auth;
-	int ret;
-
-	send_event(1, SERVER_READY);
-	wait_event(1, CLIENT_MAGIC);
-	ret = read(commfd[1], &auth.magic, sizeof(auth.magic));
-	if (ret == -1)
-		err(1, "Failure to read client magic");
-
-	ret = ioctl(drmfd, DRM_IOCTL_AUTH_MAGIC, &auth);
-	if (ret == -1)
-		err(1, "Failure to authenticate client magic\n");
-}
-
-/** Tests that locking is successful in normal conditions */
-static void
-test_lock_unlock(int drmfd)
-{
-	int ret;
-
-	ret = drmGetLock(drmfd, lock1, 0);
-	if (ret != 0)
-		err(1, "Locking failed");
-	ret = drmUnlock(drmfd, lock1);
-	if (ret != 0)
-		err(1, "Unlocking failed");
-}
-
-/** Tests that unlocking the lock while it's not held works correctly */
-static void
-test_unlock_unlocked(int drmfd)
-{
-	int ret;
-
-	ret = drmUnlock(drmfd, lock1);
-	if (ret == 0)
-		err(1, "Unlocking unlocked lock succeeded");
-}
-
-/** Tests that unlocking a lock held by another context fails appropriately */
-static void
-test_unlock_unowned(int drmfd)
-{
-	int ret;
-
-	ret = drmGetLock(drmfd, lock1, 0);
-	assert(ret == 0);
-	ret = drmUnlock(drmfd, lock2);
-	if (ret == 0)
-		errx(1, "Unlocking other context's lock succeeded");
-	ret = drmUnlock(drmfd, lock1);
-	assert(ret == 0);
-}
-
-/**
- * Tests that an open/close by the same process doesn't result in the lock
- * being dropped.
- */
-static void test_open_close_locked(drmfd)
-{
-	int ret, tempfd;
-
-	ret = drmGetLock(drmfd, lock1, 0);
-	assert(ret == 0);
-	/* XXX: Need to make sure that this is the same device as drmfd */
-	tempfd = drm_open_any();
-	close(tempfd);
-	ret = drmUnlock(drmfd, lock1);
-	if (ret != 0)
-		errx(1, "lock lost during open/close by same pid");
-}
-
-static void client()
-{
-	int drmfd, ret;
-	unsigned int time;
-
-	wait_event(0, SERVER_READY);
-
-	/* XXX: Should make sure we open the same DRM as the master */
-	drmfd = drm_open_any();
-
-	client_auth(drmfd);
-
-	/* Wait for the server to grab the lock, then grab it ourselves (to
-	 * contest it).  Hopefully we hit it within the window of when the
-	 * server locks.
-	 */
-	wait_event(0, SERVER_LOCKED);
-	ret = drmGetLock(drmfd, lock2, 0);
-	time = get_millis();
-	if (ret != 0)
-		err(1, "Failed to get lock on client\n");
-	drmUnlock(drmfd, lock2);
-
-	/* Tell the server that our locking completed, and when it did */
-	send_event(0, CLIENT_LOCKED);
-	ret = write(commfd[0], &time, sizeof(time));
-
-	close(drmfd);
-	exit(0);
-}
-
-static void server()
-{
-	int drmfd, tempfd, ret;
-	unsigned int client_time, unlock_time;
-
-	drmfd = drm_open_any_master();
-
-	test_lock_unlock(drmfd);
-	test_unlock_unlocked(drmfd);
-	test_unlock_unowned(drmfd);
-	test_open_close_locked(drmfd);
-
-	/* Perform the authentication sequence with the client. */
-	server_auth(drmfd);
-
-	/* Now, test that the client attempting to lock while the server
-	 * holds the lock works correctly.
-	 */
-	ret = drmGetLock(drmfd, lock1, 0);
-	assert(ret == 0);
-	send_event(1, SERVER_LOCKED);
-	/* Wait a while for the client to do its thing */
-	sleep(1);
-	ret = drmUnlock(drmfd, lock1);
-	assert(ret == 0);
-	unlock_time = get_millis();
-
-	wait_event(1, CLIENT_LOCKED);
-	ret = read(commfd[1], &client_time, sizeof(client_time));
-	if (ret == -1)
-		err(1, "Failure to read client magic");
-
-	if (client_time < unlock_time)
-		errx(1, "Client took lock before server released it");
-
-	close(drmfd);
-}
-
-int main(int argc, char **argv)
-{
-	int ret;
-
-
-	ret = pipe(commfd);
-	if (ret == -1)
-		err(1, "Couldn't create pipe");
-
-	ret = fork();
-	if (ret == -1)
-		err(1, "failure to fork client");
-	if (ret == 0)
-		client();
-	else
-		server();
-
-	return 0;
-}
-
diff --git a/tests/modetest/Android.mk b/tests/modetest/Android.mk
index ccdae6c..ab40b80 100644
--- a/tests/modetest/Android.mk
+++ b/tests/modetest/Android.mk
@@ -10,4 +10,7 @@
 LOCAL_SHARED_LIBRARIES := libdrm
 LOCAL_STATIC_LIBRARIES := libdrm_util
 
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
+
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_EXECUTABLE)
diff --git a/tests/modetest/Makefile.am b/tests/modetest/Makefile.am
index 25ce372..4b296c8 100644
--- a/tests/modetest/Makefile.am
+++ b/tests/modetest/Makefile.am
@@ -3,6 +3,7 @@
 AM_CFLAGS = $(filter-out -Wpointer-arith, $(WARN_CFLAGS))
 
 AM_CFLAGS += \
+	-pthread \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/tests \
 	-I$(top_srcdir)
@@ -20,7 +21,4 @@
 modetest_LDADD = \
 	$(top_builddir)/libdrm.la \
 	$(top_builddir)/tests/util/libutil.la \
-	$(CAIRO_LIBS) \
-	-lpthread
-
-EXTRA_DIST = Android.mk
+	$(CAIRO_LIBS)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 2c5b283..cd91119 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -53,8 +53,11 @@
 #include <string.h>
 #include <strings.h>
 #include <errno.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/time.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
 
 #include "xf86drm.h"
 #include "xf86drmMode.h"
@@ -195,7 +198,7 @@
 
 static void dump_mode(drmModeModeInfo *mode)
 {
-	printf("  %s %d %d %d %d %d %d %d %d %d",
+	printf("  %s %d %d %d %d %d %d %d %d %d %d",
 	       mode->name,
 	       mode->vrefresh,
 	       mode->hdisplay,
@@ -205,7 +208,8 @@
 	       mode->vdisplay,
 	       mode->vsync_start,
 	       mode->vsync_end,
-	       mode->vtotal);
+	       mode->vtotal,
+	       mode->clock);
 
 	printf(" flags: ");
 	mode_flag_str(mode->flags);
@@ -311,6 +315,8 @@
 	printf("\t\tvalue:");
 	if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
 		dump_blob(dev, value);
+	else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
+		printf(" %"PRId64"\n", value);
 	else
 		printf(" %"PRIu64"\n", value);
 }
@@ -699,6 +705,7 @@
 };
 
 struct plane_arg {
+	uint32_t plane_id;  /* the id of plane to use */
 	uint32_t crtc_id;  /* the id of CRTC to bind to */
 	bool has_position;
 	int32_t x, y;
@@ -953,7 +960,7 @@
 {
 	drmModePlane *ovr;
 	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
-	uint32_t plane_id = 0;
+	uint32_t plane_id;
 	struct bo *plane_bo;
 	uint32_t plane_flags = 0;
 	int crtc_x, crtc_y, crtc_w, crtc_h;
@@ -977,16 +984,26 @@
 		return -1;
 	}
 
-	for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) {
+	plane_id = p->plane_id;
+
+	for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
 		ovr = dev->resources->planes[i].plane;
-		if (!ovr || !format_support(ovr, p->fourcc))
+		if (!ovr)
 			continue;
 
-		if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id)
+		if (plane_id && plane_id != ovr->plane_id)
+			continue;
+
+		if (!format_support(ovr, p->fourcc))
+			continue;
+
+		if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id) {
 			plane_id = ovr->plane_id;
+			break;
+		}
 	}
 
-	if (!plane_id) {
+	if (i == dev->resources->plane_res->count_planes) {
 		fprintf(stderr, "no unused plane available for CRTC %u\n",
 			crtc->crtc->crtc_id);
 		return -1;
@@ -1354,6 +1371,11 @@
 {
 	char *end;
 
+	plane->plane_id = strtoul(p, &end, 10);
+	if (*end != '@')
+		return -EINVAL;
+
+	p = end + 1;
 	plane->crtc_id = strtoul(p, &end, 10);
 	if (*end != ':')
 		return -EINVAL;
@@ -1425,7 +1447,7 @@
 	fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
 
 	fprintf(stderr, "\n Test options:\n\n");
-	fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
+	fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
 	fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n");
 	fprintf(stderr, "\t-C\ttest hw cursor\n");
 	fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
@@ -1604,7 +1626,7 @@
 	if (!args)
 		encoders = connectors = crtcs = planes = framebuffers = 1;
 
-	dev.fd = util_open(module, device);
+	dev.fd = util_open(device, module);
 	if (dev.fd < 0)
 		return -1;
 
diff --git a/tests/name_from_fd.c b/tests/name_from_fd.c
deleted file mode 100644
index 5264681..0000000
--- a/tests/name_from_fd.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright © 2009 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Kristian Høgsberg <krh@bitplanet.net>
- *
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <string.h>
-#include "drmtest.h"
-
-/**
- * Checks drmGetDeviceNameFromFd
- *
- * This tests that we can get the actual version out, and that setting invalid
- * major/minor numbers fails appropriately.  It does not check the actual
- * behavior differenses resulting from an increased DI version.
- */
-int main(int argc, char **argv)
-{
-	int fd;
-	const char *name = "/dev/dri/card0";
-	char *v;
-
-	fd = open("/dev/dri/card0", O_RDWR);
-	if (fd < 0)
-		return 0;
-
-	v = drmGetDeviceNameFromFd(fd);
-	close(fd);
-
-	assert(strcmp(name, v) == 0);
-	drmFree(v);
-
-	return 0;
-}
diff --git a/tests/nouveau/Makefile.am b/tests/nouveau/Makefile.am
index c4f6e29..3c799a8 100644
--- a/tests/nouveau/Makefile.am
+++ b/tests/nouveau/Makefile.am
@@ -1,14 +1,14 @@
-AM_CPPFLAGS = \
+AM_CFLAGS = \
+	-pthread \
+	$(WARN_CFLAGS) \
 	-I$(top_srcdir)/include/drm \
 	-I$(top_srcdir)/nouveau \
 	-I$(top_srcdir)
 
-AM_CFLAGS = $(WARN_CFLAGS)
-
 LDADD = \
 	../../nouveau/libdrm_nouveau.la \
 	../../libdrm.la \
-	-ldl -lpthread
+	-ldl
 
 TESTS = threaded
 
diff --git a/tests/openclose.c b/tests/openclose.c
deleted file mode 100644
index 946a445..0000000
--- a/tests/openclose.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include "drmtest.h"
-
-int main(int argc, char **argv)
-{
-	int fd;
-
-	fd = drm_open_any();
-	close(fd);
-	return 0;
-}
diff --git a/tests/proptest/Android.mk b/tests/proptest/Android.mk
index d0ab5c9..588fbed 100644
--- a/tests/proptest/Android.mk
+++ b/tests/proptest/Android.mk
@@ -10,4 +10,7 @@
 LOCAL_SHARED_LIBRARIES := libdrm
 LOCAL_STATIC_LIBRARIES := libdrm_util
 
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
+
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_EXECUTABLE)
diff --git a/tests/proptest/proptest.c b/tests/proptest/proptest.c
index 24c6345..5abbf02 100644
--- a/tests/proptest/proptest.c
+++ b/tests/proptest/proptest.c
@@ -151,6 +151,8 @@
 	printf("\t\tvalue:");
 	if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
 		dump_blob(value);
+	else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
+		printf(" %"PRId64"\n", value);
 	else
 		printf(" %"PRIu64"\n", value);
 
@@ -295,7 +297,7 @@
 
 	args = argc - optind;
 
-	fd = util_open(module, device);
+	fd = util_open(device, module);
 	if (fd < 0)
 		return 1;
 
diff --git a/tests/setversion.c b/tests/setversion.c
deleted file mode 100644
index 2f7b529..0000000
--- a/tests/setversion.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <limits.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include "drmtest.h"
-
-/**
- * Checks DRM_IOCTL_SET_VERSION.
- *
- * This tests that we can get the actual version out, and that setting invalid
- * major/minor numbers fails appropriately.  It does not check the actual
- * behavior differenses resulting from an increased DI version.
- */
-int main(int argc, char **argv)
-{
-	int fd, ret;
-	drm_set_version_t sv, version;
-
-	if (getuid() != 0) {
-		fprintf(stderr, "setversion test requires root, skipping\n");
-		return 0;
-	}
-
-	fd = drm_open_any_master();
-
-	/* First, check that we can get the DD/DI versions. */
-	memset(&version, 0, sizeof(version));
-	version.drm_di_major = -1;
-	version.drm_di_minor = -1;
-	version.drm_dd_major = -1;
-	version.drm_dd_minor = -1;
-	ret = ioctl(fd, DRM_IOCTL_SET_VERSION, &version);
-	assert(ret == 0);
-	assert(version.drm_di_major != -1);
-	assert(version.drm_di_minor != -1);
-	assert(version.drm_dd_major != -1);
-	assert(version.drm_dd_minor != -1);
-
-	/* Check that an invalid DI major fails */
-	sv = version;
-	sv.drm_di_major++;
-	ret = ioctl(fd, DRM_IOCTL_SET_VERSION, &sv);
-	assert(ret == -1 && errno == EINVAL);
-
-	/* Check that an invalid DI minor fails */
-	sv = version;
-	sv.drm_di_major++;
-	ret = ioctl(fd, DRM_IOCTL_SET_VERSION, &sv);
-	assert(ret == -1 && errno == EINVAL);
-
-	/* Check that an invalid DD major fails */
-	sv = version;
-	sv.drm_dd_major++;
-	ret = ioctl(fd, DRM_IOCTL_SET_VERSION, &sv);
-	assert(ret == -1 && errno == EINVAL);
-
-	/* Check that an invalid DD minor fails */
-	sv = version;
-	sv.drm_dd_minor++;
-	ret = ioctl(fd, DRM_IOCTL_SET_VERSION, &sv);
-	assert(ret == -1 && errno == EINVAL);
-
-	close(fd);
-	return 0;
-}
diff --git a/tests/updatedraw.c b/tests/updatedraw.c
deleted file mode 100644
index d01fa96..0000000
--- a/tests/updatedraw.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright © 2007 Intel Corporation
- *
- * 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.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *
- */
-
-#include <sys/ioctl.h>
-#include "drmtest.h"
-
-static void
-set_draw_cliprects_empty(int fd, int drawable)
-{
-	int ret;
-	struct drm_update_draw update;
-
-	update.handle = drawable;
-	update.type = DRM_DRAWABLE_CLIPRECTS;
-	update.num = 0;
-	update.data = 0;
-
-	ret = ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update);
-	assert(ret == 0);
-}
-
-static void
-set_draw_cliprects_empty_fail(int fd, int drawable)
-{
-	int ret;
-	struct drm_update_draw update;
-
-	update.handle = drawable;
-	update.type = DRM_DRAWABLE_CLIPRECTS;
-	update.num = 0;
-	update.data = 0;
-
-	ret = ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update);
-	assert(ret == -1 && errno == EINVAL);
-}
-
-static void
-set_draw_cliprects_2(int fd, int drawable)
-{
-	int ret;
-	struct drm_update_draw update;
-	drm_clip_rect_t rects[2];
-
-	rects[0].x1 = 0;
-	rects[0].y1 = 0;
-	rects[0].x2 = 10;
-	rects[0].y2 = 10;
-
-	rects[1].x1 = 10;
-	rects[1].y1 = 10;
-	rects[1].x2 = 20;
-	rects[1].y2 = 20;
-
-	update.handle = drawable;
-	update.type = DRM_DRAWABLE_CLIPRECTS;
-	update.num = 2;
-	update.data = (unsigned long long)(uintptr_t)&rects;
-
-	ret = ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update);
-	assert(ret == 0);
-}
-
-static int add_drawable(int fd)
-{
-	drm_draw_t drawarg;
-	int ret;
-
-	/* Create a drawable.
-	 * IOCTL_ADD_DRAW is RDWR, though it should really just be RD
-	 */
-	drawarg.handle = 0;
-	ret = ioctl(fd, DRM_IOCTL_ADD_DRAW, &drawarg);
-	assert(ret == 0);
-	return drawarg.handle;
-}
-
-static int rm_drawable(int fd, int drawable, int fail)
-{
-	drm_draw_t drawarg;
-	int ret;
-
-	/* Create a drawable.
-	 * IOCTL_ADD_DRAW is RDWR, though it should really just be RD
-	 */
-	drawarg.handle = drawable;
-	ret = ioctl(fd, DRM_IOCTL_RM_DRAW, &drawarg);
-	if (!fail)
-		assert(ret == 0);
-	else
-		assert(ret == -1 && errno == EINVAL);
-
-	return drawarg.handle;
-}
-
-/**
- * Tests drawable management: adding, removing, and updating the cliprects of
- * drawables.
- */
-int main(int argc, char **argv)
-{
-	int fd, d1, d2;
-
-	if (getuid() != 0) {
-		fprintf(stderr, "updatedraw test requires root, skipping\n");
-		return 0;
-	}
-
-	fd = drm_open_any_master();
-
-	d1 = add_drawable(fd);
-	d2 = add_drawable(fd);
-	/* Do a series of cliprect updates */
-	set_draw_cliprects_empty(fd, d1);
-	set_draw_cliprects_empty(fd, d2);
-	set_draw_cliprects_2(fd, d1);
-	set_draw_cliprects_empty(fd, d1);
-
-	/* Remove our drawables */
-	rm_drawable(fd, d1, 0);
-	rm_drawable(fd, d2, 0);
-
-	/* Check that removing an unknown drawable returns error */
-	rm_drawable(fd, 0x7fffffff, 1);
-
-	/* Attempt to set cliprects on a nonexistent drawable */
-	set_draw_cliprects_empty_fail(fd, d1);
-
-	close(fd);
-	return 0;
-}
diff --git a/tests/util/Android.mk b/tests/util/Android.mk
index a78341f..7656c4c 100644
--- a/tests/util/Android.mk
+++ b/tests/util/Android.mk
@@ -27,13 +27,10 @@
 include $(LOCAL_PATH)/Makefile.sources
 
 LOCAL_MODULE := libdrm_util
-LOCAL_MODULE_TAGS := optional
 
 LOCAL_SHARED_LIBRARIES := libdrm
 
-LOCAL_SRC_FILES := $(filter-out %.h,$(UTIL_FILES))
+LOCAL_SRC_FILES := $(UTIL_FILES)
 
-# avoid name clashes by requiring users to include util/*.h
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(dir $(LOCAL_PATH))
-
+include $(LIBDRM_COMMON_MK)
 include $(BUILD_STATIC_LIBRARY)
diff --git a/tests/util/kms.c b/tests/util/kms.c
index 57b0191..959b688 100644
--- a/tests/util/kms.c
+++ b/tests/util/kms.c
@@ -127,6 +127,7 @@
 
 static const char * const modules[] = {
 	"i915",
+	"amdgpu",
 	"radeon",
 	"nouveau",
 	"vmwgfx",
@@ -139,6 +140,11 @@
 	"imx-drm",
 	"rockchip",
 	"atmel-hlcdc",
+	"fsl-dcu-drm",
+	"vc4",
+	"virtio_gpu",
+	"mediatek",
+	"meson",
 };
 
 int util_open(const char *device, const char *module)
diff --git a/tests/vbltest/vbltest.c b/tests/vbltest/vbltest.c
index 1833321..3f6b803 100644
--- a/tests/vbltest/vbltest.c
+++ b/tests/vbltest/vbltest.c
@@ -35,8 +35,11 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/time.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
 
 #include "xf86drm.h"
 #include "xf86drmMode.h"
@@ -120,7 +123,7 @@
 		}
 	}
 
-	fd = util_open(module, device);
+	fd = util_open(device, module);
 	if (fd < 0)
 		return 1;
 
diff --git a/util_double_list.h b/util_double_list.h
index 27e0761..7e48b26 100644
--- a/util_double_list.h
+++ b/util_double_list.h
@@ -98,13 +98,19 @@
 #define LIST_ENTRY(__type, __item, __field)   \
     ((__type *)(((char *)(__item)) - offsetof(__type, __field)))
 
+#define LIST_FIRST_ENTRY(__ptr, __type, __field)   \
+    LIST_ENTRY(__type, (__ptr)->next, __field)
+
+#define LIST_LAST_ENTRY(__ptr, __type, __field)   \
+    LIST_ENTRY(__type, (__ptr)->prev, __field)
+
 #define LIST_IS_EMPTY(__list)                   \
     ((__list)->next == (__list))
 
 #ifndef container_of
 #define container_of(ptr, sample, member)				\
     (void *)((char *)(ptr)						\
-	     - ((char *)&(sample)->member - (char *)(sample)))
+	     - ((char *)&((typeof(sample))0)->member))
 #endif
 
 #define LIST_FOR_EACH_ENTRY(pos, head, member)				\
diff --git a/vc4/Makefile.am b/vc4/Makefile.am
new file mode 100644
index 0000000..7e486b4
--- /dev/null
+++ b/vc4/Makefile.am
@@ -0,0 +1,34 @@
+# Copyright © 2016 Broadcom
+#
+# 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 Makefile.sources
+
+AM_CFLAGS = \
+	$(WARN_CFLAGS) \
+	-I$(top_srcdir) \
+	$(PTHREADSTUBS_CFLAGS) \
+	$(VALGRIND_CFLAGS) \
+	-I$(top_srcdir)/include/drm
+
+libdrm_vc4includedir = ${includedir}/libdrm
+libdrm_vc4include_HEADERS = $(LIBDRM_VC4_H_FILES)
+
+pkgconfig_DATA = libdrm_vc4.pc
diff --git a/vc4/Makefile.sources b/vc4/Makefile.sources
new file mode 100644
index 0000000..8bf97ff
--- /dev/null
+++ b/vc4/Makefile.sources
@@ -0,0 +1,3 @@
+LIBDRM_VC4_H_FILES := \
+	vc4_packet.h \
+	vc4_qpu_defines.h
diff --git a/vc4/libdrm_vc4.pc.in b/vc4/libdrm_vc4.pc.in
new file mode 100644
index 0000000..a92678e
--- /dev/null
+++ b/vc4/libdrm_vc4.pc.in
@@ -0,0 +1,9 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdrm_vc4
+Description: Userspace interface to vc4 kernel DRM services
+Version: @PACKAGE_VERSION@
+Requires.private: libdrm
diff --git a/vc4/vc4_packet.h b/vc4/vc4_packet.h
new file mode 100644
index 0000000..e18e0bd
--- /dev/null
+++ b/vc4/vc4_packet.h
@@ -0,0 +1,397 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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 VC4_PACKET_H
+#define VC4_PACKET_H
+
+enum vc4_packet {
+        VC4_PACKET_HALT = 0,
+        VC4_PACKET_NOP = 1,
+
+        VC4_PACKET_FLUSH = 4,
+        VC4_PACKET_FLUSH_ALL = 5,
+        VC4_PACKET_START_TILE_BINNING = 6,
+        VC4_PACKET_INCREMENT_SEMAPHORE = 7,
+        VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
+
+        VC4_PACKET_BRANCH = 16,
+        VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
+        VC4_PACKET_RETURN_FROM_SUB_LIST = 18,
+
+        VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
+        VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
+        VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
+        VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
+        VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
+        VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
+
+        VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
+        VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
+
+        VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
+        VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
+
+        VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
+
+        VC4_PACKET_GL_SHADER_STATE = 64,
+        VC4_PACKET_NV_SHADER_STATE = 65,
+        VC4_PACKET_VG_SHADER_STATE = 66,
+
+        VC4_PACKET_CONFIGURATION_BITS = 96,
+        VC4_PACKET_FLAT_SHADE_FLAGS = 97,
+        VC4_PACKET_POINT_SIZE = 98,
+        VC4_PACKET_LINE_WIDTH = 99,
+        VC4_PACKET_RHT_X_BOUNDARY = 100,
+        VC4_PACKET_DEPTH_OFFSET = 101,
+        VC4_PACKET_CLIP_WINDOW = 102,
+        VC4_PACKET_VIEWPORT_OFFSET = 103,
+        VC4_PACKET_Z_CLIPPING = 104,
+        VC4_PACKET_CLIPPER_XY_SCALING = 105,
+        VC4_PACKET_CLIPPER_Z_SCALING = 106,
+
+        VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
+        VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
+        VC4_PACKET_CLEAR_COLORS = 114,
+        VC4_PACKET_TILE_COORDINATES = 115,
+
+        /* Not an actual hardware packet -- this is what we use to put
+         * references to GEM bos in the command stream, since we need the u32
+         * int the actual address packet in order to store the offset from the
+         * start of the BO.
+         */
+        VC4_PACKET_GEM_HANDLES = 254,
+} __attribute__ ((__packed__));
+
+#define VC4_PACKET_HALT_SIZE						1
+#define VC4_PACKET_NOP_SIZE						1
+#define VC4_PACKET_FLUSH_SIZE						1
+#define VC4_PACKET_FLUSH_ALL_SIZE					1
+#define VC4_PACKET_START_TILE_BINNING_SIZE				1
+#define VC4_PACKET_INCREMENT_SEMAPHORE_SIZE				1
+#define VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE				1
+#define VC4_PACKET_BRANCH_SIZE						5
+#define VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE				5
+#define VC4_PACKET_RETURN_FROM_SUB_LIST_SIZE				1
+#define VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE				1
+#define VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF_SIZE			1
+#define VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE			5
+#define VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE			5
+#define VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE			7
+#define VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE			7
+#define VC4_PACKET_GL_INDEXED_PRIMITIVE_SIZE				14
+#define VC4_PACKET_GL_ARRAY_PRIMITIVE_SIZE				10
+#define VC4_PACKET_COMPRESSED_PRIMITIVE_SIZE				1
+#define VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE_SIZE			1
+#define VC4_PACKET_PRIMITIVE_LIST_FORMAT_SIZE				2
+#define VC4_PACKET_GL_SHADER_STATE_SIZE					5
+#define VC4_PACKET_NV_SHADER_STATE_SIZE					5
+#define VC4_PACKET_VG_SHADER_STATE_SIZE					5
+#define VC4_PACKET_CONFIGURATION_BITS_SIZE				4
+#define VC4_PACKET_FLAT_SHADE_FLAGS_SIZE				5
+#define VC4_PACKET_POINT_SIZE_SIZE					5
+#define VC4_PACKET_LINE_WIDTH_SIZE					5
+#define VC4_PACKET_RHT_X_BOUNDARY_SIZE					3
+#define VC4_PACKET_DEPTH_OFFSET_SIZE					5
+#define VC4_PACKET_CLIP_WINDOW_SIZE					9
+#define VC4_PACKET_VIEWPORT_OFFSET_SIZE					5
+#define VC4_PACKET_Z_CLIPPING_SIZE					9
+#define VC4_PACKET_CLIPPER_XY_SCALING_SIZE				9
+#define VC4_PACKET_CLIPPER_Z_SCALING_SIZE				9
+#define VC4_PACKET_TILE_BINNING_MODE_CONFIG_SIZE			16
+#define VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE			11
+#define VC4_PACKET_CLEAR_COLORS_SIZE					14
+#define VC4_PACKET_TILE_COORDINATES_SIZE				3
+#define VC4_PACKET_GEM_HANDLES_SIZE					9
+
+#define VC4_MASK(high, low) (((1 << ((high) - (low) + 1)) - 1) << (low))
+/* Using the GNU statement expression extension */
+#define VC4_SET_FIELD(value, field)                                       \
+        ({                                                                \
+                uint32_t fieldval = (value) << field ## _SHIFT;		  \
+                assert((fieldval & ~ field ## _MASK) == 0);               \
+                fieldval & field ## _MASK;                                \
+         })
+
+#define VC4_GET_FIELD(word, field) (((word)  & field ## _MASK) >> field ## _SHIFT)
+
+/** @{
+ * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_TILE_RENDERING_MODE_CONFIG.
+*/
+#define VC4_TILING_FORMAT_LINEAR    0
+#define VC4_TILING_FORMAT_T         1
+#define VC4_TILING_FORMAT_LT        2
+/** @} */
+
+/** @{
+ *
+ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
+ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
+ */
+#define VC4_LOADSTORE_FULL_RES_EOF                     (1 << 3)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL       (1 << 2)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS              (1 << 1)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR           (1 << 0)
+
+/** @{
+ *
+ * byte 2 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address)
+ */
+
+#define VC4_LOADSTORE_TILE_BUFFER_EOF                  (1 << 3)
+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK (1 << 2)
+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS      (1 << 1)
+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR   (1 << 0)
+
+/** @} */
+
+/** @{
+ *
+ * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
+ */
+#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR (1 << 15)
+#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR     (1 << 14)
+#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR  (1 << 13)
+#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP         (1 << 12)
+
+#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK      VC4_MASK(9, 8)
+#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT     8
+#define VC4_LOADSTORE_TILE_BUFFER_RGBA8888         0
+#define VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER    1
+#define VC4_LOADSTORE_TILE_BUFFER_BGR565           2
+/** @} */
+
+/** @{
+ *
+ * byte 0 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
+ */
+#define VC4_STORE_TILE_BUFFER_MODE_MASK            VC4_MASK(7, 6)
+#define VC4_STORE_TILE_BUFFER_MODE_SHIFT           6
+#define VC4_STORE_TILE_BUFFER_MODE_SAMPLE0         (0 << 6)
+#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X4     (1 << 6)
+#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X16    (2 << 6)
+
+/** The values of the field are VC4_TILING_FORMAT_* */
+#define VC4_LOADSTORE_TILE_BUFFER_TILING_MASK      VC4_MASK(5, 4)
+#define VC4_LOADSTORE_TILE_BUFFER_TILING_SHIFT     4
+
+#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK      VC4_MASK(2, 0)
+#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_SHIFT     0
+#define VC4_LOADSTORE_TILE_BUFFER_NONE             0
+#define VC4_LOADSTORE_TILE_BUFFER_COLOR            1
+#define VC4_LOADSTORE_TILE_BUFFER_ZS               2
+#define VC4_LOADSTORE_TILE_BUFFER_Z                3
+#define VC4_LOADSTORE_TILE_BUFFER_VG_MASK          4
+#define VC4_LOADSTORE_TILE_BUFFER_FULL             5
+/** @} */
+
+#define VC4_INDEX_BUFFER_U8                        (0 << 4)
+#define VC4_INDEX_BUFFER_U16                       (1 << 4)
+
+/* This flag is only present in NV shader state. */
+#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS         (1 << 3)
+#define VC4_SHADER_FLAG_ENABLE_CLIPPING            (1 << 2)
+#define VC4_SHADER_FLAG_VS_POINT_SIZE              (1 << 1)
+#define VC4_SHADER_FLAG_FS_SINGLE_THREAD           (1 << 0)
+
+/** @{ byte 2 of config bits. */
+#define VC4_CONFIG_BITS_EARLY_Z_UPDATE             (1 << 1)
+#define VC4_CONFIG_BITS_EARLY_Z                    (1 << 0)
+/** @} */
+
+/** @{ byte 1 of config bits. */
+#define VC4_CONFIG_BITS_Z_UPDATE                   (1 << 7)
+/** same values in this 3-bit field as PIPE_FUNC_* */
+#define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT           4
+#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE        (1 << 3)
+
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO    (0 << 1)
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD        (1 << 1)
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR         (2 << 1)
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO       (3 << 1)
+
+#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT       (1 << 0)
+/** @} */
+
+/** @{ byte 0 of config bits. */
+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_NONE (0 << 6)
+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X   (1 << 6)
+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X  (2 << 6)
+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_MASK (3 << 6)
+
+#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES        (1 << 4)
+#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET        (1 << 3)
+#define VC4_CONFIG_BITS_CW_PRIMITIVES              (1 << 2)
+#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK           (1 << 1)
+#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT          (1 << 0)
+/** @} */
+
+/** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */
+#define VC4_BIN_CONFIG_DB_NON_MS                   (1 << 7)
+
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK       VC4_MASK(6, 5)
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT      5
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32         0
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_64         1
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128        2
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_256        3
+
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK  VC4_MASK(4, 3)
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_SHIFT 3
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32    0
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64    1
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128   2
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256   3
+
+#define VC4_BIN_CONFIG_AUTO_INIT_TSDA              (1 << 2)
+#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT           (1 << 1)
+#define VC4_BIN_CONFIG_MS_MODE_4X                  (1 << 0)
+/** @} */
+
+/** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */
+#define VC4_RENDER_CONFIG_DB_NON_MS                (1 << 12)
+#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE (1 << 11)
+#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G      (1 << 10)
+#define VC4_RENDER_CONFIG_COVERAGE_MODE            (1 << 9)
+#define VC4_RENDER_CONFIG_ENABLE_VG_MASK           (1 << 8)
+
+/** The values of the field are VC4_TILING_FORMAT_* */
+#define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK       VC4_MASK(7, 6)
+#define VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT      6
+
+#define VC4_RENDER_CONFIG_DECIMATE_MODE_1X         (0 << 4)
+#define VC4_RENDER_CONFIG_DECIMATE_MODE_4X         (1 << 4)
+#define VC4_RENDER_CONFIG_DECIMATE_MODE_16X        (2 << 4)
+#define VC4_RENDER_CONFIG_DECIMATE_MODE_MASK       (3 << 4)
+
+#define VC4_RENDER_CONFIG_FORMAT_MASK              VC4_MASK(3, 2)
+#define VC4_RENDER_CONFIG_FORMAT_SHIFT             2
+#define VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED   0
+#define VC4_RENDER_CONFIG_FORMAT_RGBA8888          1
+#define VC4_RENDER_CONFIG_FORMAT_BGR565            2
+
+#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT        (1 << 1)
+#define VC4_RENDER_CONFIG_MS_MODE_4X               (1 << 0)
+
+#define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX         (1 << 4)
+#define VC4_PRIMITIVE_LIST_FORMAT_32_XY            (3 << 4)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_POINTS      (0 << 0)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_LINES       (1 << 0)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_TRIANGLES   (2 << 0)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT         (3 << 0)
+
+enum vc4_texture_data_type {
+        VC4_TEXTURE_TYPE_RGBA8888 = 0,
+        VC4_TEXTURE_TYPE_RGBX8888 = 1,
+        VC4_TEXTURE_TYPE_RGBA4444 = 2,
+        VC4_TEXTURE_TYPE_RGBA5551 = 3,
+        VC4_TEXTURE_TYPE_RGB565 = 4,
+        VC4_TEXTURE_TYPE_LUMINANCE = 5,
+        VC4_TEXTURE_TYPE_ALPHA = 6,
+        VC4_TEXTURE_TYPE_LUMALPHA = 7,
+        VC4_TEXTURE_TYPE_ETC1 = 8,
+        VC4_TEXTURE_TYPE_S16F = 9,
+        VC4_TEXTURE_TYPE_S8 = 10,
+        VC4_TEXTURE_TYPE_S16 = 11,
+        VC4_TEXTURE_TYPE_BW1 = 12,
+        VC4_TEXTURE_TYPE_A4 = 13,
+        VC4_TEXTURE_TYPE_A1 = 14,
+        VC4_TEXTURE_TYPE_RGBA64 = 15,
+        VC4_TEXTURE_TYPE_RGBA32R = 16,
+        VC4_TEXTURE_TYPE_YUV422R = 17,
+};
+
+#define VC4_TEX_P0_OFFSET_MASK                     VC4_MASK(31, 12)
+#define VC4_TEX_P0_OFFSET_SHIFT                    12
+#define VC4_TEX_P0_CSWIZ_MASK                      VC4_MASK(11, 10)
+#define VC4_TEX_P0_CSWIZ_SHIFT                     10
+#define VC4_TEX_P0_CMMODE_MASK                     VC4_MASK(9, 9)
+#define VC4_TEX_P0_CMMODE_SHIFT                    9
+#define VC4_TEX_P0_FLIPY_MASK                      VC4_MASK(8, 8)
+#define VC4_TEX_P0_FLIPY_SHIFT                     8
+#define VC4_TEX_P0_TYPE_MASK                       VC4_MASK(7, 4)
+#define VC4_TEX_P0_TYPE_SHIFT                      4
+#define VC4_TEX_P0_MIPLVLS_MASK                    VC4_MASK(3, 0)
+#define VC4_TEX_P0_MIPLVLS_SHIFT                   0
+
+#define VC4_TEX_P1_TYPE4_MASK                      VC4_MASK(31, 31)
+#define VC4_TEX_P1_TYPE4_SHIFT                     31
+#define VC4_TEX_P1_HEIGHT_MASK                     VC4_MASK(30, 20)
+#define VC4_TEX_P1_HEIGHT_SHIFT                    20
+#define VC4_TEX_P1_ETCFLIP_MASK                    VC4_MASK(19, 19)
+#define VC4_TEX_P1_ETCFLIP_SHIFT                   19
+#define VC4_TEX_P1_WIDTH_MASK                      VC4_MASK(18, 8)
+#define VC4_TEX_P1_WIDTH_SHIFT                     8
+
+#define VC4_TEX_P1_MAGFILT_MASK                    VC4_MASK(7, 7)
+#define VC4_TEX_P1_MAGFILT_SHIFT                   7
+# define VC4_TEX_P1_MAGFILT_LINEAR                 0
+# define VC4_TEX_P1_MAGFILT_NEAREST                1
+
+#define VC4_TEX_P1_MINFILT_MASK                    VC4_MASK(6, 4)
+#define VC4_TEX_P1_MINFILT_SHIFT                   4
+# define VC4_TEX_P1_MINFILT_LINEAR                 0
+# define VC4_TEX_P1_MINFILT_NEAREST                1
+# define VC4_TEX_P1_MINFILT_NEAR_MIP_NEAR          2
+# define VC4_TEX_P1_MINFILT_NEAR_MIP_LIN           3
+# define VC4_TEX_P1_MINFILT_LIN_MIP_NEAR           4
+# define VC4_TEX_P1_MINFILT_LIN_MIP_LIN            5
+
+#define VC4_TEX_P1_WRAP_T_MASK                     VC4_MASK(3, 2)
+#define VC4_TEX_P1_WRAP_T_SHIFT                    2
+#define VC4_TEX_P1_WRAP_S_MASK                     VC4_MASK(1, 0)
+#define VC4_TEX_P1_WRAP_S_SHIFT                    0
+# define VC4_TEX_P1_WRAP_REPEAT                    0
+# define VC4_TEX_P1_WRAP_CLAMP                     1
+# define VC4_TEX_P1_WRAP_MIRROR                    2
+# define VC4_TEX_P1_WRAP_BORDER                    3
+
+#define VC4_TEX_P2_PTYPE_MASK                      VC4_MASK(31, 30)
+#define VC4_TEX_P2_PTYPE_SHIFT                     30
+# define VC4_TEX_P2_PTYPE_IGNORED                  0
+# define VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE          1
+# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS   2
+# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS      3
+
+/* VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE bits */
+#define VC4_TEX_P2_CMST_MASK                       VC4_MASK(29, 12)
+#define VC4_TEX_P2_CMST_SHIFT                      12
+#define VC4_TEX_P2_BSLOD_MASK                      VC4_MASK(0, 0)
+#define VC4_TEX_P2_BSLOD_SHIFT                     0
+
+/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS */
+#define VC4_TEX_P2_CHEIGHT_MASK                    VC4_MASK(22, 12)
+#define VC4_TEX_P2_CHEIGHT_SHIFT                   12
+#define VC4_TEX_P2_CWIDTH_MASK                     VC4_MASK(10, 0)
+#define VC4_TEX_P2_CWIDTH_SHIFT                    0
+
+/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS */
+#define VC4_TEX_P2_CYOFF_MASK                      VC4_MASK(22, 12)
+#define VC4_TEX_P2_CYOFF_SHIFT                     12
+#define VC4_TEX_P2_CXOFF_MASK                      VC4_MASK(10, 0)
+#define VC4_TEX_P2_CXOFF_SHIFT                     0
+
+#endif /* VC4_PACKET_H */
diff --git a/vc4/vc4_qpu_defines.h b/vc4/vc4_qpu_defines.h
new file mode 100644
index 0000000..26fcf50
--- /dev/null
+++ b/vc4/vc4_qpu_defines.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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 VC4_QPU_DEFINES_H
+#define VC4_QPU_DEFINES_H
+
+enum qpu_op_add {
+        QPU_A_NOP,
+        QPU_A_FADD,
+        QPU_A_FSUB,
+        QPU_A_FMIN,
+        QPU_A_FMAX,
+        QPU_A_FMINABS,
+        QPU_A_FMAXABS,
+        QPU_A_FTOI,
+        QPU_A_ITOF,
+        QPU_A_ADD = 12,
+        QPU_A_SUB,
+        QPU_A_SHR,
+        QPU_A_ASR,
+        QPU_A_ROR,
+        QPU_A_SHL,
+        QPU_A_MIN,
+        QPU_A_MAX,
+        QPU_A_AND,
+        QPU_A_OR,
+        QPU_A_XOR,
+        QPU_A_NOT,
+        QPU_A_CLZ,
+        QPU_A_V8ADDS = 30,
+        QPU_A_V8SUBS = 31,
+};
+
+enum qpu_op_mul {
+        QPU_M_NOP,
+        QPU_M_FMUL,
+        QPU_M_MUL24,
+        QPU_M_V8MULD,
+        QPU_M_V8MIN,
+        QPU_M_V8MAX,
+        QPU_M_V8ADDS,
+        QPU_M_V8SUBS,
+};
+
+enum qpu_raddr {
+        QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
+        /* 0-31 are the plain regfile a or b fields */
+        QPU_R_UNIF = 32,
+        QPU_R_VARY = 35,
+        QPU_R_ELEM_QPU = 38,
+        QPU_R_NOP,
+        QPU_R_XY_PIXEL_COORD = 41,
+        QPU_R_MS_REV_FLAGS = 42,
+        QPU_R_VPM = 48,
+        QPU_R_VPM_LD_BUSY,
+        QPU_R_VPM_LD_WAIT,
+        QPU_R_MUTEX_ACQUIRE,
+};
+
+enum qpu_waddr {
+        /* 0-31 are the plain regfile a or b fields */
+        QPU_W_ACC0 = 32, /* aka r0 */
+        QPU_W_ACC1,
+        QPU_W_ACC2,
+        QPU_W_ACC3,
+        QPU_W_TMU_NOSWAP,
+        QPU_W_ACC5,
+        QPU_W_HOST_INT,
+        QPU_W_NOP,
+        QPU_W_UNIFORMS_ADDRESS,
+        QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
+        QPU_W_MS_FLAGS = 42,
+        QPU_W_REV_FLAG = 42,
+        QPU_W_TLB_STENCIL_SETUP = 43,
+        QPU_W_TLB_Z,
+        QPU_W_TLB_COLOR_MS,
+        QPU_W_TLB_COLOR_ALL,
+        QPU_W_TLB_ALPHA_MASK,
+        QPU_W_VPM,
+        QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
+        QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
+        QPU_W_MUTEX_RELEASE,
+        QPU_W_SFU_RECIP,
+        QPU_W_SFU_RECIPSQRT,
+        QPU_W_SFU_EXP,
+        QPU_W_SFU_LOG,
+        QPU_W_TMU0_S,
+        QPU_W_TMU0_T,
+        QPU_W_TMU0_R,
+        QPU_W_TMU0_B,
+        QPU_W_TMU1_S,
+        QPU_W_TMU1_T,
+        QPU_W_TMU1_R,
+        QPU_W_TMU1_B,
+};
+
+enum qpu_sig_bits {
+        QPU_SIG_SW_BREAKPOINT,
+        QPU_SIG_NONE,
+        QPU_SIG_THREAD_SWITCH,
+        QPU_SIG_PROG_END,
+        QPU_SIG_WAIT_FOR_SCOREBOARD,
+        QPU_SIG_SCOREBOARD_UNLOCK,
+        QPU_SIG_LAST_THREAD_SWITCH,
+        QPU_SIG_COVERAGE_LOAD,
+        QPU_SIG_COLOR_LOAD,
+        QPU_SIG_COLOR_LOAD_END,
+        QPU_SIG_LOAD_TMU0,
+        QPU_SIG_LOAD_TMU1,
+        QPU_SIG_ALPHA_MASK_LOAD,
+        QPU_SIG_SMALL_IMM,
+        QPU_SIG_LOAD_IMM,
+        QPU_SIG_BRANCH
+};
+
+enum qpu_mux {
+        /* hardware mux values */
+        QPU_MUX_R0,
+        QPU_MUX_R1,
+        QPU_MUX_R2,
+        QPU_MUX_R3,
+        QPU_MUX_R4,
+        QPU_MUX_R5,
+        QPU_MUX_A,
+        QPU_MUX_B,
+
+        /**
+         * Non-hardware mux value, stores a small immediate field to be
+         * programmed into raddr_b in the qpu_reg.index.
+         */
+        QPU_MUX_SMALL_IMM,
+};
+
+enum qpu_cond {
+        QPU_COND_NEVER,
+        QPU_COND_ALWAYS,
+        QPU_COND_ZS,
+        QPU_COND_ZC,
+        QPU_COND_NS,
+        QPU_COND_NC,
+        QPU_COND_CS,
+        QPU_COND_CC,
+};
+
+enum qpu_pack_mul {
+        QPU_PACK_MUL_NOP,
+        QPU_PACK_MUL_8888 = 3, /* replicated to each 8 bits of the 32-bit dst. */
+        QPU_PACK_MUL_8A,
+        QPU_PACK_MUL_8B,
+        QPU_PACK_MUL_8C,
+        QPU_PACK_MUL_8D,
+};
+
+enum qpu_pack_a {
+        QPU_PACK_A_NOP,
+        /* convert to 16 bit float if float input, or to int16. */
+        QPU_PACK_A_16A,
+        QPU_PACK_A_16B,
+        /* replicated to each 8 bits of the 32-bit dst. */
+        QPU_PACK_A_8888,
+        /* Convert to 8-bit unsigned int. */
+        QPU_PACK_A_8A,
+        QPU_PACK_A_8B,
+        QPU_PACK_A_8C,
+        QPU_PACK_A_8D,
+
+        /* Saturating variants of the previous instructions. */
+        QPU_PACK_A_32_SAT, /* int-only */
+        QPU_PACK_A_16A_SAT, /* int or float */
+        QPU_PACK_A_16B_SAT,
+        QPU_PACK_A_8888_SAT,
+        QPU_PACK_A_8A_SAT,
+        QPU_PACK_A_8B_SAT,
+        QPU_PACK_A_8C_SAT,
+        QPU_PACK_A_8D_SAT,
+};
+
+enum qpu_unpack {
+        QPU_UNPACK_NOP,
+        QPU_UNPACK_16A,
+        QPU_UNPACK_16B,
+        QPU_UNPACK_8D_REP,
+        QPU_UNPACK_8A,
+        QPU_UNPACK_8B,
+        QPU_UNPACK_8C,
+        QPU_UNPACK_8D,
+};
+
+#define QPU_MASK(high, low) ((((uint64_t)1<<((high)-(low)+1))-1)<<(low))
+/* Using the GNU statement expression extension */
+#define QPU_SET_FIELD(value, field)                                       \
+        ({                                                                \
+                uint64_t fieldval = (uint64_t)(value) << field ## _SHIFT; \
+                assert((fieldval & ~ field ## _MASK) == 0);               \
+                fieldval & field ## _MASK;                                \
+         })
+
+#define QPU_GET_FIELD(word, field) ((uint32_t)(((word)  & field ## _MASK) >> field ## _SHIFT))
+
+#define QPU_UPDATE_FIELD(inst, value, field)                              \
+        (((inst) & ~(field ## _MASK)) | QPU_SET_FIELD(value, field))
+
+#define QPU_SIG_SHIFT                   60
+#define QPU_SIG_MASK                    QPU_MASK(63, 60)
+
+#define QPU_UNPACK_SHIFT                57
+#define QPU_UNPACK_MASK                 QPU_MASK(59, 57)
+
+/**
+ * If set, the pack field means PACK_MUL or R4 packing, instead of normal
+ * regfile a packing.
+ */
+#define QPU_PM                          ((uint64_t)1 << 56)
+
+#define QPU_PACK_SHIFT                  52
+#define QPU_PACK_MASK                   QPU_MASK(55, 52)
+
+#define QPU_COND_ADD_SHIFT              49
+#define QPU_COND_ADD_MASK               QPU_MASK(51, 49)
+#define QPU_COND_MUL_SHIFT              46
+#define QPU_COND_MUL_MASK               QPU_MASK(48, 46)
+
+#define QPU_SF                          ((uint64_t)1 << 45)
+
+#define QPU_WADDR_ADD_SHIFT             38
+#define QPU_WADDR_ADD_MASK              QPU_MASK(43, 38)
+#define QPU_WADDR_MUL_SHIFT             32
+#define QPU_WADDR_MUL_MASK              QPU_MASK(37, 32)
+
+#define QPU_OP_MUL_SHIFT                29
+#define QPU_OP_MUL_MASK                 QPU_MASK(31, 29)
+
+#define QPU_RADDR_A_SHIFT               18
+#define QPU_RADDR_A_MASK                QPU_MASK(23, 18)
+#define QPU_RADDR_B_SHIFT               12
+#define QPU_RADDR_B_MASK                QPU_MASK(17, 12)
+#define QPU_SMALL_IMM_SHIFT             12
+#define QPU_SMALL_IMM_MASK              QPU_MASK(17, 12)
+
+#define QPU_ADD_A_SHIFT                 9
+#define QPU_ADD_A_MASK                  QPU_MASK(11, 9)
+#define QPU_ADD_B_SHIFT                 6
+#define QPU_ADD_B_MASK                  QPU_MASK(8, 6)
+#define QPU_MUL_A_SHIFT                 3
+#define QPU_MUL_A_MASK                  QPU_MASK(5, 3)
+#define QPU_MUL_B_SHIFT                 0
+#define QPU_MUL_B_MASK                  QPU_MASK(2, 0)
+
+#define QPU_WS                          ((uint64_t)1 << 44)
+
+#define QPU_OP_ADD_SHIFT                24
+#define QPU_OP_ADD_MASK                 QPU_MASK(28, 24)
+
+#endif /* VC4_QPU_DEFINES_H */
diff --git a/xf86drm.c b/xf86drm.c
index 7e28b4f..88f86ed 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -1,5 +1,5 @@
 /**
- * \file xf86drm.c 
+ * \file xf86drm.c
  * User-level interface to DRM device
  *
  * \author Rickard E. (Rik) Faith <faith@valinux.com>
@@ -54,8 +54,11 @@
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <stdarg.h>
-#ifdef HAVE_SYS_MKDEV_H
-# include <sys/mkdev.h> /* defines major(), minor(), and makedev() on Solaris */
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
 #endif
 #include <math.h>
 
@@ -70,13 +73,13 @@
 #include "util_math.h"
 
 #ifdef __OpenBSD__
-#define DRM_PRIMARY_MINOR_NAME	"drm"
-#define DRM_CONTROL_MINOR_NAME	"drmC"
-#define DRM_RENDER_MINOR_NAME	"drmR"
+#define DRM_PRIMARY_MINOR_NAME  "drm"
+#define DRM_CONTROL_MINOR_NAME  "drmC"
+#define DRM_RENDER_MINOR_NAME   "drmR"
 #else
-#define DRM_PRIMARY_MINOR_NAME	"card"
-#define DRM_CONTROL_MINOR_NAME	"controlD"
-#define DRM_RENDER_MINOR_NAME	"renderD"
+#define DRM_PRIMARY_MINOR_NAME  "card"
+#define DRM_CONTROL_MINOR_NAME  "controlD"
+#define DRM_RENDER_MINOR_NAME   "renderD"
 #endif
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
@@ -96,7 +99,23 @@
 #endif /* __OpenBSD__ */
 
 #ifndef DRM_MAJOR
-#define DRM_MAJOR 226		/* Linux */
+#define DRM_MAJOR 226 /* Linux */
+#endif
+
+#ifdef __OpenBSD__
+struct drm_pciinfo {
+	uint16_t	domain;
+	uint8_t		bus;
+	uint8_t		dev;
+	uint8_t		func;
+	uint16_t	vendor_id;
+	uint16_t	device_id;
+	uint16_t	subvendor_id;
+	uint16_t	subdevice_id;
+	uint8_t		revision_id;
+};
+
+#define DRM_IOCTL_GET_PCIINFO	DRM_IOR(0x15, struct drm_pciinfo)
 #endif
 
 #define DRM_MSG_VERBOSITY 3
@@ -128,18 +147,18 @@
 void
 drmMsg(const char *format, ...)
 {
-    va_list	ap;
+    va_list ap;
     const char *env;
     if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
         (drm_server_info && drm_server_info->debug_print))
     {
-	va_start(ap, format);
-	if (drm_server_info) {
-	  drm_server_info->debug_print(format,ap);
-	} else {
-	  drmDebugPrint(format, ap);
-	}
-	va_end(ap);
+        va_start(ap, format);
+        if (drm_server_info) {
+            drm_server_info->debug_print(format,ap);
+        } else {
+            drmDebugPrint(format, ap);
+        }
+        va_end(ap);
     }
 }
 
@@ -166,10 +185,10 @@
 int
 drmIoctl(int fd, unsigned long request, void *arg)
 {
-    int	ret;
+    int ret;
 
     do {
-	ret = ioctl(fd, request, arg);
+        ret = ioctl(fd, request, arg);
     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
     return ret;
 }
@@ -190,16 +209,16 @@
     drmHashEntry  *entry;
 
     if (!drmHashTable)
-	drmHashTable = drmHashCreate();
+        drmHashTable = drmHashCreate();
 
     if (drmHashLookup(drmHashTable, key, &value)) {
-	entry           = drmMalloc(sizeof(*entry));
-	entry->fd       = fd;
-	entry->f        = NULL;
-	entry->tagTable = drmHashCreate();
-	drmHashInsert(drmHashTable, key, entry);
+        entry           = drmMalloc(sizeof(*entry));
+        entry->fd       = fd;
+        entry->f        = NULL;
+        entry->tagTable = drmHashCreate();
+        drmHashInsert(drmHashTable, key, entry);
     } else {
-	entry = value;
+        entry = value;
     }
     return entry;
 }
@@ -221,41 +240,41 @@
 {
     /* First, check if the IDs are exactly the same */
     if (strcasecmp(id1, id2) == 0)
-	return 1;
+        return 1;
 
     /* Try to match old/new-style PCI bus IDs. */
     if (strncasecmp(id1, "pci", 3) == 0) {
-	unsigned int o1, b1, d1, f1;
-	unsigned int o2, b2, d2, f2;
-	int ret;
+        unsigned int o1, b1, d1, f1;
+        unsigned int o2, b2, d2, f2;
+        int ret;
 
-	ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
-	if (ret != 4) {
-	    o1 = 0;
-	    ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
-	    if (ret != 3)
-		return 0;
-	}
+        ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
+        if (ret != 4) {
+            o1 = 0;
+            ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
+            if (ret != 3)
+                return 0;
+        }
 
-	ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
-	if (ret != 4) {
-	    o2 = 0;
-	    ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
-	    if (ret != 3)
-		return 0;
-	}
+        ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
+        if (ret != 4) {
+            o2 = 0;
+            ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
+            if (ret != 3)
+                return 0;
+        }
 
-	/* If domains aren't properly supported by the kernel interface,
-	 * just ignore them, which sucks less than picking a totally random
-	 * card with "open by name"
-	 */
-	if (!pci_domain_ok)
-		o1 = o2 = 0;
+        /* If domains aren't properly supported by the kernel interface,
+         * just ignore them, which sucks less than picking a totally random
+         * card with "open by name"
+         */
+        if (!pci_domain_ok)
+            o1 = o2 = 0;
 
-	if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
-	    return 0;
-	else
-	    return 1;
+        if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
+            return 0;
+        else
+            return 1;
     }
     return 0;
 }
@@ -277,18 +296,18 @@
 #if !defined(UDEV)
 static int chown_check_return(const char *path, uid_t owner, gid_t group)
 {
-	int rv;
+        int rv;
 
-	do {
-		rv = chown(path, owner, group);
-	} while (rv != 0 && errno == EINTR);
+        do {
+            rv = chown(path, owner, group);
+        } while (rv != 0 && errno == EINTR);
 
-	if (rv == 0)
-		return 0;
+        if (rv == 0)
+            return 0;
 
-	drmMsg("Failed to change owner or group for file %s! %d: %s\n",
-			path, errno, strerror(errno));
-	return -1;
+        drmMsg("Failed to change owner or group for file %s! %d: %s\n",
+               path, errno, strerror(errno));
+        return -1;
 }
 #endif
 
@@ -297,7 +316,7 @@
  *
  * \param dev major and minor numbers of the device.
  * \param minor minor number of the device.
- * 
+ *
  * \return a file descriptor on success, or a negative value on error.
  *
  * \internal
@@ -321,99 +340,99 @@
 
     switch (type) {
     case DRM_NODE_PRIMARY:
-	    dev_name = DRM_DEV_NAME;
-	    break;
+        dev_name = DRM_DEV_NAME;
+        break;
     case DRM_NODE_CONTROL:
-	    dev_name = DRM_CONTROL_DEV_NAME;
-	    break;
+        dev_name = DRM_CONTROL_DEV_NAME;
+        break;
     case DRM_NODE_RENDER:
-	    dev_name = DRM_RENDER_DEV_NAME;
-	    break;
+        dev_name = DRM_RENDER_DEV_NAME;
+        break;
     default:
-	    return -EINVAL;
+        return -EINVAL;
     };
 
     sprintf(buf, dev_name, DRM_DIR_NAME, minor);
     drmMsg("drmOpenDevice: node name is %s\n", buf);
 
     if (drm_server_info && drm_server_info->get_perms) {
-	drm_server_info->get_perms(&serv_group, &serv_mode);
-	devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
-	devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
+        drm_server_info->get_perms(&serv_group, &serv_mode);
+        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
+        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
     }
 
 #if !defined(UDEV)
     if (stat(DRM_DIR_NAME, &st)) {
-	if (!isroot)
-	    return DRM_ERR_NOT_ROOT;
-	mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
-	chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
-	chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
+        if (!isroot)
+            return DRM_ERR_NOT_ROOT;
+        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
+        chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
+        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
     }
 
     /* Check if the device node exists and create it if necessary. */
     if (stat(buf, &st)) {
-	if (!isroot)
-	    return DRM_ERR_NOT_ROOT;
-	remove(buf);
-	mknod(buf, S_IFCHR | devmode, dev);
+        if (!isroot)
+            return DRM_ERR_NOT_ROOT;
+        remove(buf);
+        mknod(buf, S_IFCHR | devmode, dev);
     }
 
     if (drm_server_info && drm_server_info->get_perms) {
-	group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
-	chown_check_return(buf, user, group);
-	chmod(buf, devmode);
+        group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
+        chown_check_return(buf, user, group);
+        chmod(buf, devmode);
     }
 #else
     /* if we modprobed then wait for udev */
     {
-	int udev_count = 0;
+        int udev_count = 0;
 wait_for_udev:
         if (stat(DRM_DIR_NAME, &st)) {
-		usleep(20);
-		udev_count++;
+            usleep(20);
+            udev_count++;
 
-		if (udev_count == 50)
-			return -1;
-		goto wait_for_udev;
-	}
+            if (udev_count == 50)
+                return -1;
+            goto wait_for_udev;
+        }
 
-    	if (stat(buf, &st)) {
-		usleep(20);
-		udev_count++;
+        if (stat(buf, &st)) {
+            usleep(20);
+            udev_count++;
 
-		if (udev_count == 50)
-			return -1;
-		goto wait_for_udev;
-    	}
+            if (udev_count == 50)
+                return -1;
+            goto wait_for_udev;
+        }
     }
 #endif
 
     fd = open(buf, O_RDWR, 0);
     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
-		fd, fd < 0 ? strerror(errno) : "OK");
+           fd, fd < 0 ? strerror(errno) : "OK");
     if (fd >= 0)
-	return fd;
+        return fd;
 
 #if !defined(UDEV)
     /* Check if the device node is not what we expect it to be, and recreate it
      * and try again if so.
      */
     if (st.st_rdev != dev) {
-	if (!isroot)
-	    return DRM_ERR_NOT_ROOT;
-	remove(buf);
-	mknod(buf, S_IFCHR | devmode, dev);
-	if (drm_server_info && drm_server_info->get_perms) {
-	    chown_check_return(buf, user, group);
-	    chmod(buf, devmode);
-	}
+        if (!isroot)
+            return DRM_ERR_NOT_ROOT;
+        remove(buf);
+        mknod(buf, S_IFCHR | devmode, dev);
+        if (drm_server_info && drm_server_info->get_perms) {
+            chown_check_return(buf, user, group);
+            chmod(buf, devmode);
+        }
     }
     fd = open(buf, O_RDWR, 0);
     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
-		fd, fd < 0 ? strerror(errno) : "OK");
+           fd, fd < 0 ? strerror(errno) : "OK");
     if (fd >= 0)
-	return fd;
+        return fd;
 
     drmMsg("drmOpenDevice: Open failed\n");
     remove(buf);
@@ -429,7 +448,7 @@
  * \param create allow to create the device if set.
  *
  * \return a file descriptor on success, or a negative value on error.
- * 
+ *
  * \internal
  * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
  * name from \p minor and opens it.
@@ -439,37 +458,37 @@
     int  fd;
     char buf[64];
     const char *dev_name;
-    
+
     if (create)
-	return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
-    
+        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
+
     switch (type) {
     case DRM_NODE_PRIMARY:
-	    dev_name = DRM_DEV_NAME;
-	    break;
+        dev_name = DRM_DEV_NAME;
+        break;
     case DRM_NODE_CONTROL:
-	    dev_name = DRM_CONTROL_DEV_NAME;
-	    break;
+        dev_name = DRM_CONTROL_DEV_NAME;
+        break;
     case DRM_NODE_RENDER:
-	    dev_name = DRM_RENDER_DEV_NAME;
-	    break;
+        dev_name = DRM_RENDER_DEV_NAME;
+        break;
     default:
-	    return -EINVAL;
+        return -EINVAL;
     };
 
     sprintf(buf, dev_name, DRM_DIR_NAME, minor);
     if ((fd = open(buf, O_RDWR, 0)) >= 0)
-	return fd;
+        return fd;
     return -errno;
 }
 
 
 /**
  * Determine whether the DRM kernel driver has been loaded.
- * 
+ *
  * \return 1 if the DRM driver is loaded, 0 otherwise.
  *
- * \internal 
+ * \internal
  * Determine the presence of the kernel driver by attempting to open the 0
  * minor and get version information.  For backward compatibility with older
  * Linux implementations, /proc/dri is also checked.
@@ -482,16 +501,16 @@
 
     if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
 #ifdef __linux__
-	/* Try proc for backward Linux compatibility */
-	if (!access("/proc/dri/0", R_OK))
-	    return 1;
+        /* Try proc for backward Linux compatibility */
+        if (!access("/proc/dri/0", R_OK))
+            return 1;
 #endif
-	return 0;
+        return 0;
     }
-    
+
     if ((version = drmGetVersion(fd))) {
-	retval = 1;
-	drmFreeVersion(version);
+        retval = 1;
+        drmFreeVersion(version);
     }
     close(fd);
 
@@ -570,37 +589,37 @@
 
     drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
     for (i = base; i < base + DRM_MAX_MINOR; i++) {
-	fd = drmOpenMinor(i, 1, type);
-	drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
-	if (fd >= 0) {
-	    /* We need to try for 1.4 first for proper PCI domain support
-	     * and if that fails, we know the kernel is busted
-	     */
-	    sv.drm_di_major = 1;
-	    sv.drm_di_minor = 4;
-	    sv.drm_dd_major = -1;	/* Don't care */
-	    sv.drm_dd_minor = -1;	/* Don't care */
-	    if (drmSetInterfaceVersion(fd, &sv)) {
+        fd = drmOpenMinor(i, 1, type);
+        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
+        if (fd >= 0) {
+            /* We need to try for 1.4 first for proper PCI domain support
+             * and if that fails, we know the kernel is busted
+             */
+            sv.drm_di_major = 1;
+            sv.drm_di_minor = 4;
+            sv.drm_dd_major = -1;        /* Don't care */
+            sv.drm_dd_minor = -1;        /* Don't care */
+            if (drmSetInterfaceVersion(fd, &sv)) {
 #ifndef __alpha__
-		pci_domain_ok = 0;
+                pci_domain_ok = 0;
 #endif
-		sv.drm_di_major = 1;
-		sv.drm_di_minor = 1;
-		sv.drm_dd_major = -1;       /* Don't care */
-		sv.drm_dd_minor = -1;       /* Don't care */
-		drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
-		drmSetInterfaceVersion(fd, &sv);
-	    }
-	    buf = drmGetBusid(fd);
-	    drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
-	    if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
-		drmFreeBusid(buf);
-		return fd;
-	    }
-	    if (buf)
-		drmFreeBusid(buf);
-	    close(fd);
-	}
+                sv.drm_di_major = 1;
+                sv.drm_di_minor = 1;
+                sv.drm_dd_major = -1;       /* Don't care */
+                sv.drm_dd_minor = -1;       /* Don't care */
+                drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
+                drmSetInterfaceVersion(fd, &sv);
+            }
+            buf = drmGetBusid(fd);
+            drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
+            if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
+                drmFreeBusid(buf);
+                return fd;
+            }
+            if (buf)
+                drmFreeBusid(buf);
+            close(fd);
+        }
     }
     return -1;
 }
@@ -611,14 +630,14 @@
  *
  * \param name driver name.
  * \param type the device node type.
- * 
+ *
  * \return a file descriptor on success, or a negative value on error.
- * 
+ *
  * \internal
  * This function opens the first minor number that matches the driver name and
  * isn't already in use.  If it's in use it then it will already have a bus ID
  * assigned.
- * 
+ *
  * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
  */
 static int drmOpenByName(const char *name, int type)
@@ -637,56 +656,56 @@
      * already in use.  If it's in use it will have a busid assigned already.
      */
     for (i = base; i < base + DRM_MAX_MINOR; i++) {
-	if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
-	    if ((version = drmGetVersion(fd))) {
-		if (!strcmp(version->name, name)) {
-		    drmFreeVersion(version);
-		    id = drmGetBusid(fd);
-		    drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
-		    if (!id || !*id) {
-			if (id)
-			    drmFreeBusid(id);
-			return fd;
-		    } else {
-			drmFreeBusid(id);
-		    }
-		} else {
-		    drmFreeVersion(version);
-		}
-	    }
-	    close(fd);
-	}
+        if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
+            if ((version = drmGetVersion(fd))) {
+                if (!strcmp(version->name, name)) {
+                    drmFreeVersion(version);
+                    id = drmGetBusid(fd);
+                    drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
+                    if (!id || !*id) {
+                        if (id)
+                            drmFreeBusid(id);
+                        return fd;
+                    } else {
+                        drmFreeBusid(id);
+                    }
+                } else {
+                    drmFreeVersion(version);
+                }
+            }
+            close(fd);
+        }
     }
 
 #ifdef __linux__
     /* Backward-compatibility /proc support */
     for (i = 0; i < 8; i++) {
-	char proc_name[64], buf[512];
-	char *driver, *pt, *devstring;
-	int  retcode;
-	
-	sprintf(proc_name, "/proc/dri/%d/name", i);
-	if ((fd = open(proc_name, 0, 0)) >= 0) {
-	    retcode = read(fd, buf, sizeof(buf)-1);
-	    close(fd);
-	    if (retcode) {
-		buf[retcode-1] = '\0';
-		for (driver = pt = buf; *pt && *pt != ' '; ++pt)
-		    ;
-		if (*pt) { /* Device is next */
-		    *pt = '\0';
-		    if (!strcmp(driver, name)) { /* Match */
-			for (devstring = ++pt; *pt && *pt != ' '; ++pt)
-			    ;
-			if (*pt) { /* Found busid */
-			    return drmOpenByBusid(++pt, type);
-			} else { /* No busid */
-			    return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
-			}
-		    }
-		}
-	    }
-	}
+        char proc_name[64], buf[512];
+        char *driver, *pt, *devstring;
+        int  retcode;
+
+        sprintf(proc_name, "/proc/dri/%d/name", i);
+        if ((fd = open(proc_name, 0, 0)) >= 0) {
+            retcode = read(fd, buf, sizeof(buf)-1);
+            close(fd);
+            if (retcode) {
+                buf[retcode-1] = '\0';
+                for (driver = pt = buf; *pt && *pt != ' '; ++pt)
+                    ;
+                if (*pt) { /* Device is next */
+                    *pt = '\0';
+                    if (!strcmp(driver, name)) { /* Match */
+                        for (devstring = ++pt; *pt && *pt != ' '; ++pt)
+                            ;
+                        if (*pt) { /* Found busid */
+                            return drmOpenByBusid(++pt, type);
+                        } else { /* No busid */
+                            return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
+                        }
+                    }
+                }
+            }
+        }
     }
 #endif
 
@@ -702,9 +721,9 @@
  *
  * \param name driver name. Not referenced if bus ID is supplied.
  * \param busid bus ID. Zero if not known.
- * 
+ *
  * \return a file descriptor on success, or a negative value on error.
- * 
+ *
  * \internal
  * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
  * otherwise.
@@ -734,21 +753,21 @@
 {
     if (!drmAvailable() && name != NULL && drm_server_info &&
         drm_server_info->load_module) {
-	/* try to load the kernel module */
-	if (!drm_server_info->load_module(name)) {
-	    drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
-	    return -1;
-	}
+        /* try to load the kernel module */
+        if (!drm_server_info->load_module(name)) {
+            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
+            return -1;
+        }
     }
 
     if (busid) {
-	int fd = drmOpenByBusid(busid, type);
-	if (fd >= 0)
-	    return fd;
+        int fd = drmOpenByBusid(busid, type);
+        if (fd >= 0)
+            return fd;
     }
-    
+
     if (name)
-	return drmOpenByName(name, type);
+        return drmOpenByName(name, type);
 
     return -1;
 }
@@ -775,7 +794,7 @@
 void drmFreeVersion(drmVersionPtr v)
 {
     if (!v)
-	return;
+        return;
     drmFree(v->name);
     drmFree(v->date);
     drmFree(v->desc);
@@ -795,7 +814,7 @@
 static void drmFreeKernelVersion(drm_version_t *v)
 {
     if (!v)
-	return;
+        return;
     drmFree(v->name);
     drmFree(v->date);
     drmFree(v->desc);
@@ -805,10 +824,10 @@
 
 /**
  * Copy version information.
- * 
+ *
  * \param d destination pointer.
  * \param s source pointer.
- * 
+ *
  * \internal
  * Used by drmGetVersion() to translate the information returned by the ioctl
  * interface in a private structure into the public structure counterpart.
@@ -831,12 +850,12 @@
  * Query the driver version information.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return pointer to a drmVersion structure which should be freed with
  * drmFreeVersion().
- * 
+ *
  * \note Similar information is available via /proc/dri.
- * 
+ *
  * \internal
  * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
  * first with zeros to get the string lengths, and then the actually strings.
@@ -850,21 +869,21 @@
     memclear(*version);
 
     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
-	drmFreeKernelVersion(version);
-	return NULL;
+        drmFreeKernelVersion(version);
+        return NULL;
     }
 
     if (version->name_len)
-	version->name    = drmMalloc(version->name_len + 1);
+        version->name    = drmMalloc(version->name_len + 1);
     if (version->date_len)
-	version->date    = drmMalloc(version->date_len + 1);
+        version->date    = drmMalloc(version->date_len + 1);
     if (version->desc_len)
-	version->desc    = drmMalloc(version->desc_len + 1);
+        version->desc    = drmMalloc(version->desc_len + 1);
 
     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
-	drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
-	drmFreeKernelVersion(version);
-	return NULL;
+        drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
+        drmFreeKernelVersion(version);
+        return NULL;
     }
 
     /* The results might not be null-terminated strings, so terminate them. */
@@ -881,13 +900,13 @@
 
 /**
  * Get version information for the DRM user space library.
- * 
+ *
  * This version number is driver independent.
- * 
+ *
  * \param fd file descriptor.
  *
  * \return version information.
- * 
+ *
  * \internal
  * This function allocates and fills a drm_version structure with a hard coded
  * version number.
@@ -915,29 +934,29 @@
 
 int drmGetCap(int fd, uint64_t capability, uint64_t *value)
 {
-	struct drm_get_cap cap;
-	int ret;
+    struct drm_get_cap cap;
+    int ret;
 
-	memclear(cap);
-	cap.capability = capability;
+    memclear(cap);
+    cap.capability = capability;
 
-	ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
-	if (ret)
-		return ret;
+    ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
+    if (ret)
+        return ret;
 
-	*value = cap.value;
-	return 0;
+    *value = cap.value;
+    return 0;
 }
 
 int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
 {
-	struct drm_set_client_cap cap;
+    struct drm_set_client_cap cap;
 
-	memclear(cap);
-	cap.capability = capability;
-	cap.value = value;
+    memclear(cap);
+    cap.capability = capability;
+    cap.value = value;
 
-	return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
+    return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
 }
 
 /**
@@ -973,10 +992,10 @@
     memclear(u);
 
     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
-	return NULL;
+        return NULL;
     u.unique = drmMalloc(u.unique_len + 1);
     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
-	return NULL;
+        return NULL;
     u.unique[u.unique_len] = '\0';
 
     return u.unique;
@@ -1004,7 +1023,7 @@
     u.unique_len = strlen(busid);
 
     if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
-	return -errno;
+        return -errno;
     }
     return 0;
 }
@@ -1017,7 +1036,7 @@
 
     *magic = 0;
     if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
-	return -errno;
+        return -errno;
     *magic = auth.magic;
     return 0;
 }
@@ -1029,7 +1048,7 @@
     memclear(auth);
     auth.magic = magic;
     if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1045,7 +1064,7 @@
  * \param flags combination of several flags to modify the function actions.
  * \param handle will be set to a value that may be used as the offset
  * parameter for mmap().
- * 
+ *
  * \return zero on success or a negative value on error.
  *
  * \par Mapping the frame buffer
@@ -1056,7 +1075,7 @@
  *
  * \par
  * The area mapped will be uncached. If MTRR support is available in the
- * kernel, the frame buffer area will be set to write combining. 
+ * kernel, the frame buffer area will be set to write combining.
  *
  * \par Mapping the MMIO register area
  * For the MMIO register area,
@@ -1064,19 +1083,19 @@
  * - \p size will be the size of the register area bytes, and
  * - \p type will be DRM_REGISTERS.
  * \par
- * The area mapped will be uncached. 
- * 
+ * The area mapped will be uncached.
+ *
  * \par Mapping the SAREA
  * For the SAREA,
  * - \p offset will be ignored and should be set to zero,
  * - \p size will be the desired size of the SAREA in bytes,
  * - \p type will be DRM_SHM.
- * 
+ *
  * \par
  * A shared memory area of the requested size will be created and locked in
  * kernel memory. This area may be mapped into client-space by using the handle
- * returned. 
- * 
+ * returned.
+ *
  * \note May only be called by root.
  *
  * \internal
@@ -1084,7 +1103,7 @@
  * the arguments in a drm_map structure.
  */
 int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
-	      drmMapFlags flags, drm_handle_t *handle)
+              drmMapFlags flags, drm_handle_t *handle)
 {
     drm_map_t map;
 
@@ -1094,9 +1113,9 @@
     map.type    = type;
     map.flags   = flags;
     if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
-	return -errno;
+        return -errno;
     if (handle)
-	*handle = (drm_handle_t)(uintptr_t)map.handle;
+        *handle = (drm_handle_t)(uintptr_t)map.handle;
     return 0;
 }
 
@@ -1108,18 +1127,18 @@
     map.handle = (void *)(uintptr_t)handle;
 
     if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
-	return -errno;
+        return -errno;
     return 0;
 }
 
 /**
  * Make buffers available for DMA transfers.
- * 
+ *
  * \param fd file descriptor.
  * \param count number of buffers.
  * \param size size of each buffer.
  * \param flags buffer allocation flags.
- * \param agp_offset offset in the AGP aperture 
+ * \param agp_offset offset in the AGP aperture
  *
  * \return number of buffers allocated, negative on error.
  *
@@ -1129,7 +1148,7 @@
  * \sa drm_buf_desc.
  */
 int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
-	       int agp_offset)
+               int agp_offset)
 {
     drm_buf_desc_t request;
 
@@ -1140,7 +1159,7 @@
     request.agp_start = agp_offset;
 
     if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
-	return -errno;
+        return -errno;
     return request.count;
 }
 
@@ -1152,28 +1171,28 @@
     memclear(info);
 
     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
-	return -EINVAL;
+        return -EINVAL;
 
     if (!info.count)
-	return -EINVAL;
+        return -EINVAL;
 
     if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
-	return -ENOMEM;
+        return -ENOMEM;
 
     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
-	int retval = -errno;
-	drmFree(info.list);
-	return retval;
+        int retval = -errno;
+        drmFree(info.list);
+        return retval;
     }
 
     for (i = 0; i < info.count; i++) {
-	info.list[i].low_mark  = low  * info.list[i].count;
-	info.list[i].high_mark = high * info.list[i].count;
-	if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
-	    int retval = -errno;
-	    drmFree(info.list);
-	    return retval;
-	}
+        info.list[i].low_mark  = low  * info.list[i].count;
+        info.list[i].high_mark = high * info.list[i].count;
+        if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
+            int retval = -errno;
+            drmFree(info.list);
+            return retval;
+        }
     }
     drmFree(info.list);
 
@@ -1188,9 +1207,9 @@
  * \param list list of buffers to be freed.
  *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \note This function is primarily used for debugging.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
  * the arguments in a drm_buf_free structure.
@@ -1203,7 +1222,7 @@
     request.count = count;
     request.list  = list;
     if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1243,7 +1262,7 @@
  * begins.
  *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper for mmap().
  */
@@ -1252,16 +1271,16 @@
     static unsigned long pagesize_mask = 0;
 
     if (fd < 0)
-	return -EINVAL;
+        return -EINVAL;
 
     if (!pagesize_mask)
-	pagesize_mask = getpagesize() - 1;
+        pagesize_mask = getpagesize() - 1;
 
     size = (size + pagesize_mask) & ~pagesize_mask;
 
     *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
     if (*address == MAP_FAILED)
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1271,7 +1290,7 @@
  *
  * \param address address as given by drmMap().
  * \param size size in bytes. Must match the size used by drmMap().
- * 
+ *
  * \return zero on success, or a negative value on failure.
  *
  * \internal
@@ -1291,28 +1310,28 @@
     memclear(info);
 
     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
-	return NULL;
+        return NULL;
 
     if (info.count) {
-	if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
-	    return NULL;
+        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
+            return NULL;
 
-	if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
-	    drmFree(info.list);
-	    return NULL;
-	}
+        if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
+            drmFree(info.list);
+            return NULL;
+        }
 
-	retval = drmMalloc(sizeof(*retval));
-	retval->count = info.count;
-	retval->list  = drmMalloc(info.count * sizeof(*retval->list));
-	for (i = 0; i < info.count; i++) {
-	    retval->list[i].count     = info.list[i].count;
-	    retval->list[i].size      = info.list[i].size;
-	    retval->list[i].low_mark  = info.list[i].low_mark;
-	    retval->list[i].high_mark = info.list[i].high_mark;
-	}
-	drmFree(info.list);
-	return retval;
+        retval = drmMalloc(sizeof(*retval));
+        retval->count = info.count;
+        retval->list  = drmMalloc(info.count * sizeof(*retval->list));
+        for (i = 0; i < info.count; i++) {
+            retval->list[i].count     = info.list[i].count;
+            retval->list[i].size      = info.list[i].size;
+            retval->list[i].low_mark  = info.list[i].low_mark;
+            retval->list[i].high_mark = info.list[i].high_mark;
+        }
+        drmFree(info.list);
+        return retval;
     }
     return NULL;
 }
@@ -1326,12 +1345,12 @@
  *
  * \note The client may not use these buffers until obtaining buffer indices
  * with drmDMA().
- * 
+ *
  * \internal
  * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
  * information about the buffers in a drm_buf_map structure into the
  * client-visible data structures.
- */ 
+ */
 drmBufMapPtr drmMapBufs(int fd)
 {
     drm_buf_map_t bufs;
@@ -1340,32 +1359,31 @@
 
     memclear(bufs);
     if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
-	return NULL;
+        return NULL;
 
     if (!bufs.count)
-	return NULL;
+        return NULL;
 
-	if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
-	    return NULL;
+    if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
+        return NULL;
 
-	if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
-	    drmFree(bufs.list);
-	    return NULL;
-	}
+    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
+        drmFree(bufs.list);
+        return NULL;
+    }
 
-	retval = drmMalloc(sizeof(*retval));
-	retval->count = bufs.count;
-	retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
-	for (i = 0; i < bufs.count; i++) {
-	    retval->list[i].idx     = bufs.list[i].idx;
-	    retval->list[i].total   = bufs.list[i].total;
-	    retval->list[i].used    = 0;
-	    retval->list[i].address = bufs.list[i].address;
-	}
+    retval = drmMalloc(sizeof(*retval));
+    retval->count = bufs.count;
+    retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
+    for (i = 0; i < bufs.count; i++) {
+        retval->list[i].idx     = bufs.list[i].idx;
+        retval->list[i].total   = bufs.list[i].total;
+        retval->list[i].used    = 0;
+        retval->list[i].address = bufs.list[i].address;
+    }
 
-	drmFree(bufs.list);
-	
-	return retval;
+    drmFree(bufs.list);
+    return retval;
 }
 
 
@@ -1383,24 +1401,23 @@
     int i;
 
     for (i = 0; i < bufs->count; i++) {
-	drm_munmap(bufs->list[i].address, bufs->list[i].total);
+        drm_munmap(bufs->list[i].address, bufs->list[i].total);
     }
 
     drmFree(bufs->list);
     drmFree(bufs);
-	
     return 0;
 }
 
 
-#define DRM_DMA_RETRY		16
+#define DRM_DMA_RETRY  16
 
 /**
  * Reserve DMA buffers.
  *
  * \param fd file descriptor.
- * \param request 
- * 
+ * \param request
+ *
  * \return zero on success, or a negative value on failure.
  *
  * \internal
@@ -1424,14 +1441,14 @@
     dma.granted_count   = 0;
 
     do {
-	ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
+        ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
     } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
 
     if ( ret == 0 ) {
-	request->granted_count = dma.granted_count;
-	return 0;
+        request->granted_count = dma.granted_count;
+        return 0;
     } else {
-	return -errno;
+        return -errno;
     }
 }
 
@@ -1443,9 +1460,9 @@
  * \param context context.
  * \param flags flags that determine the sate of the hardware when the function
  * returns.
- * 
+ *
  * \return always zero.
- * 
+ *
  * \internal
  * This function translates the arguments into a drm_lock structure and issue
  * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
@@ -1465,7 +1482,7 @@
     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
 
     while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
-	;
+        ;
     return 0;
 }
 
@@ -1474,9 +1491,9 @@
  *
  * \param fd file descriptor.
  * \param context context.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
  * argument in a drm_lock structure.
@@ -1499,24 +1516,24 @@
 
     memclear(res);
     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
-	return NULL;
+        return NULL;
 
     if (!res.count)
-	return NULL;
+        return NULL;
 
     if (!(list   = drmMalloc(res.count * sizeof(*list))))
-	return NULL;
+        return NULL;
     if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
-	drmFree(list);
-	return NULL;
+        drmFree(list);
+        return NULL;
     }
 
     res.contexts = list;
     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
-	return NULL;
+        return NULL;
 
     for (i = 0; i < res.count; i++)
-	retval[i] = list[i].handle;
+        retval[i] = list[i].handle;
     drmFree(list);
 
     *count = res.count;
@@ -1537,11 +1554,11 @@
  * \param fd file descriptor.
  * \param handle is set on success. To be used by the client when requesting DMA
  * dispatch with drmDMA().
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \note May only be called by root.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
  * argument in a drm_ctx structure.
@@ -1552,7 +1569,7 @@
 
     memclear(ctx);
     if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
-	return -errno;
+        return -errno;
     *handle = ctx.handle;
     return 0;
 }
@@ -1564,7 +1581,7 @@
     memclear(ctx);
     ctx.handle = context;
     if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1581,11 +1598,11 @@
     memclear(ctx);
     ctx.handle = context;
     if (flags & DRM_CONTEXT_PRESERVED)
-	ctx.flags |= _DRM_CONTEXT_PRESERVED;
+        ctx.flags |= _DRM_CONTEXT_PRESERVED;
     if (flags & DRM_CONTEXT_2DONLY)
-	ctx.flags |= _DRM_CONTEXT_2DONLY;
+        ctx.flags |= _DRM_CONTEXT_2DONLY;
     if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1597,12 +1614,12 @@
     memclear(ctx);
     ctx.handle = context;
     if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
-	return -errno;
+        return -errno;
     *flags = 0;
     if (ctx.flags & _DRM_CONTEXT_PRESERVED)
-	*flags |= DRM_CONTEXT_PRESERVED;
+        *flags |= DRM_CONTEXT_PRESERVED;
     if (ctx.flags & _DRM_CONTEXT_2DONLY)
-	*flags |= DRM_CONTEXT_2DONLY;
+        *flags |= DRM_CONTEXT_2DONLY;
     return 0;
 }
 
@@ -1611,14 +1628,14 @@
  *
  * Free any kernel-level resources allocated with drmCreateContext() associated
  * with the context.
- * 
+ *
  * \param fd file descriptor.
  * \param handle handle given by drmCreateContext().
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \note May only be called by root.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
  * argument in a drm_ctx structure.
@@ -1630,7 +1647,7 @@
     memclear(ctx);
     ctx.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1640,7 +1657,7 @@
 
     memclear(draw);
     if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
-	return -errno;
+        return -errno;
     *handle = draw.handle;
     return 0;
 }
@@ -1652,13 +1669,13 @@
     memclear(draw);
     draw.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
-	return -errno;
+        return -errno;
     return 0;
 }
 
 int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
-			   drm_drawable_info_type_t type, unsigned int num,
-			   void *data)
+                          drm_drawable_info_type_t type, unsigned int num,
+                          void *data)
 {
     drm_update_draw_t update;
 
@@ -1669,7 +1686,7 @@
     update.data = (unsigned long long)(unsigned long)data;
 
     if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
-	return -errno;
+        return -errno;
 
     return 0;
 }
@@ -1680,16 +1697,16 @@
  * Must be called before any of the other AGP related calls.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
  */
 int drmAgpAcquire(int fd)
 {
     if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1698,16 +1715,16 @@
  * Release the AGP device.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
  */
 int drmAgpRelease(int fd)
 {
     if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1717,9 +1734,9 @@
  *
  * \param fd file descriptor.
  * \param mode AGP mode.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
  * argument in a drm_agp_mode structure.
@@ -1731,7 +1748,7 @@
     memclear(m);
     m.mode = mode;
     if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1745,15 +1762,15 @@
  * \param address if not zero, will be set to the physical address of the
  * allocated memory.
  * \param handle on success will be set to a handle of the allocated memory.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
  * arguments in a drm_agp_buffer structure.
  */
 int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
-		unsigned long *address, drm_handle_t *handle)
+                unsigned long *address, drm_handle_t *handle)
 {
     drm_agp_buffer_t b;
 
@@ -1762,9 +1779,9 @@
     b.size   = size;
     b.type   = type;
     if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
-	return -errno;
+        return -errno;
     if (address != 0UL)
-	*address = b.physical;
+        *address = b.physical;
     *handle = b.handle;
     return 0;
 }
@@ -1775,9 +1792,9 @@
  *
  * \param fd file descriptor.
  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
  * argument in a drm_agp_buffer structure.
@@ -1789,7 +1806,7 @@
     memclear(b);
     b.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1800,9 +1817,9 @@
  * \param fd file descriptor.
  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
  * \param offset offset in bytes. It will round to page boundary.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
  * argument in a drm_agp_binding structure.
@@ -1815,7 +1832,7 @@
     b.handle = handle;
     b.offset = offset;
     if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1825,9 +1842,9 @@
  *
  * \param fd file descriptor.
  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
  * the argument in a drm_agp_binding structure.
@@ -1839,7 +1856,7 @@
     memclear(b);
     b.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -1848,9 +1865,9 @@
  * Get AGP driver major version number.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return major version number on success, or a negative value on failure..
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -1862,7 +1879,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return -errno;
+        return -errno;
     return i.agp_version_major;
 }
 
@@ -1871,9 +1888,9 @@
  * Get AGP driver minor version number.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return minor version number on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -1885,7 +1902,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return -errno;
+        return -errno;
     return i.agp_version_minor;
 }
 
@@ -1894,9 +1911,9 @@
  * Get AGP mode.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return mode on success, or zero on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -1908,7 +1925,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return 0;
+        return 0;
     return i.mode;
 }
 
@@ -1917,9 +1934,9 @@
  * Get AGP aperture base.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return aperture base on success, zero on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -1931,7 +1948,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return 0;
+        return 0;
     return i.aperture_base;
 }
 
@@ -1940,9 +1957,9 @@
  * Get AGP aperture size.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return aperture size on success, zero on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -1954,7 +1971,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return 0;
+        return 0;
     return i.aperture_size;
 }
 
@@ -1963,9 +1980,9 @@
  * Get used AGP memory.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return memory used on success, or zero on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -1977,7 +1994,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return 0;
+        return 0;
     return i.memory_used;
 }
 
@@ -1986,9 +2003,9 @@
  * Get available AGP memory.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return memory available on success, or zero on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -2000,7 +2017,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return 0;
+        return 0;
     return i.memory_allowed;
 }
 
@@ -2009,9 +2026,9 @@
  * Get hardware vendor ID.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return vendor ID on success, or zero on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -2023,7 +2040,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return 0;
+        return 0;
     return i.id_vendor;
 }
 
@@ -2032,9 +2049,9 @@
  * Get hardware device ID.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return zero on success, or zero on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  * necessary information in a drm_agp_info structure.
@@ -2046,7 +2063,7 @@
     memclear(i);
 
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
-	return 0;
+        return 0;
     return i.id_device;
 }
 
@@ -2059,7 +2076,7 @@
     *handle = 0;
     sg.size   = size;
     if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
-	return -errno;
+        return -errno;
     *handle = sg.handle;
     return 0;
 }
@@ -2071,7 +2088,7 @@
     memclear(sg);
     sg.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -2080,9 +2097,9 @@
  *
  * \param fd file descriptor.
  * \param vbl pointer to a drmVBlank structure.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
  */
@@ -2093,8 +2110,8 @@
 
     ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
     if (ret < 0) {
-	fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
-	goto out;
+        fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
+        goto out;
     }
     timeout.tv_sec++;
 
@@ -2102,15 +2119,15 @@
        ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
        vbl->request.type &= ~DRM_VBLANK_RELATIVE;
        if (ret && errno == EINTR) {
-	       clock_gettime(CLOCK_MONOTONIC, &cur);
-	       /* Timeout after 1s */
-	       if (cur.tv_sec > timeout.tv_sec + 1 ||
-		   (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
-		    timeout.tv_nsec)) {
-		       errno = EBUSY;
-		       ret = -1;
-		       break;
-	       }
+           clock_gettime(CLOCK_MONOTONIC, &cur);
+           /* Timeout after 1s */
+           if (cur.tv_sec > timeout.tv_sec + 1 ||
+               (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
+                timeout.tv_nsec)) {
+                   errno = EBUSY;
+                   ret = -1;
+                   break;
+           }
        }
     } while (ret && errno == EINTR);
 
@@ -2122,22 +2139,22 @@
 {
     switch (err) {
     case DRM_ERR_NO_DEVICE:
-	fprintf(stderr, "%s: no device\n", label);
-	break;
+        fprintf(stderr, "%s: no device\n", label);
+        break;
     case DRM_ERR_NO_ACCESS:
-	fprintf(stderr, "%s: no access\n", label);
-	break;
+        fprintf(stderr, "%s: no access\n", label);
+        break;
     case DRM_ERR_NOT_ROOT:
-	fprintf(stderr, "%s: not root\n", label);
-	break;
+        fprintf(stderr, "%s: not root\n", label);
+        break;
     case DRM_ERR_INVALID:
-	fprintf(stderr, "%s: invalid args\n", label);
-	break;
+        fprintf(stderr, "%s: invalid args\n", label);
+        break;
     default:
-	if (err < 0)
-	    err = -err;
-	fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
-	break;
+        if (err < 0)
+            err = -err;
+        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
+        break;
     }
 
     return 1;
@@ -2148,9 +2165,9 @@
  *
  * \param fd file descriptor.
  * \param irq IRQ number.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
  * argument in a drm_control structure.
@@ -2163,7 +2180,7 @@
     ctl.func  = DRM_INST_HANDLER;
     ctl.irq   = irq;
     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -2172,9 +2189,9 @@
  * Uninstall IRQ handler.
  *
  * \param fd file descriptor.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
  * argument in a drm_control structure.
@@ -2187,7 +2204,7 @@
     ctl.func  = DRM_UNINST_HANDLER;
     ctl.irq   = 0;
     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -2204,7 +2221,7 @@
     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
     if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -2215,9 +2232,9 @@
  * \param busnum bus number.
  * \param devnum device number.
  * \param funcnum function number.
- * 
+ *
  * \return IRQ number on success, or a negative value on failure.
- * 
+ *
  * \internal
  * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
  * arguments in a drm_irq_busid structure.
@@ -2231,7 +2248,7 @@
     p.devnum  = devnum;
     p.funcnum = funcnum;
     if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
-	return -errno;
+        return -errno;
     return p.irq;
 }
 
@@ -2240,8 +2257,8 @@
     drmHashEntry  *entry = drmGetEntry(fd);
 
     if (drmHashInsert(entry->tagTable, context, tag)) {
-	drmHashDelete(entry->tagTable, context);
-	drmHashInsert(entry->tagTable, context, tag);
+        drmHashDelete(entry->tagTable, context);
+        drmHashInsert(entry->tagTable, context, tag);
     }
     return 0;
 }
@@ -2259,7 +2276,7 @@
     void          *value;
 
     if (drmHashLookup(entry->tagTable, context, &value))
-	return NULL;
+        return NULL;
 
     return value;
 }
@@ -2274,7 +2291,7 @@
     map.handle = (void *)(uintptr_t)handle;
 
     if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -2287,23 +2304,23 @@
     map.ctx_id = ctx_id;
 
     if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
-	return -errno;
+        return -errno;
     if (handle)
-	*handle = (drm_handle_t)(uintptr_t)map.handle;
+        *handle = (drm_handle_t)(uintptr_t)map.handle;
 
     return 0;
 }
 
 int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
-	      drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
-	      int *mtrr)
+              drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
+              int *mtrr)
 {
     drm_map_t map;
 
     memclear(map);
     map.offset = idx;
     if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
-	return -errno;
+        return -errno;
     *offset = map.offset;
     *size   = map.size;
     *type   = map.type;
@@ -2314,14 +2331,14 @@
 }
 
 int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
-		 unsigned long *magic, unsigned long *iocs)
+                 unsigned long *magic, unsigned long *iocs)
 {
     drm_client_t client;
 
     memclear(client);
     client.idx = idx;
     if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
-	return -errno;
+        return -errno;
     *auth      = client.auth;
     *pid       = client.pid;
     *uid       = client.uid;
@@ -2337,12 +2354,12 @@
 
     memclear(s);
     if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
-	return -errno;
+        return -errno;
 
     stats->count = 0;
     memset(stats, 0, sizeof(*stats));
     if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
-	return -1;
+        return -1;
 
 #define SET_VALUE                              \
     stats->data[i].long_format = "%-20.20s";   \
@@ -2369,87 +2386,87 @@
 
     stats->count = s.count;
     for (i = 0; i < s.count; i++) {
-	stats->data[i].value = s.data[i].value;
-	switch (s.data[i].type) {
-	case _DRM_STAT_LOCK:
-	    stats->data[i].long_name = "Lock";
-	    stats->data[i].rate_name = "Lock";
-	    SET_VALUE;
-	    break;
-	case _DRM_STAT_OPENS:
-	    stats->data[i].long_name = "Opens";
-	    stats->data[i].rate_name = "O";
-	    SET_COUNT;
-	    stats->data[i].verbose   = 1;
-	    break;
-	case _DRM_STAT_CLOSES:
-	    stats->data[i].long_name = "Closes";
-	    stats->data[i].rate_name = "Lock";
-	    SET_COUNT;
-	    stats->data[i].verbose   = 1;
-	    break;
-	case _DRM_STAT_IOCTLS:
-	    stats->data[i].long_name = "Ioctls";
-	    stats->data[i].rate_name = "Ioc/s";
-	    SET_COUNT;
-	    break;
-	case _DRM_STAT_LOCKS:
-	    stats->data[i].long_name = "Locks";
-	    stats->data[i].rate_name = "Lck/s";
-	    SET_COUNT;
-	    break;
-	case _DRM_STAT_UNLOCKS:
-	    stats->data[i].long_name = "Unlocks";
-	    stats->data[i].rate_name = "Unl/s";
-	    SET_COUNT;
-	    break;
-	case _DRM_STAT_IRQ:
-	    stats->data[i].long_name = "IRQs";
-	    stats->data[i].rate_name = "IRQ/s";
-	    SET_COUNT;
-	    break;
-	case _DRM_STAT_PRIMARY:
-	    stats->data[i].long_name = "Primary Bytes";
-	    stats->data[i].rate_name = "PB/s";
-	    SET_BYTE;
-	    break;
-	case _DRM_STAT_SECONDARY:
-	    stats->data[i].long_name = "Secondary Bytes";
-	    stats->data[i].rate_name = "SB/s";
-	    SET_BYTE;
-	    break;
-	case _DRM_STAT_DMA:
-	    stats->data[i].long_name = "DMA";
-	    stats->data[i].rate_name = "DMA/s";
-	    SET_COUNT;
-	    break;
-	case _DRM_STAT_SPECIAL:
-	    stats->data[i].long_name = "Special DMA";
-	    stats->data[i].rate_name = "dma/s";
-	    SET_COUNT;
-	    break;
-	case _DRM_STAT_MISSED:
-	    stats->data[i].long_name = "Miss";
-	    stats->data[i].rate_name = "Ms/s";
-	    SET_COUNT;
-	    break;
-	case _DRM_STAT_VALUE:
-	    stats->data[i].long_name = "Value";
-	    stats->data[i].rate_name = "Value";
-	    SET_VALUE;
-	    break;
-	case _DRM_STAT_BYTE:
-	    stats->data[i].long_name = "Bytes";
-	    stats->data[i].rate_name = "B/s";
-	    SET_BYTE;
-	    break;
-	case _DRM_STAT_COUNT:
-	default:
-	    stats->data[i].long_name = "Count";
-	    stats->data[i].rate_name = "Cnt/s";
-	    SET_COUNT;
-	    break;
-	}
+        stats->data[i].value = s.data[i].value;
+        switch (s.data[i].type) {
+        case _DRM_STAT_LOCK:
+            stats->data[i].long_name = "Lock";
+            stats->data[i].rate_name = "Lock";
+            SET_VALUE;
+            break;
+        case _DRM_STAT_OPENS:
+            stats->data[i].long_name = "Opens";
+            stats->data[i].rate_name = "O";
+            SET_COUNT;
+            stats->data[i].verbose   = 1;
+            break;
+        case _DRM_STAT_CLOSES:
+            stats->data[i].long_name = "Closes";
+            stats->data[i].rate_name = "Lock";
+            SET_COUNT;
+            stats->data[i].verbose   = 1;
+            break;
+        case _DRM_STAT_IOCTLS:
+            stats->data[i].long_name = "Ioctls";
+            stats->data[i].rate_name = "Ioc/s";
+            SET_COUNT;
+            break;
+        case _DRM_STAT_LOCKS:
+            stats->data[i].long_name = "Locks";
+            stats->data[i].rate_name = "Lck/s";
+            SET_COUNT;
+            break;
+        case _DRM_STAT_UNLOCKS:
+            stats->data[i].long_name = "Unlocks";
+            stats->data[i].rate_name = "Unl/s";
+            SET_COUNT;
+            break;
+        case _DRM_STAT_IRQ:
+            stats->data[i].long_name = "IRQs";
+            stats->data[i].rate_name = "IRQ/s";
+            SET_COUNT;
+            break;
+        case _DRM_STAT_PRIMARY:
+            stats->data[i].long_name = "Primary Bytes";
+            stats->data[i].rate_name = "PB/s";
+            SET_BYTE;
+            break;
+        case _DRM_STAT_SECONDARY:
+            stats->data[i].long_name = "Secondary Bytes";
+            stats->data[i].rate_name = "SB/s";
+            SET_BYTE;
+            break;
+        case _DRM_STAT_DMA:
+            stats->data[i].long_name = "DMA";
+            stats->data[i].rate_name = "DMA/s";
+            SET_COUNT;
+            break;
+        case _DRM_STAT_SPECIAL:
+            stats->data[i].long_name = "Special DMA";
+            stats->data[i].rate_name = "dma/s";
+            SET_COUNT;
+            break;
+        case _DRM_STAT_MISSED:
+            stats->data[i].long_name = "Miss";
+            stats->data[i].rate_name = "Ms/s";
+            SET_COUNT;
+            break;
+        case _DRM_STAT_VALUE:
+            stats->data[i].long_name = "Value";
+            stats->data[i].rate_name = "Value";
+            SET_VALUE;
+            break;
+        case _DRM_STAT_BYTE:
+            stats->data[i].long_name = "Bytes";
+            stats->data[i].rate_name = "B/s";
+            SET_BYTE;
+            break;
+        case _DRM_STAT_COUNT:
+        default:
+            stats->data[i].long_name = "Count";
+            stats->data[i].rate_name = "Cnt/s";
+            SET_COUNT;
+            break;
+        }
     }
     return 0;
 }
@@ -2458,14 +2475,14 @@
  * Issue a set-version ioctl.
  *
  * \param fd file descriptor.
- * \param drmCommandIndex command index 
+ * \param drmCommandIndex command index
  * \param data source pointer of the data to be read and written.
  * \param size size of the data to be read and written.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
- * It issues a read-write ioctl given by 
+ * It issues a read-write ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
 int drmSetInterfaceVersion(int fd, drmSetVersion *version)
@@ -2480,7 +2497,7 @@
     sv.drm_dd_minor = version->drm_dd_minor;
 
     if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
-	retcode = -errno;
+        retcode = -errno;
     }
 
     version->drm_di_major = sv.drm_di_major;
@@ -2495,12 +2512,12 @@
  * Send a device-specific command.
  *
  * \param fd file descriptor.
- * \param drmCommandIndex command index 
- * 
+ * \param drmCommandIndex command index
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
- * It issues a ioctl given by 
+ * It issues a ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
 int drmCommandNone(int fd, unsigned long drmCommandIndex)
@@ -2510,7 +2527,7 @@
     request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
 
     if (drmIoctl(fd, request, NULL)) {
-	return -errno;
+        return -errno;
     }
     return 0;
 }
@@ -2520,14 +2537,14 @@
  * Send a device-specific read command.
  *
  * \param fd file descriptor.
- * \param drmCommandIndex command index 
+ * \param drmCommandIndex command index
  * \param data destination pointer of the data to be read.
  * \param size size of the data to be read.
- * 
+ *
  * \return zero on success, or a negative value on failure.
  *
  * \internal
- * It issues a read ioctl given by 
+ * It issues a read ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
 int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
@@ -2535,11 +2552,11 @@
 {
     unsigned long request;
 
-    request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 
-	DRM_COMMAND_BASE + drmCommandIndex, size);
+    request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
+        DRM_COMMAND_BASE + drmCommandIndex, size);
 
     if (drmIoctl(fd, request, data)) {
-	return -errno;
+        return -errno;
     }
     return 0;
 }
@@ -2549,14 +2566,14 @@
  * Send a device-specific write command.
  *
  * \param fd file descriptor.
- * \param drmCommandIndex command index 
+ * \param drmCommandIndex command index
  * \param data source pointer of the data to be written.
  * \param size size of the data to be written.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
- * It issues a write ioctl given by 
+ * It issues a write ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
 int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
@@ -2564,11 +2581,11 @@
 {
     unsigned long request;
 
-    request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 
-	DRM_COMMAND_BASE + drmCommandIndex, size);
+    request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
+        DRM_COMMAND_BASE + drmCommandIndex, size);
 
     if (drmIoctl(fd, request, data)) {
-	return -errno;
+        return -errno;
     }
     return 0;
 }
@@ -2578,14 +2595,14 @@
  * Send a device-specific read-write command.
  *
  * \param fd file descriptor.
- * \param drmCommandIndex command index 
+ * \param drmCommandIndex command index
  * \param data source pointer of the data to be read and written.
  * \param size size of the data to be read and written.
- * 
+ *
  * \return zero on success, or a negative value on failure.
- * 
+ *
  * \internal
- * It issues a read-write ioctl given by 
+ * It issues a read-write ioctl given by
  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  */
 int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
@@ -2593,11 +2610,11 @@
 {
     unsigned long request;
 
-    request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 
-	DRM_COMMAND_BASE + drmCommandIndex, size);
+    request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
+        DRM_COMMAND_BASE + drmCommandIndex, size);
 
     if (drmIoctl(fd, request, data))
-	return -errno;
+        return -errno;
     return 0;
 }
 
@@ -2611,9 +2628,9 @@
 
 static int nr_fds = 0;
 
-int drmOpenOnce(void *unused, 
-		const char *BusID,
-		int *newlyopened)
+int drmOpenOnce(void *unused,
+                const char *BusID,
+                int *newlyopened)
 {
     return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
 }
@@ -2622,19 +2639,19 @@
 {
     int i;
     int fd;
-   
+
     for (i = 0; i < nr_fds; i++)
-	if ((strcmp(BusID, connection[i].BusID) == 0) &&
-	    (connection[i].type == type)) {
-	    connection[i].refcount++;
-	    *newlyopened = 0;
-	    return connection[i].fd;
-	}
+        if ((strcmp(BusID, connection[i].BusID) == 0) &&
+            (connection[i].type == type)) {
+            connection[i].refcount++;
+            *newlyopened = 0;
+            return connection[i].fd;
+        }
 
     fd = drmOpenWithType(NULL, BusID, type);
     if (fd < 0 || nr_fds == DRM_MAX_FDS)
-	return fd;
-   
+        return fd;
+
     connection[nr_fds].BusID = strdup(BusID);
     connection[nr_fds].fd = fd;
     connection[nr_fds].refcount = 1;
@@ -2642,9 +2659,9 @@
     *newlyopened = 1;
 
     if (0)
-	fprintf(stderr, "saved connection %d for %s %d\n", 
-		nr_fds, connection[nr_fds].BusID, 
-		strcmp(BusID, connection[nr_fds].BusID));
+        fprintf(stderr, "saved connection %d for %s %d\n",
+                nr_fds, connection[nr_fds].BusID,
+                strcmp(BusID, connection[nr_fds].BusID));
 
     nr_fds++;
 
@@ -2656,182 +2673,263 @@
     int i;
 
     for (i = 0; i < nr_fds; i++) {
-	if (fd == connection[i].fd) {
-	    if (--connection[i].refcount == 0) {
-		drmClose(connection[i].fd);
-		free(connection[i].BusID);
-	    
-		if (i < --nr_fds) 
-		    connection[i] = connection[nr_fds];
+        if (fd == connection[i].fd) {
+            if (--connection[i].refcount == 0) {
+                drmClose(connection[i].fd);
+                free(connection[i].BusID);
 
-		return;
-	    }
-	}
+                if (i < --nr_fds)
+                    connection[i] = connection[nr_fds];
+
+                return;
+            }
+        }
     }
 }
 
 int drmSetMaster(int fd)
 {
-	return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
+        return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
 }
 
 int drmDropMaster(int fd)
 {
-	return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
+        return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
 }
 
 char *drmGetDeviceNameFromFd(int fd)
 {
-	char name[128];
-	struct stat sbuf;
-	dev_t d;
-	int i;
+    char name[128];
+    struct stat sbuf;
+    dev_t d;
+    int i;
 
-	/* The whole drmOpen thing is a fiasco and we need to find a way
-	 * back to just using open(2).  For now, however, lets just make
-	 * things worse with even more ad hoc directory walking code to
-	 * discover the device file name. */
+    /* The whole drmOpen thing is a fiasco and we need to find a way
+     * back to just using open(2).  For now, however, lets just make
+     * things worse with even more ad hoc directory walking code to
+     * discover the device file name. */
 
-	fstat(fd, &sbuf);
-	d = sbuf.st_rdev;
+    fstat(fd, &sbuf);
+    d = sbuf.st_rdev;
 
-	for (i = 0; i < DRM_MAX_MINOR; i++) {
-		snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
-		if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
-			break;
-	}
-	if (i == DRM_MAX_MINOR)
-		return NULL;
+    for (i = 0; i < DRM_MAX_MINOR; i++) {
+        snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
+        if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
+            break;
+    }
+    if (i == DRM_MAX_MINOR)
+        return NULL;
 
-	return strdup(name);
+    return strdup(name);
 }
 
 int drmGetNodeTypeFromFd(int fd)
 {
-	struct stat sbuf;
-	int maj, min, type;
+    struct stat sbuf;
+    int maj, min, type;
 
-	if (fstat(fd, &sbuf))
-		return -1;
+    if (fstat(fd, &sbuf))
+        return -1;
 
-	maj = major(sbuf.st_rdev);
-	min = minor(sbuf.st_rdev);
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
 
-	if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
-		errno = EINVAL;
-		return -1;
-	}
+    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
+        errno = EINVAL;
+        return -1;
+    }
 
-	type = drmGetMinorType(min);
-	if (type == -1)
-		errno = ENODEV;
-	return type;
+    type = drmGetMinorType(min);
+    if (type == -1)
+        errno = ENODEV;
+    return type;
 }
 
 int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
 {
-	struct drm_prime_handle args;
-	int ret;
+    struct drm_prime_handle args;
+    int ret;
 
-	memclear(args);
-	args.fd = -1;
-	args.handle = handle;
-	args.flags = flags;
-	ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
-	if (ret)
-		return ret;
+    memclear(args);
+    args.fd = -1;
+    args.handle = handle;
+    args.flags = flags;
+    ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
+    if (ret)
+        return ret;
 
-	*prime_fd = args.fd;
-	return 0;
+    *prime_fd = args.fd;
+    return 0;
 }
 
 int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
 {
-	struct drm_prime_handle args;
-	int ret;
+    struct drm_prime_handle args;
+    int ret;
 
-	memclear(args);
-	args.fd = prime_fd;
-	ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
-	if (ret)
-		return ret;
+    memclear(args);
+    args.fd = prime_fd;
+    ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
+    if (ret)
+        return ret;
 
-	*handle = args.handle;
-	return 0;
+    *handle = args.handle;
+    return 0;
 }
 
 static char *drmGetMinorNameForFD(int fd, int type)
 {
 #ifdef __linux__
-	DIR *sysdir;
-	struct dirent *pent, *ent;
-	struct stat sbuf;
-	const char *name = drmGetMinorName(type);
-	int len;
-	char dev_name[64], buf[64];
-	long name_max;
-	int maj, min;
+    DIR *sysdir;
+    struct dirent *pent, *ent;
+    struct stat sbuf;
+    const char *name = drmGetMinorName(type);
+    int len;
+    char dev_name[64], buf[64];
+    long name_max;
+    int maj, min;
 
-	if (!name)
-		return NULL;
+    if (!name)
+        return NULL;
 
-	len = strlen(name);
+    len = strlen(name);
 
-	if (fstat(fd, &sbuf))
-		return NULL;
+    if (fstat(fd, &sbuf))
+        return NULL;
 
-	maj = major(sbuf.st_rdev);
-	min = minor(sbuf.st_rdev);
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
 
-	if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
-		return NULL;
+    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+        return NULL;
 
-	snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
+    snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
 
-	sysdir = opendir(buf);
-	if (!sysdir)
-		return NULL;
+    sysdir = opendir(buf);
+    if (!sysdir)
+        return NULL;
 
-	name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
-	if (name_max == -1)
-		goto out_close_dir;
+    name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
+    if (name_max == -1)
+        goto out_close_dir;
 
-	pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
-	if (pent == NULL)
-		 goto out_close_dir;
+    pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
+    if (pent == NULL)
+         goto out_close_dir;
 
-	while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
-		if (strncmp(ent->d_name, name, len) == 0) {
-			snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
-				 ent->d_name);
+    while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
+        if (strncmp(ent->d_name, name, len) == 0) {
+            snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
+                 ent->d_name);
 
-			free(pent);
-			closedir(sysdir);
+            free(pent);
+            closedir(sysdir);
 
-			return strdup(dev_name);
-		}
-	}
+            return strdup(dev_name);
+        }
+    }
 
-	free(pent);
+    free(pent);
 
 out_close_dir:
-	closedir(sysdir);
+    closedir(sysdir);
 #else
-#warning "Missing implementation of drmGetMinorNameForFD"
+    struct stat sbuf;
+    char buf[PATH_MAX + 1];
+    const char *dev_name;
+    unsigned int maj, min;
+    int n, base;
+
+    if (fstat(fd, &sbuf))
+        return NULL;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+
+    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+        return NULL;
+
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+        dev_name = DRM_DEV_NAME;
+        break;
+    case DRM_NODE_CONTROL:
+        dev_name = DRM_CONTROL_DEV_NAME;
+        break;
+    case DRM_NODE_RENDER:
+        dev_name = DRM_RENDER_DEV_NAME;
+        break;
+    default:
+        return NULL;
+    };
+
+    base = drmGetMinorBase(type);
+    if (base < 0)
+        return NULL;
+
+    n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base);
+    if (n == -1 || n >= sizeof(buf))
+        return NULL;
+
+    return strdup(buf);
 #endif
-	return NULL;
+    return NULL;
 }
 
 char *drmGetPrimaryDeviceNameFromFd(int fd)
 {
-	return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
+    return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
 }
 
 char *drmGetRenderDeviceNameFromFd(int fd)
 {
-	return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
+    return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
 }
 
+#ifdef __linux__
+static char * DRM_PRINTFLIKE(2, 3)
+sysfs_uevent_get(const char *path, const char *fmt, ...)
+{
+    char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
+    size_t size = 0, len;
+    ssize_t num;
+    va_list ap;
+    FILE *fp;
+
+    va_start(ap, fmt);
+    num = vasprintf(&key, fmt, ap);
+    va_end(ap);
+    len = num;
+
+    snprintf(filename, sizeof(filename), "%s/uevent", path);
+
+    fp = fopen(filename, "r");
+    if (!fp) {
+        free(key);
+        return NULL;
+    }
+
+    while ((num = getline(&line, &size, fp)) >= 0) {
+        if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
+            char *start = line + len + 1, *end = line + num - 1;
+
+            if (*end != '\n')
+                end++;
+
+            value = strndup(start, end - start);
+            break;
+        }
+    }
+
+    free(line);
+    fclose(fp);
+
+    free(key);
+
+    return value;
+}
+#endif
+
 static int drmParseSubsystemType(int maj, int min)
 {
 #ifdef __linux__
@@ -2852,7 +2950,18 @@
     if (strncmp(name, "/pci", 4) == 0)
         return DRM_BUS_PCI;
 
+    if (strncmp(name, "/usb", 4) == 0)
+        return DRM_BUS_USB;
+
+    if (strncmp(name, "/platform", 9) == 0)
+        return DRM_BUS_PLATFORM;
+
+    if (strncmp(name, "/host1x", 7) == 0)
+        return DRM_BUS_HOST1X;
+
     return -EINVAL;
+#elif defined(__OpenBSD__)
+    return DRM_BUS_PCI;
 #else
 #warning "Missing implementation of drmParseSubsystemType"
     return -EINVAL;
@@ -2862,38 +2971,52 @@
 static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
 {
 #ifdef __linux__
-    char path[PATH_MAX + 1];
-    char data[128];
-    char *str;
-    int domain, bus, dev, func;
-    int fd, ret;
+    unsigned int domain, bus, dev, func;
+    char path[PATH_MAX + 1], *value;
+    int num;
 
-    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent", maj, min);
-    fd = open(path, O_RDONLY);
-    if (fd < 0)
-        return -errno;
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
 
-    ret = read(fd, data, sizeof(data));
-    close(fd);
-    if (ret < 0)
-        return -errno;
+    value = sysfs_uevent_get(path, "PCI_SLOT_NAME");
+    if (!value)
+        return -ENOENT;
 
-#define TAG "PCI_SLOT_NAME="
-    str = strstr(data, TAG);
-    if (str == NULL)
+    num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
+    free(value);
+
+    if (num != 4)
         return -EINVAL;
 
-    if (sscanf(str, TAG "%04x:%02x:%02x.%1u",
-               &domain, &bus, &dev, &func) != 4)
-        return -EINVAL;
-#undef TAG
-
     info->domain = domain;
     info->bus = bus;
     info->dev = dev;
     info->func = func;
 
     return 0;
+#elif defined(__OpenBSD__)
+    struct drm_pciinfo pinfo;
+    int fd, type;
+
+    type = drmGetMinorType(min);
+    if (type == -1)
+        return -ENODEV;
+
+    fd = drmOpenMinor(min, 0, type);
+    if (fd < 0)
+        return -errno;
+
+    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
+        close(fd);
+        return -errno;
+    }
+    close(fd);
+
+    info->domain = pinfo.domain;
+    info->bus = pinfo.bus;
+    info->dev = pinfo.dev;
+    info->func = pinfo.func;
+
+    return 0;
 #else
 #warning "Missing implementation of drmParsePciBusInfo"
     return -EINVAL;
@@ -2911,6 +3034,16 @@
     switch (a->bustype) {
     case DRM_BUS_PCI:
         return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
+
+    case DRM_BUS_USB:
+        return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
+
+    case DRM_BUS_PLATFORM:
+        return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo));
+
+    case DRM_BUS_HOST1X:
+        return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo));
+
     default:
         break;
     }
@@ -2941,18 +3074,58 @@
            MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
                 sizeof(DRM_CONTROL_MINOR_NAME),
                 sizeof(DRM_RENDER_MINOR_NAME)) +
-           3 /* lenght of the node number */;
+           3 /* length of the node number */;
 }
 
-static int drmParsePciDeviceInfo(const char *d_name,
-                                 drmPciDeviceInfoPtr device)
-{
 #ifdef __linux__
+static int parse_separate_sysfs_files(int maj, int min,
+                                      drmPciDeviceInfoPtr device,
+                                      bool ignore_revision)
+{
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+    static const char *attrs[] = {
+      "revision", /* Older kernels are missing the file, so check for it first */
+      "vendor",
+      "device",
+      "subsystem_vendor",
+      "subsystem_device",
+    };
+    char path[PATH_MAX + 1];
+    unsigned int data[ARRAY_SIZE(attrs)];
+    FILE *fp;
+    int ret;
+
+    for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
+        snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min,
+                 attrs[i]);
+        fp = fopen(path, "r");
+        if (!fp)
+            return -errno;
+
+        ret = fscanf(fp, "%x", &data[i]);
+        fclose(fp);
+        if (ret != 1)
+            return -errno;
+
+    }
+
+    device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
+    device->vendor_id = data[1] & 0xffff;
+    device->device_id = data[2] & 0xffff;
+    device->subvendor_id = data[3] & 0xffff;
+    device->subdevice_id = data[4] & 0xffff;
+
+    return 0;
+}
+
+static int parse_config_sysfs_file(int maj, int min,
+                                   drmPciDeviceInfoPtr device)
+{
     char path[PATH_MAX + 1];
     unsigned char config[64];
     int fd, ret;
 
-    snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config", d_name);
+    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min);
     fd = open(path, O_RDONLY);
     if (fd < 0)
         return -errno;
@@ -2969,17 +3142,101 @@
     device->subdevice_id = config[46] | (config[47] << 8);
 
     return 0;
+}
+#endif
+
+static int drmParsePciDeviceInfo(int maj, int min,
+                                 drmPciDeviceInfoPtr device,
+                                 uint32_t flags)
+{
+#ifdef __linux__
+    if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
+        return parse_separate_sysfs_files(maj, min, device, true);
+
+    if (parse_separate_sysfs_files(maj, min, device, false))
+        return parse_config_sysfs_file(maj, min, device);
+
+    return 0;
+#elif defined(__OpenBSD__)
+    struct drm_pciinfo pinfo;
+    int fd, type;
+
+    type = drmGetMinorType(min);
+    if (type == -1)
+        return -ENODEV;
+
+    fd = drmOpenMinor(min, 0, type);
+    if (fd < 0)
+        return -errno;
+
+    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
+        close(fd);
+        return -errno;
+    }
+    close(fd);
+
+    device->vendor_id = pinfo.vendor_id;
+    device->device_id = pinfo.device_id;
+    device->revision_id = pinfo.revision_id;
+    device->subvendor_id = pinfo.subvendor_id;
+    device->subdevice_id = pinfo.subdevice_id;
+
+    return 0;
 #else
 #warning "Missing implementation of drmParsePciDeviceInfo"
     return -EINVAL;
 #endif
 }
 
+static void drmFreePlatformDevice(drmDevicePtr device)
+{
+    if (device->deviceinfo.platform) {
+        if (device->deviceinfo.platform->compatible) {
+            char **compatible = device->deviceinfo.platform->compatible;
+
+            while (*compatible) {
+                free(*compatible);
+                compatible++;
+            }
+
+            free(device->deviceinfo.platform->compatible);
+        }
+    }
+}
+
+static void drmFreeHost1xDevice(drmDevicePtr device)
+{
+    if (device->deviceinfo.host1x) {
+        if (device->deviceinfo.host1x->compatible) {
+            char **compatible = device->deviceinfo.host1x->compatible;
+
+            while (*compatible) {
+                free(*compatible);
+                compatible++;
+            }
+
+            free(device->deviceinfo.host1x->compatible);
+        }
+    }
+}
+
 void drmFreeDevice(drmDevicePtr *device)
 {
     if (device == NULL)
         return;
 
+    if (*device) {
+        switch ((*device)->bustype) {
+        case DRM_BUS_PLATFORM:
+            drmFreePlatformDevice(*device);
+            break;
+
+        case DRM_BUS_HOST1X:
+            drmFreeHost1xDevice(*device);
+            break;
+        }
+    }
+
     free(*device);
     *device = NULL;
 }
@@ -2991,63 +3248,415 @@
     if (devices == NULL)
         return;
 
-    for (i = 0; i < count && devices[i] != NULL; i++)
-        drmFreeDevice(&devices[i]);
+    for (i = 0; i < count; i++)
+        if (devices[i])
+            drmFreeDevice(&devices[i]);
 }
 
-static int drmProcessPciDevice(drmDevicePtr *device, const char *d_name,
-                               const char *node, int node_type,
-                               int maj, int min, bool fetch_deviceinfo)
+static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
+                                   size_t bus_size, size_t device_size,
+                                   char **ptrp)
 {
-    const int max_node_str = drmGetMaxNodeName();
-    int ret, i;
-    char *addr;
+    size_t max_node_length, extra, size;
+    drmDevicePtr device;
+    unsigned int i;
+    char *ptr;
 
-    *device = calloc(1, sizeof(drmDevice) +
-		     (DRM_NODE_MAX * (sizeof(void *) + max_node_str)) +
-		     sizeof(drmPciBusInfo) +
-		     sizeof(drmPciDeviceInfo));
-    if (!*device)
+    max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
+    extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
+
+    size = sizeof(*device) + extra + bus_size + device_size;
+
+    device = calloc(1, size);
+    if (!device)
+        return NULL;
+
+    device->available_nodes = 1 << type;
+
+    ptr = (char *)device + sizeof(*device);
+    device->nodes = (char **)ptr;
+
+    ptr += DRM_NODE_MAX * sizeof(void *);
+
+    for (i = 0; i < DRM_NODE_MAX; i++) {
+        device->nodes[i] = ptr;
+        ptr += max_node_length;
+    }
+
+    memcpy(device->nodes[type], node, max_node_length);
+
+    *ptrp = ptr;
+
+    return device;
+}
+
+static int drmProcessPciDevice(drmDevicePtr *device,
+                               const char *node, int node_type,
+                               int maj, int min, bool fetch_deviceinfo,
+                               uint32_t flags)
+{
+    drmDevicePtr dev;
+    char *addr;
+    int ret;
+
+    dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
+                         sizeof(drmPciDeviceInfo), &addr);
+    if (!dev)
         return -ENOMEM;
 
-    addr = (char*)*device;
-  
-    (*device)->bustype = DRM_BUS_PCI;
-    (*device)->available_nodes = 1 << node_type;
+    dev->bustype = DRM_BUS_PCI;
 
-    addr += sizeof(drmDevice);
-    (*device)->nodes = (char**)addr;
+    dev->businfo.pci = (drmPciBusInfoPtr)addr;
 
-    addr += DRM_NODE_MAX * sizeof(void *);
-    for (i = 0; i < DRM_NODE_MAX; i++) {
-        (*device)->nodes[i] = addr;
-        addr += max_node_str;
-    }
-    memcpy((*device)->nodes[node_type], node, max_node_str);
-
-    (*device)->businfo.pci = (drmPciBusInfoPtr)addr;
-
-    ret = drmParsePciBusInfo(maj, min, (*device)->businfo.pci);
+    ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
     if (ret)
         goto free_device;
 
     // Fetch the device info if the user has requested it
     if (fetch_deviceinfo) {
         addr += sizeof(drmPciBusInfo);
-        (*device)->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
+        dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
 
-        ret = drmParsePciDeviceInfo(d_name, (*device)->deviceinfo.pci);
+        ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
         if (ret)
             goto free_device;
     }
+
+    *device = dev;
+
     return 0;
 
 free_device:
-    free(*device);
-    *device = NULL;
+    free(dev);
     return ret;
 }
 
+static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1], *value;
+    unsigned int bus, dev;
+    int ret;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+
+    value = sysfs_uevent_get(path, "BUSNUM");
+    if (!value)
+        return -ENOENT;
+
+    ret = sscanf(value, "%03u", &bus);
+    free(value);
+
+    if (ret <= 0)
+        return -errno;
+
+    value = sysfs_uevent_get(path, "DEVNUM");
+    if (!value)
+        return -ENOENT;
+
+    ret = sscanf(value, "%03u", &dev);
+    free(value);
+
+    if (ret <= 0)
+        return -errno;
+
+    info->bus = bus;
+    info->dev = dev;
+
+    return 0;
+#else
+#warning "Missing implementation of drmParseUsbBusInfo"
+    return -EINVAL;
+#endif
+}
+
+static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1], *value;
+    unsigned int vendor, product;
+    int ret;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+
+    value = sysfs_uevent_get(path, "PRODUCT");
+    if (!value)
+        return -ENOENT;
+
+    ret = sscanf(value, "%x/%x", &vendor, &product);
+    free(value);
+
+    if (ret <= 0)
+        return -errno;
+
+    info->vendor = vendor;
+    info->product = product;
+
+    return 0;
+#else
+#warning "Missing implementation of drmParseUsbDeviceInfo"
+    return -EINVAL;
+#endif
+}
+
+static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
+                               int node_type, int maj, int min,
+                               bool fetch_deviceinfo, uint32_t flags)
+{
+    drmDevicePtr dev;
+    char *ptr;
+    int ret;
+
+    dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
+                         sizeof(drmUsbDeviceInfo), &ptr);
+    if (!dev)
+        return -ENOMEM;
+
+    dev->bustype = DRM_BUS_USB;
+
+    dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
+
+    ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
+    if (ret < 0)
+        goto free_device;
+
+    if (fetch_deviceinfo) {
+        ptr += sizeof(drmUsbBusInfo);
+        dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
+
+        ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
+        if (ret < 0)
+            goto free_device;
+    }
+
+    *device = dev;
+
+    return 0;
+
+free_device:
+    free(dev);
+    return ret;
+}
+
+static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1], *name;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+
+    name = sysfs_uevent_get(path, "OF_FULLNAME");
+    if (!name)
+        return -ENOENT;
+
+    strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
+    info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
+    free(name);
+
+    return 0;
+#else
+#warning "Missing implementation of drmParsePlatformBusInfo"
+    return -EINVAL;
+#endif
+}
+
+static int drmParsePlatformDeviceInfo(int maj, int min,
+                                      drmPlatformDeviceInfoPtr info)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1], *value;
+    unsigned int count, i;
+    int err;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+
+    value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
+    if (!value)
+        return -ENOENT;
+
+    sscanf(value, "%u", &count);
+    free(value);
+
+    info->compatible = calloc(count + 1, sizeof(*info->compatible));
+    if (!info->compatible)
+        return -ENOMEM;
+
+    for (i = 0; i < count; i++) {
+        value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
+        if (!value) {
+            err = -ENOENT;
+            goto free;
+        }
+
+        info->compatible[i] = value;
+    }
+
+    return 0;
+
+free:
+    while (i--)
+        free(info->compatible[i]);
+
+    free(info->compatible);
+    return err;
+#else
+#warning "Missing implementation of drmParsePlatformDeviceInfo"
+    return -EINVAL;
+#endif
+}
+
+static int drmProcessPlatformDevice(drmDevicePtr *device,
+                                    const char *node, int node_type,
+                                    int maj, int min, bool fetch_deviceinfo,
+                                    uint32_t flags)
+{
+    drmDevicePtr dev;
+    char *ptr;
+    int ret;
+
+    dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
+                         sizeof(drmPlatformDeviceInfo), &ptr);
+    if (!dev)
+        return -ENOMEM;
+
+    dev->bustype = DRM_BUS_PLATFORM;
+
+    dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
+
+    ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
+    if (ret < 0)
+        goto free_device;
+
+    if (fetch_deviceinfo) {
+        ptr += sizeof(drmPlatformBusInfo);
+        dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
+
+        ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
+        if (ret < 0)
+            goto free_device;
+    }
+
+    *device = dev;
+
+    return 0;
+
+free_device:
+    free(dev);
+    return ret;
+}
+
+static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1], *name;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+
+    name = sysfs_uevent_get(path, "OF_FULLNAME");
+    if (!name)
+        return -ENOENT;
+
+    strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
+    info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
+    free(name);
+
+    return 0;
+#else
+#warning "Missing implementation of drmParseHost1xBusInfo"
+    return -EINVAL;
+#endif
+}
+
+static int drmParseHost1xDeviceInfo(int maj, int min,
+                                    drmHost1xDeviceInfoPtr info)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1], *value;
+    unsigned int count, i;
+    int err;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+
+    value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
+    if (!value)
+        return -ENOENT;
+
+    sscanf(value, "%u", &count);
+    free(value);
+
+    info->compatible = calloc(count + 1, sizeof(*info->compatible));
+    if (!info->compatible)
+        return -ENOMEM;
+
+    for (i = 0; i < count; i++) {
+        value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
+        if (!value) {
+            err = -ENOENT;
+            goto free;
+        }
+
+        info->compatible[i] = value;
+    }
+
+    return 0;
+
+free:
+    while (i--)
+        free(info->compatible[i]);
+
+    free(info->compatible);
+    return err;
+#else
+#warning "Missing implementation of drmParseHost1xDeviceInfo"
+    return -EINVAL;
+#endif
+}
+
+static int drmProcessHost1xDevice(drmDevicePtr *device,
+                                  const char *node, int node_type,
+                                  int maj, int min, bool fetch_deviceinfo,
+                                  uint32_t flags)
+{
+    drmDevicePtr dev;
+    char *ptr;
+    int ret;
+
+    dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
+                         sizeof(drmHost1xDeviceInfo), &ptr);
+    if (!dev)
+        return -ENOMEM;
+
+    dev->bustype = DRM_BUS_HOST1X;
+
+    dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
+
+    ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
+    if (ret < 0)
+        goto free_device;
+
+    if (fetch_deviceinfo) {
+        ptr += sizeof(drmHost1xBusInfo);
+        dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
+
+        ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
+        if (ret < 0)
+            goto free_device;
+    }
+
+    *device = dev;
+
+    return 0;
+
+free_device:
+    free(dev);
+    return ret;
+}
+
+/* Consider devices located on the same bus as duplicate and fold the respective
+ * entries into a single one.
+ *
+ * Note: this leaves "gaps" in the array, while preserving the length.
+ */
 static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
 {
     int node_type, i, j;
@@ -3065,17 +3674,93 @@
     }
 }
 
+/* Check that the given flags are valid returning 0 on success */
+static int
+drm_device_validate_flags(uint32_t flags)
+{
+        return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
+}
+
 /**
  * Get information about the opened drm device
  *
  * \param fd file descriptor of the drm device
+ * \param flags feature/behaviour bitmask
  * \param device the address of a drmDevicePtr where the information
  *               will be allocated in stored
  *
  * \return zero on success, negative error code otherwise.
+ *
+ * \note Unlike drmGetDevice it does not retrieve the pci device revision field
+ * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
  */
-int drmGetDevice(int fd, drmDevicePtr *device)
+int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
 {
+#ifdef __OpenBSD__
+    /*
+     * DRI device nodes on OpenBSD are not in their own directory, they reside
+     * in /dev along with a large number of statically generated /dev nodes.
+     * Avoid stat'ing all of /dev needlessly by implementing this custom path.
+     */
+    drmDevicePtr     d;
+    struct stat      sbuf;
+    char             node[PATH_MAX + 1];
+    const char      *dev_name;
+    int              node_type, subsystem_type;
+    int              maj, min, n, ret, base;
+
+    if (fd == -1 || device == NULL)
+        return -EINVAL;
+
+    if (fstat(fd, &sbuf))
+        return -errno;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+
+    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+        return -EINVAL;
+
+    node_type = drmGetMinorType(min);
+    if (node_type == -1)
+        return -ENODEV;
+
+    switch (node_type) {
+    case DRM_NODE_PRIMARY:
+        dev_name = DRM_DEV_NAME;
+        break;
+    case DRM_NODE_CONTROL:
+        dev_name = DRM_CONTROL_DEV_NAME;
+        break;
+    case DRM_NODE_RENDER:
+        dev_name = DRM_RENDER_DEV_NAME;
+        break;
+    default:
+        return -EINVAL;
+    };
+
+    base = drmGetMinorBase(node_type);
+    if (base < 0)
+        return -EINVAL;
+
+    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
+    if (n == -1 || n >= PATH_MAX)
+      return -errno;
+    if (stat(node, &sbuf))
+        return -EINVAL;
+
+    subsystem_type = drmParseSubsystemType(maj, min);
+    if (subsystem_type != DRM_BUS_PCI)
+        return -ENODEV;
+
+    ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
+    if (ret)
+        return ret;
+
+    *device = d;
+
+    return 0;
+#else
     drmDevicePtr *local_devices;
     drmDevicePtr d;
     DIR *sysdir;
@@ -3086,6 +3771,10 @@
     int maj, min;
     int ret, i, node_count;
     int max_count = 16;
+    dev_t find_rdev;
+
+    if (drm_device_validate_flags(flags))
+        return -EINVAL;
 
     if (fd == -1 || device == NULL)
         return -EINVAL;
@@ -3093,6 +3782,7 @@
     if (fstat(fd, &sbuf))
         return -errno;
 
+    find_rdev = sbuf.st_rdev;
     maj = major(sbuf.st_rdev);
     min = minor(sbuf.st_rdev);
 
@@ -3132,14 +3822,34 @@
 
         switch (subsystem_type) {
         case DRM_BUS_PCI:
-            ret = drmProcessPciDevice(&d, dent->d_name, node, node_type,
-                                      maj, min, true);
+            ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
             if (ret)
-                goto free_devices;
+                continue;
 
             break;
+
+        case DRM_BUS_USB:
+            ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
+            if (ret)
+                continue;
+
+            break;
+
+        case DRM_BUS_PLATFORM:
+            ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
+            if (ret)
+                continue;
+
+            break;
+
+        case DRM_BUS_HOST1X:
+            ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
+            if (ret)
+                continue;
+
+            break;
+
         default:
-            fprintf(stderr, "The subsystem type is not supported yet\n");
             continue;
         }
 
@@ -3153,20 +3863,26 @@
             local_devices = temp;
         }
 
-        local_devices[i] = d;
+        /* store target at local_devices[0] for ease to use below */
+        if (find_rdev == sbuf.st_rdev && i) {
+            local_devices[i] = local_devices[0];
+            local_devices[0] = d;
+        }
+        else
+            local_devices[i] = d;
         i++;
     }
     node_count = i;
 
-    /* Fold nodes into a single device if they share the same bus info */
     drmFoldDuplicatedDevices(local_devices, node_count);
 
     *device = local_devices[0];
-    for (i = 1; i < node_count && local_devices[i]; i++)
-            drmFreeDevice(&local_devices[i]);
+    drmFreeDevices(&local_devices[1], node_count - 1);
 
     closedir(sysdir);
     free(local_devices);
+    if (*device == NULL)
+        return -ENODEV;
     return 0;
 
 free_devices:
@@ -3176,11 +3892,27 @@
 free_locals:
     free(local_devices);
     return ret;
+#endif
+}
+
+/**
+ * Get information about the opened drm device
+ *
+ * \param fd file descriptor of the drm device
+ * \param device the address of a drmDevicePtr where the information
+ *               will be allocated in stored
+ *
+ * \return zero on success, negative error code otherwise.
+ */
+int drmGetDevice(int fd, drmDevicePtr *device)
+{
+    return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
 }
 
 /**
  * Get drm devices on the system
  *
+ * \param flags feature/behaviour bitmask
  * \param devices the array of devices with drmDevicePtr elements
  *                can be NULL to get the device number first
  * \param max_devices the maximum number of devices for the array
@@ -3189,8 +3921,11 @@
  *         if devices is NULL - total number of devices available on the system,
  *         alternatively the number of devices stored in devices[], which is
  *         capped by the max_devices.
+ *
+ * \note Unlike drmGetDevices it does not retrieve the pci device revision field
+ * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
  */
-int drmGetDevices(drmDevicePtr devices[], int max_devices)
+int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
 {
     drmDevicePtr *local_devices;
     drmDevicePtr device;
@@ -3203,6 +3938,9 @@
     int ret, i, node_count, device_count;
     int max_count = 16;
 
+    if (drm_device_validate_flags(flags))
+        return -EINVAL;
+
     local_devices = calloc(max_count, sizeof(drmDevicePtr));
     if (local_devices == NULL)
         return -ENOMEM;
@@ -3236,14 +3974,38 @@
 
         switch (subsystem_type) {
         case DRM_BUS_PCI:
-            ret = drmProcessPciDevice(&device, dent->d_name, node, node_type,
-                                      maj, min, devices != NULL);
+            ret = drmProcessPciDevice(&device, node, node_type,
+                                      maj, min, devices != NULL, flags);
+            if (ret)
+                continue;
+
+            break;
+
+        case DRM_BUS_USB:
+            ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
+                                      devices != NULL, flags);
             if (ret)
                 goto free_devices;
 
             break;
+
+        case DRM_BUS_PLATFORM:
+            ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
+                                           devices != NULL, flags);
+            if (ret)
+                goto free_devices;
+
+            break;
+
+        case DRM_BUS_HOST1X:
+            ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
+                                         devices != NULL, flags);
+            if (ret)
+                goto free_devices;
+
+            break;
+
         default:
-            fprintf(stderr, "The subsystem type is not supported yet\n");
             continue;
         }
 
@@ -3262,11 +4024,13 @@
     }
     node_count = i;
 
-    /* Fold nodes into a single device if they share the same bus info */
     drmFoldDuplicatedDevices(local_devices, node_count);
 
     device_count = 0;
-    for (i = 0; i < node_count && local_devices[i]; i++) {
+    for (i = 0; i < node_count; i++) {
+        if (!local_devices[i])
+            continue;
+
         if ((devices != NULL) && (device_count < max_devices))
             devices[device_count] = local_devices[i];
         else
@@ -3287,3 +4051,92 @@
     free(local_devices);
     return ret;
 }
+
+/**
+ * Get drm devices on the system
+ *
+ * \param devices the array of devices with drmDevicePtr elements
+ *                can be NULL to get the device number first
+ * \param max_devices the maximum number of devices for the array
+ *
+ * \return on error - negative error code,
+ *         if devices is NULL - total number of devices available on the system,
+ *         alternatively the number of devices stored in devices[], which is
+ *         capped by the max_devices.
+ */
+int drmGetDevices(drmDevicePtr devices[], int max_devices)
+{
+    return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
+}
+
+char *drmGetDeviceNameFromFd2(int fd)
+{
+#ifdef __linux__
+    struct stat sbuf;
+    char path[PATH_MAX + 1], *value;
+    unsigned int maj, min;
+
+    if (fstat(fd, &sbuf))
+        return NULL;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+
+    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+        return NULL;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
+
+    value = sysfs_uevent_get(path, "DEVNAME");
+    if (!value)
+        return NULL;
+
+    snprintf(path, sizeof(path), "/dev/%s", value);
+    free(value);
+
+    return strdup(path);
+#else
+    struct stat      sbuf;
+    char             node[PATH_MAX + 1];
+    const char      *dev_name;
+    int              node_type;
+    int              maj, min, n, base;
+
+    if (fstat(fd, &sbuf))
+        return NULL;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+
+    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+        return NULL;
+
+    node_type = drmGetMinorType(min);
+    if (node_type == -1)
+        return NULL;
+
+    switch (node_type) {
+    case DRM_NODE_PRIMARY:
+        dev_name = DRM_DEV_NAME;
+        break;
+    case DRM_NODE_CONTROL:
+        dev_name = DRM_CONTROL_DEV_NAME;
+        break;
+    case DRM_NODE_RENDER:
+        dev_name = DRM_RENDER_DEV_NAME;
+        break;
+    default:
+        return NULL;
+    };
+
+    base = drmGetMinorBase(node_type);
+    if (base < 0)
+        return NULL;
+
+    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
+    if (n == -1 || n >= PATH_MAX)
+      return NULL;
+
+    return strdup(node);
+#endif
+}
diff --git a/xf86drm.h b/xf86drm.h
index 481d882..0d92701 100644
--- a/xf86drm.h
+++ b/xf86drm.h
@@ -753,6 +753,11 @@
 extern int drmHandleEvent(int fd, drmEventContextPtr evctx);
 
 extern char *drmGetDeviceNameFromFd(int fd);
+
+/* Improved version of drmGetDeviceNameFromFd which attributes for any type of
+ * device/node - card, control or renderD.
+ */
+extern char *drmGetDeviceNameFromFd2(int fd);
 extern int drmGetNodeTypeFromFd(int fd);
 
 extern int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd);
@@ -761,7 +766,10 @@
 extern char *drmGetPrimaryDeviceNameFromFd(int fd);
 extern char *drmGetRenderDeviceNameFromFd(int fd);
 
-#define DRM_BUS_PCI   0
+#define DRM_BUS_PCI       0
+#define DRM_BUS_USB       1
+#define DRM_BUS_PLATFORM  2
+#define DRM_BUS_HOST1X    3
 
 typedef struct _drmPciBusInfo {
     uint16_t domain;
@@ -778,15 +786,51 @@
     uint8_t revision_id;
 } drmPciDeviceInfo, *drmPciDeviceInfoPtr;
 
+typedef struct _drmUsbBusInfo {
+    uint8_t bus;
+    uint8_t dev;
+} drmUsbBusInfo, *drmUsbBusInfoPtr;
+
+typedef struct _drmUsbDeviceInfo {
+    uint16_t vendor;
+    uint16_t product;
+} drmUsbDeviceInfo, *drmUsbDeviceInfoPtr;
+
+#define DRM_PLATFORM_DEVICE_NAME_LEN 512
+
+typedef struct _drmPlatformBusInfo {
+    char fullname[DRM_PLATFORM_DEVICE_NAME_LEN];
+} drmPlatformBusInfo, *drmPlatformBusInfoPtr;
+
+typedef struct _drmPlatformDeviceInfo {
+    char **compatible; /* NULL terminated list of compatible strings */
+} drmPlatformDeviceInfo, *drmPlatformDeviceInfoPtr;
+
+#define DRM_HOST1X_DEVICE_NAME_LEN 512
+
+typedef struct _drmHost1xBusInfo {
+    char fullname[DRM_HOST1X_DEVICE_NAME_LEN];
+} drmHost1xBusInfo, *drmHost1xBusInfoPtr;
+
+typedef struct _drmHost1xDeviceInfo {
+    char **compatible; /* NULL terminated list of compatible strings */
+} drmHost1xDeviceInfo, *drmHost1xDeviceInfoPtr;
+
 typedef struct _drmDevice {
     char **nodes; /* DRM_NODE_MAX sized array */
     int available_nodes; /* DRM_NODE_* bitmask */
     int bustype;
     union {
         drmPciBusInfoPtr pci;
+        drmUsbBusInfoPtr usb;
+        drmPlatformBusInfoPtr platform;
+        drmHost1xBusInfoPtr host1x;
     } businfo;
     union {
         drmPciDeviceInfoPtr pci;
+        drmUsbDeviceInfoPtr usb;
+        drmPlatformDeviceInfoPtr platform;
+        drmHost1xDeviceInfoPtr host1x;
     } deviceinfo;
 } drmDevice, *drmDevicePtr;
 
@@ -796,6 +840,10 @@
 extern int drmGetDevices(drmDevicePtr devices[], int max_devices);
 extern void drmFreeDevices(drmDevicePtr devices[], int count);
 
+#define DRM_DEVICE_GET_PCI_REVISION (1 << 0)
+extern int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device);
+extern int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices);
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/xf86drmMode.c b/xf86drmMode.c
index b341f38..e1c9974 100644
--- a/xf86drmMode.c
+++ b/xf86drmMode.c
@@ -34,7 +34,7 @@
  */
 
 /*
- * TODO the types we are after are defined in diffrent headers on diffrent
+ * TODO the types we are after are defined in different headers on different
  * platforms find which headers to include to get uint32_t
  */
 
@@ -270,10 +270,10 @@
 	return 0;
 }
 
-int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
-		  uint32_t pixel_format, uint32_t bo_handles[4],
-		  uint32_t pitches[4], uint32_t offsets[4],
-		  uint32_t *buf_id, uint32_t flags)
+int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height,
+                               uint32_t pixel_format, uint32_t bo_handles[4],
+                               uint32_t pitches[4], uint32_t offsets[4],
+                               uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)
 {
 	struct drm_mode_fb_cmd2 f;
 	int ret;
@@ -286,6 +286,8 @@
 	memcpy(f.handles, bo_handles, 4 * sizeof(bo_handles[0]));
 	memcpy(f.pitches, pitches, 4 * sizeof(pitches[0]));
 	memcpy(f.offsets, offsets, 4 * sizeof(offsets[0]));
+	if (modifier)
+		memcpy(f.modifier, modifier, 4 * sizeof(modifier[0]));
 
 	if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f)))
 		return ret;
@@ -294,6 +296,17 @@
 	return 0;
 }
 
+int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
+                  uint32_t pixel_format, uint32_t bo_handles[4],
+                  uint32_t pitches[4], uint32_t offsets[4],
+                  uint32_t *buf_id, uint32_t flags)
+{
+	return drmModeAddFB2WithModifiers(fd, width, height,
+					  pixel_format, bo_handles,
+					  pitches, offsets, NULL,
+					  buf_id, flags);
+}
+
 int drmModeRmFB(int fd, uint32_t bufferId)
 {
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
@@ -475,12 +488,13 @@
 {
 	struct drm_mode_get_connector conn, counts;
 	drmModeConnectorPtr r = NULL;
+	struct drm_mode_modeinfo stack_mode;
 
 	memclear(conn);
 	conn.connector_id = connector_id;
 	if (!probe) {
 		conn.count_modes = 1;
-		conn.modes_ptr = VOID2U64(drmMalloc(sizeof(struct drm_mode_modeinfo)));
+		conn.modes_ptr = VOID2U64(&stack_mode);
 	}
 
 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
@@ -504,7 +518,7 @@
 			goto err_allocs;
 	} else {
 		conn.count_modes = 1;
-		conn.modes_ptr = VOID2U64(drmMalloc(sizeof(struct drm_mode_modeinfo)));
+		conn.modes_ptr = VOID2U64(&stack_mode);
 	}
 
 	if (conn.count_encoders) {
@@ -525,7 +539,8 @@
 	    counts.count_encoders < conn.count_encoders) {
 		drmFree(U642VOID(conn.props_ptr));
 		drmFree(U642VOID(conn.prop_values_ptr));
-		drmFree(U642VOID(conn.modes_ptr));
+		if (U642VOID(conn.modes_ptr) != &stack_mode)
+			drmFree(U642VOID(conn.modes_ptr));
 		drmFree(U642VOID(conn.encoders_ptr));
 
 		goto retry;
@@ -567,7 +582,8 @@
 err_allocs:
 	drmFree(U642VOID(conn.prop_values_ptr));
 	drmFree(U642VOID(conn.props_ptr));
-	drmFree(U642VOID(conn.modes_ptr));
+	if (U642VOID(conn.modes_ptr) != &stack_mode)
+		drmFree(U642VOID(conn.modes_ptr));
 	drmFree(U642VOID(conn.encoders_ptr));
 
 	return r;
@@ -885,7 +901,7 @@
 
 	i = 0;
 	while (i < len) {
-		e = (struct drm_event *) &buffer[i];
+		e = (struct drm_event *)(buffer + i);
 		switch (e->type) {
 		case DRM_EVENT_VBLANK:
 			if (evctx->version < 1 ||
@@ -932,6 +948,22 @@
 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
 }
 
+int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id,
+			  uint32_t flags, void *user_data,
+			  uint32_t target_vblank)
+{
+	struct drm_mode_crtc_page_flip_target flip_target;
+
+	memclear(flip_target);
+	flip_target.fb_id = fb_id;
+	flip_target.crtc_id = crtc_id;
+	flip_target.user_data = VOID2U64(user_data);
+	flip_target.flags = flags;
+	flip_target.sequence = target_vblank;
+
+	return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target);
+}
+
 int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id,
 		    uint32_t fb_id, uint32_t flags,
 		    int32_t crtc_x, int32_t crtc_y,
diff --git a/xf86drmMode.h b/xf86drmMode.h
index 53bb423..9d73be9 100644
--- a/xf86drmMode.h
+++ b/xf86drmMode.h
@@ -123,13 +123,15 @@
 #define DRM_MODE_DITHERING_OFF  0
 #define DRM_MODE_DITHERING_ON   1
 
-#define DRM_MODE_ENCODER_NONE   0
-#define DRM_MODE_ENCODER_DAC    1
-#define DRM_MODE_ENCODER_TMDS   2
-#define DRM_MODE_ENCODER_LVDS   3
-#define DRM_MODE_ENCODER_TVDAC  4
+#define DRM_MODE_ENCODER_NONE    0
+#define DRM_MODE_ENCODER_DAC     1
+#define DRM_MODE_ENCODER_TMDS    2
+#define DRM_MODE_ENCODER_LVDS    3
+#define DRM_MODE_ENCODER_TVDAC   4
 #define DRM_MODE_ENCODER_VIRTUAL 5
-#define DRM_MODE_ENCODER_DSI	6
+#define DRM_MODE_ENCODER_DSI     6
+#define DRM_MODE_ENCODER_DPMST   7
+#define DRM_MODE_ENCODER_DPI     8
 
 #define DRM_MODE_SUBCONNECTOR_Automatic 0
 #define DRM_MODE_SUBCONNECTOR_Unknown   0
@@ -153,10 +155,11 @@
 #define DRM_MODE_CONNECTOR_DisplayPort  10
 #define DRM_MODE_CONNECTOR_HDMIA        11
 #define DRM_MODE_CONNECTOR_HDMIB        12
-#define DRM_MODE_CONNECTOR_TV		13
-#define DRM_MODE_CONNECTOR_eDP		14
+#define DRM_MODE_CONNECTOR_TV           13
+#define DRM_MODE_CONNECTOR_eDP          14
 #define DRM_MODE_CONNECTOR_VIRTUAL      15
 #define DRM_MODE_CONNECTOR_DSI          16
+#define DRM_MODE_CONNECTOR_DPI          17
 
 #define DRM_MODE_PROP_PENDING   (1<<0)
 #define DRM_MODE_PROP_RANGE     (1<<1)
@@ -369,6 +372,13 @@
 			 uint32_t pixel_format, uint32_t bo_handles[4],
 			 uint32_t pitches[4], uint32_t offsets[4],
 			 uint32_t *buf_id, uint32_t flags);
+
+/* ...with format modifiers */
+int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height,
+			       uint32_t pixel_format, uint32_t bo_handles[4],
+			       uint32_t pitches[4], uint32_t offsets[4],
+			       uint64_t modifier[4], uint32_t *buf_id, uint32_t flags);
+
 /**
  * Destroies the given framebuffer.
  */
@@ -466,6 +476,9 @@
 			       uint16_t *red, uint16_t *green, uint16_t *blue);
 extern int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
 			   uint32_t flags, void *user_data);
+extern int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id,
+				 uint32_t flags, void *user_data,
+				 uint32_t target_vblank);
 
 extern drmModePlaneResPtr drmModeGetPlaneResources(int fd);
 extern drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id);