summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYi Sun <yi.sun@intel.com>2015-03-05 15:56:04 +0800
committerYi Sun <yi.sun@intel.com>2015-03-05 15:56:04 +0800
commitc9f6fc5585acfad91f3c4f918fd62b8c37209a80 (patch)
treee9bfefaf402728922a8f5e7fc56b9cf3f9f4cd5d
Init the repo for upstream.
Signed-off-by: Yi Sun <yi.sun@intel.com>
-rw-r--r--Makefile.am25
-rwxr-xr-xautogen.sh19
-rw-r--r--configure.ac231
-rw-r--r--lib/.gitignore1
-rw-r--r--lib/Makefile.am20
-rw-r--r--lib/Makefile.sources56
-rw-r--r--lib/check-ndebug.h3
-rw-r--r--lib/drmtest.c378
-rw-r--r--lib/drmtest.h105
-rw-r--r--lib/igt_aux.c699
-rw-r--r--lib/igt_aux.h104
-rw-r--r--lib/igt_core.c1689
-rw-r--r--lib/igt_core.h652
-rw-r--r--lib/igt_debugfs.c615
-rw-r--r--lib/igt_debugfs.h145
-rw-r--r--lib/igt_fb.c807
-rw-r--r--lib/igt_fb.h105
-rw-r--r--lib/igt_gt.c341
-rw-r--r--lib/igt_gt.h77
-rw-r--r--lib/igt_kms.c1853
-rw-r--r--lib/igt_kms.h280
-rw-r--r--lib/intel_batchbuffer.c532
-rw-r--r--lib/intel_batchbuffer.h268
-rw-r--r--lib/intel_chipset.c206
-rw-r--r--lib/intel_chipset.h444
-rw-r--r--lib/intel_io.h85
-rw-r--r--lib/intel_reg.h3600
-rw-r--r--lib/ioctl_wrappers.c1144
-rw-r--r--lib/ioctl_wrappers.h138
-rw-r--r--lib/media_fill.h42
-rw-r--r--lib/rendercopy.h55
-rw-r--r--m4/ax_pkg_swig.m4135
-rw-r--r--m4/ax_python_devel.m4324
-rw-r--r--m4/ax_swig_python.m464
-rw-r--r--tests/.gitignore154
-rw-r--r--tests/1080p-left.pngbin0 -> 41858 bytes
-rw-r--r--tests/1080p-right.pngbin0 -> 42502 bytes
-rw-r--r--tests/Makefile.am23
-rw-r--r--tests/Makefile.sources16
-rw-r--r--tests/pass.pngbin0 -> 569 bytes
-rw-r--r--tests/template.c80
-rw-r--r--tests/testdisplay.c477
-rw-r--r--tests/testdisplay.h35
-rw-r--r--tests/testdisplay_hotplug.c138
44 files changed, 16165 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..d36dd0a
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,25 @@
+# Copyright © 2005 Adam Jackson.
+# Copyright © 2009,2013 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
+# on 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
+# ADAM JACKSON 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.
+
+ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
+
+#SUBDIRS = lib man tools scripts benchmarks demos overlay
+SUBDIRS = lib tests
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..629a257
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,19 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+if ! type gtkdocize > /dev/null 2>&1; then
+ echo "EXTRA_DIST =" > gtk-doc.make
+ echo "CLEANFILES =" >> gtk-doc.make
+else
+ gtkdocize || exit $?
+fi
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..3e77f7d
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,231 @@
+# Copyright 2005 Adam Jackson.
+#
+# 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
+# on 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
+# ADAM JACKSON 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.
+#
+# Process this file with autoconf to produce a configure script
+
+AC_PREREQ([2.60])
+AC_INIT([intel-gpu-tools],
+ [1.9],
+ [https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=DRM/Intel],
+ [intel-gpu-tools])
+
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_USE_SYSTEM_EXTENSIONS
+AC_SYS_LARGEFILE
+AC_GNU_SOURCE
+AC_CANONICAL_HOST
+
+AM_INIT_AUTOMAKE([1.11 foreign dist-bzip2])
+AM_PATH_PYTHON([3],, [:])
+
+AC_PROG_CC
+AM_PROG_LEX
+AC_PROG_YACC
+
+# check for gtk-doc
+m4_ifdef([GTK_DOC_CHECK], [
+GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
+],[
+AM_CONDITIONAL([ENABLE_GTK_DOC], false)
+enable_gtk_doc=no
+])
+
+
+# Checks for functions, headers, structures, etc.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([termios.h linux/kd.h sys/kd.h libgen.h])
+AC_CHECK_MEMBERS([struct sysinfo.totalram],[],[],[AC_INCLUDES_DEFAULT
+ #include <sys/sysinfo.h>
+ ])
+AC_CHECK_TYPES([sighandler_t],[],[],[AC_INCLUDES_DEFAULT
+#include <signal.h>])
+AC_CHECK_FUNCS([swapctl])
+AC_CHECK_FUNCS([asprintf])
+
+# Initialize libtool
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+# Require X.Org macros 1.16 or later for XORG_TESTSET_CFLAG
+m4_ifndef([XORG_MACROS_VERSION],
+ [m4_fatal([must install xorg-macros 1.16 or later before running autoconf/autogen])])
+XORG_MACROS_VERSION(1.16)
+XORG_DEFAULT_OPTIONS
+
+# warning flags for the assembler. We can't quite use CWARNFLAGS for it yet as
+# it generates waaaay too many warnings.
+ASSEMBLER_WARN_CFLAGS=""
+if test "x$GCC" = "xyes"; then
+ ASSEMBLER_WARN_CFLAGS="-Wall -Wstrict-prototypes \
+ -Wmissing-prototypes -Wmissing-declarations \
+ -Wnested-externs -fno-strict-aliasing"
+fi
+AC_SUBST(ASSEMBLER_WARN_CFLAGS)
+
+PKG_CHECK_MODULES(DRM, [libdrm_intel >= 2.4.52 libdrm])
+PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10])
+PKG_CHECK_MODULES(OVERLAY_XVLIB, [xv x11 xext dri2proto >= 2.6], enable_overlay_xvlib=yes, enable_overlay_xvlib=no)
+PKG_CHECK_MODULES(OVERLAY_XLIB, [cairo-xlib dri2proto >= 2.6], enable_overlay_xlib=yes, enable_overlay_xlib=no)
+
+AM_CONDITIONAL(BUILD_OVERLAY_XVLIB, [test "x$enable_overlay_xvlib" = xyes])
+AM_CONDITIONAL(BUILD_OVERLAY_XLIB, [test "x$enable_overlay_xlib" = xyes])
+AM_CONDITIONAL(BUILD_OVERLAY, [test "x$enable_overlay_xlib" = xyes -o "x$enable_overlay_xvlib"])
+if test x$enable_overlay_xvlib = xyes; then
+ AC_DEFINE(HAVE_OVERLAY_XVLIB, 1, [Enable XV backend])
+fi
+if test x$enable_overlay_xlib = xyes; then
+ AC_DEFINE(HAVE_OVERLAY_XLIB, 1, [Enable X backend])
+fi
+PKG_CHECK_MODULES(XRANDR, xrandr >= 1.3, AC_DEFINE(HAVE_XRANDR, 1, [Have libXrandr]), [have_xrandr=no])
+
+# for testdisplay
+PKG_CHECK_MODULES(CAIRO, [cairo >= 1.12.0])
+PKG_CHECK_MODULES(LIBUDEV, [libudev], [udev=yes], [udev=no])
+if test x"$udev" = xyes; then
+ AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
+fi
+PKG_CHECK_MODULES(GLIB, glib-2.0)
+
+# can we build the assembler?
+AS_IF([test x"$LEX" != "x:" -a x"$YACC" != xyacc],
+ [enable_assembler=yes],
+ [enable_assembler=no])
+AM_CONDITIONAL(BUILD_ASSEMBLER, [test "x$enable_assembler" = xyes])
+
+# -----------------------------------------------------------------------------
+# Configuration options
+# -----------------------------------------------------------------------------
+# for dma-buf tests
+AC_ARG_ENABLE(nouveau, AS_HELP_STRING([--disable-nouveau],
+ [Enable use of nouveau API for prime tests (default: auto)]),
+ [NOUVEAU=$enableval], [NOUVEAU=auto])
+if test "x$NOUVEAU" = xauto; then
+ PKG_CHECK_EXISTS([libdrm_nouveau >= 2.4.33], [NOUVEAU=yes], [NOUVEAU=no])
+fi
+if test "x$NOUVEAU" = xyes; then
+ PKG_CHECK_MODULES(DRM_NOUVEAU, [libdrm_nouveau >= 2.4.33])
+ AC_DEFINE(HAVE_NOUVEAU, 1, [Have nouveau support])
+fi
+AM_CONDITIONAL(HAVE_NOUVEAU, [test "x$NOUVEAU" = xyes])
+
+#Configure options for the python quick-dumper
+AC_ARG_ENABLE(dumper,
+ AS_HELP_STRING([--disable-dumper],
+ [Disable the python based register dumper (default: enabled)]),
+ [DUMPER=$enableval], [DUMPER=auto])
+if test "x$DUMPER" = xauto; then
+ # AX_PYTHON_DEVEL/AX_SWIG_PYTHON are not super friendly and don't
+ # easily allow us to introspect the result of their checks. So if we
+ # find SWING on the system, that's enough to try compiling the dumper.
+ AX_PKG_SWIG(2.0.0, [DUMPER=yes], [DUMPER=no])
+fi
+if test "x$DUMPER" = xyes; then
+ AC_DEFINE(HAVE_DUMPER, 1, [Have dumper support])
+ # SWIG configuration
+ AX_PKG_SWIG(2.0.0, [], [ AC_MSG_ERROR([SWIG 2.0.0 or higher is required to build..]) ])
+ AX_PYTHON_DEVEL([>= '3.0'])
+ AX_SWIG_PYTHON
+fi
+AM_CONDITIONAL(HAVE_DUMPER, [test "x$DUMPER" = xyes])
+
+# Define a configure option for the shader debugger
+AC_ARG_ENABLE(shader-debugger, AS_HELP_STRING([--enable-shader-debugger],
+ [Enable shader debugging support [autodetected]]),
+ [BUILD_SHADER_DEBUGGER="$enableval"], [BUILD_SHADER_DEBUGGER=auto])
+
+# Shader debugger depends on python3, intel-genasm and objcopy
+if test "x$BUILD_SHADER_DEBUGGER" != xno; then
+ # Check that the assembler is built
+ if test "x$enable_assembler" = xno; then
+ BUILD_SHADER_DEBUGGER=no
+ if test "x$BUILD_SHADER_DEBUGGER" = xyes; then
+ AC_MSG_ERROR([Shader debugger requested, but assembler not enabled.])
+ fi
+ fi
+
+ # Check Python 3 is installed
+ if test "$PYTHON" = ":" ; then
+ if test "x$BUILD_SHADER_DEBUGGER" = xyes; then
+ AC_MSG_ERROR([Shader debugger requested, python version 3 not found.])
+ else
+ BUILD_SHADER_DEBUGGER=no
+ fi
+ fi
+
+ # Check for the objcopy GNU binary utiliy command
+ AC_PATH_PROGS([OBJCOPY], objcopy)
+ if test -z "$OBJCOPY" ; then
+ if test "x$BUILD_SHADER_DEBUGGER" = xyes; then
+ AC_MSG_ERROR([Shader debugger requested, but objcopy command not found.])
+ else
+ BUILD_SHADER_DEBUGGER=no
+ fi
+ fi
+fi
+
+AM_CONDITIONAL(BUILD_SHADER_DEBUGGER, [test "x$BUILD_SHADER_DEBUGGER" != xno])
+AS_IF([test "x$BUILD_SHADER_DEBUGGER" != xno],
+ [enable_debugger=yes], [enable_debugger=no])
+
+# -----------------------------------------------------------------------------
+
+# To build multithread code, gcc uses -pthread, Solaris Studio cc uses -mt
+XORG_TESTSET_CFLAG([THREAD_CFLAGS], [-pthread], [-mt])
+AC_SUBST([THREAD_CFLAGS])
+
+AC_ARG_ENABLE(tests,
+ AS_HELP_STRING([--disable-tests],
+ [Disable tests build (default: enabled)]),
+ [BUILD_TESTS=$enableval], [BUILD_TESTS="yes"])
+if test "x$BUILD_TESTS" = xyes; then
+ AC_DEFINE(BUILD_TESTS, 1, [Build tests])
+fi
+AM_CONDITIONAL(BUILD_TESTS, [test "x$BUILD_TESTS" = xyes])
+AC_DEFINE_UNQUOTED(TARGET_CPU_PLATFORM, ["$host_cpu"], [Target platform])
+
+AC_CONFIG_FILES([
+ Makefile
+ lib/Makefile
+ tests/Makefile
+ ])
+AC_OUTPUT
+
+# Print a summary of the compilation
+echo ""
+echo "Intel GPU tools"
+
+echo ""
+echo " • Tests:"
+echo " Build tests : ${BUILD_TESTS}"
+echo " Compile prime tests: ${NOUVEAU}"
+echo ""
+echo " • Tools:"
+echo " Assembler : ${enable_assembler}"
+echo " Debugger : ${enable_debugger}"
+echo " Python dumper : ${DUMPER}"
+echo " Overlay : X: ${enable_overlay_xlib}, Xv: ${enable_overlay_xvlib}"
+echo ""
+echo " • API-Documentation : ${enable_gtk_doc}"
+echo ""
+
+# vim: set ft=config ts=8 sw=8 tw=0 noet :
diff --git a/lib/.gitignore b/lib/.gitignore
new file mode 100644
index 0000000..6702033
--- /dev/null
+++ b/lib/.gitignore
@@ -0,0 +1 @@
+version.h
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..fcef049
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,20 @@
+IGT_LIB_PATH := $(builddir)
+GPU_TOOLS_PATH := $(top_srcdir)
+
+SUBDIRS = .
+
+include Makefile.sources
+
+noinst_LTLIBRARIES = libintel_tools.la
+noinst_HEADERS = check-ndebug.h
+
+AM_CPPFLAGS = -I$(top_srcdir)
+AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) \
+ -DIGT_DATADIR=\""$(abs_top_srcdir)/tests"\" \
+ -DIGT_LOG_DOMAIN=\""$(subst _,-,$*)"\" \
+ -pthread
+
+
+LDADD = $(CAIRO_LIBS)
+AM_CFLAGS += $(CAIRO_CFLAGS)
+
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
new file mode 100644
index 0000000..518f020
--- /dev/null
+++ b/lib/Makefile.sources
@@ -0,0 +1,56 @@
+libintel_tools_la_SOURCES = \
+ drmtest.c \
+ drmtest.h \
+ igt_debugfs.c \
+ igt_debugfs.h \
+ igt_aux.c \
+ igt_aux.h \
+ igt_gt.c \
+ igt_gt.h \
+ intel_batchbuffer.c \
+ intel_batchbuffer.h \
+ intel_chipset.h \
+ intel_chipset.c \
+ intel_io.h \
+ intel_reg.h \
+ ioctl_wrappers.c \
+ ioctl_wrappers.h \
+ igt_kms.c \
+ igt_kms.h \
+ igt_fb.c \
+ igt_fb.h \
+ igt_core.c \
+ igt_core.h \
+ rendercopy.h \
+ media_fill.h \
+ intel_chipset.h \
+ intel_chipset.c \
+ $(NULL)
+
+.PHONY: version.h.tmp
+
+$(IGT_LIB_PATH)/version.h.tmp:
+ @touch $@
+ @if test -d $(GPU_TOOLS_PATH)/.git; then \
+ if which git > /dev/null 2>&1; then \
+ cd $(GPU_TOOLS_PATH); \
+ git log -n 1 --oneline | \
+ sed 's/^\([^ ]*\) .*/#define IGT_GIT_SHA1 "g\1"/' ; \
+ else \
+ echo '#define IGT_GIT_SHA1 "NO-GIT"' ; \
+ fi \
+ else \
+ echo '#define IGT_GIT_SHA1 "NOT-GIT"' ; \
+ fi >> $@
+
+
+$(IGT_LIB_PATH)/version.h: $(IGT_LIB_PATH)/version.h.tmp
+ @if ! cmp -s $(IGT_LIB_PATH)/version.h.tmp $(IGT_LIB_PATH)/version.h; then \
+ mv $(IGT_LIB_PATH)/version.h.tmp $(IGT_LIB_PATH)/version.h ; \
+ else \
+ rm $(IGT_LIB_PATH)/version.h.tmp ; \
+ fi
+
+BUILT_SOURCES = $(IGT_LIB_PATH)/version.h
+CLEANFILES = $(IGT_LIB_PATH)/version.h $(IGT_LIB_PATH)/version.h.tmp
+
diff --git a/lib/check-ndebug.h b/lib/check-ndebug.h
new file mode 100644
index 0000000..68a6ec4
--- /dev/null
+++ b/lib/check-ndebug.h
@@ -0,0 +1,3 @@
+#ifdef NDEBUG
+#error "Testsuite needs its asserts!"
+#endif
diff --git a/lib/drmtest.c b/lib/drmtest.c
new file mode 100644
index 0000000..ee5c123
--- /dev/null
+++ b/lib/drmtest.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright © 2007, 2011, 2013 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>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef ANDROID
+#define _GNU_SOURCE
+#else
+#include <libgen.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <pciaccess.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <termios.h>
+
+#include "drmtest.h"
+#include "i915_drm.h"
+#include "intel_chipset.h"
+#include "intel_io.h"
+#include "igt_gt.h"
+#include "igt_debugfs.h"
+#include "version.h"
+#include "config.h"
+#include "intel_reg.h"
+#include "ioctl_wrappers.h"
+
+/**
+ * SECTION:drmtest
+ * @short_description: Base library for drm tests and tools
+ * @title: drmtest
+ * @include: drmtest.h
+ *
+ * This library contains the basic support for writing tests, with the most
+ * important part being the helper function to open drm device nodes.
+ *
+ * But there's also a bit of other assorted stuff here.
+ *
+ * Note that this library's header pulls in the [i-g-t core](intel-gpu-tools-i-g-t-core.html)
+ * and [batchbuffer](intel-gpu-tools-intel-batchbuffer.html) libraries as dependencies.
+ */
+
+uint16_t __drm_device_id;
+
+static int is_i915_device(int fd)
+{
+ drm_version_t version;
+ char name[5] = "";
+
+ memset(&version, 0, sizeof(version));
+ version.name_len = 4;
+ version.name = name;
+
+ if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
+ return 0;
+
+ return strcmp("i915", name) == 0;
+}
+
+static int
+is_intel(int fd)
+{
+ struct drm_i915_getparam gp;
+ int devid = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = I915_PARAM_CHIPSET_ID;
+ gp.value = &devid;
+
+ if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
+ return 0;
+
+ if (!IS_INTEL(devid))
+ return 0;
+
+ __drm_device_id = devid;
+ return 1;
+}
+
+static void check_stop_rings(void)
+{
+ enum stop_ring_flags flags;
+ flags = igt_get_stop_rings();
+ igt_warn_on_f(flags != 0,
+ "i915_ring_stop flags on exit 0x%x, can't quiescent gpu cleanly\n",
+ flags);
+
+ if (flags)
+ igt_set_stop_rings(STOP_RING_NONE);
+}
+
+#define LOCAL_I915_EXEC_VEBOX (4 << 0)
+/**
+ * gem_quiescent_gpu:
+ * @fd: open i915 drm file descriptor
+ *
+ * Ensure the gpu is idle by launching a nop execbuf and stalling for it. This
+ * is automatically run when opening a drm device node and is also installed as
+ * an exit handler to have the best assurance that the test is run in a pristine
+ * and controlled environment.
+ *
+ * This function simply allows tests to make additional calls in-between, if so
+ * desired.
+ */
+void gem_quiescent_gpu(int fd)
+{
+ uint32_t batch[2] = {MI_BATCH_BUFFER_END, 0};
+ uint32_t handle;
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 gem_exec[1];
+
+ check_stop_rings();
+
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, sizeof(batch));
+
+ gem_exec[0].handle = handle;
+ gem_exec[0].relocation_count = 0;
+ gem_exec[0].relocs_ptr = 0;
+ gem_exec[0].alignment = 0;
+ gem_exec[0].offset = 0;
+ gem_exec[0].flags = 0;
+ gem_exec[0].rsvd1 = 0;
+ gem_exec[0].rsvd2 = 0;
+
+ execbuf.buffers_ptr = (uintptr_t)gem_exec;
+ execbuf.buffer_count = 1;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = 8;
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = 0;
+ i915_execbuffer2_set_context_id(execbuf, 0);
+ execbuf.rsvd2 = 0;
+
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+
+ if (gem_has_blt(fd)) {
+ execbuf.flags = I915_EXEC_BLT;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+ }
+
+ if (gem_has_bsd(fd)) {
+ execbuf.flags = I915_EXEC_BSD;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+ }
+
+ if (gem_has_vebox(fd)) {
+ execbuf.flags = LOCAL_I915_EXEC_VEBOX;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+ }
+
+ gem_sync(fd, handle);
+ igt_drop_caches_set(DROP_RETIRE);
+ gem_close(fd, handle);
+}
+
+/**
+ * drm_get_card:
+ *
+ * Get an i915 drm card index number for use in /dev or /sys. The minor index of
+ * the legacy node is returned, not of the control or render node.
+ *
+ * Returns:
+ * The i915 drm index or -1 on error
+ */
+int drm_get_card(void)
+{
+ char *name;
+ int i, fd;
+
+ for (i = 0; i < 16; i++) {
+ int ret;
+
+ ret = asprintf(&name, "/dev/dri/card%u", i);
+ igt_assert(ret != -1);
+
+ fd = open(name, O_RDWR);
+ free(name);
+
+ if (fd == -1)
+ continue;
+
+ if (!is_i915_device(fd) || !is_intel(fd)) {
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+ return i;
+ }
+
+ igt_skip("No intel gpu found\n");
+
+ return -1;
+}
+
+/** Open the first DRM device we can find, searching up to 16 device nodes */
+int __drm_open_any(void)
+{
+ for (int i = 0; i < 16; i++) {
+ char name[80];
+ int fd;
+
+ sprintf(name, "/dev/dri/card%u", i);
+ fd = open(name, O_RDWR);
+ if (fd == -1)
+ continue;
+
+ if (is_i915_device(fd) && is_intel(fd))
+ return fd;
+
+ close(fd);
+ }
+
+ igt_skip("No intel gpu found\n");
+ return -1;
+}
+
+static int __drm_open_any_render(void)
+{
+ char *name;
+ int i, fd;
+
+ for (i = 128; i < (128 + 16); i++) {
+ int ret;
+
+ ret = asprintf(&name, "/dev/dri/renderD%u", i);
+ igt_assert(ret != -1);
+
+ fd = open(name, O_RDWR);
+ free(name);
+
+ if (fd == -1)
+ continue;
+
+ if (!is_i915_device(fd) || !is_intel(fd)) {
+ close(fd);
+ fd = -1;
+ continue;
+ }
+
+ return fd;
+ }
+
+ return fd;
+}
+
+static int at_exit_drm_fd = -1;
+static int at_exit_drm_render_fd = -1;
+
+static void quiescent_gpu_at_exit(int sig)
+{
+ if (at_exit_drm_fd < 0)
+ return;
+
+ check_stop_rings();
+ gem_quiescent_gpu(at_exit_drm_fd);
+ close(at_exit_drm_fd);
+ at_exit_drm_fd = -1;
+}
+
+static void quiescent_gpu_at_exit_render(int sig)
+{
+ if (at_exit_drm_render_fd < 0)
+ return;
+
+ check_stop_rings();
+ gem_quiescent_gpu(at_exit_drm_render_fd);
+ close(at_exit_drm_render_fd);
+ at_exit_drm_render_fd = -1;
+}
+
+/**
+ * drm_open_any:
+ *
+ * Open an i915 drm legacy device node. This function always returns a valid
+ * file descriptor.
+ *
+ * Returns: a i915 drm file descriptor
+ */
+int drm_open_any(void)
+{
+ static int open_count;
+ int fd = __drm_open_any();
+
+ igt_require(fd >= 0);
+
+ if (__sync_fetch_and_add(&open_count, 1))
+ return fd;
+
+ gem_quiescent_gpu(fd);
+ at_exit_drm_fd = __drm_open_any();
+ igt_install_exit_handler(quiescent_gpu_at_exit);
+
+ return fd;
+}
+
+/**
+ * drm_open_any_master:
+ *
+ * Open an i915 drm legacy device node and ensure that it is drm master.
+ *
+ * Returns:
+ * The i915 drm file descriptor or -1 on error
+ */
+int drm_open_any_master(void)
+{
+ int fd = drm_open_any();
+
+ igt_require(fd >= 0);
+ igt_require_f(drmSetMaster(fd) == 0, "Can't become DRM master, "
+ "please check if no other DRM client is running.\n");
+
+ return fd;
+}
+
+/**
+ * drm_open_any_render:
+ *
+ * Open an i915 drm render device node.
+ *
+ * Returns:
+ * The i915 drm file descriptor or -1 on error
+ */
+int drm_open_any_render(void)
+{
+ static int open_count;
+ int fd = __drm_open_any_render();
+
+ /* no render nodes, fallback to drm_open_any() */
+ if (fd == -1)
+ return drm_open_any();
+
+ if (__sync_fetch_and_add(&open_count, 1))
+ return fd;
+
+ at_exit_drm_render_fd = __drm_open_any();
+ gem_quiescent_gpu(fd);
+ igt_install_exit_handler(quiescent_gpu_at_exit_render);
+
+ return fd;
+}
diff --git a/lib/drmtest.h b/lib/drmtest.h
new file mode 100644
index 0000000..508cc83
--- /dev/null
+++ b/lib/drmtest.h
@@ -0,0 +1,105 @@
+/*
+ * 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>
+ *
+ */
+
+#ifndef DRMTEST_H
+#define DRMTEST_H
+
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include <xf86drm.h>
+
+#include "intel_batchbuffer.h"
+
+#ifdef ANDROID
+#ifndef HAVE_MMAP64
+extern void* __mmap2(void *, size_t, int, int, int, off_t);
+
+/* mmap64 is a recent addition to bionic and not available in all android builds. */
+/* I can find no reliable way to know if it is defined or not - so just avoid it */
+#define mmap64 igt_mmap64
+static inline void *igt_mmap64(void *addr, size_t length, int prot, int flags,
+ int fd, off64_t offset)
+{
+ return __mmap2(addr, length, prot, flags, fd, offset >> 12);
+}
+#endif
+#endif
+
+/**
+ * ARRAY_SIZE:
+ * @arr: static array
+ *
+ * Macro to compute the size of the static array @arr.
+ */
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
+/**
+ * ALIGN:
+ * @v: value to be aligned
+ * @a: alignment unit in bytes
+ *
+ * Macro to align a value @v to a specified unit @a.
+ */
+#define ALIGN(v, a) (((v) + (a)-1) & ~((a)-1))
+
+int drm_get_card(void);
+int __drm_open_any(void);
+int drm_open_any(void);
+int drm_open_any_master(void);
+int drm_open_any_render(void);
+
+void gem_quiescent_gpu(int fd);
+
+/**
+ * do_or_die:
+ * @x: command
+ *
+ * Simple macro to execute x and check that it's return value is 0. Presumes
+ * that in any failure case the return value is non-zero and a precise error is
+ * logged into errno. Uses igt_assert() internally.
+ */
+#define do_or_die(x) igt_assert((x) == 0)
+
+/**
+ * do_ioctl:
+ * @fd: open i915 drm file descriptor
+ * @ioc: ioctl op definition from drm headers
+ * @ioc_data: data pointer for the ioctl operation
+ *
+ * This macro wraps drmIoctl() and uses igt_assert to check that it has been
+ * successfully executed.
+ */
+#define do_ioctl(fd, ioc, ioc_data) do { \
+ igt_assert(drmIoctl((fd), (ioc), (ioc_data)) == 0); \
+ errno = 0; \
+} while (0)
+
+#endif /* DRMTEST_H */
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
new file mode 100644
index 0000000..131ff4b
--- /dev/null
+++ b/lib/igt_aux.c
@@ -0,0 +1,699 @@
+/*
+ * Copyright © 2007, 2011, 2013, 2014, 2015 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>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef ANDROID
+#define _GNU_SOURCE
+#else
+#include <libgen.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <pciaccess.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <termios.h>
+
+#include "drmtest.h"
+#include "i915_drm.h"
+#include "intel_chipset.h"
+#include "igt_aux.h"
+#include "igt_debugfs.h"
+#include "igt_gt.h"
+#include "config.h"
+#include "intel_reg.h"
+#include "ioctl_wrappers.h"
+#include "igt_kms.h"
+
+/**
+ * SECTION:igt_aux
+ * @short_description: Auxiliary libraries and support functions
+ * @title: i-g-t aux
+ * @include: igt_aux.h
+ *
+ * This library provides various auxiliary helper functions that don't really
+ * fit into any other topic.
+ */
+
+
+/* signal interrupt helpers */
+static struct igt_helper_process signal_helper;
+long long int sig_stat;
+static void __attribute__((noreturn)) signal_helper_process(pid_t pid)
+{
+ /* Interrupt the parent process at 500Hz, just to be annoying */
+ while (1) {
+ usleep(1000 * 1000 / 500);
+ if (kill(pid, SIGUSR1)) /* Parent has died, so must we. */
+ exit(0);
+ }
+}
+
+static void sig_handler(int i)
+{
+ sig_stat++;
+}
+
+/**
+ * igt_fork_signal_helper:
+ *
+ * Fork a child process using #igt_fork_helper to interrupt the parent process
+ * with a SIGUSR1 signal at regular quick intervals. The corresponding dummy
+ * signal handler is installed in the parent process.
+ *
+ * This is useful to exercise ioctl error paths, at least where those can be
+ * exercises by interrupting blocking waits, like stalling for the gpu. This
+ * helper can also be used from children spawned with #igt_fork.
+ *
+ * In tests with subtests this function can be called outside of failure
+ * catching code blocks like #igt_fixture or #igt_subtest.
+ */
+void igt_fork_signal_helper(void)
+{
+ if (igt_only_list_subtests())
+ return;
+
+ signal(SIGUSR1, sig_handler);
+
+ igt_fork_helper(&signal_helper) {
+ signal_helper_process(getppid());
+ }
+}
+
+/**
+ * igt_stop_signal_helper:
+ *
+ * Stops the child process spawned with igt_fork_signal_helper() again.
+ *
+ * In tests with subtests this function can be called outside of failure
+ * catching code blocks like #igt_fixture or #igt_subtest.
+ */
+void igt_stop_signal_helper(void)
+{
+ if (igt_only_list_subtests())
+ return;
+
+ igt_stop_helper(&signal_helper);
+
+ sig_stat = 0;
+}
+
+/**
+ * igt_check_boolean_env_var:
+ * @env_var: environment variable name
+ * @default_value: default value for the environment variable
+ *
+ * This function should be used to parse boolean environment variable options.
+ *
+ * Returns:
+ * The boolean value of the environment variable @env_var as decoded by atoi()
+ * if it is set and @default_value if the variable is not set.
+ */
+bool igt_check_boolean_env_var(const char *env_var, bool default_value)
+{
+ char *val;
+
+ val = getenv(env_var);
+ if (!val)
+ return default_value;
+
+ return atoi(val) != 0;
+}
+
+/**
+ * igt_aub_dump_enabled:
+ *
+ * Returns:
+ * True if AUB dumping is enabled with IGT_DUMP_AUB=1 in the environment, false
+ * otherwise.
+ */
+bool igt_aub_dump_enabled(void)
+{
+ static int dump_aub = -1;
+
+ if (dump_aub == -1)
+ dump_aub = igt_check_boolean_env_var("IGT_DUMP_AUB", false);
+
+ return dump_aub;
+}
+
+/* other helpers */
+/**
+ * igt_exchange_int:
+ * @array: pointer to the array of integers
+ * @i: first position
+ * @j: second position
+ *
+ * Exchanges the two values at array indices @i and @j. Useful as an exchange
+ * function for igt_permute_array().
+ */
+void igt_exchange_int(void *array, unsigned i, unsigned j)
+{
+ int *int_arr, tmp;
+ int_arr = array;
+
+ tmp = int_arr[i];
+ int_arr[i] = int_arr[j];
+ int_arr[j] = tmp;
+}
+
+static uint32_t
+hars_petruska_f54_1_random_unsafe(void)
+{
+ static uint32_t state = 0x12345678;
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ return state = (state ^ rol (state, 5) ^ rol (state, 24)) + 0x37798849;
+#undef rol
+}
+
+/**
+ * igt_permute_array:
+ * @array: pointer to array
+ * @size: size of the array
+ * @exchange_func: function to exchange array elements
+ *
+ * This function randomly permutes the array using random() as the PRNG source.
+ * The @exchange_func function is called to exchange two elements in the array
+ * when needed.
+ */
+void igt_permute_array(void *array, unsigned size,
+ void (*exchange_func)(void *array,
+ unsigned i,
+ unsigned j))
+{
+ int i;
+
+ for (i = size - 1; i > 1; i--) {
+ /* yes, not perfectly uniform, who cares */
+ long l = hars_petruska_f54_1_random_unsafe() % (i +1);
+ if (i != l)
+ exchange_func(array, i, l);
+ }
+}
+
+__attribute__((format(printf, 1, 2)))
+static void igt_interactive_info(const char *format, ...)
+{
+ va_list args;
+
+ if (!isatty(STDERR_FILENO))
+ return;
+
+ if (igt_log_level > IGT_LOG_INFO)
+ return;
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+
+/**
+ * igt_progress:
+ * @header: header string to prepend to the progress indicator
+ * @i: work processed thus far
+ * @total: total amount of work
+ *
+ * This function draws a progress indicator, which is useful for running
+ * long-winded tests manually on the console. To avoid spamming logfiles in
+ * automated runs the progress indicator is suppressed when not running on a
+ * terminal.
+ */
+void igt_progress(const char *header, uint64_t i, uint64_t total)
+{
+ int divider = 200;
+
+ if (i+1 >= total) {
+ igt_interactive_info("\r%s100%%\n", header);
+ return;
+ }
+
+ if (total / 200 == 0)
+ divider = 1;
+
+ /* only bother updating about every 0.5% */
+ if (i % (total / divider) == 0)
+ igt_interactive_info("\r%s%3llu%%", header,
+ (long long unsigned)i * 100 / total);
+}
+
+/**
+ * igt_print_activity:
+ *
+ * Print a '.' to indicate activity. This is printed without a newline and
+ * only if output is to a terminal.
+ */
+void igt_print_activity(void)
+{
+ igt_interactive_info(".");
+}
+
+/* mappable aperture trasher helper */
+drm_intel_bo **trash_bos;
+int num_trash_bos;
+
+/**
+ * igt_init_aperture_trashers:
+ * @bufmgr: libdrm buffer manager
+ *
+ * Initialize the aperture trasher using @bufmgr, which can then be run with
+ * igt_trash_aperture().
+ */
+void igt_init_aperture_trashers(drm_intel_bufmgr *bufmgr)
+{
+ int i;
+
+ num_trash_bos = gem_mappable_aperture_size() / (1024*1024);
+
+ trash_bos = malloc(num_trash_bos * sizeof(drm_intel_bo *));
+ igt_assert(trash_bos);
+
+ for (i = 0; i < num_trash_bos; i++)
+ trash_bos[i] = drm_intel_bo_alloc(bufmgr, "trash bo", 1024*1024, 4096);
+}
+
+/**
+ * igt_trash_aperture:
+ *
+ * Trash the aperture by walking a set of GTT memory mapped objects.
+ */
+void igt_trash_aperture(void)
+{
+ int i;
+ uint8_t *gtt_ptr;
+
+ for (i = 0; i < num_trash_bos; i++) {
+ drm_intel_gem_bo_map_gtt(trash_bos[i]);
+ gtt_ptr = trash_bos[i]->virtual;
+ *gtt_ptr = 0;
+ drm_intel_gem_bo_unmap_gtt(trash_bos[i]);
+ }
+}
+
+/**
+ * igt_cleanup_aperture_trashers:
+ *
+ * Clean up all aperture trasher state set up with igt_init_aperture_trashers().
+ */
+void igt_cleanup_aperture_trashers(void)
+{
+ int i;
+
+ for (i = 0; i < num_trash_bos; i++)
+ drm_intel_bo_unreference(trash_bos[i]);
+
+ free(trash_bos);
+}
+
+/**
+ * igt_system_suspend_autoresume:
+ *
+ * Execute a system suspend-to-mem cycle and automatically wake up again using
+ * the firmware's resume timer.
+ *
+ * This is very handy for implementing any kind of suspend/resume test.
+ */
+void igt_system_suspend_autoresume(void)
+{
+ int ret;
+
+ /* FIXME: Simulation doesn't like suspend/resume, and not even a lighter
+ * approach using /sys/power/pm_test to just test our driver's callbacks
+ * seems to fare better. We need to investigate what's going on. */
+ igt_skip_on_simulation();
+
+ ret = system("rtcwake -s 30 -m mem");
+ igt_assert_f(ret == 0, "This failure means that something is wrong with the rtcwake tool "
+ "or how your distro is set up. This is not a i915.ko or i-g-t bug.");
+}
+
+/**
+ * igt_system_hibernate_autoresume:
+ *
+ * Execute a system suspend-to-disk cycle and automatically wake up again using
+ * the firmware's resume timer.
+ *
+ * This is very handy for implementing any kind of hibernate/resume test.
+ */
+void igt_system_hibernate_autoresume(void)
+{
+ int ret;
+
+ /* FIXME: I'm guessing simulation behaves the same way as with
+ * suspend/resume, but it might be prudent to make sure
+ */
+ /* FIXME: Simulation doesn't like suspend/resume, and not even a lighter
+ * approach using /sys/power/pm_test to just test our driver's callbacks
+ * seems to fare better. We need to investigate what's going on. */
+ igt_skip_on_simulation();
+
+ /* The timeout might need to be adjusted if hibernation takes too long
+ * or if we have to wait excessively long before resume
+ */
+ ret = system("rtcwake -s 90 -m disk");
+ igt_assert_f(ret == 0, "This failure means that something is wrong with the rtcwake tool "
+ "or how your distro is set up. This is not a i915.ko or i-g-t bug.");
+}
+
+/**
+ * igt_drop_root:
+ *
+ * Drop root privileges and make sure it actually worked. Useful for tests
+ * which need to check security constraints. Note that this should only be
+ * called from manually forked processes, since the lack of root privileges
+ * will wreak havoc with the automatic cleanup handlers.
+ */
+void igt_drop_root(void)
+{
+ igt_assert(getuid() == 0);
+
+ igt_assert(setgid(2) == 0);
+ igt_assert(setuid(2) == 0);
+
+ igt_assert(getgid() == 2);
+ igt_assert(getuid() == 2);
+}
+
+/**
+ * igt_debug_wait_for_keypress:
+ * @var: var lookup to to enable this wait
+ *
+ * Waits for a key press when run interactively and when the corresponding debug
+ * var is set in the --interactive-debug=&lt;var&gt; variable. Multiple keys
+ * can be specified as a comma-separated list or alternatively "all" if a wait
+ * should happen for all cases.
+ *
+ * When not connected to a terminal interactive_debug is ignored
+ * and execution immediately continues.
+ *
+ * This is useful for display tests where under certain situation manual
+ * inspection of the display is useful. Or when running a testcase in the
+ * background.
+ */
+void igt_debug_wait_for_keypress(const char *var)
+{
+ struct termios oldt, newt;
+
+ if (!isatty(STDIN_FILENO))
+ return;
+
+ if (!igt_interactive_debug)
+ return;
+
+ if (!strstr(igt_interactive_debug, var) &&
+ !strstr(igt_interactive_debug, "all"))
+ return;
+
+ igt_info("Press any key to continue ...\n");
+
+ tcgetattr ( STDIN_FILENO, &oldt );
+ newt = oldt;
+ newt.c_lflag &= ~( ICANON | ECHO );
+ tcsetattr ( STDIN_FILENO, TCSANOW, &newt );
+ getchar();
+ tcsetattr ( STDIN_FILENO, TCSANOW, &oldt );
+}
+
+#define POWER_DIR "/sys/devices/pci0000:00/0000:00:02.0/power"
+/* We just leak this on exit ... */
+int pm_status_fd = -1;
+
+/**
+ * igt_setup_runtime_pm:
+ *
+ * Sets up the runtime PM helper functions and enables runtime PM. To speed up
+ * tests the autosuspend delay is set to 0.
+ *
+ * Returns:
+ * True if runtime pm is available, false otherwise.
+ */
+bool igt_setup_runtime_pm(void)
+{
+ int fd;
+ ssize_t size;
+ char buf[6];
+
+ if (pm_status_fd >= 0)
+ return true;
+
+ /* The Audio driver can get runtime PM references, so we need to make
+ * sure its runtime PM is enabled, so it can release the refs and
+ * actually enable us to runtime suspend. */
+ fd = open("/sys/module/snd_hda_intel/parameters/power_save", O_WRONLY);
+ if (fd >= 0) {
+ igt_assert(write(fd, "1\n", 2) == 2);
+ close(fd);
+ }
+ fd = open("/sys/bus/pci/devices/0000:00:03.0/power/control", O_WRONLY);
+ if (fd >= 0) {
+ igt_assert(write(fd, "auto\n", 5) == 5);
+ close(fd);
+ }
+
+ /* Our implementation uses autosuspend. Try to set it to 0ms so the test
+ * suite goes faster and we have a higher probability of triggering race
+ * conditions. */
+ fd = open(POWER_DIR "/autosuspend_delay_ms", O_WRONLY);
+ igt_assert_f(fd >= 0,
+ "Can't open " POWER_DIR "/autosuspend_delay_ms\n");
+
+ /* If we fail to write to the file, it means this system doesn't support
+ * runtime PM. */
+ size = write(fd, "0\n", 2);
+
+ close(fd);
+
+ if (size != 2)
+ return false;
+
+ /* We know we support runtime PM, let's try to enable it now. */
+ fd = open(POWER_DIR "/control", O_RDWR);
+ igt_assert_f(fd >= 0, "Can't open " POWER_DIR "/control\n");
+
+ size = write(fd, "auto\n", 5);
+ igt_assert(size == 5);
+
+ lseek(fd, 0, SEEK_SET);
+ size = read(fd, buf, ARRAY_SIZE(buf));
+ igt_assert(size == 5);
+ igt_assert(strncmp(buf, "auto\n", 5) == 0);
+
+ close(fd);
+
+ pm_status_fd = open(POWER_DIR "/runtime_status", O_RDONLY);
+ igt_assert_f(pm_status_fd >= 0,
+ "Can't open " POWER_DIR "/runtime_status\n");
+
+ return true;
+}
+
+/**
+ * igt_get_runtime_pm_status:
+ *
+ * Returns: The current runtime PM status.
+ */
+enum igt_runtime_pm_status igt_get_runtime_pm_status(void)
+{
+ ssize_t n_read;
+ char buf[32];
+
+ lseek(pm_status_fd, 0, SEEK_SET);
+ n_read = read(pm_status_fd, buf, ARRAY_SIZE(buf));
+ igt_assert(n_read >= 0);
+ buf[n_read] = '\0';
+
+ if (strncmp(buf, "suspended\n", n_read) == 0)
+ return IGT_RUNTIME_PM_STATUS_SUSPENDED;
+ else if (strncmp(buf, "active\n", n_read) == 0)
+ return IGT_RUNTIME_PM_STATUS_ACTIVE;
+ else if (strncmp(buf, "suspending\n", n_read) == 0)
+ return IGT_RUNTIME_PM_STATUS_SUSPENDING;
+ else if (strncmp(buf, "resuming\n", n_read) == 0)
+ return IGT_RUNTIME_PM_STATUS_RESUMING;
+
+ igt_assert_f(false, "Unknown status %s\n", buf);
+ return IGT_RUNTIME_PM_STATUS_UNKNOWN;
+}
+
+/**
+ * igt_wait_for_pm_status:
+ * @status: desired runtime PM status
+ *
+ * Waits until for the driver to switch to into the desired runtime PM status,
+ * with a 10 second timeout.
+ *
+ * Some subtests call this function while the signal helper is active, so we
+ * can't assume each usleep() call will sleep for 100ms.
+ *
+ * Returns:
+ * True if the desired runtime PM status was attained, false if the operation
+ * timed out.
+ */
+bool igt_wait_for_pm_status(enum igt_runtime_pm_status status)
+{
+ struct timeval start, end, diff;
+
+ igt_assert(gettimeofday(&start, NULL) == 0);
+ do {
+ if (igt_get_runtime_pm_status() == status)
+ return true;
+
+ usleep(100 * 1000);
+
+ igt_assert(gettimeofday(&end, NULL) == 0);
+ timersub(&end, &start, &diff);
+ } while (diff.tv_sec < 10);
+
+ return false;
+}
+
+/* Functions with prefix kmstest_ independent of cairo library are pulled out
+ * from file igt_kms.c since this file is skipped in lib/Android.mk when flag
+ * ANDROID_HAS_CAIRO is 0. This ensures the usability of these functions even
+ * when cairo library is not present on Android.
+ */
+
+struct type_name {
+ int type;
+ const char *name;
+};
+
+#define type_name_fn(res) \
+const char * kmstest_##res##_str(int type) { \
+ unsigned int i; \
+ for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
+ if (res##_names[i].type == type) \
+ return res##_names[i].name; \
+ } \
+ return "(invalid)"; \
+}
+
+struct type_name encoder_type_names[] = {
+ { DRM_MODE_ENCODER_NONE, "none" },
+ { DRM_MODE_ENCODER_DAC, "DAC" },
+ { DRM_MODE_ENCODER_TMDS, "TMDS" },
+ { DRM_MODE_ENCODER_LVDS, "LVDS" },
+ { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
+};
+
+type_name_fn(encoder_type)
+
+struct type_name connector_status_names[] = {
+ { DRM_MODE_CONNECTED, "connected" },
+ { DRM_MODE_DISCONNECTED, "disconnected" },
+ { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
+};
+
+type_name_fn(connector_status)
+
+struct type_name connector_type_names[] = {
+ { DRM_MODE_CONNECTOR_Unknown, "unknown" },
+ { DRM_MODE_CONNECTOR_VGA, "VGA" },
+ { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
+ { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
+ { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
+ { DRM_MODE_CONNECTOR_Composite, "composite" },
+ { DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
+ { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
+ { DRM_MODE_CONNECTOR_Component, "component" },
+ { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
+ { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
+ { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
+ { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
+ { DRM_MODE_CONNECTOR_TV, "TV" },
+ { DRM_MODE_CONNECTOR_eDP, "eDP" },
+};
+
+type_name_fn(connector_type)
+
+
+/**
+ * igt_lock_mem:
+ * @size: the amount of memory to lock into RAM, in MB
+ *
+ * Allocate @size MB of memory and lock it into RAM. This releases any
+ * previously locked memory.
+ *
+ * Use #igt_unlock_mem to release the currently locked memory.
+ */
+static char *locked_mem;
+static size_t locked_size;
+
+void igt_lock_mem(size_t size)
+{
+ long pagesize = sysconf(_SC_PAGESIZE);
+ size_t i;
+ int ret;
+
+ if (size == 0) {
+ return;
+ }
+
+ if (locked_mem) {
+ igt_unlock_mem();
+ igt_warn("Unlocking previously locked memory.\n");
+ }
+
+ locked_size = size * 1024 * 1024;
+
+ locked_mem = malloc(locked_size);
+ igt_require_f(locked_mem,
+ "Could not allocate enough memory to lock.\n");
+
+ /* write into each page to ensure it is allocated */
+ for (i = 0; i < locked_size; i += pagesize)
+ locked_mem[i] = i;
+
+ ret = mlock(locked_mem, locked_size);
+ igt_assert_f(ret == 0, "Could not lock memory into RAM.\n");
+}
+
+/**
+ * igt_unlock_mem:
+ *
+ * Release and free the RAM used by #igt_lock_mem.
+ */
+void igt_unlock_mem(void)
+{
+ if (!locked_mem)
+ return;
+
+ munlock(locked_mem, locked_size);
+
+ free(locked_mem);
+ locked_mem = NULL;
+}
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
new file mode 100644
index 0000000..0c361f2
--- /dev/null
+++ b/lib/igt_aux.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2014, 2015 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef IGT_AUX_H
+#define IGT_AUX_H
+
+#include <intel_bufmgr.h>
+#include <stdbool.h>
+
+extern drm_intel_bo **trash_bos;
+extern int num_trash_bos;
+
+/* auxialiary igt helpers from igt_aux.c */
+/* generally useful helpers */
+void igt_fork_signal_helper(void);
+void igt_stop_signal_helper(void);
+
+void igt_exchange_int(void *array, unsigned i, unsigned j);
+void igt_permute_array(void *array, unsigned size,
+ void (*exchange_func)(void *array,
+ unsigned i,
+ unsigned j));
+void igt_progress(const char *header, uint64_t i, uint64_t total);
+void igt_print_activity(void);
+bool igt_check_boolean_env_var(const char *env_var, bool default_value);
+
+bool igt_aub_dump_enabled(void);
+
+/* helpers based upon the libdrm buffer manager */
+void igt_init_aperture_trashers(drm_intel_bufmgr *bufmgr);
+void igt_trash_aperture(void);
+void igt_cleanup_aperture_trashers(void);
+
+/* suspend/hibernate and auto-resume system */
+void igt_system_suspend_autoresume(void);
+void igt_system_hibernate_autoresume(void);
+
+/* dropping priviledges */
+void igt_drop_root(void);
+
+void igt_debug_wait_for_keypress(const char *var);
+
+enum igt_runtime_pm_status {
+ IGT_RUNTIME_PM_STATUS_ACTIVE,
+ IGT_RUNTIME_PM_STATUS_SUSPENDED,
+ IGT_RUNTIME_PM_STATUS_SUSPENDING,
+ IGT_RUNTIME_PM_STATUS_RESUMING,
+ IGT_RUNTIME_PM_STATUS_UNKNOWN,
+};
+bool igt_setup_runtime_pm(void);
+enum igt_runtime_pm_status igt_get_runtime_pm_status(void);
+bool igt_wait_for_pm_status(enum igt_runtime_pm_status status);
+
+/* sysinfo cross-arch wrappers from intel_os.c */
+
+/* These are separate to allow easier testing when porting, see the comment at
+ * the bottom of intel_os.c. */
+void intel_purge_vm_caches(void);
+uint64_t intel_get_avail_ram_mb(void);
+uint64_t intel_get_total_ram_mb(void);
+uint64_t intel_get_total_swap_mb(void);
+
+void intel_require_memory(uint32_t count, uint32_t size, unsigned mode);
+#define CHECK_RAM 0x1
+#define CHECK_SWAP 0x2
+
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+#define igt_swap(a, b) do { \
+ typeof(a) _tmp = (a); \
+ (a) = (b); \
+ (b) = _tmp; \
+} while (0)
+
+void igt_lock_mem(size_t size);
+void igt_unlock_mem(void);
+
+#endif /* IGT_AUX_H */
diff --git a/lib/igt_core.c b/lib/igt_core.c
new file mode 100644
index 0000000..8f75e48
--- /dev/null
+++ b/lib/igt_core.c
@@ -0,0 +1,1689 @@
+/*
+ * Copyright © 2007, 2011, 2013, 2014 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>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef ANDROID
+#define _GNU_SOURCE
+#else
+#include <libgen.h>
+#endif
+#include <stdio.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <pciaccess.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#ifdef __linux__
+#include <sys/syscall.h>
+#endif
+#include <pthread.h>
+#include <sys/utsname.h>
+#include <termios.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "drmtest.h"
+#include "intel_chipset.h"
+#include "intel_io.h"
+#include "igt_debugfs.h"
+#include "version.h"
+#include "config.h"
+
+#include "igt_core.h"
+#include "igt_aux.h"
+
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h> /* for basename() on Solaris */
+#endif
+
+/**
+ * SECTION:igt_core
+ * @short_description: Core i-g-t testing support
+ * @title: i-g-t core
+ * @include: igt_core.h
+ *
+ * This library implements the core of the i-g-t test support infrastructure.
+ * Main features are the subtest enumeration, cmdline option parsing helpers for
+ * subtest handling and various helpers to structure testcases with subtests and
+ * handle subtest test results.
+ *
+ * Auxiliary code provides exit handlers, support for forked processes with test
+ * result propagation. Other generally useful functionality includes optional
+ * structure logging infrastructure and some support code for running reduced
+ * test set on in simulated hardware environments.
+ *
+ * When writing tests with subtests it is extremely important that nothing
+ * interferes with the subtest enumeration. In i-g-t subtests are enumerated at
+ * runtime, which allows powerful testcase enumeration. But it makes subtest
+ * enumeration a bit more tricky since the test code needs to be careful to
+ * never run any code which might fail (like trying to do privileged operations
+ * or opening device driver nodes).
+ *
+ * To allow this i-g-t provides #igt_fixture code blocks for setup code outside
+ * of subtests and automatically skips the subtest code blocks themselves. For
+ * special cases igt_only_list_subtests() is also provided.
+ *
+ * # Magic Control Blocks
+ *
+ * i-g-t makes heavy use of C macros which serve as magic control blocks. They
+ * work fairly well and transparently but since C doesn't have full-blown
+ * closures there are caveats:
+ *
+ * - Asynchronous blocks which are used to spawn children internally use fork().
+ * Which means that nonsensical control flow like jumping out of the control
+ * block is possible, but it will badly confuse the i-g-t library code. And of
+ * course all caveats of a real fork() call apply, namely that file
+ * descriptors are copied, but still point at the original file. This will
+ * terminally upset the libdrm buffer manager if both parent and child keep on
+ * using the same open instance of the drm device. Usually everything related
+ * to interacting with the kernel driver must be reinitialized to avoid such
+ * issues.
+ *
+ * - Code blocks with magic control flow are implemented with setjmp() and
+ * longjmp(). This applies to #igt_fixture and #igt_subtest blocks and all the
+ * three variants to finish test: igt_success(), igt_skip() and igt_fail().
+ * Mostly this is of no concern, except when such a control block changes
+ * stack variables defined in the same function as the control block resides.
+ * Any store/load behaviour after a longjmp() is ill-defined for these
+ * variables. Avoid such code.
+ *
+ * Quoting the man page for longjmp():
+ *
+ * "The values of automatic variables are unspecified after a call to
+ * longjmp() if they meet all the following criteria:"
+ * - "they are local to the function that made the corresponding setjmp() call;
+ * - "their values are changed between the calls to setjmp() and longjmp(); and
+ * - "they are not declared as volatile."
+ *
+ * # Best Practices for Test Helper Libraries Design
+ *
+ * Kernel tests itself tend to have fairly complex logic already. It is
+ * therefore paramount that helper code, both in libraries and test-private
+ * functions, add as little boilerplate code to the main test logic as possible.
+ * But then dense code is hard to understand without constantly consulting
+ * the documentation and implementation of all the helper functions if it
+ * doesn't follow some clear patterns. Hence follow these established best
+ * practices:
+ *
+ * - Make extensive use of the implicit control flow afforded by igt_skip(),
+ * igt_fail and igt_success(). When dealing with optional kernel features
+ * combine igt_skip() with igt_fail() to skip when the kernel support isn't
+ * available but fail when anything else goes awry. void should be the most
+ * common return type in all your functions, except object constructors of
+ * course.
+ *
+ * - The main test logic should have no explicit control flow for failure
+ * conditions, but instead such assumptions should be written in a declarative
+ * style. Use one of the many macros which encapsulate i-g-t's implicit
+ * control flow. Pick the most suitable one to have as much debug output as
+ * possible without polluting the code unnecessarily. For example
+ * igt_assert_cmpint() for comparing integers or do_ioctl() for running ioctls
+ * and checking their results. Feel free to add new ones to the library or
+ * wrap up a set of checks into a private function to further condense your
+ * test logic.
+ *
+ * - When adding a new feature test function which uses igt_skip() internally,
+ * use the &lt;prefix&gt;_require_&lt;feature_name&gt; naming scheme. When you
+ * instead add a feature test function which returns a boolean, because your
+ * main test logic must take different actions depending upon the feature's
+ * availability, then instead use the &lt;prefix&gt;_has_&lt;feature_name&gt;.
+ *
+ * - As already mentioned eschew explicit error handling logic as much as
+ * possible. If your test absolutely has to handle the error of some function
+ * the customary naming pattern is to prefix those variants with __. Try to
+ * restrict explicit error handling to leaf functions. For the main test flow
+ * simply pass the expected error condition down into your helper code, which
+ * results in tidy and declarative test logic.
+ *
+ * - Make your library functions as simple to use as possible. Automatically
+ * register cleanup handlers through igt_install_exit_handler(). Reduce the
+ * amount of setup boilerplate needed by using implicit singletons and lazy
+ * structure initialization and similar design patterns.
+ *
+ * - Don't shy away from refactoring common code, even when there are just 2-3
+ * users and even if it's not a net reduction in code. As long as it helps to
+ * remove boilerplate and makes the code more declarative the resulting
+ * clearer test flow is worth it. All i-g-t library code has been organically
+ * extracted from testcases in this fashion.
+ *
+ * - For general coding style issues please follow the kernel's rules laid out
+ * in
+ * [CodingStyle](https://www.kernel.org/doc/Documentation/CodingStyle).
+ *
+ * # Interface with Testrunners
+ *
+ * i-g-t testcase are all executables which should be run as root on an
+ * otherwise completely idle system. The test status is reflected in the
+ * exitcode. #IGT_EXIT_SUCCESS means "success", #IGT_EXIT_SKIP "skip",
+ * #IGT_EXIT_TIMEOUT that some operation "timed out". All other exit codes
+ * encode a failed test result, including any abnormal termination of the test
+ * (e.g. by SIGKILL).
+ *
+ * On top of that tests may report unexpected results and minor issues to
+ * stderr. If stderr is non-empty the test result should be treated as "warn".
+ *
+ * The test lists are generated at build time. Simple testcases are listed in
+ * tests/single-tests.txt and tests with subtests are listed in
+ * tests/multi-tests.txt. When running tests with subtest from a test runner it
+ * is recommend to run each subtest individually, since otherwise the return
+ * code will only reflect the overall result.
+ *
+ * To do that obtain the lists of subtests with "--list-subtests", which can be
+ * run as non-root and doesn't require the i915 driver to be loaded (or any
+ * intel gpu to be present). Then individual subtests can be run with
+ * "--run-subtest". Usage help for tests with subtests can be obtained with the
+ * "--help" command line option.
+ */
+
+static unsigned int exit_handler_count;
+
+/* subtests helpers */
+static bool list_subtests = false;
+static char *run_single_subtest = NULL;
+static bool run_single_subtest_found = false;
+static const char *in_subtest = NULL;
+static struct timespec subtest_time;
+static bool in_fixture = false;
+static bool test_with_subtests = false;
+static enum {
+ CONT = 0, SKIP, FAIL
+} skip_subtests_henceforth = CONT;
+
+/* fork support state */
+pid_t *test_children;
+int num_test_children;
+int test_children_sz;
+bool test_child;
+
+enum {
+ OPT_LIST_SUBTESTS,
+ OPT_RUN_SUBTEST,
+ OPT_DESCRIPTION,
+ OPT_DEBUG,
+ OPT_INTERACTIVE_DEBUG,
+ OPT_HELP = 'h'
+};
+
+static int igt_exitcode = IGT_EXIT_SUCCESS;
+static const char *command_str;
+
+static char* igt_log_domain_filter;
+static struct {
+ char *entries[256];
+ uint8_t start, end;
+} log_buffer;
+static pthread_mutex_t log_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void _igt_log_buffer_append(char *line)
+{
+ pthread_mutex_lock(&log_buffer_mutex);
+
+ free(log_buffer.entries[log_buffer.end]);
+ log_buffer.entries[log_buffer.end] = line;
+ log_buffer.end++;
+ if (log_buffer.end == log_buffer.start)
+ log_buffer.start++;
+
+ pthread_mutex_unlock(&log_buffer_mutex);
+}
+
+static void _igt_log_buffer_reset(void)
+{
+ pthread_mutex_lock(&log_buffer_mutex);
+
+ log_buffer.start = log_buffer.end = 0;
+
+ pthread_mutex_unlock(&log_buffer_mutex);
+}
+
+static void _igt_log_buffer_dump(void)
+{
+ uint8_t i;
+
+ if (in_subtest)
+ fprintf(stderr, "Subtest %s failed.\n", in_subtest);
+ else
+ fprintf(stderr, "Test %s failed.\n", command_str);
+
+ if (log_buffer.start == log_buffer.end) {
+ fprintf(stderr, "No log.\n");
+ return;
+ }
+
+ pthread_mutex_lock(&log_buffer_mutex);
+
+ fprintf(stderr, "Log Start\n");
+
+ i = log_buffer.start;
+ do {
+ char *last_line = log_buffer.entries[i];
+ fprintf(stderr, "%s", last_line);
+ i++;
+ } while (i != log_buffer.start && i != log_buffer.end);
+
+ /* reset the buffer */
+ log_buffer.start = log_buffer.end = 0;
+
+ pthread_mutex_unlock(&log_buffer_mutex);
+
+ fprintf(stderr, "Log End\n");
+}
+
+__attribute__((format(printf, 1, 2)))
+static void kmsg(const char *format, ...)
+#define KERN_EMER "<0>"
+#define KERN_ALERT "<1>"
+#define KERN_CRIT "<2>"
+#define KERN_ERR "<3>"
+#define KERN_WARNING "<4>"
+#define KERN_NOTICE "<5>"
+#define KERN_INFO "<6>"
+#define KERN_DEBUG "<7>"
+{
+ va_list ap;
+ FILE *file;
+
+ file = fopen("/dev/kmsg", "w");
+ if (file == NULL)
+ return;
+
+ va_start(ap, format);
+ vfprintf(file, format, ap);
+ va_end(ap);
+
+ fclose(file);
+}
+
+static void gettime(struct timespec *ts)
+{
+ memset(ts, 0, sizeof(*ts));
+
+#ifdef CLOCK_MONOTONIC_COARSE
+ if (clock_gettime(CLOCK_MONOTONIC_COARSE, ts))
+#endif
+ clock_gettime(CLOCK_MONOTONIC, ts);
+}
+
+bool __igt_fixture(void)
+{
+ assert(!in_fixture);
+
+ if (igt_only_list_subtests())
+ return false;
+
+ if (skip_subtests_henceforth)
+ return false;
+
+ in_fixture = true;
+ return true;
+}
+
+void __igt_fixture_complete(void)
+{
+ assert(in_fixture);
+
+ in_fixture = false;
+}
+
+void __igt_fixture_end(void)
+{
+ assert(in_fixture);
+
+ in_fixture = false;
+ longjmp(igt_subtest_jmpbuf, 1);
+}
+
+/*
+ * Some of the IGT tests put quite a lot of pressure on memory and when
+ * running on Android they are sometimes killed by the Android low memory killer.
+ * This seems to be due to some incompatibility between the kswapd free memory
+ * targets and the way the lowmemorykiller assesses free memory.
+ * The low memory killer really isn't usefull in this context and has no
+ * interaction with the gpu driver that we are testing, so the following
+ * function is used to disable it by modifying one of its module parameters.
+ * We still have the normal linux oom killer to protect the kernel.
+ * Apparently it is also possible for the lowmemorykiller to get included
+ * in some linux distributions; so rather than check for Android we directly
+ * check for the existence of the module parameter we want to adjust.
+ *
+ * In future, if we can get the lowmemorykiller to play nicely then we can
+ * remove this hack.
+ */
+static void low_mem_killer_disable(bool disable)
+{
+ static const char* adj_fname="/sys/module/lowmemorykiller/parameters/adj";
+ static const char no_lowmem_killer[] = "9999";
+ int fd;
+ struct stat buf;
+ /* The following must persist across invocations */
+ static char prev_adj_scores[256];
+ static int adj_scores_len = 0;
+
+ /* capture the permissions bits for the lowmemkiller adj pseudo-file.
+ * Bail out if the stat fails; it probably means that there is no
+ * lowmemorykiller, but in any case we're doomed. */
+ if (stat(adj_fname, &buf)) {
+ igt_assert(errno == ENOENT);
+ return;
+ }
+
+ /* make sure the file can be read/written - by default it is write-only */
+ chmod(adj_fname, S_IRUSR | S_IWUSR);
+
+ if (disable) {
+ /* read the current oom adj parameters for lowmemorykiller */
+ fd = open(adj_fname, O_RDWR);
+ igt_assert(fd != -1);
+ adj_scores_len = read(fd, (void*)prev_adj_scores, 255);
+ igt_assert(adj_scores_len > 0);
+
+ /* writing 9999 to this module parameter effectively diables the
+ * low memory killer. This is not a real file, so we dont need to
+ * seek to the start or truncate it */
+ write(fd, no_lowmem_killer, sizeof(no_lowmem_killer));
+ close(fd);
+ } else {
+ /* just re-enstate the original settings */
+ fd = open(adj_fname, O_WRONLY);
+ igt_assert(fd != -1);
+ write(fd, prev_adj_scores, adj_scores_len);
+ close(fd);
+ }
+
+ /* re-enstate the file permissions */
+ chmod(adj_fname, buf.st_mode);
+}
+
+bool igt_exit_called;
+static void common_exit_handler(int sig)
+{
+ low_mem_killer_disable(false);
+
+ /* When not killed by a signal check that igt_exit() has been properly
+ * called. */
+ assert(sig != 0 || igt_exit_called);
+}
+
+static void print_test_description(void)
+{
+ if (&__igt_test_description)
+ printf("%s\n", __igt_test_description);
+}
+
+static void print_version(void)
+{
+ struct utsname uts;
+
+ if (list_subtests)
+ return;
+
+ uname(&uts);
+
+ fprintf(stdout, "IGT-Version: %s-%s (%s) (%s: %s %s)\n", PACKAGE_VERSION,
+ IGT_GIT_SHA1, TARGET_CPU_PLATFORM,
+ uts.sysname, uts.release, uts.machine);
+}
+
+static void print_usage(const char *help_str, bool output_on_stderr)
+{
+ FILE *f = output_on_stderr ? stderr : stdout;
+
+ fprintf(f, "Usage: %s [OPTIONS]\n", command_str);
+ fprintf(f, " --list-subtests\n"
+ " --run-subtest <pattern>\n"
+ " --debug[=log-domain]\n"
+ " --interactive-debug[=domain]\n"
+ " --help-description\n"
+ " --help\n");
+ if (help_str)
+ fprintf(f, "%s\n", help_str);
+}
+
+
+static void oom_adjust_for_doom(void)
+{
+ int fd;
+ const char always_kill[] = "1000";
+
+ fd = open("/proc/self/oom_score_adj", O_WRONLY);
+ igt_assert(fd != -1);
+ igt_assert(write(fd, always_kill, sizeof(always_kill)) == sizeof(always_kill));
+ close(fd);
+
+ low_mem_killer_disable(true);
+}
+
+static int common_init(int *argc, char **argv,
+ const char *extra_short_opts,
+ struct option *extra_long_opts,
+ const char *help_str,
+ igt_opt_handler_t extra_opt_handler)
+{
+ int c, option_index = 0, i, x;
+ static struct option long_options[] = {
+ {"list-subtests", 0, 0, OPT_LIST_SUBTESTS},
+ {"run-subtest", 1, 0, OPT_RUN_SUBTEST},
+ {"help-description", 0, 0, OPT_DESCRIPTION},
+ {"debug", optional_argument, 0, OPT_DEBUG},
+ {"interactive-debug", optional_argument, 0, OPT_INTERACTIVE_DEBUG},
+ {"help", 0, 0, OPT_HELP},
+ {0, 0, 0, 0}
+ };
+ char *short_opts;
+ const char *std_short_opts = "h";
+ struct option *combined_opts;
+ int extra_opt_count;
+ int all_opt_count;
+ int ret = 0;
+ char *env = getenv("IGT_LOG_LEVEL");
+
+ if (env) {
+ if (strcmp(env, "debug") == 0)
+ igt_log_level = IGT_LOG_DEBUG;
+ else if (strcmp(env, "info") == 0)
+ igt_log_level = IGT_LOG_INFO;
+ else if (strcmp(env, "warn") == 0)
+ igt_log_level = IGT_LOG_WARN;
+ else if (strcmp(env, "none") == 0)
+ igt_log_level = IGT_LOG_NONE;
+ }
+
+ command_str = argv[0];
+ if (strrchr(command_str, '/'))
+ command_str = strrchr(command_str, '/') + 1;
+
+ /* First calculate space for all passed-in extra long options */
+ all_opt_count = 0;
+ while (extra_long_opts && extra_long_opts[all_opt_count].name) {
+
+ /* check for conflicts with standard long option values */
+ for (i = 0; long_options[i].name; i++)
+ if (extra_long_opts[all_opt_count].val == long_options[i].val)
+ igt_warn("Conflicting long option values between --%s and --%s\n",
+ extra_long_opts[all_opt_count].name,
+ long_options[i].name);
+
+ /* check for conflicts with short options */
+ if (extra_long_opts[all_opt_count].val != ':'
+ && strchr(std_short_opts, extra_long_opts[all_opt_count].val)) {
+ igt_warn("Conflicting long and short option values between --%s and -%s\n",
+ extra_long_opts[all_opt_count].name,
+ long_options[i].name);
+ }
+
+
+ all_opt_count++;
+ }
+ extra_opt_count = all_opt_count;
+
+ /* check for conflicts in extra short options*/
+ for (i = 0; extra_short_opts && extra_short_opts[i]; i++) {
+
+ if (extra_short_opts[i] == ':')
+ continue;
+
+ /* check for conflicts with standard short options */
+ if (strchr(std_short_opts, extra_short_opts[i]))
+ igt_warn("Conflicting short option: -%c\n", std_short_opts[i]);
+
+ /* check for conflicts with standard long option values */
+ for (x = 0; long_options[x].name; x++)
+ if (long_options[x].val == extra_short_opts[i])
+ igt_warn("Conflicting short option and long option value: --%s and -%c\n",
+ long_options[x].name, extra_short_opts[i]);
+ }
+
+ all_opt_count += ARRAY_SIZE(long_options);
+
+ combined_opts = malloc(all_opt_count * sizeof(*combined_opts));
+ memcpy(combined_opts, extra_long_opts,
+ extra_opt_count * sizeof(*combined_opts));
+
+ /* Copy the subtest long options (and the final NULL entry) */
+ memcpy(&combined_opts[extra_opt_count], long_options,
+ ARRAY_SIZE(long_options) * sizeof(*combined_opts));
+
+ ret = asprintf(&short_opts, "%s%s",
+ extra_short_opts ? extra_short_opts : "",
+ std_short_opts);
+ assert(ret >= 0);
+
+ while ((c = getopt_long(*argc, argv, short_opts, combined_opts,
+ &option_index)) != -1) {
+ switch(c) {
+ case OPT_INTERACTIVE_DEBUG:
+ if (optarg && strlen(optarg) > 0)
+ igt_interactive_debug = strdup(optarg);
+ else
+ igt_interactive_debug = "all";
+ break;
+ case OPT_DEBUG:
+ igt_log_level = IGT_LOG_DEBUG;
+ if (optarg && strlen(optarg) > 0)
+ igt_log_domain_filter = strdup(optarg);
+ break;
+ case OPT_LIST_SUBTESTS:
+ if (!run_single_subtest)
+ list_subtests = true;
+ break;
+ case OPT_RUN_SUBTEST:
+ if (!list_subtests)
+ run_single_subtest = strdup(optarg);
+ break;
+ case OPT_DESCRIPTION:
+ print_test_description();
+ ret = -1;
+ goto out;
+ case OPT_HELP:
+ print_usage(help_str, false);
+ ret = -1;
+ goto out;
+ case '?':
+ print_usage(help_str, true);
+ ret = -2;
+ goto out;
+ default:
+ ret = extra_opt_handler(c, option_index);
+ if (ret)
+ goto out;
+ }
+ }
+
+out:
+ free(short_opts);
+ free(combined_opts);
+
+ /* exit immediately if this test has no subtests and a subtest or the
+ * list of subtests has been requested */
+ if (!test_with_subtests) {
+ if (run_single_subtest) {
+ igt_warn("Unknown subtest: %s\n", run_single_subtest);
+ exit(IGT_EXIT_INVALID);
+ }
+ if (list_subtests)
+ exit(IGT_EXIT_INVALID);
+ }
+
+ if (ret < 0)
+ /* exit with no error for -h/--help */
+ exit(ret == -1 ? 0 : IGT_EXIT_INVALID);
+
+ if (!list_subtests) {
+ kmsg(KERN_INFO "%s: executing\n", command_str);
+ print_version();
+
+ oom_adjust_for_doom();
+ }
+
+ /* install exit handler, to ensure we clean up */
+ igt_install_exit_handler(common_exit_handler);
+
+ if (!test_with_subtests)
+ gettime(&subtest_time);
+
+ for (i = 0; (optind + i) < *argc; i++)
+ argv[i + 1] = argv[optind + i];
+
+ *argc = *argc - optind + 1;
+
+ return ret;
+}
+
+
+/**
+ * igt_subtest_init_parse_opts:
+ * @argc: argc from the test's main()
+ * @argv: argv from the test's main()
+ * @extra_short_opts: getopt_long() compliant list with additional short options
+ * @extra_long_opts: getopt_long() compliant list with additional long options
+ * @help_str: help string for the additional options
+ * @extra_opt_handler: handler for the additional options
+ *
+ * This function handles the subtest related cmdline options and allows an
+ * arbitrary set of additional options. This is useful for tests which have
+ * additional knobs to tune when run manually like the number of rounds execute
+ * or the size of the allocated buffer objects.
+ *
+ * Tests without special needs should just use igt_subtest_init() or use
+ * #igt_main directly instead of their own main() function.
+ *
+ * Returns: Forwards any option parsing errors from getopt_long.
+ */
+int igt_subtest_init_parse_opts(int *argc, char **argv,
+ const char *extra_short_opts,
+ struct option *extra_long_opts,
+ const char *help_str,
+ igt_opt_handler_t extra_opt_handler)
+{
+ int ret;
+
+ test_with_subtests = true;
+ ret = common_init(argc, argv, extra_short_opts, extra_long_opts,
+ help_str, extra_opt_handler);
+
+ return ret;
+}
+
+enum igt_log_level igt_log_level = IGT_LOG_INFO;
+
+/**
+ * igt_simple_init_parse_opts:
+ * @argc: argc from the test's main()
+ * @argv: argv from the test's main()
+ * @extra_short_opts: getopt_long() compliant list with additional short options
+ * @extra_long_opts: getopt_long() compliant list with additional long options
+ * @help_str: help string for the additional options
+ * @extra_opt_handler: handler for the additional options
+ *
+ * This initializes a simple test without any support for subtests and allows
+ * an arbitrary set of additional options.
+ */
+void igt_simple_init_parse_opts(int *argc, char **argv,
+ const char *extra_short_opts,
+ struct option *extra_long_opts,
+ const char *help_str,
+ igt_opt_handler_t extra_opt_handler)
+{
+ common_init(argc, argv, extra_short_opts, extra_long_opts, help_str,
+ extra_opt_handler);
+}
+
+/*
+ * Note: Testcases which use these helpers MUST NOT output anything to stdout
+ * outside of places protected by igt_run_subtest checks - the piglit
+ * runner adds every line to the subtest list.
+ */
+bool __igt_run_subtest(const char *subtest_name)
+{
+ int i;
+
+ assert(!in_subtest);
+ assert(!in_fixture);
+ assert(test_with_subtests);
+
+ /* check the subtest name only contains a-z, A-Z, 0-9, '-' and '_' */
+ for (i = 0; subtest_name[i] != '\0'; i++)
+ if (subtest_name[i] != '_' && subtest_name[i] != '-'
+ && !isalnum(subtest_name[i])) {
+ igt_critical("Invalid subtest name \"%s\".\n",
+ subtest_name);
+ igt_exit();
+ }
+
+ if (list_subtests) {
+ printf("%s\n", subtest_name);
+ return false;
+ }
+
+ if (run_single_subtest) {
+ if (strcmp(subtest_name, run_single_subtest) != 0)
+ return false;
+ else
+ run_single_subtest_found = true;
+ }
+
+ if (skip_subtests_henceforth) {
+ printf("Subtest %s: %s\n", subtest_name,
+ skip_subtests_henceforth == SKIP ?
+ "SKIP" : "FAIL");
+ return false;
+ }
+
+ kmsg(KERN_INFO "%s: starting subtest %s\n", command_str, subtest_name);
+ igt_debug("Starting subtest: %s\n", subtest_name);
+
+ _igt_log_buffer_reset();
+
+ gettime(&subtest_time);
+ return (in_subtest = subtest_name);
+}
+
+/**
+ * igt_subtest_name:
+ *
+ * Returns: The name of the currently executed subtest or NULL if called from
+ * outside a subtest block.
+ */
+const char *igt_subtest_name(void)
+{
+ return in_subtest;
+}
+
+/**
+ * igt_only_list_subtests:
+ *
+ * Returns: Returns true if only subtest should be listed and any setup code
+ * must be skipped, false otherwise.
+ */
+bool igt_only_list_subtests(void)
+{
+ return list_subtests;
+}
+
+static bool skipped_one = false;
+static bool succeeded_one = false;
+static bool failed_one = false;
+
+static void exit_subtest(const char *) __attribute__((noreturn));
+static void exit_subtest(const char *result)
+{
+ struct timespec now;
+ double elapsed;
+
+ gettime(&now);
+ elapsed = now.tv_sec - subtest_time.tv_sec;
+ elapsed += (now.tv_nsec - subtest_time.tv_nsec) * 1e-9;
+
+ printf("Subtest %s: %s (%.3fs)\n", in_subtest, result, elapsed);
+ in_subtest = NULL;
+ longjmp(igt_subtest_jmpbuf, 1);
+}
+
+/**
+ * igt_skip:
+ * @f: format string
+ * @...: optional arguments used in the format string
+ *
+ * Subtest aware test skipping. The format string is printed to stderr as the
+ * reason why the test skipped.
+ *
+ * For tests with subtests this will either bail out of the current subtest or
+ * mark all subsequent subtests as SKIP (presuming some global setup code
+ * failed).
+ *
+ * For normal tests without subtest it will directly exit.
+ */
+void igt_skip(const char *f, ...)
+{
+ va_list args;
+ skipped_one = true;
+
+ assert(!test_child);
+
+ if (!igt_only_list_subtests()) {
+ va_start(args, f);
+ vprintf(f, args);
+ va_end(args);
+ }
+
+ if (in_subtest) {
+ exit_subtest("SKIP");
+ } else if (test_with_subtests) {
+ skip_subtests_henceforth = SKIP;
+ assert(in_fixture);
+ __igt_fixture_end();
+ } else {
+ igt_exitcode = IGT_EXIT_SKIP;
+ igt_exit();
+ }
+}
+
+void __igt_skip_check(const char *file, const int line,
+ const char *func, const char *check,
+ const char *f, ...)
+{
+ va_list args;
+ int err = errno;
+ char *err_str = NULL;
+
+ if (err)
+ asprintf(&err_str, "Last errno: %i, %s\n", err, strerror(err));
+
+ if (f) {
+ static char *buf;
+
+ /* igt_skip never returns, so try to not leak too badly. */
+ if (buf)
+ free(buf);
+
+ va_start(args, f);
+ vasprintf(&buf, f, args);
+ va_end(args);
+
+ igt_skip("Test requirement not met in function %s, file %s:%i:\n"
+ "Test requirement: %s\n%s"
+ "%s",
+ func, file, line, check, buf, err_str ?: "");
+ } else {
+ igt_skip("Test requirement not met in function %s, file %s:%i:\n"
+ "Test requirement: %s\n"
+ "%s",
+ func, file, line, check, err_str ?: "");
+ }
+}
+
+/**
+ * igt_success:
+ *
+ * Complete a (subtest) as successful
+ *
+ * This bails out of a subtests and marks it as successful. For global tests it
+ * it won't bail out of anything.
+ */
+void igt_success(void)
+{
+ succeeded_one = true;
+ if (in_subtest)
+ exit_subtest("SUCCESS");
+}
+
+/**
+ * igt_fail:
+ * @exitcode: exitcode
+ *
+ * Fail a testcase. The exitcode is used as the exit code of the test process.
+ * It may not be 0 (which indicates success) or 77 (which indicates a skipped
+ * test).
+ *
+ * For tests with subtests this will either bail out of the current subtest or
+ * mark all subsequent subtests as FAIL (presuming some global setup code
+ * failed).
+ *
+ * For normal tests without subtest it will directly exit with the given
+ * exitcode.
+ */
+void igt_fail(int exitcode)
+{
+ assert(exitcode != IGT_EXIT_SUCCESS && exitcode != IGT_EXIT_SKIP);
+
+ if (!failed_one)
+ igt_exitcode = exitcode;
+
+ failed_one = true;
+
+ /* Silent exit, parent will do the yelling. */
+ if (test_child)
+ exit(exitcode);
+
+ _igt_log_buffer_dump();
+
+ if (in_subtest) {
+ if (exitcode == IGT_EXIT_TIMEOUT)
+ exit_subtest("TIMEOUT");
+ else
+ exit_subtest("FAIL");
+ } else {
+ assert(!test_with_subtests || in_fixture);
+
+ if (in_fixture) {
+ skip_subtests_henceforth = FAIL;
+ __igt_fixture_end();
+ }
+
+ igt_exit();
+ }
+}
+
+static bool run_under_gdb(void)
+{
+ char buf[1024];
+
+ sprintf(buf, "/proc/%d/exe", getppid());
+ return (readlink (buf, buf, sizeof (buf)) != -1 &&
+ strncmp(basename(buf), "gdb", 3) == 0);
+}
+
+void __igt_fail_assert(int exitcode, const char *domain, const char *file,
+ const int line, const char *func, const char *assertion,
+ const char *f, ...)
+{
+ va_list args;
+ int err = errno;
+
+ igt_log(domain, IGT_LOG_CRITICAL,
+ "Test assertion failure function %s, file %s:%i:\n", func, file,
+ line);
+ igt_log(domain, IGT_LOG_CRITICAL, "Failed assertion: %s\n", assertion);
+ if (err)
+ igt_log(domain, IGT_LOG_CRITICAL, "Last errno: %i, %s\n", err,
+ strerror(err));
+
+ if (f) {
+ va_start(args, f);
+ igt_vlog(domain, IGT_LOG_CRITICAL, f, args);
+ va_end(args);
+ }
+
+ if (run_under_gdb())
+ abort();
+ igt_fail(exitcode);
+}
+
+/**
+ * igt_exit:
+ *
+ * exit() for both types (simple and with subtests) of i-g-t tests.
+ *
+ * This will exit the test with the right exit code when subtests have been
+ * skipped. For normal tests it exits with a successful exit code, presuming
+ * everything has worked out. For subtests it also checks that at least one
+ * subtest has been run (save when only listing subtests.
+ *
+ * It is an error to normally exit a test calling igt_exit() - without it the
+ * result reporting will be wrong. To avoid such issues it is highly recommended
+ * to use #igt_main or #igt_simple_main instead of a hand-rolled main() function.
+ */
+void igt_exit(void)
+{
+ igt_exit_called = true;
+
+ if (run_single_subtest && !run_single_subtest_found) {
+ igt_warn("Unknown subtest: %s\n", run_single_subtest);
+ exit(IGT_EXIT_INVALID);
+ }
+
+
+ if (igt_only_list_subtests())
+ exit(IGT_EXIT_SUCCESS);
+
+ kmsg(KERN_INFO "%s: exiting, ret=%d\n", command_str, igt_exitcode);
+ igt_debug("Exiting with status code %d\n", igt_exitcode);
+
+ if (!test_with_subtests) {
+ struct timespec now;
+ double elapsed;
+ const char *result;
+
+ gettime(&now);
+ elapsed = now.tv_sec - subtest_time.tv_sec;
+ elapsed += (now.tv_nsec - subtest_time.tv_nsec) * 1e-9;
+
+ switch (igt_exitcode) {
+ case IGT_EXIT_SUCCESS:
+ result = "SUCCESS";
+ break;
+ case IGT_EXIT_TIMEOUT:
+ result = "TIMEOUT";
+ break;
+ case IGT_EXIT_SKIP:
+ result = "SKIP";
+ break;
+ default:
+ result = "FAIL";
+ }
+
+
+ printf("%s (%.3fs)\n", result, elapsed);
+ exit(igt_exitcode);
+ }
+
+ /* Calling this without calling one of the above is a failure */
+ assert(skipped_one || succeeded_one || failed_one);
+
+ if (failed_one)
+ exit(igt_exitcode);
+ else if (succeeded_one)
+ exit(IGT_EXIT_SUCCESS);
+ else
+ exit(IGT_EXIT_SKIP);
+}
+
+/* fork support code */
+static int helper_process_count;
+static pid_t helper_process_pids[] =
+{ -1, -1, -1, -1};
+
+static void reset_helper_process_list(void)
+{
+ for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++)
+ helper_process_pids[i] = -1;
+ helper_process_count = 0;
+}
+
+static int __waitpid(pid_t pid)
+{
+ int status = -1;
+ while (waitpid(pid, &status, 0) == -1 &&
+ errno == EINTR)
+ ;
+
+ return status;
+}
+
+static void fork_helper_exit_handler(int sig)
+{
+ /* Inside a signal handler, play safe */
+ for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++) {
+ pid_t pid = helper_process_pids[i];
+ if (pid != -1) {
+ kill(pid, SIGTERM);
+ __waitpid(pid);
+ helper_process_count--;
+ }
+ }
+
+ assert(helper_process_count == 0);
+}
+
+bool __igt_fork_helper(struct igt_helper_process *proc)
+{
+ pid_t pid;
+ int id;
+ int tmp_count;
+
+ assert(!proc->running);
+ assert(helper_process_count < ARRAY_SIZE(helper_process_pids));
+
+ for (id = 0; helper_process_pids[id] != -1; id++)
+ ;
+
+ igt_install_exit_handler(fork_helper_exit_handler);
+
+ /*
+ * Avoid races when the parent stops the child before the setup code
+ * had a chance to run. This happens e.g. when skipping tests wrapped in
+ * the signal helper.
+ */
+ tmp_count = exit_handler_count;
+ exit_handler_count = 0;
+
+ /* ensure any buffers are flushed before fork */
+ fflush(NULL);
+
+ switch (pid = fork()) {
+ case -1:
+ exit_handler_count = tmp_count;
+ igt_assert(0);
+ case 0:
+ reset_helper_process_list();
+ oom_adjust_for_doom();
+
+ return true;
+ default:
+ exit_handler_count = tmp_count;
+ proc->running = true;
+ proc->pid = pid;
+ proc->id = id;
+ helper_process_pids[id] = pid;
+ helper_process_count++;
+
+ return false;
+ }
+
+}
+
+/**
+ * igt_wait_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * Joins a helper process. It is an error to call this on a helper process which
+ * hasn't been spawned yet.
+ */
+int igt_wait_helper(struct igt_helper_process *proc)
+{
+ int status;
+
+ assert(proc->running);
+
+ status = __waitpid(proc->pid);
+
+ proc->running = false;
+
+ helper_process_pids[proc->id] = -1;
+ helper_process_count--;
+
+ return status;
+}
+
+/**
+ * igt_stop_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * Terminates a helper process. It is an error to call this on a helper process
+ * which hasn't been spawned yet.
+ */
+void igt_stop_helper(struct igt_helper_process *proc)
+{
+ int status;
+
+ /* failure here means the pid is already dead and so waiting is safe */
+ kill(proc->pid, proc->use_SIGKILL ? SIGKILL : SIGTERM);
+
+ status = igt_wait_helper(proc);
+ assert(WIFSIGNALED(status) &&
+ WTERMSIG(status) == (proc->use_SIGKILL ? SIGKILL : SIGTERM));
+}
+
+static void children_exit_handler(int sig)
+{
+ int status;
+
+ /* The exit handler can be called from a fatal signal, so play safe */
+ while (num_test_children-- && wait(&status))
+ ;
+}
+
+bool __igt_fork(void)
+{
+ assert(!test_with_subtests || in_subtest);
+ assert(!test_child);
+
+ igt_install_exit_handler(children_exit_handler);
+
+ if (num_test_children >= test_children_sz) {
+ if (!test_children_sz)
+ test_children_sz = 4;
+ else
+ test_children_sz *= 2;
+
+ test_children = realloc(test_children,
+ sizeof(pid_t)*test_children_sz);
+ igt_assert(test_children);
+ }
+
+ /* ensure any buffers are flushed before fork */
+ fflush(NULL);
+
+ switch (test_children[num_test_children++] = fork()) {
+ case -1:
+ igt_assert(0);
+ case 0:
+ test_child = true;
+ exit_handler_count = 0;
+ reset_helper_process_list();
+ oom_adjust_for_doom();
+
+ return true;
+ default:
+ return false;
+ }
+
+}
+
+/**
+ * igt_waitchildren:
+ *
+ * Wait for all children forked with igt_fork.
+ *
+ * The magic here is that exit codes from children will be correctly propagated
+ * to the main thread, including the relevant exit code if a child thread failed.
+ * Of course if multiple children failed with different exit codes the resulting
+ * exit code will be non-deterministic.
+ *
+ * Note that igt_skip() will not be forwarded, feature tests need to be done
+ * before spawning threads with igt_fork().
+ */
+void igt_waitchildren(void)
+{
+ int err = 0;
+ int count;
+
+ assert(!test_child);
+
+ count = 0;
+ while (count < num_test_children) {
+ int status = -1;
+ pid_t pid;
+ int c;
+
+ pid = wait(&status);
+ if (pid == -1)
+ continue;
+
+ for (c = 0; c < num_test_children; c++)
+ if (pid == test_children[c])
+ break;
+ if (c == num_test_children)
+ continue;
+
+ if (err == 0 && status != 0) {
+ if (WIFEXITED(status)) {
+ printf("child %i failed with exit status %i\n",
+ c, WEXITSTATUS(status));
+ err = WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ printf("child %i died with signal %i, %s\n",
+ c, WTERMSIG(status),
+ strsignal(WTERMSIG(status)));
+ err = 128 + WTERMSIG(status);
+ } else {
+ printf("Unhandled failure [%d] in child %i\n", status, c);
+ err = 256;
+ }
+
+ for (c = 0; c < num_test_children; c++)
+ kill(test_children[c], SIGKILL);
+ }
+
+ count++;
+ }
+
+ num_test_children = 0;
+ if (err)
+ igt_fail(err);
+}
+
+/* exit handler code */
+#define MAX_SIGNALS 32
+#define MAX_EXIT_HANDLERS 10
+
+#ifndef HAVE_SIGHANDLER_T
+typedef void (*sighandler_t)(int);
+#endif
+
+static struct {
+ sighandler_t handler;
+ bool installed;
+} orig_sig[MAX_SIGNALS];
+
+static igt_exit_handler_t exit_handler_fn[MAX_EXIT_HANDLERS];
+static bool exit_handler_disabled;
+static sigset_t saved_sig_mask;
+#define SIGDEF(x) { x, #x, sizeof(#x) - 1 }
+static const struct { int number; const char *name; size_t name_len; } handled_signals[] =
+ { SIGDEF(SIGINT), SIGDEF(SIGHUP), SIGDEF(SIGTERM), SIGDEF(SIGQUIT),
+ SIGDEF(SIGPIPE), SIGDEF(SIGABRT), SIGDEF(SIGSEGV), SIGDEF(SIGBUS) };
+
+static int install_sig_handler(int sig_num, sighandler_t handler)
+{
+ orig_sig[sig_num].handler = signal(sig_num, handler);
+
+ if (orig_sig[sig_num].handler == SIG_ERR)
+ return -1;
+
+ orig_sig[sig_num].installed = true;
+
+ return 0;
+}
+
+static void restore_sig_handler(int sig_num)
+{
+ /* Just restore the default so that we properly fall over. */
+ signal(sig_num, SIG_DFL);
+}
+
+static void restore_all_sig_handler(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(orig_sig); i++)
+ restore_sig_handler(i);
+}
+
+static void call_exit_handlers(int sig)
+{
+ int i;
+
+ if (!exit_handler_count) {
+ return;
+ }
+
+ for (i = exit_handler_count - 1; i >= 0; i--)
+ exit_handler_fn[i](sig);
+
+ /* ensure we don't get called twice */
+ exit_handler_count = 0;
+}
+
+static void igt_atexit_handler(void)
+{
+ restore_all_sig_handler();
+
+ if (!exit_handler_disabled)
+ call_exit_handlers(0);
+}
+
+static void fatal_sig_handler(int sig)
+{
+ int i;
+
+ restore_all_sig_handler();
+
+ for (i = 0; i < ARRAY_SIZE(handled_signals); i++) {
+ if (handled_signals[i].number == sig) {
+ write(STDERR_FILENO, "Received signal ", 16);
+ write(STDERR_FILENO, handled_signals[i].name,
+ handled_signals[i].name_len);
+ write(STDERR_FILENO, ".\n", 2);
+ break;
+ }
+ }
+
+ /*
+ * exit_handler_disabled is always false here, since when we set it
+ * we also block signals.
+ */
+ call_exit_handlers(sig);
+
+ {
+#ifdef __linux__
+ /* Workaround cached PID and TID races on glibc and Bionic libc. */
+ pid_t pid = syscall(SYS_getpid);
+ pid_t tid = syscall(SYS_gettid);
+
+ syscall(SYS_tgkill, pid, tid, sig);
+#else
+ pthread_t tid = pthread_self();
+ union sigval value = { .sival_ptr = NULL };
+
+ pthread_sigqueue(tid, sig, value);
+#endif
+ }
+}
+
+/**
+ * igt_install_exit_handler:
+ * @fn: exit handler function
+ *
+ * Set a handler that will be called either when the process calls exit() or
+ * <!-- -->returns from the main function, or one of the signals in
+ * 'handled_signals' is raised. MAX_EXIT_HANDLERS handlers can be installed,
+ * each of which will be called only once, even if a subsequent signal is
+ * raised. If the exit handlers are called due to a signal, the signal will be
+ * re-raised with the original signal disposition after all handlers returned.
+ *
+ * The handler will be passed the signal number if called due to a signal, or
+ * 0 otherwise. Exit handlers can also be used from test children spawned with
+ * igt_fork(), but not from within helper processes spawned with
+ * igt_fork_helper(). The list of exit handlers is reset when forking to
+ * avoid issues with children cleanup up the parent's state too early.
+ */
+void igt_install_exit_handler(igt_exit_handler_t fn)
+{
+ int i;
+
+ for (i = 0; i < exit_handler_count; i++)
+ if (exit_handler_fn[i] == fn)
+ return;
+
+ igt_assert(exit_handler_count < MAX_EXIT_HANDLERS);
+
+ exit_handler_fn[exit_handler_count] = fn;
+ exit_handler_count++;
+
+ if (exit_handler_count > 1)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(handled_signals); i++) {
+ if (install_sig_handler(handled_signals[i].number,
+ fatal_sig_handler))
+ goto err;
+ }
+
+ if (atexit(igt_atexit_handler))
+ goto err;
+
+ return;
+err:
+ restore_all_sig_handler();
+ exit_handler_count--;
+
+ igt_assert_f(0, "failed to install the signal handler\n");
+}
+
+/**
+ * igt_disable_exit_handler:
+ *
+ * Temporarily disable all exit handlers. Useful for library code doing tricky
+ * things.
+ */
+void igt_disable_exit_handler(void)
+{
+ sigset_t set;
+ int i;
+
+ if (exit_handler_disabled)
+ return;
+
+ sigemptyset(&set);
+ for (i = 0; i < ARRAY_SIZE(handled_signals); i++)
+ sigaddset(&set, handled_signals[i].number);
+
+ if (sigprocmask(SIG_BLOCK, &set, &saved_sig_mask)) {
+ perror("sigprocmask");
+ return;
+ }
+
+ exit_handler_disabled = true;
+}
+
+/**
+ * igt_enable_exit_handler:
+ *
+ * Re-enable all exit handlers temporarily disabled with
+ * igt_disable_exit_handler().
+ */
+void igt_enable_exit_handler(void)
+{
+ if (!exit_handler_disabled)
+ return;
+
+ if (sigprocmask(SIG_SETMASK, &saved_sig_mask, NULL)) {
+ perror("sigprocmask");
+ return;
+ }
+
+ exit_handler_disabled = false;
+}
+
+/* simulation enviroment support */
+
+/**
+ * igt_run_in_simulation:
+ *
+ * This function can be used to select a reduced test set when running in
+ * simulation environments. This i-g-t mode is selected by setting the
+ * INTEL_SIMULATION environment variable to 1.
+ *
+ * Returns: True when run in simulation mode, false otherwise.
+ */
+bool igt_run_in_simulation(void)
+{
+ static int simulation = -1;
+
+ if (simulation == -1)
+ simulation = igt_check_boolean_env_var("INTEL_SIMULATION", false);
+
+ return simulation;
+}
+
+/**
+ * igt_skip_on_simulation:
+ *
+ * Skip tests when INTEL_SIMULATION environment variable is set. It uses
+ * igt_skip() internally and hence is fully subtest aware.
+ *
+ * Note that in contrast to all other functions which use igt_skip() internally
+ * it is allowed to use this outside of an #igt_fixture block in a test with
+ * subtests. This is because in contrast to most other test requirements,
+ * checking for simulation mode doesn't depend upon the present hardware and it
+ * so makes a lot of sense to have this check in the outermost #igt_main block.
+ */
+void igt_skip_on_simulation(void)
+{
+ if (igt_only_list_subtests())
+ return;
+
+ if (!in_fixture && !in_subtest) {
+ igt_fixture
+ igt_require(!igt_run_in_simulation());
+ } else
+ igt_require(!igt_run_in_simulation());
+}
+
+/* structured logging */
+
+/**
+ * igt_log:
+ * @domain: the log domain, or NULL for no domain
+ * @level: #igt_log_level
+ * @format: format string
+ * @...: optional arguments used in the format string
+ *
+ * This is the generic structured logging helper function. i-g-t testcase should
+ * output all normal message to stdout. Warning level message should be printed
+ * to stderr and the test runner should treat this as an intermediate result
+ * between SUCESS and FAILURE.
+ *
+ * The log level can be set through the IGT_LOG_LEVEL environment variable with
+ * values "debug", "info", "warn", "critical" and "none". By default verbose
+ * debug message are disabled. "none" completely disables all output and is not
+ * recommended since crucial issues only reported at the IGT_LOG_WARN level are
+ * ignored.
+ */
+void igt_log(const char *domain, enum igt_log_level level, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ igt_vlog(domain, level, format, args);
+ va_end(args);
+}
+
+/**
+ * igt_vlog:
+ * @domain: the log domain, or NULL for no domain
+ * @level: #igt_log_level
+ * @format: format string
+ * @args: variable arguments lists
+ *
+ * This is the generic logging helper function using an explicit varargs
+ * structure and hence useful to implement domain-specific logging
+ * functions.
+ *
+ * If there is no need to wrap up a vararg list in the caller it is simpler to
+ * just use igt_log().
+ */
+void igt_vlog(const char *domain, enum igt_log_level level, const char *format, va_list args)
+{
+ FILE *file;
+ char *line, *formatted_line;
+ const char *program_name;
+ const char *igt_log_level_str[] = {
+ "DEBUG",
+ "INFO",
+ "WARNING",
+ "CRITICAL",
+ "NONE"
+ };
+ static bool line_continuation = false;
+
+ assert(format);
+
+#ifdef __GLIBC__
+ program_name = program_invocation_short_name;
+#else
+ program_name = command_str;
+#endif
+
+ if (list_subtests && level <= IGT_LOG_WARN)
+ return;
+
+ if (vasprintf(&line, format, args) == -1)
+ return;
+
+ if (line_continuation) {
+ formatted_line = strdup(line);
+ if (!formatted_line)
+ goto out;
+ } else if (asprintf(&formatted_line, "(%s:%d) %s%s%s: %s", program_name,
+ getpid(), (domain) ? domain : "", (domain) ? "-" : "",
+ igt_log_level_str[level], line) == -1) {
+ goto out;
+ }
+
+ line_continuation = line[strlen(line)] != '\n';
+
+ /* append log buffer */
+ _igt_log_buffer_append(formatted_line);
+
+ /* check print log level */
+ if (igt_log_level > level)
+ goto out;
+
+ /* check domain filter */
+ if (igt_log_domain_filter) {
+ /* if null domain and filter is not "application", return */
+ if (!domain && strcmp(igt_log_domain_filter, "application"))
+ goto out;
+ /* else if domain and filter do not match, return */
+ else if (domain && strcmp(igt_log_domain_filter, domain))
+ goto out;
+ }
+
+ /* use stderr for warning messages and above */
+ if (level >= IGT_LOG_WARN) {
+ file = stderr;
+ fflush(stdout);
+ }
+ else
+ file = stdout;
+
+ /* prepend all except information messages with process, domain and log
+ * level information */
+ if (level != IGT_LOG_INFO)
+ fwrite(formatted_line, sizeof(char), strlen(formatted_line),
+ file);
+ else
+ fwrite(line, sizeof(char), strlen(line), file);
+
+out:
+ free(line);
+}
+
+static void igt_alarm_handler(int signal)
+{
+ /* exit with timeout status */
+ igt_fail(IGT_EXIT_TIMEOUT);
+}
+
+/**
+ * igt_set_timeout:
+ * @seconds: number of seconds before timeout
+ *
+ * Fail a test and exit with #IGT_EXIT_TIMEOUT status after the specified
+ * number of seconds have elapsed. If the current test has subtests and the
+ * timeout occurs outside a subtest, subsequent subtests will be skipped and
+ * marked as failed.
+ *
+ * Any previous timer is cancelled and no timeout is scheduled if @seconds is
+ * zero.
+ */
+void igt_set_timeout(unsigned int seconds)
+{
+ struct sigaction sa;
+
+ sa.sa_handler = igt_alarm_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ if (seconds == 0)
+ sigaction(SIGALRM, NULL, NULL);
+ else
+ sigaction(SIGALRM, &sa, NULL);
+
+ alarm(seconds);
+}
diff --git a/lib/igt_core.h b/lib/igt_core.h
new file mode 100644
index 0000000..c2c820d
--- /dev/null
+++ b/lib/igt_core.h
@@ -0,0 +1,652 @@
+/*
+ * Copyright © 2007,2014 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>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+
+#ifndef IGT_CORE_H
+#define IGT_CORE_H
+
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <getopt.h>
+
+#ifndef IGT_LOG_DOMAIN
+#define IGT_LOG_DOMAIN (NULL)
+#endif
+
+
+extern const char* __igt_test_description __attribute__((weak));
+
+/**
+ * IGT_TEST_DESCRIPTION:
+ * @str: description string
+ *
+ * Defines a description for a test. This is used as the output for the
+ * "--help-description" option and is also included in the generated
+ * documentation.
+ */
+#define IGT_TEST_DESCRIPTION(str) const char* __igt_test_description = str
+
+/**
+ * IGT_EXIT_TIMEOUT:
+ *
+ * Exit status indicating a timeout occurred.
+ */
+#define IGT_EXIT_TIMEOUT 78
+
+/**
+ * IGT_EXIT_SKIP:
+ *
+ * Exit status indicating the test was skipped.
+ */
+#define IGT_EXIT_SKIP 77
+
+/**
+ * IGT_EXIT_SUCCESS
+ *
+ * Exit status indicating the test executed successfully.
+ */
+#define IGT_EXIT_SUCCESS 0
+
+/**
+ * IGT_EXIT_INVALID
+ *
+ * Exit status indicating an invalid option or subtest was specified
+ */
+#define IGT_EXIT_INVALID 79
+
+
+bool __igt_fixture(void);
+void __igt_fixture_complete(void);
+void __igt_fixture_end(void) __attribute__((noreturn));
+/**
+ * igt_fixture:
+ *
+ * Annotate global test fixture code
+ *
+ * Testcase with subtests often need to set up a bunch of global state as the
+ * common test fixture. To avoid such code interferring with the subtest
+ * enumeration (e.g. when enumerating on systemes without an intel gpu) such
+ * blocks should be annotated with igt_fixture.
+ */
+#define igt_fixture for (int igt_tokencat(__tmpint,__LINE__) = 0; \
+ igt_tokencat(__tmpint,__LINE__) < 1 && \
+ __igt_fixture() && \
+ (setjmp(igt_subtest_jmpbuf) == 0); \
+ igt_tokencat(__tmpint,__LINE__) ++, \
+ __igt_fixture_complete())
+
+/* subtest infrastructure */
+jmp_buf igt_subtest_jmpbuf;
+typedef int (*igt_opt_handler_t)(int opt, int opt_index);
+#ifndef __GTK_DOC_IGNORE__ /* gtkdoc wants to document this forward decl */
+struct option;
+#endif
+int igt_subtest_init_parse_opts(int *argc, char **argv,
+ const char *extra_short_opts,
+ struct option *extra_long_opts,
+ const char *help_str,
+ igt_opt_handler_t extra_opt_handler);
+
+
+/**
+ * igt_subtest_init:
+ * @argc: argc from the test's main()
+ * @argv: argv from the test's main()
+ *
+ * This initializes the for tests with subtests without the need for additional
+ * cmdline options. It is just a simplified version of
+ * igt_subtest_init_parse_opts().
+ *
+ * If there's not a reason to the contrary it's less error prone to just use an
+ * #igt_main block instead of stitching the test's main() function together
+ * manually.
+ */
+#define igt_subtest_init(argc, argv) igt_subtest_init_parse_opts(&argc, argv, NULL, NULL, NULL, NULL);
+
+bool __igt_run_subtest(const char *subtest_name);
+#define __igt_tokencat2(x, y) x ## y
+
+/**
+ * igt_tokencat:
+ * @x: first variable
+ * @y: second variable
+ *
+ * C preprocessor helper to concatenate two variables while properly expanding
+ * them.
+ */
+#define igt_tokencat(x, y) __igt_tokencat2(x, y)
+
+/**
+ * igt_subtest:
+ * @name: name of the subtest
+ *
+ * This is a magic control flow block which denotes a subtest code block. Within
+ * that code block igt_skip|success will only bail out of the subtest. The _f
+ * variant accepts a printf format string, which is useful for constructing
+ * combinatorial tests.
+ *
+ * This is a simpler version of igt_subtest_f()
+ */
+#define igt_subtest(name) for (; __igt_run_subtest((name)) && \
+ (setjmp(igt_subtest_jmpbuf) == 0); \
+ igt_success())
+#define __igt_subtest_f(tmp, format...) \
+ for (char tmp [256]; \
+ snprintf( tmp , sizeof( tmp ), \
+ format), \
+ __igt_run_subtest( tmp ) && \
+ (setjmp(igt_subtest_jmpbuf) == 0); \
+ igt_success())
+
+/**
+ * igt_subtest_f:
+ * @...: format string and optional arguments
+ *
+ * This is a magic control flow block which denotes a subtest code block. Within
+ * that code block igt_skip|success will only bail out of the subtest. The _f
+ * variant accepts a printf format string, which is useful for constructing
+ * combinatorial tests.
+ *
+ * Like igt_subtest(), but also accepts a printf format string instead of a
+ * static string.
+ */
+#define igt_subtest_f(f...) \
+ __igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f)
+
+const char *igt_subtest_name(void);
+bool igt_only_list_subtests(void);
+
+/**
+ * igt_main:
+ *
+ * This is a magic control flow block used instead of a main() function for
+ * tests with subtests. Open-coding the main() function is only recommended if
+ * the test needs to parse additional cmdline arguments of its own.
+ */
+#define igt_main \
+ static void igt_tokencat(__real_main, __LINE__)(void); \
+ int main(int argc, char **argv) { \
+ igt_subtest_init_parse_opts(&argc, argv, NULL, NULL, NULL, NULL); \
+ igt_tokencat(__real_main, __LINE__)(); \
+ igt_exit(); \
+ } \
+ static void igt_tokencat(__real_main, __LINE__)(void) \
+
+
+void igt_simple_init_parse_opts(int *argc, char **argv,
+ const char *extra_short_opts,
+ struct option *extra_long_opts,
+ const char *help_str,
+ igt_opt_handler_t extra_opt_handler);
+
+/**
+ * igt_simple_init:
+ * @argc: argc from the test's main()
+ * @argv: argv from the test's main()
+ *
+ * This initializes a simple test without any support for subtests.
+ *
+ * If there's not a reason to the contrary it's less error prone to just use an
+ * #igt_simple_main block instead of stitching the test's main() function together
+ * manually.
+ */
+#define igt_simple_init(argc, argv) igt_simple_init_parse_opts(&argc, argv, NULL, NULL, NULL, NULL);
+
+/**
+ * igt_simple_main:
+ *
+ * This is a magic control flow block used instead of a main() function for
+ * simple tests. Open-coding the main() function is only recommended if
+ * the test needs to parse additional cmdline arguments of its own.
+ */
+#define igt_simple_main \
+ static void igt_tokencat(__real_main, __LINE__)(void); \
+ int main(int argc, char **argv) { \
+ igt_simple_init_parse_opts(&argc, argv, NULL, NULL, NULL, NULL); \
+ igt_tokencat(__real_main, __LINE__)(); \
+ igt_exit(); \
+ } \
+ static void igt_tokencat(__real_main, __LINE__)(void) \
+
+__attribute__((format(printf, 1, 2)))
+void igt_skip(const char *f, ...) __attribute__((noreturn));
+__attribute__((format(printf, 5, 6)))
+void __igt_skip_check(const char *file, const int line,
+ const char *func, const char *check,
+ const char *format, ...) __attribute__((noreturn));
+#define igt_skip_check(E, F...) \
+ __igt_skip_check(__FILE__, __LINE__, __func__, E, F)
+void igt_success(void);
+
+void igt_fail(int exitcode) __attribute__((noreturn));
+__attribute__((format(printf, 7, 8)))
+void __igt_fail_assert(int exitcode, const char *domain, const char *file,
+ const int line, const char *func, const char *assertion,
+ const char *format, ...)
+ __attribute__((noreturn));
+void igt_exit(void) __attribute__((noreturn));
+
+/**
+ * igt_assert:
+ * @expr: condition to test
+ *
+ * Fails (sub-)test if the condition is not met.
+ *
+ * Should be used everywhere where a test checks results.
+ */
+#define igt_assert(expr) \
+ do { if (!(expr)) \
+ __igt_fail_assert(99, IGT_LOG_DOMAIN, __FILE__, __LINE__, __func__, #expr , NULL); \
+ } while (0)
+
+/**
+ * igt_assert_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Fails (sub-)test if the condition is not met.
+ *
+ * Should be used everywhere where a test checks results.
+ *
+ * In addition to the plain igt_assert() helper this allows to print additional
+ * information to help debugging test failures.
+ */
+#define igt_assert_f(expr, f...) \
+ do { if (!(expr)) \
+ __igt_fail_assert(99, IGT_LOG_DOMAIN, __FILE__, __LINE__, __func__, #expr , f); \
+ } while (0)
+
+/**
+ * igt_fail_on:
+ * @expr: condition to test
+ *
+ * Fails (sub-)test if the condition is met.
+ *
+ * Should be used everywhere where a test checks results.
+ */
+#define igt_fail_on(expr) igt_assert(!(expr))
+
+/**
+ * igt_fail_on_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Fails (sub-)test if the condition is met.
+ *
+ * Should be used everywhere where a test checks results.
+ *
+ * In addition to the plain igt_assert() helper this allows to print additional
+ * information to help debugging test failures.
+ */
+#define igt_fail_on_f(expr, f...) igt_assert_f(!(expr), f)
+
+/**
+ * igt_assert_cmpint:
+ * @n1: first value
+ * @cmp: compare operator
+ * @ncmp: negated version of @cmp
+ * @n2: second value
+ *
+ * Fails (sub-)test if the condition is not met
+ *
+ * Should be used everywhere where a test compares two integer values.
+ *
+ * Like igt_assert(), but displays the values being compared on failure instead
+ * of simply printing the stringified expression.
+ */
+#define igt_assert_cmpint(n1, cmp, ncmp, n2) \
+ do { \
+ int __n1 = (n1), __n2 = (n2); \
+ if (__n1 cmp __n2) ; else \
+ __igt_fail_assert(99, IGT_LOG_DOMAIN, __FILE__, __LINE__, __func__, \
+ #n1 " " #cmp " " #n2, \
+ "error: %d " #ncmp " %d\n", __n1, __n2); \
+ } while (0)
+
+#define igt_assert_cmpuint(n1, cmp, ncmp, n2) \
+ do { \
+ uint32_t __n1 = (n1), __n2 = (n2); \
+ if (__n1 cmp __n2) ; else \
+ __igt_fail_assert(99, IGT_LOG_DOMAIN, __FILE__, __LINE__, __func__, \
+ #n1 " " #cmp " " #n2, \
+ "error: %#x " #ncmp " %#x\n", __n1, __n2); \
+ } while (0)
+
+/**
+ * igt_assert_eq:
+ * @n1: first integer
+ * @n2: second integer
+ *
+ * Fails (sub-)test if the two integers are not equal. Beware that for now this
+ * only works on integers.
+ *
+ * Like igt_assert(), but displays the values being compared on failure instead
+ * of simply printing the stringified expression.
+ */
+#define igt_assert_eq(n1, n2) igt_assert_cmpint(n1, ==, !=, n2)
+#define igt_assert_eq_u32(n1, n2) igt_assert_cmpuint(n1, ==, !=, n2)
+
+/**
+ * igt_assert_neq:
+ * @n1: first integer
+ * @n2: second integer
+ *
+ * Fails (sub-)test if the two integers are equal. Beware that for now this
+ * only works on integers.
+ *
+ * Like igt_assert(), but displays the values being compared on failure instead
+ * of simply printing the stringified expression.
+ */
+#define igt_assert_neq(n1, n2) igt_assert_cmpint(n1, !=, ==, n2)
+
+/**
+ * igt_assert_lte:
+ * @n1: first integer
+ * @n2: second integer
+ *
+ * Fails (sub-)test if the second integers is greater than the first.
+ * Beware that for now this only works on integers.
+ *
+ * Like igt_assert(), but displays the values being compared on failure instead
+ * of simply printing the stringified expression.
+ */
+#define igt_assert_lte(n1, n2) igt_assert_cmpint(n1, <=, >, n2)
+
+/**
+ * igt_assert_lt:
+ * @n1: first integer
+ * @n2: second integer
+ *
+ * Fails (sub-)test if the second integers is strictly smaller than the first.
+ * Beware that for now this only works on integers.
+ *
+ * Like igt_assert(), but displays the values being compared on failure instead
+ * of simply printing the stringified expression.
+ */
+#define igt_assert_lt(n1, n2) igt_assert_cmpint(n1, <, >=, n2)
+
+/**
+ * igt_require:
+ * @expr: condition to test
+ *
+ * Skip a (sub-)test if a condition is not met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
+ */
+#define igt_require(expr) do { \
+ if (!(expr)) igt_skip_check(#expr , NULL); \
+ else igt_debug("Test requirement passed: "#expr"\n"); \
+} while (0)
+
+/**
+ * igt_skip_on:
+ * @expr: condition to test
+ *
+ * Skip a (sub-)test if a condition is met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
+ */
+#define igt_skip_on(expr) do { \
+ if ((expr)) igt_skip_check("!(" #expr ")" , NULL); \
+ else igt_debug("Test requirement passed: !("#expr")\n"); \
+} while (0)
+
+/**
+ * igt_require_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Skip a (sub-)test if a condition is not met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
+ *
+ * In addition to the plain igt_require() helper this allows to print additional
+ * information to help debugging test failures.
+ */
+#define igt_require_f(expr, f...) do { \
+ if (!(expr)) igt_skip_check(#expr , f); \
+ else igt_debug("Test requirement passed: "#expr"\n"); \
+} while (0)
+
+/**
+ * igt_skip_on_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Skip a (sub-)test if a condition is met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
+ *
+ * In addition to the plain igt_skip_on() helper this allows to print additional
+ * information to help debugging test failures.
+ */
+#define igt_skip_on_f(expr, f...) do { \
+ if ((expr)) igt_skip_check("!("#expr")", f); \
+ else igt_debug("Test requirement passed: !("#expr")\n"); \
+} while (0)
+
+/* fork support code */
+bool __igt_fork(void);
+
+/**
+ * igt_fork:
+ * @child: name of the int variable with the child number
+ * @num_children: number of children to fork
+ *
+ * This is a magic control flow block which spawns parallel test threads with
+ * fork().
+ *
+ * The test children execute in parallel to the main test thread. Joining all
+ * test threads should be done with igt_waitchildren to ensure that the exit
+ * codes of all children are properly reflected in the test status.
+ *
+ * Note that igt_skip() will not be forwarded, feature tests need to be done
+ * before spawning threads with igt_fork().
+ */
+#define igt_fork(child, num_children) \
+ for (int child = 0; child < (num_children); child++) \
+ for (; __igt_fork(); exit(0))
+void igt_waitchildren(void);
+
+/**
+ * igt_helper_process:
+ * @running: indicates whether the process is currently running
+ * @use_SIGKILL: whether the helper should be terminated with SIGKILL or SIGTERM
+ * @pid: pid of the helper if @running is true
+ * @id: internal id
+ *
+ * Tracking structure for helper processes. Users of the i-g-t library should
+ * only set @use_SIGKILL directly.
+ */
+struct igt_helper_process {
+ bool running;
+ bool use_SIGKILL;
+ pid_t pid;
+ int id;
+};
+bool __igt_fork_helper(struct igt_helper_process *proc);
+
+/**
+ * igt_fork_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * This is a magic control flow block which denotes an asynchronous helper
+ * process block. The difference compared to igt_fork() is that failures from
+ * the child process will not be forwarded, making this construct more suitable
+ * for background processes. Common use cases are regular interference of the
+ * main test thread through e.g. sending signals or evicting objects through
+ * debugfs. Through the explicit #igt_helper_process they can also be controlled
+ * in a more fine-grained way than test children spawned through igt_fork().
+ *
+ * For tests with subtest helper process can be started outside of a
+ * #igt_subtest block.
+ *
+ * Calling igt_wait_helper() joins a helper process and igt_stop_helper()
+ * forcefully terminates it.
+ */
+#define igt_fork_helper(proc) \
+ for (; __igt_fork_helper(proc); exit(0))
+int igt_wait_helper(struct igt_helper_process *proc);
+void igt_stop_helper(struct igt_helper_process *proc);
+
+/* exit handler code */
+
+/**
+ * igt_exit_handler_t:
+ * @sig: Signal number which caused the exit or 0.
+ *
+ * Exit handler type used by igt_install_exit_handler(). Note that exit handlers
+ * can potentially be run from signal handling contexts, the @sig parameter can
+ * be used to figure this out and act accordingly.
+ */
+typedef void (*igt_exit_handler_t)(int sig);
+
+/* reliable atexit helpers, also work when killed by a signal (if possible) */
+void igt_install_exit_handler(igt_exit_handler_t fn);
+void igt_enable_exit_handler(void);
+void igt_disable_exit_handler(void);
+
+/* helpers to automatically reduce test runtime in simulation */
+bool igt_run_in_simulation(void);
+/**
+ * SLOW_QUICK:
+ * @slow: value in simulation mode
+ * @quick: value in normal mode
+ *
+ * Simple macro to select between two values (e.g. number of test rounds or test
+ * buffer size) depending upon whether i-g-t is run in simulation mode or not.
+ */
+#define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
+
+void igt_skip_on_simulation(void);
+
+const char *igt_interactive_debug;
+
+/* structured logging */
+enum igt_log_level {
+ IGT_LOG_DEBUG,
+ IGT_LOG_INFO,
+ IGT_LOG_WARN,
+ IGT_LOG_CRITICAL,
+ IGT_LOG_NONE,
+};
+__attribute__((format(printf, 3, 4)))
+void igt_log(const char *domain, enum igt_log_level level, const char *format, ...);
+__attribute__((format(printf, 3, 0)))
+void igt_vlog(const char *domain, enum igt_log_level level, const char *format, va_list args);
+
+/**
+ * igt_debug:
+ * @...: format string and optional arguments
+ *
+ * Wrapper for igt_log() for message at the IGT_LOG_DEBUG level.
+ */
+#define igt_debug(f...) igt_log(IGT_LOG_DOMAIN, IGT_LOG_DEBUG, f)
+
+/**
+ * igt_info:
+ * @...: format string and optional arguments
+ *
+ * Wrapper for igt_log() for message at the IGT_LOG_INFO level.
+ */
+#define igt_info(f...) igt_log(IGT_LOG_DOMAIN, IGT_LOG_INFO, f)
+
+/**
+ * igt_warn:
+ * @...: format string and optional arguments
+ *
+ * Wrapper for igt_log() for message at the IGT_LOG_WARN level.
+ */
+#define igt_warn(f...) igt_log(IGT_LOG_DOMAIN, IGT_LOG_WARN, f)
+
+/**
+ * igt_critical:
+ * @...: format string and optional arguments
+ *
+ * Wrapper for igt_log() for message at the IGT_LOG_CRITICAL level.
+ */
+#define igt_critical(f...) igt_log(IGT_LOG_DOMAIN, IGT_LOG_CRITICAL, f)
+
+extern enum igt_log_level igt_log_level;
+
+/**
+ * igt_warn_on:
+ * @condition: condition to test
+ *
+ * Print a IGT_LOG_WARN level message if a condition is not met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * printing warnings. This is useful to streamline the test logic since it
+ * allows for a more flat code control flow, similar to igt_assert()
+ */
+#define igt_warn_on(condition) do {\
+ if (condition) \
+ igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
+ #condition, __func__, __FILE__, __LINE__); \
+ } while (0)
+
+/**
+ * igt_warn_on_f:
+ * @condition: condition to test
+ * @...: format string and optional arguments
+ *
+ * Skip a (sub-)test if a condition is not met.
+ *
+ * Print a IGT_LOG_WARN level message if a condition is not met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * printing warnings. This is useful to streamline the test logic since it
+ * allows for a more flat code control flow, similar to igt_assert()
+ *
+ * In addition to the plain igt_warn_on_f() helper this allows to print
+ * additional information (again as warnings) to help debugging test failures.
+ */
+#define igt_warn_on_f(condition, f...) do {\
+ if (condition) {\
+ igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
+ #condition, __func__, __FILE__, __LINE__); \
+ igt_warn(f); \
+ } \
+ } while (0)
+
+
+void igt_set_timeout(unsigned int seconds);
+
+#endif /* IGT_CORE_H */
diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
new file mode 100644
index 0000000..a2cec45
--- /dev/null
+++ b/lib/igt_debugfs.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright © 2013 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.
+ *
+ */
+
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <i915_drm.h>
+
+#include "drmtest.h"
+#include "igt_kms.h"
+#include "igt_debugfs.h"
+
+/**
+ * SECTION:igt_debugfs
+ * @short_description: Support code for debugfs features
+ * @title: i-g-t debugfs
+ * @include: igt_debugfs.h
+ *
+ * This library provides helpers to access debugfs features. On top of some
+ * basic functions to access debugfs files with e.g. igt_debugfs_open() it also
+ * provides higher-level wrappers for some debugfs features
+ *
+ * # Pipe CRC Support
+ *
+ * This library wraps up the kernel's support for capturing pipe CRCs into a
+ * neat and tidy package. For the detailed usage see all the functions which
+ * work on #igt_pipe_crc_t. This is supported on all platforms and outputs.
+ *
+ * Actually using pipe CRCs to write modeset tests is a bit tricky though, so
+ * there is no way to directly check a CRC: Both the details of the plane
+ * blending, color correction and other hardware and how exactly the CRC is
+ * computed at each tap point vary by hardware generation and are not disclosed.
+ *
+ * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each
+ * another either for equality or difference. Otherwise CRCs must be treated as
+ * completely opaque values. Note that not even CRCs from different pipes or tap
+ * points on the same platform can be compared. Hence only use igt_crc_is_null()
+ * and igt_crc_equal() to inspect CRC values captured by the same
+ * #igt_pipe_crc_t object.
+ *
+ * # Other debugfs interface wrappers
+ *
+ * This covers the miscellaneous debugfs interface wrappers:
+ *
+ * - drm/i915 supports interfaces to evict certain clases of gem buffer objects,
+ * see igt_drop_caches_set().
+ *
+ * - drm/i915 supports an interface to disable prefaulting, useful to test
+ * slowpaths in ioctls. See igt_disable_prefault().
+ */
+
+/*
+ * General debugfs helpers
+ */
+
+typedef struct {
+ char root[128];
+ char dri_path[128];
+} igt_debugfs_t;
+
+static bool __igt_debugfs_init(igt_debugfs_t *debugfs)
+{
+ const char *path = "/sys/kernel/debug";
+ struct stat st;
+ int n;
+
+ if (stat("/debug/dri", &st) == 0) {
+ path = "/debug/dri";
+ goto find_minor;
+ }
+
+ if (stat("/sys/kernel/debug/dri", &st) == 0)
+ goto find_minor;
+
+ igt_assert(stat("/sys/kernel/debug", &st) == 0);
+
+ mount("debug", "/sys/kernel/debug", "debugfs", 0, 0);
+
+find_minor:
+ strcpy(debugfs->root, path);
+ for (n = 0; n < 16; n++) {
+ int len = sprintf(debugfs->dri_path, "%s/dri/%d", path, n);
+ sprintf(debugfs->dri_path + len, "/i915_error_state");
+ if (stat(debugfs->dri_path, &st) == 0) {
+ debugfs->dri_path[len] = '\0';
+ return true;
+ }
+ }
+
+ debugfs->dri_path[0] = '\0';
+
+ return false;
+}
+
+static igt_debugfs_t *__igt_debugfs_singleton(void)
+{
+ static igt_debugfs_t singleton;
+ static bool init_done = false;
+
+ if (init_done)
+ return &singleton;
+
+ if (__igt_debugfs_init(&singleton)) {
+ init_done = true;
+ return &singleton;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * igt_debugfs_open:
+ * @filename: name of the debugfs node to open
+ * @mode: mode bits as used by open()
+ *
+ * This opens a debugfs file as a Unix file descriptor. The filename should be
+ * relative to the drm device's root, i.e without "drm/&lt;minor&gt;".
+ *
+ * Returns:
+ * The Unix file descriptor for the debugfs file or -1 if that didn't work out.
+ */
+int igt_debugfs_open(const char *filename, int mode)
+{
+ char buf[1024];
+ igt_debugfs_t *debugfs = __igt_debugfs_singleton();
+
+ if (!debugfs)
+ return -1;
+
+ sprintf(buf, "%s/%s", debugfs->dri_path, filename);
+ return open(buf, mode);
+}
+
+/**
+ * igt_debugfs_fopen:
+ * @filename: name of the debugfs node to open
+ * @mode: mode string as used by fopen()
+ *
+ * This opens a debugfs file as a libc FILE. The filename should be
+ * relative to the drm device's root, i.e without "drm/&lt;minor&gt;".
+ *
+ * Returns:
+ * The libc FILE pointer for the debugfs file or NULL if that didn't work out.
+ */
+FILE *igt_debugfs_fopen(const char *filename,
+ const char *mode)
+{
+ char buf[1024];
+
+ igt_debugfs_t *debugfs = __igt_debugfs_singleton();
+
+ if (!debugfs)
+ return NULL;
+
+ sprintf(buf, "%s/%s", debugfs->dri_path, filename);
+ return fopen(buf, mode);
+}
+
+/*
+ * Pipe CRC
+ */
+
+/**
+ * igt_crc_is_null:
+ * @crc: pipe CRC value to check
+ *
+ * Returns: True if the CRC is null/invalid, false if it represents a captured
+ * valid CRC.
+ */
+bool igt_crc_is_null(igt_crc_t *crc)
+{
+ int i;
+
+ for (i = 0; i < crc->n_words; i++) {
+ igt_warn_on_f(crc->crc[i] == 0xffffffff,
+ "Suspicious CRC: it looks like the CRC "
+ "read back was from a register in a powered "
+ "down well\n");
+ if (crc->crc[i])
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * igt_crc_equal:
+ * @a: first pipe CRC value
+ * @b: second pipe CRC value
+ *
+ * Compares two CRC values.
+ *
+ * Returns: true if the two CRCs match, false otherwise.
+ */
+bool igt_crc_equal(igt_crc_t *a, igt_crc_t *b)
+{
+ int i;
+
+ if (a->n_words != b->n_words)
+ return false;
+
+ for (i = 0; i < a->n_words; i++)
+ if (a->crc[i] != b->crc[i])
+ return false;
+
+ return true;
+}
+
+/**
+ * igt_crc_to_string:
+ * @crc: pipe CRC value to print
+ *
+ * This formats @crc into a string buffer which is owned by igt_crc_to_string().
+ * The next call will override the buffer again, which makes this multithreading
+ * unsafe.
+ *
+ * This should only ever be used for diagnostic debug output.
+ */
+char *igt_crc_to_string(igt_crc_t *crc)
+{
+ char buf[128];
+
+ if (crc->n_words == 5)
+ sprintf(buf, "%08x %08x %08x %08x %08x", crc->crc[0],
+ crc->crc[1], crc->crc[2], crc->crc[3], crc->crc[4]);
+ else
+ igt_assert(0);
+
+ return strdup(buf);
+}
+
+/* (6 fields, 8 chars each, space separated (5) + '\n') */
+#define PIPE_CRC_LINE_LEN (6 * 8 + 5 + 1)
+/* account for \'0' */
+#define PIPE_CRC_BUFFER_LEN (PIPE_CRC_LINE_LEN + 1)
+
+struct _igt_pipe_crc {
+ int ctl_fd;
+ int crc_fd;
+ int line_len;
+ int buffer_len;
+
+ enum pipe pipe;
+ enum intel_pipe_crc_source source;
+};
+
+static const char *pipe_crc_sources[] = {
+ "none",
+ "plane1",
+ "plane2",
+ "pf",
+ "pipe",
+ "TV",
+ "DP-B",
+ "DP-C",
+ "DP-D",
+ "auto"
+};
+
+static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
+{
+ return pipe_crc_sources[source];
+}
+
+static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
+{
+ char buf[64];
+
+ /* Stop first just to make sure we don't have lingering state left. */
+ igt_pipe_crc_stop(pipe_crc);
+
+ sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
+ pipe_crc_source_name(pipe_crc->source));
+ errno = 0;
+ write(pipe_crc->ctl_fd, buf, strlen(buf));
+ if (errno != 0)
+ return false;
+
+ return true;
+}
+
+static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
+{
+ char buf[32];
+
+ sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
+ write(fd, buf, strlen(buf));
+}
+
+static void igt_pipe_crc_reset(void)
+{
+ int fd;
+
+ fd = igt_debugfs_open("i915_display_crc_ctl", O_WRONLY);
+
+ igt_pipe_crc_pipe_off(fd, PIPE_A);
+ igt_pipe_crc_pipe_off(fd, PIPE_B);
+ igt_pipe_crc_pipe_off(fd, PIPE_C);
+
+ close(fd);
+}
+
+static void pipe_crc_exit_handler(int sig)
+{
+ igt_pipe_crc_reset();
+}
+
+/**
+ * igt_require_pipe_crc:
+ *
+ * Convenience helper to check whether pipe CRC capturing is supported by the
+ * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't
+ * the case.
+ */
+void igt_require_pipe_crc(void)
+{
+ const char *cmd = "pipe A none";
+ FILE *ctl;
+ size_t written;
+ int ret;
+
+ ctl = igt_debugfs_fopen("i915_display_crc_ctl", "r+");
+ igt_require_f(ctl,
+ "No display_crc_ctl found, kernel too old\n");
+ written = fwrite(cmd, 1, strlen(cmd), ctl);
+ ret = fflush(ctl);
+ igt_require_f((written == strlen(cmd) && ret == 0) || errno != ENODEV,
+ "CRCs not supported on this platform\n");
+
+ fclose(ctl);
+}
+
+/**
+ * igt_pipe_crc_new:
+ * @pipe: display pipe to use as source
+ * @source: CRC tap point to use as source
+ *
+ * This sets up a new pipe CRC capture object for the given @pipe and @source.
+ *
+ * Returns: A pipe CRC object if the given @pipe and @source. The library
+ * assumes that the source is always available since recent kernels support at
+ * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
+ */
+igt_pipe_crc_t *
+igt_pipe_crc_new(enum pipe pipe, enum intel_pipe_crc_source source)
+{
+ igt_pipe_crc_t *pipe_crc;
+ char buf[128];
+
+ igt_install_exit_handler(pipe_crc_exit_handler);
+
+ pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
+
+ pipe_crc->ctl_fd = igt_debugfs_open("i915_display_crc_ctl", O_WRONLY);
+ igt_assert(pipe_crc->ctl_fd != -1);
+
+ sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
+ pipe_crc->crc_fd = igt_debugfs_open(buf, O_RDONLY);
+ igt_assert(pipe_crc->crc_fd != -1);
+
+ pipe_crc->line_len = PIPE_CRC_LINE_LEN;
+ pipe_crc->buffer_len = PIPE_CRC_BUFFER_LEN;
+ pipe_crc->pipe = pipe;
+ pipe_crc->source = source;
+
+ return pipe_crc;
+}
+
+/**
+ * igt_pipe_crc_free:
+ * @pipe_crc: pipe CRC object
+ *
+ * Frees all resources associated with @pipe_crc.
+ */
+void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
+{
+ if (!pipe_crc)
+ return;
+
+ close(pipe_crc->ctl_fd);
+ close(pipe_crc->crc_fd);
+ free(pipe_crc);
+}
+
+/**
+ * igt_pipe_crc_start:
+ * @pipe_crc: pipe CRC object
+ *
+ * Starts the CRC capture process on @pipe_crc.
+ */
+void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
+{
+ igt_crc_t *crcs = NULL;
+
+ igt_assert(igt_pipe_crc_do_start(pipe_crc));
+
+ /*
+ * For some no yet identified reason, the first CRC is bonkers. So
+ * let's just wait for the next vblank and read out the buggy result.
+ *
+ * On CHV sometimes the second CRC is bonkers as well, so don't trust
+ * that one either.
+ */
+ igt_pipe_crc_get_crcs(pipe_crc, 2, &crcs);
+ free(crcs);
+}
+
+/**
+ * igt_pipe_crc_stop:
+ * @pipe_crc: pipe CRC object
+ *
+ * Stops the CRC capture process on @pipe_crc.
+ */
+void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
+{
+ char buf[32];
+
+ sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
+ write(pipe_crc->ctl_fd, buf, strlen(buf));
+}
+
+static bool pipe_crc_init_from_string(igt_crc_t *crc, const char *line)
+{
+ int n;
+
+ crc->n_words = 5;
+ n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame, &crc->crc[0],
+ &crc->crc[1], &crc->crc[2], &crc->crc[3], &crc->crc[4]);
+ return n == 6;
+}
+
+static bool read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
+{
+ ssize_t bytes_read;
+ char buf[pipe_crc->buffer_len];
+
+ igt_set_timeout(5);
+ bytes_read = read(pipe_crc->crc_fd, &buf, pipe_crc->line_len);
+ igt_set_timeout(0);
+
+ igt_assert_eq(bytes_read, pipe_crc->line_len);
+ buf[bytes_read] = '\0';
+
+ if (!pipe_crc_init_from_string(out, buf))
+ return false;
+
+ return true;
+}
+
+/**
+ * igt_pipe_crc_get_crcs:
+ * @pipe_crc: pipe CRC object
+ * @n_crcs: number of CRCs to capture
+ * @out_crcs: buffer pointer for the captured CRC values
+ *
+ * Read @n_crcs from @pipe_crc. This function blocks until @n_crcs are
+ * retrieved. @out_crcs is alloced by this function and must be released with
+ * free() by the caller.
+ *
+ * Callers must start and stop the capturing themselves by calling
+ * igt_pipe_crc_start() and igt_pipe_crc_stop().
+ */
+void
+igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
+ igt_crc_t **out_crcs)
+{
+ igt_crc_t *crcs;
+ int n = 0;
+
+ crcs = calloc(n_crcs, sizeof(igt_crc_t));
+
+ do {
+ igt_crc_t *crc = &crcs[n];
+
+ if (!read_one_crc(pipe_crc, crc))
+ continue;
+
+ n++;
+ } while (n < n_crcs);
+
+ *out_crcs = crcs;
+}
+
+/**
+ * igt_pipe_crc_collect_crc:
+ * @pipe_crc: pipe CRC object
+ * @out_crc: buffer for the captured CRC values
+ *
+ * Read a single CRC from @pipe_crc. This function blocks until the CRC is
+ * retrieved. @out_crc must be allocated by the caller.
+ *
+ * This function takes care of the pipe_crc book-keeping, it will start/stop
+ * the collection of the CRC.
+ */
+void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
+{
+ igt_pipe_crc_start(pipe_crc);
+ read_one_crc(pipe_crc, out_crc);
+ igt_pipe_crc_stop(pipe_crc);
+
+ igt_assert(!igt_crc_is_null(out_crc));
+}
+
+/*
+ * Drop caches
+ */
+
+/**
+ * igt_drop_caches_set:
+ * @val: bitmask for DROP_* values
+ *
+ * This calls the debugfs interface the drm/i915 GEM driver exposes to drop or
+ * evict certain classes of gem buffer objects.
+ */
+void igt_drop_caches_set(uint64_t val)
+{
+ int fd;
+ char data[19];
+ size_t nbytes;
+
+ sprintf(data, "0x%" PRIx64, val);
+
+ fd = igt_debugfs_open("i915_gem_drop_caches", O_WRONLY);
+
+ igt_assert(fd >= 0);
+ do {
+ nbytes = write(fd, data, strlen(data) + 1);
+ } while (nbytes == -1 && (errno == EINTR || errno == EAGAIN));
+ igt_assert(nbytes == strlen(data) + 1);
+ close(fd);
+}
+
+/*
+ * Prefault control
+ */
+
+#define PREFAULT_DEBUGFS "/sys/module/i915/parameters/prefault_disable"
+static void igt_prefault_control(bool enable)
+{
+ const char *name = PREFAULT_DEBUGFS;
+ int fd;
+ char buf[2] = {'Y', 'N'};
+ int index;
+
+ fd = open(name, O_RDWR);
+ igt_require(fd >= 0);
+
+ if (enable)
+ index = 1;
+ else
+ index = 0;
+
+ igt_require(write(fd, &buf[index], 1) == 1);
+
+ close(fd);
+}
+
+static void enable_prefault_at_exit(int sig)
+{
+ igt_enable_prefault();
+}
+
+/**
+ * igt_disable_prefault:
+ *
+ * Disable prefaulting in certain gem ioctls through the debugfs interface. As
+ * usual this installs an exit handler to clean up and re-enable prefaulting
+ * even when the test exited abnormally.
+ *
+ * igt_enable_prefault() will enable normale operation again.
+ */
+void igt_disable_prefault(void)
+{
+ igt_prefault_control(false);
+
+ igt_install_exit_handler(enable_prefault_at_exit);
+}
+
+/**
+ * igt_enable_prefault:
+ *
+ * Enable prefault (again) through the debugfs interface.
+ */
+void igt_enable_prefault(void)
+{
+ igt_prefault_control(true);
+}
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
new file mode 100644
index 0000000..8285029
--- /dev/null
+++ b/lib/igt_debugfs.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2013 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.
+ *
+ */
+
+#ifndef __IGT_DEBUGFS_H__
+#define __IGT_DEBUGFS_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+enum pipe;
+
+int igt_debugfs_open(const char *filename, int mode);
+FILE *igt_debugfs_fopen(const char *filename,
+ const char *mode);
+
+/*
+ * Pipe CRC
+ */
+
+/**
+ * igt_pipe_crc_t:
+ *
+ * Pipe CRC support structure. Needs to be allocated and set up with
+ * igt_pipe_crc_new() for a specific pipe and pipe CRC source value.
+ */
+typedef struct _igt_pipe_crc igt_pipe_crc_t;
+
+/**
+ * igt_crc_t:
+ * @frame: frame number of the capture CRC
+ * @n_words: internal field, don't access
+ * @crc: internal field, don't access
+ *
+ * Pipe CRC value. All other members than @frame are private and should not be
+ * inspected by testcases.
+ */
+typedef struct {
+ uint32_t frame;
+ int n_words;
+ uint32_t crc[5];
+} igt_crc_t;
+
+/**
+ * intel_pipe_crc_source:
+ *
+ * Enumeration of all supported pipe CRC sources. Not all platforms and all
+ * outputs support all of them. Generic tests should just use
+ * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC
+ * suitable for checking planes, cursor, color correction and any other
+ * output-agnostic features.
+ */
+enum intel_pipe_crc_source {
+ INTEL_PIPE_CRC_SOURCE_NONE,
+ INTEL_PIPE_CRC_SOURCE_PLANE1,
+ INTEL_PIPE_CRC_SOURCE_PLANE2,
+ INTEL_PIPE_CRC_SOURCE_PF,
+ INTEL_PIPE_CRC_SOURCE_PIPE,
+ INTEL_PIPE_CRC_SOURCE_TV,
+ INTEL_PIPE_CRC_SOURCE_DP_B,
+ INTEL_PIPE_CRC_SOURCE_DP_C,
+ INTEL_PIPE_CRC_SOURCE_DP_D,
+ INTEL_PIPE_CRC_SOURCE_AUTO,
+ INTEL_PIPE_CRC_SOURCE_MAX,
+};
+
+bool igt_crc_is_null(igt_crc_t *crc);
+bool igt_crc_equal(igt_crc_t *a, igt_crc_t *b);
+char *igt_crc_to_string(igt_crc_t *crc);
+
+void igt_require_pipe_crc(void);
+igt_pipe_crc_t *
+igt_pipe_crc_new(enum pipe pipe, enum intel_pipe_crc_source source);
+void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc);
+void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc);
+void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc);
+void igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
+ igt_crc_t **out_crcs);
+void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc);
+
+/*
+ * Drop caches
+ */
+
+/**
+ * DROP_UNBOUND:
+ *
+ * Drop all currently unbound gem buffer objects from the cache.
+ */
+#define DROP_UNBOUND 0x1
+/**
+ * DROP_BOUND:
+ *
+ * Drop all inactive objects which are bound into some gpu address space.
+ */
+#define DROP_BOUND 0x2
+/**
+ * DROP_RETIRE:
+ *
+ * Wait for all outstanding gpu commands to complete, but do not take any
+ * further actions.
+ */
+#define DROP_RETIRE 0x4
+/**
+ * DROP_ACTIVE:
+ *
+ * Also drop active objects once retired.
+ */
+#define DROP_ACTIVE 0x8
+#define DROP_ALL (DROP_UNBOUND | \
+ DROP_BOUND | \
+ DROP_RETIRE | \
+ DROP_ACTIVE)
+
+void igt_drop_caches_set(uint64_t val);
+
+/*
+ * Prefault control
+ */
+
+void igt_disable_prefault(void);
+void igt_enable_prefault(void);
+
+#endif /* __IGT_DEBUGFS_H__ */
diff --git a/lib/igt_fb.c b/lib/igt_fb.c
new file mode 100644
index 0000000..9b41301
--- /dev/null
+++ b/lib/igt_fb.c
@@ -0,0 +1,807 @@
+/*
+ * Copyright © 2013,2014 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ * Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <math.h>
+
+#include "drmtest.h"
+#include "igt_fb.h"
+#include "ioctl_wrappers.h"
+
+/**
+ * SECTION:igt_fb
+ * @short_description: Framebuffer handling and drawing library
+ * @title: i-g-t framebuffer
+ * @include: igt_fb.h
+ *
+ * This library contains helper functions for handling kms framebuffer objects
+ * using #igt_fb structures to track all the metadata. igt_create_fb() creates
+ * a basic framebufffer and igt_remove_fb() cleans everything up again.
+ *
+ * It also supports drawing using the cairo library and provides some simplified
+ * helper functions to easily draw test patterns. The main function to create a
+ * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
+ *
+ * Finally it also pulls in the drm fourcc headers and provides some helper
+ * functions to work with these pixel format codes.
+ */
+
+/* drm fourcc/cairo format maps */
+#define DF(did, cid, _bpp, _depth) \
+ { DRM_FORMAT_##did, CAIRO_FORMAT_##cid, # did, _bpp, _depth }
+static struct format_desc_struct {
+ uint32_t drm_id;
+ cairo_format_t cairo_id;
+ const char *name;
+ int bpp;
+ int depth;
+} format_desc[] = {
+ DF(RGB565, RGB16_565, 16, 16),
+ //DF(RGB888, INVALID, 24, 24),
+ DF(XRGB8888, RGB24, 32, 24),
+ DF(XRGB2101010, RGB30, 32, 30),
+ DF(ARGB8888, ARGB32, 32, 32),
+};
+#undef DF
+
+#define for_each_format(f) \
+ for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
+
+
+/* helpers to create nice-looking framebuffers */
+static int create_bo_for_fb(int fd, int width, int height, int bpp,
+ unsigned int tiling, unsigned bo_size,
+ uint32_t *gem_handle_ret,
+ unsigned *size_ret,
+ unsigned *stride_ret)
+{
+ uint32_t gem_handle;
+ int size, ret = 0;
+ unsigned stride;
+
+ if (tiling) {
+ int v;
+
+ /* Round the tiling up to the next power-of-two and the
+ * region up to the next pot fence size so that this works
+ * on all generations.
+ *
+ * This can still fail if the framebuffer is too large to
+ * be tiled. But then that failure is expected.
+ */
+
+ v = width * bpp / 8;
+ for (stride = 512; stride < v; stride *= 2)
+ ;
+
+ v = stride * height;
+ for (size = 1024*1024; size < v; size *= 2)
+ ;
+ } else {
+ /* Scan-out has a 64 byte alignment restriction */
+ stride = (width * (bpp / 8) + 63) & ~63;
+ size = stride * height;
+ }
+
+ if (bo_size == 0)
+ bo_size = size;
+ gem_handle = gem_create(fd, bo_size);
+
+ if (tiling)
+ ret = __gem_set_tiling(fd, gem_handle, tiling, stride);
+
+ *stride_ret = stride;
+ *size_ret = size;
+ *gem_handle_ret = gem_handle;
+
+ return ret;
+}
+
+/**
+ * igt_paint_color:
+ * @cr: cairo drawing context
+ * @x: pixel x-coordination of the fill rectangle
+ * @y: pixel y-coordination of the fill rectangle
+ * @w: width of the fill rectangle
+ * @h: height of the fill rectangle
+ * @r: red value to use as fill color
+ * @g: gree value to use as fill color
+ * @b: blue value to use as fill color
+ *
+ * This functions draws a solid rectangle with the given color using the drawing
+ * context @cr.
+ */
+void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b)
+{
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_set_source_rgb(cr, r, g, b);
+ cairo_fill(cr);
+}
+
+/**
+ * igt_paint_color_alpha:
+ * @cr: cairo drawing context
+ * @x: pixel x-coordination of the fill rectangle
+ * @y: pixel y-coordination of the fill rectangle
+ * @w: width of the fill rectangle
+ * @h: height of the fill rectangle
+ * @r: red value to use as fill color
+ * @g: gree value to use as fill color
+ * @b: blue value to use as fill color
+ * @a: alpha value to use as fill color
+ *
+ * This functions draws a rectangle with the given color and alpha values using
+ * the drawing context @cr.
+ */
+void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b, double a)
+{
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_set_source_rgba(cr, r, g, b, a);
+ cairo_fill(cr);
+}
+
+/**
+ * igt_paint_color_gradient:
+ * @cr: cairo drawing context
+ * @x: pixel x-coordination of the fill rectangle
+ * @y: pixel y-coordination of the fill rectangle
+ * @w: width of the fill rectangle
+ * @h: height of the fill rectangle
+ * @r: red value to use as fill color
+ * @g: gree value to use as fill color
+ * @b: blue value to use as fill color
+ *
+ * This functions draws a gradient into the rectangle which fades in from black
+ * to the given values using the drawing context @cr.
+ */
+void
+igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
+ int r, int g, int b)
+{
+ cairo_pattern_t *pat;
+
+ pat = cairo_pattern_create_linear(x, y, x + w, y + h);
+ cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
+ cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
+
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_set_source(cr, pat);
+ cairo_fill(cr);
+ cairo_pattern_destroy(pat);
+}
+
+static void
+paint_test_patterns(cairo_t *cr, int width, int height)
+{
+ double gr_height, gr_width;
+ int x, y;
+
+ y = height * 0.10;
+ gr_width = width * 0.75;
+ gr_height = height * 0.08;
+ x = (width / 2) - (gr_width / 2);
+
+ igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
+
+ y += gr_height;
+ igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
+
+ y += gr_height;
+ igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
+
+ y += gr_height;
+ igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
+}
+
+/**
+ * igt_cairo_printf_line:
+ * @cr: cairo drawing context
+ * @align: text alignment
+ * @yspacing: additional y-direction feed after this line
+ * @fmt: format string
+ * @...: optional arguments used in the format string
+ *
+ * This is a little helper to draw text onto framebuffers. All the initial setup
+ * (like setting the font size and the moving to the starting position) still
+ * needs to be done manually with explicit cairo calls on @cr.
+ *
+ * Returns:
+ * The width of the drawn text.
+ */
+int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
+ double yspacing, const char *fmt, ...)
+{
+ double x, y, xofs, yofs;
+ cairo_text_extents_t extents;
+ char *text;
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&text, fmt, ap);
+ igt_assert(ret >= 0);
+ va_end(ap);
+
+ cairo_text_extents(cr, text, &extents);
+
+ xofs = yofs = 0;
+ if (align & align_right)
+ xofs = -extents.width;
+ else if (align & align_hcenter)
+ xofs = -extents.width / 2;
+
+ if (align & align_top)
+ yofs = extents.height;
+ else if (align & align_vcenter)
+ yofs = extents.height / 2;
+
+ cairo_get_current_point(cr, &x, &y);
+ if (xofs || yofs)
+ cairo_rel_move_to(cr, xofs, yofs);
+
+ cairo_text_path(cr, text);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_fill(cr);
+
+ cairo_move_to(cr, x, y + extents.height + yspacing);
+
+ free(text);
+
+ return extents.width;
+}
+
+static void
+paint_marker(cairo_t *cr, int x, int y)
+{
+ enum igt_text_align align;
+ int xoff, yoff;
+
+ cairo_move_to(cr, x, y - 20);
+ cairo_line_to(cr, x, y + 20);
+ cairo_move_to(cr, x - 20, y);
+ cairo_line_to(cr, x + 20, y);
+ cairo_new_sub_path(cr);
+ cairo_arc(cr, x, y, 10, 0, M_PI * 2);
+ cairo_set_line_width(cr, 4);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_set_line_width(cr, 2);
+ cairo_stroke(cr);
+
+ xoff = x ? -20 : 20;
+ align = x ? align_right : align_left;
+
+ yoff = y ? -20 : 20;
+ align |= y ? align_bottom : align_top;
+
+ cairo_move_to(cr, x + xoff, y + yoff);
+ cairo_set_font_size(cr, 18);
+ igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
+}
+
+/**
+ * igt_paint_test_pattern:
+ * @cr: cairo drawing context
+ * @width: width of the visible area
+ * @height: height of the visible area
+ *
+ * This functions draws an entire set of test patterns for the given visible
+ * area using the drawing context @cr. This is useful for manual visual
+ * inspection of displayed framebuffers.
+ *
+ * The test patterns include
+ * - corner markers to check for over/underscan and
+ * - a set of color and b/w gradients.
+ */
+void igt_paint_test_pattern(cairo_t *cr, int width, int height)
+{
+ paint_test_patterns(cr, width, height);
+
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
+
+ /* Paint corner markers */
+ paint_marker(cr, 0, 0);
+ paint_marker(cr, width, 0);
+ paint_marker(cr, 0, height);
+ paint_marker(cr, width, height);
+
+ igt_assert(!cairo_status(cr));
+}
+
+/**
+ * igt_paint_image:
+ * @cr: cairo drawing context
+ * @filename: filename of the png image to draw
+ * @dst_x: pixel x-coordination of the destination rectangle
+ * @dst_y: pixel y-coordination of the destination rectangle
+ * @dst_width: width of the destination rectangle
+ * @dst_height: height of the destination rectangle
+ *
+ * This function can be used to draw a scaled version of the supplied png image.
+ * This is currently only used by the CR-code based testing in the "testdisplay"
+ * testcase.
+ */
+void igt_paint_image(cairo_t *cr, const char *filename,
+ int dst_x, int dst_y, int dst_width, int dst_height)
+{
+ cairo_surface_t *image;
+ int img_width, img_height;
+ double scale_x, scale_y;
+
+ image = cairo_image_surface_create_from_png(filename);
+ igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
+
+ img_width = cairo_image_surface_get_width(image);
+ img_height = cairo_image_surface_get_height(image);
+
+ scale_x = (double)dst_width / img_width;
+ scale_y = (double)dst_height / img_height;
+
+ cairo_save(cr);
+
+ cairo_translate(cr, dst_x, dst_y);
+ cairo_scale(cr, scale_x, scale_y);
+ cairo_set_source_surface(cr, image, 0, 0);
+ cairo_paint(cr);
+
+ cairo_surface_destroy(image);
+
+ cairo_restore(cr);
+}
+
+/**
+ * igt_create_fb_with_bo_size:
+ * @fd: open i915 drm file descriptor
+ * @width: width of the framebuffer in pixel
+ * @height: height of the framebuffer in pixel
+ * @format: drm fourcc pixel format code
+ * @tiling: tiling layout of the framebuffer
+ * @fb: pointer to an #igt_fb structure
+ * @bo_size: size of the backing bo (0 for minimum needed size)
+ *
+ * This function allocates a gem buffer object suitable to back a framebuffer
+ * with the requested properties and then wraps it up in a drm framebuffer
+ * object of the requested size. All metadata is stored in @fb.
+ *
+ * The backing storage of the framebuffer is filled with all zeros, i.e. black
+ * for rgb pixel formats.
+ *
+ * Returns:
+ * The kms id of the created framebuffer.
+ */
+unsigned int
+igt_create_fb_with_bo_size(int fd, int width, int height,
+ uint32_t format, unsigned int tiling,
+ struct igt_fb *fb, unsigned bo_size)
+{
+ uint32_t handles[4];
+ uint32_t pitches[4];
+ uint32_t offsets[4];
+ uint32_t fb_id;
+ int bpp;
+
+ memset(fb, 0, sizeof(*fb));
+ memset(handles, 0, sizeof(handles));
+ memset(pitches, 0, sizeof(pitches));
+ memset(offsets, 0, sizeof(offsets));
+
+ bpp = igt_drm_format_to_bpp(format);
+
+ igt_debug("%s(width=%d, height=%d, format=0x%x [bpp=%d], tiling=%d, size=%d\n",
+ __func__, width, height, format, bpp, tiling, bo_size);
+ do_or_die(create_bo_for_fb(fd, width, height, bpp, tiling, bo_size,
+ &fb->gem_handle, &fb->size, &fb->stride));
+
+ handles[0] = fb->gem_handle;
+ pitches[0] = fb->stride;
+
+ igt_debug("%s(handle=%d, pitch=%d)\n",
+ __func__, handles[0], pitches[0]);
+ do_or_die(drmModeAddFB2(fd, width, height, format,
+ handles, pitches, offsets,
+ &fb_id, 0));
+
+ fb->width = width;
+ fb->height = height;
+ fb->tiling = tiling;
+ fb->drm_format = format;
+ fb->fb_id = fb_id;
+
+ return fb_id;
+}
+
+/**
+ * igt_create_fb:
+ * @fd: open i915 drm file descriptor
+ * @width: width of the framebuffer in pixel
+ * @height: height of the framebuffer in pixel
+ * @format: drm fourcc pixel format code
+ * @tiling: tiling layout of the framebuffer
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This function allocates a gem buffer object suitable to back a framebuffer
+ * with the requested properties and then wraps it up in a drm framebuffer
+ * object. All metadata is stored in @fb.
+ *
+ * The backing storage of the framebuffer is filled with all zeros, i.e. black
+ * for rgb pixel formats.
+ *
+ * Returns:
+ * The kms id of the created framebuffer.
+ */
+unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
+ unsigned int tiling, struct igt_fb *fb)
+{
+ return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb, 0);
+}
+
+/**
+ * igt_create_color_fb:
+ * @fd: open i915 drm file descriptor
+ * @width: width of the framebuffer in pixel
+ * @height: height of the framebuffer in pixel
+ * @format: drm fourcc pixel format code
+ * @tiling: tiling layout of the framebuffer
+ * @r: red value to use as fill color
+ * @g: gree value to use as fill color
+ * @b: blue value to use as fill color
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This function allocates a gem buffer object suitable to back a framebuffer
+ * with the requested properties and then wraps it up in a drm framebuffer
+ * object. All metadata is stored in @fb.
+ *
+ * Compared to igt_create_fb() this function also fills the entire framebuffer
+ * with the given color, which is useful for some simple pipe crc based tests.
+ *
+ * Returns:
+ * The kms id of the created framebuffer on success or a negative error code on
+ * failure.
+ */
+unsigned int igt_create_color_fb(int fd, int width, int height,
+ uint32_t format, unsigned int tiling,
+ double r, double g, double b,
+ struct igt_fb *fb /* out */)
+{
+ unsigned int fb_id;
+ cairo_t *cr;
+
+ fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
+ igt_assert(fb_id);
+
+ cr = igt_get_cairo_ctx(fd, fb);
+ igt_paint_color(cr, 0, 0, width, height, r, g, b);
+ igt_assert(cairo_status(cr) == 0);
+ cairo_destroy(cr);
+
+ return fb_id;
+}
+
+struct box {
+ int x, y, width, height;
+};
+
+struct stereo_fb_layout {
+ int fb_width, fb_height;
+ struct box left, right;
+};
+
+static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
+{
+ box->x = x;
+ box->y = y;
+ box->width = bwidth;
+ box->height = bheight;
+}
+
+
+static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
+ drmModeModeInfo *mode)
+{
+ unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
+ const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
+ int middle;
+
+ switch (format) {
+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
+ layout->fb_width = hdisplay;
+ layout->fb_height = vdisplay;
+
+ middle = vdisplay / 2;
+ box_init(&layout->left, 0, 0, hdisplay, middle);
+ box_init(&layout->right,
+ 0, middle, hdisplay, vdisplay - middle);
+ break;
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
+ layout->fb_width = hdisplay;
+ layout->fb_height = vdisplay;
+
+ middle = hdisplay / 2;
+ box_init(&layout->left, 0, 0, middle, vdisplay);
+ box_init(&layout->right,
+ middle, 0, hdisplay - middle, vdisplay);
+ break;
+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
+ {
+ int vactive_space = mode->vtotal - vdisplay;
+
+ layout->fb_width = hdisplay;
+ layout->fb_height = 2 * vdisplay + vactive_space;
+
+ box_init(&layout->left,
+ 0, 0, hdisplay, vdisplay);
+ box_init(&layout->right,
+ 0, vdisplay + vactive_space, hdisplay, vdisplay);
+ break;
+ }
+ default:
+ igt_assert(0);
+ }
+}
+
+/**
+ * igt_create_stereo_fb:
+ * @drm_fd: open i915 drm file descriptor
+ * @mode: A stereo 3D mode.
+ * @format: drm fourcc pixel format code
+ * @tiling: tiling layout of the framebuffer
+ *
+ * Create a framebuffer for use with the stereo 3D mode specified by @mode.
+ *
+ * Returns:
+ * The kms id of the created framebuffer on success or a negative error code on
+ * failure.
+ */
+unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
+ uint32_t format, unsigned int tiling)
+{
+ struct stereo_fb_layout layout;
+ cairo_t *cr;
+ uint32_t fb_id;
+ struct igt_fb fb;
+
+ stereo_fb_layout_from_mode(&layout, mode);
+ fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
+ tiling, &fb);
+ cr = igt_get_cairo_ctx(drm_fd, &fb);
+
+ igt_paint_image(cr, IGT_DATADIR"/1080p-left.png",
+ layout.left.x, layout.left.y,
+ layout.left.width, layout.left.height);
+ igt_paint_image(cr, IGT_DATADIR"/1080p-right.png",
+ layout.right.x, layout.right.y,
+ layout.right.width, layout.right.height);
+
+ cairo_destroy(cr);
+
+ return fb_id;
+}
+
+static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->drm_id == drm_format)
+ return f->cairo_id;
+
+ igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
+ drm_format, igt_format_str(drm_format));
+}
+
+static void destroy_cairo_surface__gtt(void *arg)
+{
+ struct igt_fb *fb = arg;
+
+ munmap(cairo_image_surface_get_data(fb->cairo_surface), fb->size);
+ fb->cairo_surface = NULL;
+}
+
+static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
+{
+ fb->cairo_surface =
+ cairo_image_surface_create_for_data(gem_mmap(fd, fb->gem_handle, fb->size, PROT_READ | PROT_WRITE),
+ drm_format_to_cairo(fb->drm_format),
+ fb->width, fb->height, fb->stride);
+
+ cairo_surface_set_user_data(fb->cairo_surface,
+ (cairo_user_data_key_t *)create_cairo_surface__gtt,
+ fb, destroy_cairo_surface__gtt);
+}
+
+static cairo_surface_t *get_cairo_surface(int fd, struct igt_fb *fb)
+{
+ if (fb->cairo_surface == NULL)
+ create_cairo_surface__gtt(fd, fb);
+
+ gem_set_domain(fd, fb->gem_handle,
+ I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+
+ igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
+ return fb->cairo_surface;
+}
+
+/**
+ * igt_get_cairo_ctx:
+ * @fd: open i915 drm file descriptor
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This initializes a cairo surface for @fb and then allocates a drawing context
+ * for it. The return cairo drawing context should be released by calling
+ * cairo_destroy(). This also sets a default font for drawing text on
+ * framebuffers.
+ *
+ * Returns:
+ * The created cairo drawing context.
+ */
+cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ surface = get_cairo_surface(fd, fb);
+ cr = cairo_create(surface);
+ cairo_surface_destroy(surface);
+ igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
+
+ cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
+
+ return cr;
+}
+
+/**
+ * igt_write_fb_to_png:
+ * @fd: open i915 drm file descriptor
+ * @fb: pointer to an #igt_fb structure
+ * @filename: target name for the png image
+ *
+ * This function stores the contents of the supplied framebuffer into a png
+ * image stored at @filename.
+ */
+void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename)
+{
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ surface = get_cairo_surface(fd, fb);
+ status = cairo_surface_write_to_png(surface, filename);
+ cairo_surface_destroy(surface);
+
+ igt_assert(status == CAIRO_STATUS_SUCCESS);
+}
+
+/**
+ * igt_remove_fb:
+ * @fd: open i915 drm file descriptor
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This function releases all resources allocated in igt_create_fb() for @fb.
+ * Note that if this framebuffer is still in use on a primary plane the kernel
+ * will disable the corresponding crtc.
+ */
+void igt_remove_fb(int fd, struct igt_fb *fb)
+{
+ cairo_surface_destroy(fb->cairo_surface);
+ do_or_die(drmModeRmFB(fd, fb->fb_id));
+ gem_close(fd, fb->gem_handle);
+}
+
+/**
+ * igt_bpp_depth_to_drm_format:
+ * @bpp: desired bits per pixel
+ * @depth: desired depth
+ *
+ * Returns:
+ * The rgb drm fourcc pixel format code corresponding to the given @bpp and
+ * @depth values. Fails hard if no match was found.
+ */
+uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->bpp == bpp && f->depth == depth)
+ return f->drm_id;
+
+
+ igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
+ depth);
+}
+
+/**
+ * igt_drm_format_to_bpp:
+ * @drm_format: drm fourcc pixel format code
+ *
+ * Returns:
+ * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
+ * no match was found.
+ */
+uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->drm_id == drm_format)
+ return f->bpp;
+
+ igt_assert_f(0, "can't find a bpp format for %08x (%s)\n",
+ drm_format, igt_format_str(drm_format));
+}
+
+/**
+ * igt_format_str:
+ * @drm_format: drm fourcc pixel format code
+ *
+ * Returns:
+ * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
+ * was found.
+ */
+const char *igt_format_str(uint32_t drm_format)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->drm_id == drm_format)
+ return f->name;
+
+ return "invalid";
+}
+
+/**
+ * igt_get_all_formats:
+ * @formats: pointer to pointer to store the allocated formats array
+ * @format_count: pointer to integer to store the size of the allocated array
+ *
+ * This functions returns an array of all the drm fourcc codes supported by this
+ * library. The caller must free the allocated array again with free().
+ */
+void igt_get_all_formats(const uint32_t **formats, int *format_count)
+{
+ static uint32_t *drm_formats;
+
+ if (!drm_formats) {
+ struct format_desc_struct *f;
+ uint32_t *format;
+
+ drm_formats = calloc(ARRAY_SIZE(format_desc),
+ sizeof(*drm_formats));
+ format = &drm_formats[0];
+ for_each_format(f)
+ *format++ = f->drm_id;
+ }
+
+ *formats = drm_formats;
+ *format_count = ARRAY_SIZE(format_desc);
+}
diff --git a/lib/igt_fb.h b/lib/igt_fb.h
new file mode 100644
index 0000000..d9fb6bb
--- /dev/null
+++ b/lib/igt_fb.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2013,2014 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ * Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifndef __IGT_FB_H__
+#define __IGT_FB_H__
+
+/* cairo is assumed available on linux. On Android we check for ANDROID_HAS_CAIRO */
+#if (!defined(ANDROID)) || (defined(ANDROID) && ANDROID_HAS_CAIRO)
+#include <cairo.h>
+#else
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo cairo_t;
+#endif
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <drm_fourcc.h>
+#include <xf86drmMode.h>
+
+#include <i915_drm.h>
+
+/* helpers to create nice-looking framebuffers */
+struct igt_fb {
+ uint32_t fb_id;
+ uint32_t gem_handle;
+ uint32_t drm_format;
+ int width;
+ int height;
+ unsigned stride;
+ unsigned tiling;
+ unsigned size;
+ cairo_surface_t *cairo_surface;
+};
+
+enum igt_text_align {
+ align_left,
+ align_bottom = align_left,
+ align_right = 0x01,
+ align_top = 0x02,
+ align_vcenter = 0x04,
+ align_hcenter = 0x08,
+};
+
+unsigned int
+igt_create_fb_with_bo_size(int fd, int width, int height,
+ uint32_t format, unsigned int tiling,
+ struct igt_fb *fb, unsigned bo_size);
+unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
+ unsigned int tiling, struct igt_fb *fb);
+unsigned int igt_create_color_fb(int fd, int width, int height,
+ uint32_t format, unsigned int tiling,
+ double r, double g, double b,
+ struct igt_fb *fb /* out */);
+unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
+ uint32_t format, unsigned int tiling);
+void igt_remove_fb(int fd, struct igt_fb *fb);
+
+/* cairo-based painting */
+cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb);
+void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b);
+void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b, double a);
+void igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
+ int r, int g, int b);
+void igt_paint_test_pattern(cairo_t *cr, int width, int height);
+void igt_paint_image(cairo_t *cr, const char *filename,
+ int dst_x, int dst_y, int dst_width, int dst_height);
+void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename);
+int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
+ double yspacing, const char *fmt, ...)
+ __attribute__((format (printf, 4, 5)));
+
+/* helpers to handle drm fourcc codes */
+uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth);
+uint32_t igt_drm_format_to_bpp(uint32_t drm_format);
+const char *igt_format_str(uint32_t drm_format);
+void igt_get_all_formats(const uint32_t **formats, int *format_count);
+
+#endif /* __IGT_FB_H__ */
+
diff --git a/lib/igt_gt.c b/lib/igt_gt.c
new file mode 100644
index 0000000..84aa5d3
--- /dev/null
+++ b/lib/igt_gt.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright © 2014 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.
+ */
+
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "drmtest.h"
+#include "igt_core.h"
+#include "igt_gt.h"
+#include "igt_debugfs.h"
+#include "ioctl_wrappers.h"
+#include "intel_reg.h"
+#include "intel_chipset.h"
+
+/**
+ * SECTION:igt_gt
+ * @short_description: GT support library
+ * @title: i-g-t gt
+ * @include: igt_gt.h
+ *
+ * This library provides various auxiliary helper functions to handle general
+ * interactions with the GT like forcewake handling, injecting hangs or stopping
+ * engines.
+ */
+
+
+/**
+ * igt_require_hang_ring:
+ * @fd: open i915 drm file descriptor
+ * @ring: execbuf ring flag
+ *
+ * Convenience helper to check whether advanced hang injection is supported by
+ * the kernel. Uses igt_skip to automatically skip the test/subtest if this
+ * isn't the case.
+ */
+void igt_require_hang_ring(int fd, int ring)
+{
+ gem_context_require_param(fd, LOCAL_CONTEXT_PARAM_BAN_PERIOD);
+ igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
+}
+
+/**
+ * igt_hang_ring:
+ * @fd: open i915 drm file descriptor
+ * @ring: execbuf ring flag
+ *
+ * This helper function injects a hanging batch into @ring. It returns a
+ * #igt_hang_ring_t structure which must be passed to igt_post_hang_ring() for
+ * hang post-processing (after the gpu hang interaction has been tested.
+ *
+ * Returns:
+ * Structure with helper internal state for igt_post_hang_ring().
+ */
+igt_hang_ring_t igt_hang_ring(int fd, int ring)
+{
+ struct drm_i915_gem_relocation_entry reloc;
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 exec;
+ struct local_i915_gem_context_param param;
+ uint32_t b[8];
+ unsigned ban;
+ unsigned len;
+
+ param.context = 0;
+ param.size = 0;
+ param.param = LOCAL_CONTEXT_PARAM_BAN_PERIOD;
+ param.value = 0;
+ gem_context_get_param(fd, &param);
+ ban = param.value;
+
+ param.value = 0;
+ gem_context_set_param(fd, &param);
+
+ memset(&reloc, 0, sizeof(reloc));
+ memset(&exec, 0, sizeof(exec));
+ memset(&execbuf, 0, sizeof(execbuf));
+
+ exec.handle = gem_create(fd, 4096);
+ exec.relocation_count = 1;
+ exec.relocs_ptr = (uintptr_t)&reloc;
+
+ len = 2;
+ if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+ len++;
+ b[0] = MI_BATCH_BUFFER_START | (len - 2);
+ b[len] = MI_BATCH_BUFFER_END;
+ b[len+1] = MI_NOOP;
+ gem_write(fd, exec.handle, 0, b, sizeof(b));
+
+ reloc.offset = 4;
+ reloc.target_handle = exec.handle;
+ reloc.read_domains = I915_GEM_DOMAIN_COMMAND;
+
+ execbuf.buffers_ptr = (uintptr_t)&exec;
+ execbuf.buffer_count = 1;
+ execbuf.batch_len = sizeof(b);
+ execbuf.flags = ring;
+ gem_execbuf(fd, &execbuf);
+
+ return (struct igt_hang_ring){ exec.handle, ban };
+}
+
+/**
+ * igt_post_hang_ring:
+ * @fd: open i915 drm file descriptor
+ * @arg: hang state from igt_hang_ring()
+ *
+ * This function does the necessary post-processing after a gpu hang injected
+ * with igt_hang_ring().
+ */
+void igt_post_hang_ring(int fd, struct igt_hang_ring arg)
+{
+ struct local_i915_gem_context_param param;
+
+ if (arg.handle == 0)
+ return;
+
+ gem_set_domain(fd, arg.handle,
+ I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ gem_close(fd, arg.handle);
+
+ param.context = 0;
+ param.size = 0;
+ param.param = LOCAL_CONTEXT_PARAM_BAN_PERIOD;
+ param.value = arg.ban;
+ gem_context_set_param(fd, &param);
+}
+
+/* GPU abusers */
+static struct igt_helper_process hang_helper;
+static void __attribute__((noreturn))
+hang_helper_process(pid_t pid, int fd)
+{
+ while (1) {
+ if (kill(pid, 0)) /* Parent has died, so must we. */
+ exit(0);
+
+ igt_post_hang_ring(fd,
+ igt_hang_ring(fd, I915_EXEC_DEFAULT));
+
+ sleep(1);
+ }
+}
+
+/**
+ * igt_fork_hang_helper:
+ *
+ * Fork a child process using #igt_fork_helper to hang the default engine
+ * of the GPU at regular intervals.
+ *
+ * This is useful to exercise slow running code (such as aperture placement)
+ * which needs to be robust against a GPU reset.
+ *
+ * In tests with subtests this function can be called outside of failure
+ * catching code blocks like #igt_fixture or #igt_subtest.
+ */
+int igt_fork_hang_helper(void)
+{
+ int fd, gen;
+
+ if (igt_only_list_subtests())
+ return 1;
+
+ fd = drm_open_any();
+ if (fd == -1)
+ return 0;
+
+ gen = intel_gen(intel_get_drm_devid(fd));
+ if (gen < 5) {
+ close(fd);
+ return 0;
+ }
+
+ igt_fork_helper(&hang_helper)
+ hang_helper_process(getppid(), fd);
+
+ close(fd);
+ return 1;
+}
+
+/**
+ * igt_stop_hang_helper:
+ *
+ * Stops the child process spawned with igt_fork_hang_helper().
+ *
+ * In tests with subtests this function can be called outside of failure
+ * catching code blocks like #igt_fixture or #igt_subtest.
+ */
+void igt_stop_hang_helper(void)
+{
+ if (igt_only_list_subtests())
+ return;
+
+ igt_stop_helper(&hang_helper);
+}
+
+/**
+ * igt_open_forcewake_handle:
+ *
+ * This functions opens the debugfs forcewake file and so prevents the GT from
+ * suspending. The reference is automatically dropped when the is closed.
+ *
+ * Returns:
+ * The file descriptor of the forcewake handle or -1 if that didn't work out.
+ */
+int igt_open_forcewake_handle(void)
+{
+ if (getenv("IGT_NO_FORCEWAKE"))
+ return -1;
+ return igt_debugfs_open("i915_forcewake_user", O_WRONLY);
+}
+
+/**
+ * igt_to_stop_ring_flag:
+ * @ring: the specified ring flag from execbuf ioctl (I915_EXEC_*)
+ *
+ * This converts the specified ring to a ring flag to be used
+ * with igt_get_stop_rings() and igt_set_stop_rings().
+ *
+ * Returns:
+ * Ring flag for the given ring.
+ */
+enum stop_ring_flags igt_to_stop_ring_flag(int ring) {
+ if (ring == I915_EXEC_DEFAULT)
+ return STOP_RING_RENDER;
+
+ igt_assert(ring && ((ring & ~I915_EXEC_RING_MASK) == 0));
+ return 1 << (ring - 1);
+}
+
+static void stop_rings_write(uint32_t mask)
+{
+ int fd;
+ char buf[80];
+
+ igt_assert(snprintf(buf, sizeof(buf), "0x%08x", mask) == 10);
+ fd = igt_debugfs_open("i915_ring_stop", O_WRONLY);
+ igt_assert(fd >= 0);
+
+ igt_assert(write(fd, buf, strlen(buf)) == strlen(buf));
+ close(fd);
+}
+
+/**
+ * igt_get_stop_rings:
+ *
+ * Read current ring flags from 'i915_ring_stop' debugfs entry.
+ *
+ * Returns:
+ * Current ring flags.
+ */
+enum stop_ring_flags igt_get_stop_rings(void)
+{
+ int fd;
+ char buf[80];
+ int l;
+ unsigned long long ring_mask;
+
+ fd = igt_debugfs_open("i915_ring_stop", O_RDONLY);
+ igt_assert(fd >= 0);
+ l = read(fd, buf, sizeof(buf)-1);
+ igt_assert(l > 0);
+ igt_assert(l < sizeof(buf));
+
+ buf[l] = '\0';
+
+ close(fd);
+
+ errno = 0;
+ ring_mask = strtoull(buf, NULL, 0);
+ igt_assert(errno == 0);
+ return ring_mask;
+}
+
+/**
+ * igt_set_stop_rings:
+ * @flags: Ring flags to write
+ *
+ * This writes @flags to 'i915_ring_stop' debugfs entry. Driver will
+ * prevent the CPU from writing tail pointer for the ring that @flags
+ * specify. Note that the ring is not stopped right away. Instead any
+ * further command emissions won't be executed after the flag is set.
+ *
+ * This is the least invasive way to make the GPU stuck. Hence you must
+ * set this after a batch submission with it's own invalid or endless
+ * looping instructions. In this case it is merely for giving notification
+ * for the driver that this was simulated hang, as the batch would have
+ * caused hang in any case. On the other hand if you use a valid or noop
+ * batch and want to hang the ring (GPU), you must set corresponding flag
+ * before submitting the batch.
+ *
+ * Driver checks periodically if a ring is making any progress, and if
+ * it is not, it will declare the ring to be hung and will reset the GPU.
+ * After reset, the driver will clear flags in 'i915_ring_stop'
+ *
+ * Note: Always when hanging the GPU, use igt_set_stop_rings() to
+ * notify the driver. Driver controls hang log messaging based on
+ * these flags and thus prevents false positives on logs.
+ */
+void igt_set_stop_rings(enum stop_ring_flags flags)
+{
+ enum stop_ring_flags current;
+
+ igt_assert((flags & ~(STOP_RING_ALL |
+ STOP_RING_ALLOW_BAN |
+ STOP_RING_ALLOW_ERRORS)) == 0);
+
+ current = igt_get_stop_rings();
+ igt_assert_f(flags == 0 || current == 0,
+ "previous i915_ring_stop is still 0x%x\n", current);
+
+ stop_rings_write(flags);
+ current = igt_get_stop_rings();
+ igt_warn_on_f(current != flags,
+ "i915_ring_stop readback mismatch 0x%x vs 0x%x\n",
+ flags, current);
+}
diff --git a/lib/igt_gt.h b/lib/igt_gt.h
new file mode 100644
index 0000000..5105423
--- /dev/null
+++ b/lib/igt_gt.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2014 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.
+ */
+
+#ifndef IGT_GT_H
+#define IGT_GT_H
+
+#include "igt_debugfs.h"
+
+void igt_require_hang_ring(int fd, int ring);
+
+typedef struct igt_hang_ring {
+ unsigned handle;
+ unsigned ban;
+} igt_hang_ring_t;
+
+struct igt_hang_ring igt_hang_ring(int fd, int ring);
+void igt_post_hang_ring(int fd, struct igt_hang_ring arg);
+
+int igt_fork_hang_helper(void);
+void igt_stop_hang_helper(void);
+
+int igt_open_forcewake_handle(void);
+
+/**
+ * stop_ring_flags:
+ * @STOP_RING_NONE: Can be used to clear the pending stop (warning: hang might
+ * be declared already). Returned by igt_get_stop_rings() if there is
+ * no currently stopped rings.
+ * @STOP_RING_RENDER: Render ring
+ * @STOP_RING_BSD: Video encoding/decoding ring
+ * @STOP_RING_BLT: Blitter ring
+ * @STOP_RING_VEBOX: Video enhancement ring
+ * @STOP_RING_ALL: All rings
+ * @STOP_RING_ALLOW_ERRORS: Driver will not omit expected DRM_ERRORS
+ * @STOP_RING_ALLOW_BAN: Driver will use context ban policy
+ * @STOP_RING_DEFAULTS: STOP_RING_ALL | STOP_RING_ALLOW_ERRORS
+ *
+ * Enumeration of all supported flags for igt_set_stop_rings().
+ *
+ */
+enum stop_ring_flags {
+ STOP_RING_NONE = 0x00,
+ STOP_RING_RENDER = (1 << 0),
+ STOP_RING_BSD = (1 << 1),
+ STOP_RING_BLT = (1 << 2),
+ STOP_RING_VEBOX = (1 << 3),
+ STOP_RING_ALL = 0xff,
+ STOP_RING_ALLOW_ERRORS = (1 << 30),
+ STOP_RING_ALLOW_BAN = (1 << 31),
+ STOP_RING_DEFAULTS = STOP_RING_ALL | STOP_RING_ALLOW_ERRORS,
+};
+
+enum stop_ring_flags igt_to_stop_ring_flag(int ring);
+void igt_set_stop_rings(enum stop_ring_flags flags);
+enum stop_ring_flags igt_get_stop_rings(void);
+
+#endif /* IGT_GT_H */
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
new file mode 100644
index 0000000..9c131f0
--- /dev/null
+++ b/lib/igt_kms.c
@@ -0,0 +1,1853 @@
+/*
+ * Copyright © 2013 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ * Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#include "config.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_LINUX_KD_H
+#include <linux/kd.h>
+#elif HAVE_SYS_KD_H
+#include <sys/kd.h>
+#endif
+#include <errno.h>
+#include <time.h>
+
+#include <i915_drm.h>
+
+#include "drmtest.h"
+#include "igt_kms.h"
+#include "igt_aux.h"
+#include "intel_chipset.h"
+#include "igt_debugfs.h"
+
+/*
+ * There hasn't been a release of libdrm containing these #define's yet, so
+ * copy them here to allow compilation to succeed in the mean time.
+ *
+ * We can drop these #define's and just make i-g-t depend on the proper libdrm
+ * version in the future.
+ */
+#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
+#define DRM_PLANE_TYPE_OVERLAY 0
+#define DRM_PLANE_TYPE_PRIMARY 1
+#define DRM_PLANE_TYPE_CURSOR 2
+
+/* list of connectors that need resetting on exit */
+#define MAX_CONNECTORS 32
+static char *forced_connectors[MAX_CONNECTORS + 1];
+
+
+#define VFREQ 60
+#define CLOCK 148500
+#define HACTIVE 1920
+#define HBLANK 280
+#define VACTIVE 1080
+#define VBLANK 45
+#define HOFFSET 88
+#define HPULSE 44
+#define VOFFSET 4
+#define VPULSE 5
+
+#define HSIZE 52
+#define VSIZE 30
+
+#define GAMMA(x) (x * 100) - 100
+
+#define MANUFACTURER_ID(a, b, c) (a - '@') << 2 | (b - '@') >> 3, \
+ (b - '@') << 5 | (c - '@')
+
+
+#define ab(x, y) (x & 0xff), (y & 0xff), ((x & 0xf00) >> 4) | ((y & 0xf00) >> 8)
+#define op(ho, hp, vo, vp) (ho & 0xff), (hp & 0xff), \
+ ((vo & 0xf) << 4) | (vp & 0xf), \
+ ((ho & 0x300) >> 2) | ((hp & 0x300) >> 4) \
+ | ((vo & 0x30) >> 2) | (vp & 0x30 >> 4)
+
+static unsigned char base_edid[EDID_LENGTH] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* header */
+ MANUFACTURER_ID('I', 'G', 'T'),
+ /* product code, serial number, week and year of manufacture */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x03, /* edid version (1.3) */
+ /* basic display parameters */
+ /* digital display, maximum horizontal image size, maximum vertical
+ * image size, gamma, features: RGB 4:4:4, native pixel format and
+ * refresh rate in descriptor 1 */
+ 0x80, HSIZE, VSIZE, GAMMA(2.20), 0x02,
+ /* chromaticity coordinates */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* established timings: 640x480 60Hz, 800x600 60Hz, 1024x768 60Hz */
+ 0x21, 0x08, 0x00,
+ /* standard timings */
+ 0xd1, 0xc0, /* 1920x1080 60Hz */
+ 0x81, 0xc0, /* 1280x720 60Hz */
+ 0x61, 0x40, /* 1024x768 60Hz */
+ 0x45, 0x40, /* 800x600 60Hz */
+ 0x31, 0x40, /* 640x480 60Hz */
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ /* descriptor 1 (preferred timing) */
+ (CLOCK / 10) & 0x00ff, ((CLOCK / 10) & 0xff00) >> 8,
+ ab(HACTIVE, HBLANK), ab(VACTIVE, VBLANK),
+ op(HOFFSET, HPULSE, VOFFSET, VPULSE),
+ ab(HSIZE * 10, VSIZE * 10),
+ 0x00, 0x00, 0x00,
+ /* descriptor 2 (monitor range limits) */
+ 0x00, 0x00, 0x00, 0xfd, 0x00,
+ VFREQ - 1, VFREQ + 1, /* minimum, maximum vertical field rate */
+ (CLOCK / (HACTIVE + HBLANK)) - 1, /* minimum horizontal line rate */
+ (CLOCK / (HACTIVE + HBLANK)) + 1, /* maximum horizontal line rate */
+ (CLOCK / 10000) + 1, /* maximum pixel clock rate */
+ 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ /* descriptor 3 (name descriptor) */
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 'I', 'G', 'T', 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ /* descriptor 4 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* extensions, checksum */
+ 0x00, 0x00
+};
+
+/**
+ * igt_kms_get_base_edid:
+ *
+ * Get the base edid block, which includes the following modes:
+ *
+ * - 1920x1080 60Hz
+ * - 1280x720 60Hz
+ * - 1024x768 60Hz
+ * - 800x600 60Hz
+ * - 640x480 60Hz
+ *
+ * This can be extended with further features using functions such as
+ * #kmstest_edid_add_3d.
+ *
+ * Returns: a basic edid block
+ */
+const unsigned char* igt_kms_get_base_edid(void)
+{
+ int i, sum = 0;
+ struct tm *tm;
+ time_t t;
+
+ /* year of manufacture */
+ t = time(NULL);
+ tm = localtime(&t);
+ base_edid[17] = tm->tm_year - 90;
+
+ /* calculate checksum */
+ for (i = 0; i < 127; i++) {
+ sum = sum + base_edid[i];
+ }
+ base_edid[127] = 256 - sum;
+
+ return base_edid;
+}
+
+
+/**
+ * SECTION:igt_kms
+ * @short_description: Kernel modesetting support library
+ * @title: i-g-t kms
+ * @include: igt_kms.h
+ *
+ * This library provides support to enumerate and set modeset configurations.
+ *
+ * There are two parts in this library: First the low level helper function
+ * which directly build on top of raw ioctls or the interfaces provided by
+ * libdrm. Those functions all have a kmstest_ prefix.
+ *
+ * The second part is a high-level library to manage modeset configurations
+ * which abstracts away some of the low-level details like the difference
+ * between legacy and universal plane support for setting cursors or in the
+ * future the difference between legacy and atomic commit. These high-level
+ * functions have all igt_ prefixes. This part is still very much work in
+ * progress and so also lacks a bit documentation for the individual functions.
+ *
+ * Note that this library's header pulls in the [i-g-t framebuffer](intel-gpu-tools-i-g-t-framebuffer.html)
+ * library as a dependency.
+ */
+
+/**
+ * kmstest_pipe_name:
+ * @pipe: display pipe
+ *
+ * Returns: String represnting @pipe, e.g. "A".
+ */
+const char *kmstest_pipe_name(enum pipe pipe)
+{
+ const char *str[] = { "A", "B", "C" };
+
+ if (pipe > 2)
+ return "invalid";
+
+ return str[pipe];
+}
+
+/**
+ * kmstest_plane_name:
+ * @plane: display plane
+ *
+ * Returns: String represnting @pipe, e.g. "plane1".
+ */
+const char *kmstest_plane_name(enum igt_plane plane)
+{
+ static const char *names[] = {
+ [IGT_PLANE_1] = "plane1",
+ [IGT_PLANE_2] = "plane2",
+ [IGT_PLANE_3] = "plane3",
+ [IGT_PLANE_CURSOR] = "cursor",
+ };
+
+ igt_assert(plane < ARRAY_SIZE(names) && names[plane]);
+
+ return names[plane];
+}
+
+static const char *mode_stereo_name(const drmModeModeInfo *mode)
+{
+ switch (mode->flags & DRM_MODE_FLAG_3D_MASK) {
+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
+ return "FP";
+ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
+ return "FA";
+ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
+ return "LA";
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
+ return "SBSF";
+ case DRM_MODE_FLAG_3D_L_DEPTH:
+ return "LD";
+ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
+ return "LDGFX";
+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
+ return "TB";
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
+ return "SBSH";
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * kmstest_dump_mode:
+ * @mode: libdrm mode structure
+ *
+ * Prints @mode to stdout in a huma-readable form.
+ */
+void kmstest_dump_mode(drmModeModeInfo *mode)
+{
+ const char *stereo = mode_stereo_name(mode);
+
+ igt_info(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d%s%s%s\n",
+ mode->name, mode->vrefresh,
+ mode->hdisplay, mode->hsync_start,
+ mode->hsync_end, mode->htotal,
+ mode->vdisplay, mode->vsync_start,
+ mode->vsync_end, mode->vtotal,
+ mode->flags, mode->type, mode->clock,
+ stereo ? " (3D:" : "",
+ stereo ? stereo : "", stereo ? ")" : "");
+}
+
+/**
+ * kmstest_get_pipe_from_crtc_id:
+ * @fd: DRM fd
+ * @crtc_id: DRM CRTC id
+ *
+ * Returns: The pipe number for the given DRM CRTC @crtc_id. This maps directly
+ * to an enum pipe value used in other helper functions.
+ */
+int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id)
+{
+ struct drm_i915_get_pipe_from_crtc_id pfci;
+ int ret;
+
+ memset(&pfci, 0, sizeof(pfci));
+ pfci.crtc_id = crtc_id;
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, &pfci);
+ igt_assert(ret == 0);
+
+ return pfci.pipe;
+}
+
+/*
+ * Returns: the previous mode, or KD_GRAPHICS if no /dev/tty0 was
+ * found and nothing was done.
+ */
+static signed long set_vt_mode(unsigned long mode)
+{
+ int fd;
+ unsigned long prev_mode;
+ static const char TTY0[] = "/dev/tty0";
+
+ if (access(TTY0, F_OK)) {
+ /* errno message should be "No such file". Do not
+ hardcode but ask strerror() in the very unlikely
+ case something else happened. */
+ igt_debug("VT: %s: %s, cannot change its mode\n",
+ TTY0, strerror(errno));
+ return KD_GRAPHICS;
+ }
+
+ fd = open(TTY0, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ prev_mode = 0;
+ if (drmIoctl(fd, KDGETMODE, &prev_mode))
+ goto err;
+ if (drmIoctl(fd, KDSETMODE, (void *)mode))
+ goto err;
+
+ close(fd);
+
+ return prev_mode;
+err:
+ close(fd);
+
+ return -errno;
+}
+
+static unsigned long orig_vt_mode = -1UL;
+
+/**
+ * kmstest_restore_vt_mode:
+ *
+ * Restore the VT mode in use before #kmstest_set_vt_graphics_mode was called.
+ */
+void kmstest_restore_vt_mode(void)
+{
+ long ret;
+
+ if (orig_vt_mode != -1UL) {
+ ret = set_vt_mode(orig_vt_mode);
+
+ igt_assert(ret >= 0);
+ igt_debug("VT: original mode 0x%lx restored\n", orig_vt_mode);
+ orig_vt_mode = -1UL;
+ }
+}
+
+/**
+ * kmstest_set_vt_graphics_mode:
+ *
+ * Sets the controlling VT (if available) into graphics/raw mode and installs
+ * an igt exit handler to set the VT back to text mode on exit. Use
+ * #kmstest_restore_vt_mode to restore the previous VT mode manually.
+ *
+ * All kms tests must call this function to make sure that the fbcon doesn't
+ * interfere by e.g. blanking the screen.
+ */
+void kmstest_set_vt_graphics_mode(void)
+{
+ long ret;
+
+ igt_install_exit_handler((igt_exit_handler_t) kmstest_restore_vt_mode);
+
+ igt_disable_exit_handler();
+ ret = set_vt_mode(KD_GRAPHICS);
+ igt_enable_exit_handler();
+
+ igt_assert(ret >= 0);
+ orig_vt_mode = ret;
+
+ igt_debug("VT: graphics mode set (mode was 0x%lx)\n", ret);
+}
+
+
+static void reset_connectors_at_exit(int sig)
+{
+ igt_reset_connectors();
+}
+
+/**
+ * kmstest_force_connector:
+ * @fd: drm file descriptor
+ * @connector: connector
+ * @state: state to force on @connector
+ *
+ * Force the specified state on the specified connector.
+ *
+ * Returns: true on success
+ */
+bool kmstest_force_connector(int drm_fd, drmModeConnector *connector,
+ enum kmstest_force_connector_state state)
+{
+ char *path, **tmp;
+ const char *value;
+ int debugfs_fd, ret, len;
+ uint32_t devid;
+
+ devid = intel_get_drm_devid(drm_fd);
+
+ /* forcing hdmi or dp connectors on HSW and BDW doesn't currently work,
+ * so fail early to allow the test to skip if required */
+ if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector->connector_type == DRM_MODE_CONNECTOR_HDMIB ||
+ connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
+ && (IS_HASWELL(devid) || IS_BROADWELL(devid)))
+ return false;
+
+ switch (state) {
+ case FORCE_CONNECTOR_ON:
+ value = "on";
+ break;
+ case FORCE_CONNECTOR_DIGITAL:
+ value = "digital";
+ break;
+ case FORCE_CONNECTOR_OFF:
+ value = "off";
+ break;
+
+ default:
+ case FORCE_CONNECTOR_UNSPECIFIED:
+ value = "unspecified";
+ break;
+ }
+
+ asprintf(&path, "%s-%d/force",
+ kmstest_connector_type_str(connector->connector_type),
+ connector->connector_type_id);
+ debugfs_fd = igt_debugfs_open(path, O_WRONLY | O_TRUNC);
+
+ if (debugfs_fd == -1) {
+ return false;
+ }
+
+ ret = write(debugfs_fd, value, strlen(value));
+ close(debugfs_fd);
+
+ for (len = 0, tmp = forced_connectors; *tmp; tmp++) {
+ /* check the connector is not already present */
+ if (strcmp(*tmp, path) == 0) {
+ len = -1;
+ break;
+ }
+ len++;
+ }
+
+ if (len != -1 && len < MAX_CONNECTORS)
+ forced_connectors[len] = path;
+
+ if (len >= MAX_CONNECTORS)
+ igt_warn("Connector limit reached, %s will not be reset\n",
+ path);
+
+ igt_debug("Connector %s is now forced %s\n", path, value);
+ igt_debug("Current forced connectors:\n");
+ tmp = forced_connectors;
+ while (*tmp) {
+ igt_debug("\t%s\n", *tmp);
+ tmp++;
+ }
+
+ igt_install_exit_handler(reset_connectors_at_exit);
+
+ igt_assert(ret != -1);
+ return (ret == -1) ? false : true;
+}
+
+/**
+ * kmstest_force_edid:
+ * @drm_fd: drm file descriptor
+ * @connector: connector to set @edid on
+ * @edid: An EDID data block
+ * @length: length of the EDID data. #EDID_LENGTH defines the standard EDID
+ * length
+ *
+ * Set the EDID data on @connector to @edid. See also #igt_kms_get_base_edid.
+ *
+ * If @length is zero, the forced EDID will be removed.
+ */
+void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
+ const unsigned char *edid, size_t length)
+{
+ char *path;
+ int debugfs_fd, ret;
+
+ asprintf(&path, "%s-%d/edid_override",
+ kmstest_connector_type_str(connector->connector_type),
+ connector->connector_type_id);
+ debugfs_fd = igt_debugfs_open(path, O_WRONLY | O_TRUNC);
+ free(path);
+
+ igt_assert(debugfs_fd != -1);
+
+ if (length == 0)
+ ret = write(debugfs_fd, "reset", 5);
+ else
+ ret = write(debugfs_fd, edid, length);
+ close(debugfs_fd);
+
+ igt_assert(ret != -1);
+}
+
+/**
+ * kmstest_get_connector_default_mode:
+ * @drm_fd: DRM fd
+ * @connector: libdrm connector
+ * @mode: libdrm mode
+ *
+ * Retrieves the default mode for @connector and stores it in @mode.
+ *
+ * Returns: true on success, false on failure
+ */
+bool kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
+ drmModeModeInfo *mode)
+{
+ int i;
+
+ if (!connector->count_modes) {
+ igt_warn("no modes for connector %d\n",
+ connector->connector_id);
+ return false;
+ }
+
+ for (i = 0; i < connector->count_modes; i++) {
+ if (i == 0 ||
+ connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
+ *mode = connector->modes[i];
+ if (mode->type & DRM_MODE_TYPE_PREFERRED)
+ break;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * kmstest_get_connector_config:
+ * @drm_fd: DRM fd
+ * @connector_id: DRM connector id
+ * @crtc_idx_mask: mask of allowed DRM CRTC indices
+ * @config: structure filled with the possible configuration
+ *
+ * This tries to find a suitable configuration for the given connector and CRTC
+ * constraint and fills it into @config.
+ */
+bool kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
+ unsigned long crtc_idx_mask,
+ struct kmstest_connector_config *config)
+{
+ drmModeRes *resources;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ int i, j;
+
+ resources = drmModeGetResources(drm_fd);
+ if (!resources) {
+ igt_warn("drmModeGetResources failed");
+ goto err1;
+ }
+
+ /* First, find the connector & mode */
+ connector = drmModeGetConnector(drm_fd, connector_id);
+ if (!connector)
+ goto err2;
+
+ if (connector->connection != DRM_MODE_CONNECTED)
+ goto err3;
+
+ if (!connector->count_modes) {
+ igt_warn("connector %d has no modes\n", connector_id);
+ goto err3;
+ }
+
+ if (connector->connector_id != connector_id) {
+ igt_warn("connector id doesn't match (%d != %d)\n",
+ connector->connector_id, connector_id);
+ goto err3;
+ }
+
+ /*
+ * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
+ * In both cases find the first compatible encoder and skip the CRTC
+ * if there is non such.
+ */
+ encoder = NULL; /* suppress GCC warning */
+ for (i = 0; i < resources->count_crtcs; i++) {
+ if (!resources->crtcs[i] || !(crtc_idx_mask & (1 << i)))
+ continue;
+
+ /* Now get a compatible encoder */
+ for (j = 0; j < connector->count_encoders; j++) {
+ encoder = drmModeGetEncoder(drm_fd,
+ connector->encoders[j]);
+
+ if (!encoder) {
+ igt_warn("could not get encoder %d: %s\n",
+ resources->encoders[j],
+ strerror(errno));
+
+ continue;
+ }
+
+ if (encoder->possible_crtcs & (1 << i))
+ goto found;
+
+ drmModeFreeEncoder(encoder);
+ }
+ }
+
+ goto err3;
+
+found:
+ if (!kmstest_get_connector_default_mode(drm_fd, connector,
+ &config->default_mode))
+ goto err4;
+
+ config->connector = connector;
+ config->encoder = encoder;
+ config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]);
+ config->crtc_idx = i;
+ config->pipe = kmstest_get_pipe_from_crtc_id(drm_fd,
+ config->crtc->crtc_id);
+
+ drmModeFreeResources(resources);
+
+ return true;
+err4:
+ drmModeFreeEncoder(encoder);
+err3:
+ drmModeFreeConnector(connector);
+err2:
+ drmModeFreeResources(resources);
+err1:
+ return false;
+}
+
+/**
+ * kmstest_free_connector_config:
+ * @config: connector configuration structure
+ *
+ * Free any resources in @config allocated in kmstest_get_connector_config().
+ */
+void kmstest_free_connector_config(struct kmstest_connector_config *config)
+{
+ drmModeFreeCrtc(config->crtc);
+ drmModeFreeEncoder(config->encoder);
+ drmModeFreeConnector(config->connector);
+}
+
+/**
+ * kmstest_set_connector_dpms:
+ * @fd: DRM fd
+ * @connector: libdrm connector
+ * @mode: DRM DPMS value
+ *
+ * This function sets the DPMS setting of @connector to @mode.
+ */
+void kmstest_set_connector_dpms(int fd, drmModeConnector *connector, int mode)
+{
+ int i, dpms = 0;
+ bool found_it = false;
+
+ for (i = 0; i < connector->count_props; i++) {
+ struct drm_mode_get_property prop;
+
+ prop.prop_id = connector->props[i];
+ prop.count_values = 0;
+ prop.count_enum_blobs = 0;
+ if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
+ continue;
+
+ if (strcmp(prop.name, "DPMS"))
+ continue;
+
+ dpms = prop.prop_id;
+ found_it = true;
+ break;
+ }
+ igt_assert_f(found_it, "DPMS property not found on %d\n",
+ connector->connector_id);
+
+ igt_assert(drmModeConnectorSetProperty(fd, connector->connector_id,
+ dpms, mode) == 0);
+}
+
+/**
+ * kmstest_get_property:
+ * @drm_fd: drm file descriptor
+ * @object_id: object whose properties we're going to get
+ * @object_type: type of obj_id (DRM_MODE_OBJECT_*)
+ * @name: name of the property we're going to get
+ * @prop_id: if not NULL, returns the property id
+ * @value: if not NULL, returns the property value
+ * @prop: if not NULL, returns the property, and the caller will have to free
+ * it manually.
+ *
+ * Finds a property with the given name on the given object.
+ *
+ * Returns: true in case we found something.
+ */
+bool
+kmstest_get_property(int drm_fd, uint32_t object_id, uint32_t object_type,
+ const char *name, uint32_t *prop_id /* out */,
+ uint64_t *value /* out */,
+ drmModePropertyPtr *prop /* out */)
+{
+ drmModeObjectPropertiesPtr proplist;
+ drmModePropertyPtr _prop;
+ bool found = false;
+ int i;
+
+ proplist = drmModeObjectGetProperties(drm_fd, object_id, object_type);
+ for (i = 0; i < proplist->count_props; i++) {
+ _prop = drmModeGetProperty(drm_fd, proplist->props[i]);
+ if (!_prop)
+ continue;
+
+ if (strcmp(_prop->name, name) == 0) {
+ found = true;
+ if (prop_id)
+ *prop_id = proplist->props[i];
+ if (value)
+ *value = proplist->prop_values[i];
+ if (prop)
+ *prop = _prop;
+ else
+ drmModeFreeProperty(_prop);
+
+ break;
+ }
+ drmModeFreeProperty(_prop);
+ }
+
+ drmModeFreeObjectProperties(proplist);
+ return found;
+}
+
+/**
+ * kmstest_edid_add_3d:
+ * @edid: an existing valid edid block
+ * @length: length of @edid
+ * @new_edid_ptr: pointer to where the new edid will be placed
+ * @new_length: pointer to the size of the new edid
+ *
+ * Makes a copy of an existing edid block and adds an extension indicating
+ * stereo 3D capabilities.
+ */
+void kmstest_edid_add_3d(const unsigned char *edid, size_t length,
+ unsigned char *new_edid_ptr[], size_t *new_length)
+{
+ unsigned char *new_edid;
+ int n_extensions;
+ char sum = 0;
+ int pos;
+ int i;
+ char cea_header_len = 4, video_block_len = 6, vsdb_block_len = 11;
+
+ igt_assert(new_edid_ptr != NULL && new_length != NULL);
+
+ *new_length = length + 128;
+
+ new_edid = calloc(*new_length, sizeof(char));
+ memcpy(new_edid, edid, length);
+ *new_edid_ptr = new_edid;
+
+ n_extensions = new_edid[126];
+ n_extensions++;
+ new_edid[126] = n_extensions;
+
+ /* recompute checksum */
+ for (i = 0; i < 127; i++) {
+ sum = sum + new_edid[i];
+ }
+ new_edid[127] = 256 - sum;
+
+ /* add a cea-861 extension block */
+ pos = length;
+ new_edid[pos++] = 0x2;
+ new_edid[pos++] = 0x3;
+ new_edid[pos++] = cea_header_len + video_block_len + vsdb_block_len;
+ new_edid[pos++] = 0x0;
+
+ /* video block (id | length) */
+ new_edid[pos++] = 2 << 5 | (video_block_len - 1);
+ new_edid[pos++] = 32 | 0x80; /* 1080p @ 24Hz | (native)*/
+ new_edid[pos++] = 5; /* 1080i @ 60Hz */
+ new_edid[pos++] = 20; /* 1080i @ 50Hz */
+ new_edid[pos++] = 4; /* 720p @ 60Hz*/
+ new_edid[pos++] = 19; /* 720p @ 50Hz*/
+
+ /* vsdb block ( id | length ) */
+ new_edid[pos++] = 3 << 5 | (vsdb_block_len - 1);
+ /* registration id */
+ new_edid[pos++] = 0x3;
+ new_edid[pos++] = 0xc;
+ new_edid[pos++] = 0x0;
+ /* source physical address */
+ new_edid[pos++] = 0x10;
+ new_edid[pos++] = 0x00;
+ /* Supports_AI ... etc */
+ new_edid[pos++] = 0x00;
+ /* Max TMDS Clock */
+ new_edid[pos++] = 0x00;
+ /* Latency present, HDMI Video Present */
+ new_edid[pos++] = 0x20;
+ /* HDMI Video */
+ new_edid[pos++] = 0x80;
+ new_edid[pos++] = 0x00;
+
+ /* checksum */
+ sum = 0;
+ for (i = 0; i < 127; i++) {
+ sum = sum + new_edid[length + i];
+ }
+ new_edid[length + 127] = 256 - sum;
+}
+
+/**
+ * kmstest_unset_all_crtcs:
+ * @drm_fd: the DRM fd
+ * @resources: libdrm resources pointer
+ *
+ * Disables all the screens.
+ */
+void kmstest_unset_all_crtcs(int drm_fd, drmModeResPtr resources)
+{
+ int i, rc;
+
+ for (i = 0; i < resources->count_crtcs; i++) {
+ rc = drmModeSetCrtc(drm_fd, resources->crtcs[i], -1, 0, 0, NULL,
+ 0, NULL);
+ igt_assert(rc == 0);
+ }
+}
+
+/*
+ * A small modeset API
+ */
+
+#define LOG_SPACES " "
+#define LOG_N_SPACES (sizeof(LOG_SPACES) - 1)
+
+#define LOG_INDENT(d, section) \
+ do { \
+ igt_display_log(d, "%s {\n", section); \
+ igt_display_log_shift(d, 1); \
+ } while (0)
+#define LOG_UNINDENT(d) \
+ do { \
+ igt_display_log_shift(d, -1); \
+ igt_display_log(d, "}\n"); \
+ } while (0)
+#define LOG(d, fmt, ...) igt_display_log(d, fmt, ## __VA_ARGS__)
+
+static void __attribute__((format(printf, 2, 3)))
+igt_display_log(igt_display_t *display, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ igt_debug("display: ");
+ for (i = 0; i < display->log_shift; i++)
+ igt_debug("%s", LOG_SPACES);
+ igt_vlog(IGT_LOG_DOMAIN, IGT_LOG_DEBUG, fmt, args);
+ va_end(args);
+}
+
+static void igt_display_log_shift(igt_display_t *display, int shift)
+{
+ display->log_shift += shift;
+ igt_assert(display->log_shift >= 0);
+}
+
+static void igt_output_refresh(igt_output_t *output)
+{
+ igt_display_t *display = output->display;
+ bool ret;
+ unsigned long crtc_idx_mask;
+
+ /* we mask out the pipes already in use */
+ crtc_idx_mask = output->pending_crtc_idx_mask & ~display->pipes_in_use;
+
+ if (output->valid)
+ kmstest_free_connector_config(&output->config);
+
+ ret = kmstest_get_connector_config(display->drm_fd,
+ output->id,
+ crtc_idx_mask,
+ &output->config);
+ if (ret)
+ output->valid = true;
+ else
+ output->valid = false;
+
+ if (!output->valid)
+ return;
+
+ if (!output->name) {
+ drmModeConnector *c = output->config.connector;
+
+ asprintf(&output->name, "%s-%d",
+ kmstest_connector_type_str(c->connector_type),
+ c->connector_type_id);
+ }
+
+ LOG(display, "%s: Selecting pipe %s\n", output->name,
+ kmstest_pipe_name(output->config.pipe));
+
+ display->pipes_in_use |= 1 << output->config.pipe;
+}
+
+static bool
+get_plane_property(int drm_fd, uint32_t plane_id, const char *name,
+ uint32_t *prop_id /* out */, uint64_t *value /* out */,
+ drmModePropertyPtr *prop /* out */)
+{
+ return kmstest_get_property(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE,
+ name, prop_id, value, prop);
+}
+
+static void
+igt_plane_set_property(igt_plane_t *plane, uint32_t prop_id, uint64_t value)
+{
+ igt_pipe_t *pipe = plane->pipe;
+ igt_display_t *display = pipe->display;
+
+ drmModeObjectSetProperty(display->drm_fd, plane->drm_plane->plane_id,
+ DRM_MODE_OBJECT_PLANE, prop_id, value);
+}
+
+/*
+ * Walk a plane's property list to determine its type. If we don't
+ * find a type property, then the kernel doesn't support universal
+ * planes and we know the plane is an overlay/sprite.
+ */
+static int get_drm_plane_type(int drm_fd, uint32_t plane_id)
+{
+ uint64_t value;
+ bool has_prop;
+
+ has_prop = get_plane_property(drm_fd, plane_id, "type",
+ NULL /* prop_id */, &value, NULL);
+ if (has_prop)
+ return (int)value;
+
+ return DRM_PLANE_TYPE_OVERLAY;
+}
+
+void igt_display_init(igt_display_t *display, int drm_fd)
+{
+ drmModeRes *resources;
+ drmModePlaneRes *plane_resources;
+ int i;
+
+ memset(display, 0, sizeof(igt_display_t));
+
+ LOG_INDENT(display, "init");
+
+ display->drm_fd = drm_fd;
+
+ resources = drmModeGetResources(display->drm_fd);
+ igt_assert(resources);
+
+ /*
+ * We cache the number of pipes, that number is a physical limit of the
+ * hardware and cannot change of time (for now, at least).
+ */
+ display->n_pipes = resources->count_crtcs;
+
+ drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ plane_resources = drmModeGetPlaneResources(display->drm_fd);
+ igt_assert(plane_resources);
+
+ for (i = 0; i < display->n_pipes; i++) {
+ igt_pipe_t *pipe = &display->pipes[i];
+ igt_plane_t *plane;
+ int p = IGT_PLANE_2;
+ int j, type;
+
+ pipe->display = display;
+ pipe->pipe = i;
+
+ /* add the planes that can be used with that pipe */
+ for (j = 0; j < plane_resources->count_planes; j++) {
+ drmModePlane *drm_plane;
+ uint64_t prop_value;
+
+ drm_plane = drmModeGetPlane(display->drm_fd,
+ plane_resources->planes[j]);
+ igt_assert(drm_plane);
+
+ if (!(drm_plane->possible_crtcs & (1 << i))) {
+ drmModeFreePlane(drm_plane);
+ continue;
+ }
+
+ type = get_drm_plane_type(display->drm_fd,
+ plane_resources->planes[j]);
+ switch (type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ plane = &pipe->planes[IGT_PLANE_PRIMARY];
+ plane->is_primary = 1;
+ plane->index = IGT_PLANE_PRIMARY;
+ display->has_universal_planes = 1;
+ break;
+ case DRM_PLANE_TYPE_CURSOR:
+ /*
+ * Cursor should be the highest index in our
+ * internal list, but we don't know what that
+ * is yet. Just stick it in the last slot
+ * for now and we'll move it later, if
+ * necessary.
+ */
+ plane = &pipe->planes[IGT_PLANE_CURSOR];
+ plane->is_cursor = 1;
+ plane->index = IGT_PLANE_CURSOR;
+ display->has_universal_planes = 1;
+ break;
+ default:
+ plane = &pipe->planes[p];
+ plane->index = p++;
+ break;
+ }
+
+ plane->pipe = pipe;
+ plane->drm_plane = drm_plane;
+
+ get_plane_property(display->drm_fd, drm_plane->plane_id,
+ "rotation",
+ &plane->rotation_property,
+ &prop_value,
+ NULL);
+ plane->rotation = (igt_rotation_t)prop_value;
+ }
+
+ if (display->has_universal_planes) {
+ /*
+ * If we have universal planes, we should have both
+ * primary and cursor planes setup now.
+ */
+ igt_assert(pipe->planes[IGT_PLANE_PRIMARY].drm_plane &&
+ pipe->planes[IGT_PLANE_CURSOR].drm_plane);
+
+ /*
+ * Cursor was put in the last slot. If we have 0 or
+ * only 1 sprite, that's the wrong slot and we need to
+ * move it down.
+ */
+ if (p != IGT_PLANE_CURSOR) {
+ pipe->planes[p] = pipe->planes[IGT_PLANE_CURSOR];
+ pipe->planes[p].index = p;
+ memset(&pipe->planes[IGT_PLANE_CURSOR], 0,
+ sizeof *plane);
+ }
+ } else {
+ /*
+ * No universal plane support. Add drm_plane-less
+ * primary and cursor planes.
+ */
+ plane = &pipe->planes[IGT_PLANE_PRIMARY];
+ plane->pipe = pipe;
+ plane->index = IGT_PLANE_PRIMARY;
+ plane->is_primary = true;
+
+ plane = &pipe->planes[p];
+ plane->pipe = pipe;
+ plane->index = p;
+ plane->is_cursor = true;
+ }
+
+ /* planes = 1 primary, (p-1) sprites, 1 cursor */
+ pipe->n_planes = p + 1;
+
+ /* make sure we don't overflow the plane array */
+ igt_assert(pipe->n_planes <= IGT_MAX_PLANES);
+ }
+
+ /*
+ * The number of connectors is set, so we just initialize the outputs
+ * array in _init(). This may change when we need dynamic connectors
+ * (say DisplayPort MST).
+ */
+ display->n_outputs = resources->count_connectors;
+ display->outputs = calloc(display->n_outputs, sizeof(igt_output_t));
+ igt_assert(display->outputs);
+
+ for (i = 0; i < display->n_outputs; i++) {
+ igt_output_t *output = &display->outputs[i];
+
+ /*
+ * We're free to select any pipe to drive that output until
+ * a constraint is set with igt_output_set_pipe().
+ */
+ output->pending_crtc_idx_mask = -1UL;
+ output->id = resources->connectors[i];
+ output->display = display;
+
+ igt_output_refresh(output);
+ }
+
+ drmModeFreePlaneResources(plane_resources);
+ drmModeFreeResources(resources);
+
+ LOG_UNINDENT(display);
+}
+
+int igt_display_get_n_pipes(igt_display_t *display)
+{
+ return display->n_pipes;
+}
+
+static void igt_pipe_fini(igt_pipe_t *pipe)
+{
+ int i;
+
+ for (i = 0; i < pipe->n_planes; i++) {
+ igt_plane_t *plane = &pipe->planes[i];
+
+ if (plane->drm_plane) {
+ drmModeFreePlane(plane->drm_plane);
+ plane->drm_plane = NULL;
+ }
+ }
+}
+
+static void igt_output_fini(igt_output_t *output)
+{
+ if (output->valid)
+ kmstest_free_connector_config(&output->config);
+ free(output->name);
+}
+
+void igt_display_fini(igt_display_t *display)
+{
+ int i;
+
+ for (i = 0; i < display->n_pipes; i++)
+ igt_pipe_fini(&display->pipes[i]);
+
+ for (i = 0; i < display->n_outputs; i++)
+ igt_output_fini(&display->outputs[i]);
+ free(display->outputs);
+ display->outputs = NULL;
+}
+
+static void igt_display_refresh(igt_display_t *display)
+{
+ int i, j;
+
+ display->pipes_in_use = 0;
+
+ /* Check that two outputs aren't trying to use the same pipe */
+ for (i = 0; i < display->n_outputs; i++) {
+ igt_output_t *a = &display->outputs[i];
+
+ if (a->pending_crtc_idx_mask == -1UL)
+ continue;
+
+ for (j = 0; j < display->n_outputs; j++) {
+ igt_output_t *b = &display->outputs[j];
+
+ if (i == j)
+ continue;
+
+ if (b->pending_crtc_idx_mask == -1UL)
+ continue;
+
+ igt_assert_f(a->pending_crtc_idx_mask !=
+ b->pending_crtc_idx_mask,
+ "%s and %s are both trying to use pipe %s\n",
+ igt_output_name(a), igt_output_name(b),
+ kmstest_pipe_name(ffs(a->pending_crtc_idx_mask) - 1));
+ }
+ }
+
+ /*
+ * The pipe allocation has to be done in two phases:
+ * - first, try to satisfy the outputs where a pipe has been specified
+ * - then, allocate the outputs with PIPE_ANY
+ */
+ for (i = 0; i < display->n_outputs; i++) {
+ igt_output_t *output = &display->outputs[i];
+
+ if (output->pending_crtc_idx_mask == -1UL)
+ continue;
+
+ igt_output_refresh(output);
+ }
+ for (i = 0; i < display->n_outputs; i++) {
+ igt_output_t *output = &display->outputs[i];
+
+ if (output->pending_crtc_idx_mask != -1UL)
+ continue;
+
+ igt_output_refresh(output);
+ }
+}
+
+static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
+{
+ igt_display_t *display = output->display;
+ enum pipe pipe;
+
+ if (output->pending_crtc_idx_mask == -1UL) {
+ /*
+ * The user hasn't specified a pipe to use, take the one
+ * configured by the last refresh()
+ */
+ pipe = output->config.pipe;
+ } else {
+ /*
+ * Otherwise, return the pending pipe (ie the pipe that should
+ * drive this output after the commit()
+ */
+ pipe = ffs(output->pending_crtc_idx_mask) - 1;
+ }
+
+ igt_assert(pipe >= 0 && pipe < display->n_pipes);
+
+ return &display->pipes[pipe];
+}
+
+static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, enum igt_plane plane)
+{
+ int idx;
+
+ /* Cursor plane is always the highest index */
+ if (plane == IGT_PLANE_CURSOR)
+ idx = pipe->n_planes - 1;
+ else {
+ igt_assert_f(plane >= 0 && plane < (pipe->n_planes),
+ "plane=%d\n", plane);
+ idx = plane;
+ }
+
+ return &pipe->planes[idx];
+}
+
+static uint32_t igt_plane_get_fb_id(igt_plane_t *plane)
+{
+ if (plane->fb)
+ return plane->fb->fb_id;
+ else
+ return 0;
+}
+
+static uint32_t igt_plane_get_fb_gem_handle(igt_plane_t *plane)
+{
+ if (plane->fb)
+ return plane->fb->gem_handle;
+ else
+ return 0;
+}
+
+#define CHECK_RETURN(r, fail) { \
+ if (r && !fail) \
+ return r; \
+ igt_assert(r == 0); \
+}
+
+/*
+ * Commit position and fb changes to a DRM plane via the SetPlane ioctl; if the
+ * DRM call to program the plane fails, we'll either fail immediately (for
+ * tests that expect the commit to succeed) or return the failure code (for
+ * tests that expect a specific error code).
+ */
+static int igt_drm_plane_commit(igt_plane_t *plane,
+ igt_output_t *output,
+ bool fail_on_error)
+{
+ igt_display_t *display = output->display;
+ uint32_t fb_id, crtc_id;
+ int ret;
+
+ igt_assert(plane->drm_plane);
+
+ /* it's an error to try an unsupported feature */
+ igt_assert(igt_plane_supports_rotation(plane) ||
+ !plane->rotation_changed);
+
+ fb_id = igt_plane_get_fb_id(plane);
+ crtc_id = output->config.crtc->crtc_id;
+
+ if (plane->fb_changed && fb_id == 0) {
+ LOG(display,
+ "%s: SetPlane pipe %s, plane %d, disabling\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe),
+ plane->index);
+
+ ret = drmModeSetPlane(display->drm_fd,
+ plane->drm_plane->plane_id,
+ crtc_id,
+ fb_id,
+ 0, /* flags */
+ 0, 0, /* crtc_x, crtc_y */
+ 0, 0, /* crtc_w, crtc_h */
+ IGT_FIXED(0,0), /* src_x */
+ IGT_FIXED(0,0), /* src_y */
+ IGT_FIXED(0,0), /* src_w */
+ IGT_FIXED(0,0) /* src_h */);
+
+ CHECK_RETURN(ret, fail_on_error);
+ } else if (plane->fb_changed || plane->position_changed) {
+ LOG(display,
+ "%s: SetPlane %s.%d, fb %u, position (%d, %d)\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe),
+ plane->index,
+ fb_id,
+ plane->crtc_x, plane->crtc_y);
+
+ ret = drmModeSetPlane(display->drm_fd,
+ plane->drm_plane->plane_id,
+ crtc_id,
+ fb_id,
+ 0, /* flags */
+ plane->crtc_x, plane->crtc_y,
+ plane->crtc_w, plane->crtc_h,
+ IGT_FIXED(0,0), /* src_x */
+ IGT_FIXED(0,0), /* src_y */
+ IGT_FIXED(plane->fb->width,0), /* src_w */
+ IGT_FIXED(plane->fb->height,0) /* src_h */);
+
+ CHECK_RETURN(ret, fail_on_error);
+ }
+
+ plane->fb_changed = false;
+ plane->position_changed = false;
+
+ if (plane->rotation_changed) {
+ igt_plane_set_property(plane, plane->rotation_property,
+ plane->rotation);
+
+ plane->rotation_changed = false;
+ }
+
+ return 0;
+}
+
+/*
+ * Commit position and fb changes to a cursor via legacy ioctl's. If commit
+ * fails, we'll either fail immediately (for tests that expect the commit to
+ * succeed) or return the failure code (for tests that expect a specific error
+ * code).
+ */
+static int igt_cursor_commit_legacy(igt_plane_t *cursor,
+ igt_output_t *output,
+ bool fail_on_error)
+{
+ igt_display_t *display = output->display;
+ uint32_t crtc_id = output->config.crtc->crtc_id;
+ int ret;
+
+ if (cursor->fb_changed) {
+ uint32_t gem_handle = igt_plane_get_fb_gem_handle(cursor);
+
+ if (gem_handle) {
+ LOG(display,
+ "%s: SetCursor pipe %s, fb %u %dx%d\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe),
+ gem_handle,
+ cursor->crtc_w, cursor->crtc_h);
+
+ ret = drmModeSetCursor(display->drm_fd, crtc_id,
+ gem_handle,
+ cursor->crtc_w,
+ cursor->crtc_h);
+ } else {
+ LOG(display,
+ "%s: SetCursor pipe %s, disabling\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe));
+
+ ret = drmModeSetCursor(display->drm_fd, crtc_id,
+ 0, 0, 0);
+ }
+
+ CHECK_RETURN(ret, fail_on_error);
+
+ cursor->fb_changed = false;
+ }
+
+ if (cursor->position_changed) {
+ int x = cursor->crtc_x;
+ int y = cursor->crtc_y;
+
+ LOG(display,
+ "%s: MoveCursor pipe %s, (%d, %d)\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe),
+ x, y);
+
+ ret = drmModeMoveCursor(display->drm_fd, crtc_id, x, y);
+ CHECK_RETURN(ret, fail_on_error);
+
+ cursor->position_changed = false;
+ }
+
+ return 0;
+}
+
+/*
+ * Commit position and fb changes to a primary plane via the legacy interface
+ * (setmode).
+ */
+static int igt_primary_plane_commit_legacy(igt_plane_t *primary,
+ igt_output_t *output,
+ bool fail_on_error)
+{
+ struct igt_display *display = primary->pipe->display;
+ drmModeModeInfo *mode;
+ uint32_t fb_id, crtc_id;
+ int ret;
+
+ /* Primary planes can't be windowed when using a legacy commit */
+ igt_assert((primary->crtc_x == 0 && primary->crtc_y == 0));
+
+ /* nor rotated */
+ igt_assert(!primary->rotation_changed);
+
+ if (!primary->fb_changed && !primary->position_changed &&
+ !primary->panning_changed)
+ return 0;
+
+ crtc_id = output->config.crtc->crtc_id;
+ fb_id = igt_plane_get_fb_id(primary);
+ if (fb_id)
+ mode = igt_output_get_mode(output);
+ else
+ mode = NULL;
+
+ if (fb_id) {
+ LOG(display,
+ "%s: SetCrtc pipe %s, fb %u, panning (%d, %d), "
+ "mode %dx%d\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe),
+ fb_id,
+ primary->pan_x, primary->pan_y,
+ mode->hdisplay, mode->vdisplay);
+
+ ret = drmModeSetCrtc(display->drm_fd,
+ crtc_id,
+ fb_id,
+ primary->pan_x, primary->pan_y,
+ &output->id,
+ 1,
+ mode);
+ } else {
+ LOG(display,
+ "%s: SetCrtc pipe %s, disabling\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe));
+
+ ret = drmModeSetCrtc(display->drm_fd,
+ crtc_id,
+ fb_id,
+ 0, 0, /* x, y */
+ NULL, /* connectors */
+ 0, /* n_connectors */
+ NULL /* mode */);
+ }
+
+ CHECK_RETURN(ret, fail_on_error);
+
+ primary->pipe->enabled = (fb_id != 0);
+ primary->fb_changed = false;
+ primary->position_changed = false;
+ primary->panning_changed = false;
+
+ return 0;
+}
+
+
+/*
+ * Commit position and fb changes to a plane. The value of @s will determine
+ * which API is used to do the programming.
+ */
+static int igt_plane_commit(igt_plane_t *plane,
+ igt_output_t *output,
+ enum igt_commit_style s,
+ bool fail_on_error)
+{
+ if (plane->is_cursor && s == COMMIT_LEGACY) {
+ return igt_cursor_commit_legacy(plane, output, fail_on_error);
+ } else if (plane->is_primary && s == COMMIT_LEGACY) {
+ return igt_primary_plane_commit_legacy(plane, output,
+ fail_on_error);
+ } else {
+ return igt_drm_plane_commit(plane, output, fail_on_error);
+ }
+}
+
+/*
+ * Commit all plane changes to an output. Note that if @s is COMMIT_LEGACY,
+ * enabling/disabling the primary plane will also enable/disable the CRTC.
+ *
+ * If @fail_on_error is true, any failure to commit plane state will lead
+ * to subtest failure in the specific function where the failure occurs.
+ * Otherwise, the first error code encountered will be returned and no
+ * further programming will take place, which may result in some changes
+ * taking effect and others not taking effect.
+ */
+static int igt_output_commit(igt_output_t *output,
+ enum igt_commit_style s,
+ bool fail_on_error)
+{
+ igt_display_t *display = output->display;
+ igt_pipe_t *pipe;
+ int i;
+ int ret;
+ bool need_wait_for_vblank = false;
+
+ pipe = igt_output_get_driving_pipe(output);
+
+ for (i = 0; i < pipe->n_planes; i++) {
+ igt_plane_t *plane = &pipe->planes[i];
+
+ if (plane->fb_changed || plane->position_changed)
+ need_wait_for_vblank = true;
+
+ ret = igt_plane_commit(plane, output, s, fail_on_error);
+ CHECK_RETURN(ret, fail_on_error);
+ }
+
+ /*
+ * If the crtc is enabled, wait until the next vblank before returning
+ * if we made changes to any of the planes.
+ */
+ if (need_wait_for_vblank && pipe->enabled) {
+ igt_wait_for_vblank(display->drm_fd, pipe->pipe);
+ }
+
+ return 0;
+}
+
+/*
+ * Commit all plane changes across all outputs of the display.
+ *
+ * If @fail_on_error is true, any failure to commit plane state will lead
+ * to subtest failure in the specific function where the failure occurs.
+ * Otherwise, the first error code encountered will be returned and no
+ * further programming will take place, which may result in some changes
+ * taking effect and others not taking effect.
+ */
+static int do_display_commit(igt_display_t *display,
+ enum igt_commit_style s,
+ bool fail_on_error)
+{
+ int i, ret;
+
+ LOG_INDENT(display, "commit");
+
+ igt_display_refresh(display);
+
+ for (i = 0; i < display->n_outputs; i++) {
+ igt_output_t *output = &display->outputs[i];
+
+ if (!output->valid)
+ continue;
+
+ ret = igt_output_commit(output, s, fail_on_error);
+ CHECK_RETURN(ret, fail_on_error);
+ }
+
+ LOG_UNINDENT(display);
+
+ igt_debug_wait_for_keypress("modeset");
+
+ return 0;
+}
+
+/**
+ * igt_display_commit2:
+ * @display: DRM device handle
+ * @s: Commit style
+ *
+ * Commits framebuffer and positioning changes to all planes of each display
+ * pipe, using a specific API to perform the programming. This function should
+ * be used to exercise a specific driver programming API; igt_display_commit
+ * should be used instead if the API used is unimportant to the test being run.
+ *
+ * This function should only be used to commit changes that are expected to
+ * succeed, since any failure during the commit process will cause the IGT
+ * subtest to fail. To commit changes that are expected to fail, use
+ * @igt_try_display_commit2 instead.
+ *
+ * Returns: 0 upon success. This function will never return upon failure
+ * since igt_fail() at lower levels will longjmp out of it.
+ */
+int igt_display_commit2(igt_display_t *display,
+ enum igt_commit_style s)
+{
+ do_display_commit(display, s, true);
+
+ return 0;
+}
+
+/**
+ * igt_display_try_commit2:
+ * @display: DRM device handle
+ * @s: Commit style
+ *
+ * Attempts to commit framebuffer and positioning changes to all planes of each
+ * display pipe. This function should be used to commit changes that are
+ * expected to fail, so that the error code can be checked for correctness.
+ * For changes that are expected to succeed, use @igt_display_commit instead.
+ *
+ * Note that in non-atomic commit styles, no display programming will be
+ * performed after the first failure is encountered, so only some of the
+ * operations requested by a test may have been completed. Tests that catch
+ * errors returned by this function should take care to restore the display to
+ * a sane state after a failure is detected.
+ *
+ * Returns: 0 upon success, otherwise the error code of the first error
+ * encountered.
+ */
+int igt_display_try_commit2(igt_display_t *display, enum igt_commit_style s)
+{
+ return do_display_commit(display, s, false);
+}
+
+/**
+ * igt_display_commit:
+ * @display: DRM device handle
+ *
+ * Commits framebuffer and positioning changes to all planes of each display
+ * pipe.
+ *
+ * Returns: 0 upon success. This function will never return upon failure
+ * since igt_fail() at lower levels will longjmp out of it.
+ */
+int igt_display_commit(igt_display_t *display)
+{
+ return igt_display_commit2(display, COMMIT_LEGACY);
+}
+
+const char *igt_output_name(igt_output_t *output)
+{
+ return output->name;
+}
+
+drmModeModeInfo *igt_output_get_mode(igt_output_t *output)
+{
+ return &output->config.default_mode;
+}
+
+void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
+{
+ igt_display_t *display = output->display;
+
+ if (pipe == PIPE_ANY) {
+ LOG(display, "%s: set_pipe(any)\n", igt_output_name(output));
+ output->pending_crtc_idx_mask = -1UL;
+ } else {
+ LOG(display, "%s: set_pipe(%s)\n", igt_output_name(output),
+ kmstest_pipe_name(pipe));
+ output->pending_crtc_idx_mask = 1 << pipe;
+ }
+}
+
+igt_plane_t *igt_output_get_plane(igt_output_t *output, enum igt_plane plane)
+{
+ igt_pipe_t *pipe;
+
+ pipe = igt_output_get_driving_pipe(output);
+ return igt_pipe_get_plane(pipe, plane);
+}
+
+void igt_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb)
+{
+ igt_pipe_t *pipe = plane->pipe;
+ igt_display_t *display = pipe->display;
+
+ LOG(display, "%s.%d: plane_set_fb(%d)\n", kmstest_pipe_name(pipe->pipe),
+ plane->index, fb ? fb->fb_id : 0);
+
+ plane->fb = fb;
+ /* hack to keep tests working that don't call igt_plane_set_size() */
+ if (fb) {
+ plane->crtc_w = fb->width;
+ plane->crtc_h = fb->height;
+ } else {
+ plane->crtc_w = 0;
+ plane->crtc_h = 0;
+ }
+
+ plane->fb_changed = true;
+}
+
+void igt_plane_set_position(igt_plane_t *plane, int x, int y)
+{
+ igt_pipe_t *pipe = plane->pipe;
+ igt_display_t *display = pipe->display;
+
+ LOG(display, "%s.%d: plane_set_position(%d,%d)\n",
+ kmstest_pipe_name(pipe->pipe), plane->index, x, y);
+
+ plane->crtc_x = x;
+ plane->crtc_y = y;
+
+ plane->position_changed = true;
+}
+
+void igt_plane_set_size(igt_plane_t *plane, int w, int h)
+{
+ igt_pipe_t *pipe = plane->pipe;
+ igt_display_t *display = pipe->display;
+
+ LOG(display, "%s.%d: plane_set_size(%d,%d)\n",
+ kmstest_pipe_name(pipe->pipe), plane->index, w, h);
+
+ plane->crtc_w = w;
+ plane->crtc_h = h;
+
+ /*
+ * must be fb_changed so that legacy cursors call
+ * drmModeSetCursor() instead of drmModeMoveCursor()
+ */
+ plane->fb_changed = true;
+}
+
+void igt_plane_set_panning(igt_plane_t *plane, int x, int y)
+{
+ igt_pipe_t *pipe = plane->pipe;
+ igt_display_t *display = pipe->display;
+
+ LOG(display, "%s.%d: plane_set_panning(%d,%d)\n",
+ kmstest_pipe_name(pipe->pipe),
+ plane->index, x, y);
+
+ plane->pan_x = x;
+ plane->pan_y = y;
+
+ plane->panning_changed = true;
+}
+
+static const char *rotation_name(igt_rotation_t rotation)
+{
+ switch (rotation) {
+ case IGT_ROTATION_0:
+ return "0°";
+ case IGT_ROTATION_90:
+ return "90°";
+ case IGT_ROTATION_180:
+ return "180°";
+ case IGT_ROTATION_270:
+ return "270°";
+ default:
+ igt_assert(0);
+ }
+}
+
+void igt_plane_set_rotation(igt_plane_t *plane, igt_rotation_t rotation)
+{
+ igt_pipe_t *pipe = plane->pipe;
+ igt_display_t *display = pipe->display;
+
+ LOG(display, "%s.%d: plane_set_rotation(%s)\n",
+ kmstest_pipe_name(pipe->pipe),
+ plane->index, rotation_name(rotation));
+
+ plane->rotation = rotation;
+
+ plane->rotation_changed = true;
+}
+
+void igt_wait_for_vblank(int drm_fd, enum pipe pipe)
+{
+ drmVBlank wait_vbl;
+
+ memset(&wait_vbl, 0, sizeof(wait_vbl));
+
+ wait_vbl.request.type = pipe << DRM_VBLANK_HIGH_CRTC_SHIFT |
+ DRM_VBLANK_RELATIVE;
+ wait_vbl.request.sequence = 1;
+
+ igt_assert(drmWaitVBlank(drm_fd, &wait_vbl) == 0);
+}
+
+/**
+ * igt_enable_connectors:
+ *
+ * Force connectors to be enabled where this is known to work well. Use
+ * #igt_reset_connectors to revert the changes.
+ *
+ * An exit handler is installed to ensure connectors are reset when the test
+ * exits.
+ */
+void igt_enable_connectors(void)
+{
+ drmModeRes *res;
+ drmModeConnector *c;
+ int drm_fd;
+
+ drm_fd = drm_open_any();
+
+ res = drmModeGetResources(drm_fd);
+
+ for (int i = 0; i < res->count_connectors; i++) {
+
+ c = drmModeGetConnector(drm_fd, res->connectors[i]);
+
+ /* don't attempt to force connectors that are already connected
+ */
+ if (c->connection == DRM_MODE_CONNECTED)
+ continue;
+
+ /* just enable VGA for now */
+ if (c->connector_type == DRM_MODE_CONNECTOR_VGA) {
+ if (!kmstest_force_connector(drm_fd, c, FORCE_CONNECTOR_ON))
+ igt_info("Unable to force state on %s-%d\n",
+ kmstest_connector_type_str(c->connector_type),
+ c->connector_type_id);
+ }
+
+ drmModeFreeConnector(c);
+ }
+ close(drm_fd);
+}
+
+/**
+ * igt_reset_connectors:
+ *
+ * Remove any forced state from the connectors.
+ */
+void igt_reset_connectors(void)
+{
+ char **tmp;
+
+ /* reset the connectors stored in forced_connectors, avoiding any
+ * functions that are not safe to call in signal handlers */
+
+ for (tmp = forced_connectors; *tmp; tmp++) {
+ int fd = igt_debugfs_open(*tmp, O_WRONLY | O_TRUNC);
+ igt_assert(write(fd, "unspecified", 11) == 11);
+ close(fd);
+ }
+}
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
new file mode 100644
index 0000000..a1483a4
--- /dev/null
+++ b/lib/igt_kms.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright © 2013 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ * Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifndef __IGT_KMS_H__
+#define __IGT_KMS_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include <xf86drmMode.h>
+
+#include "igt_fb.h"
+
+/* Low-level helpers with kmstest_ prefix */
+
+enum pipe {
+ PIPE_A = 0,
+ PIPE_B,
+ PIPE_C,
+ I915_MAX_PIPES
+};
+const char *kmstest_pipe_name(enum pipe pipe);
+
+/* We namespace this enum to not conflict with the Android i915_drm.h */
+enum igt_plane {
+ IGT_PLANE_1 = 0,
+ IGT_PLANE_PRIMARY = IGT_PLANE_1,
+ IGT_PLANE_2,
+ IGT_PLANE_3,
+ IGT_PLANE_CURSOR,
+};
+
+const char *kmstest_plane_name(enum igt_plane plane);
+
+enum port {
+ PORT_A = 0,
+ PORT_B,
+ PORT_C,
+ PORT_D,
+ PORT_E,
+ I915_MAX_PORTS
+};
+
+/**
+ * kmstest_port_name:
+ * @port: display plane
+ *
+ * Returns: String representing @port, e.g. "A".
+ */
+#define kmstest_port_name(port) ((port) + 'A')
+
+/**
+ * kmstest_encoder_type_str:
+ * @type: DRM_MODE_ENCODER_* enumeration value
+ *
+ * Returns: A string representing the drm encoder @type.
+ */
+const char *kmstest_encoder_type_str(int type);
+
+/**
+ * kmstest_connector_status_str:
+ * @status: DRM_MODE_* connector status value
+ *
+ * Returns: A string representing the drm connector status @status.
+ */
+const char *kmstest_connector_status_str(int status);
+
+/**
+ * kmstest_connector_type_str:
+ * @type: DRM_MODE_CONNECTOR_* enumeration value
+ *
+ * Returns: A string representing the drm connector @type.
+ */
+const char *kmstest_connector_type_str(int type);
+
+void kmstest_dump_mode(drmModeModeInfo *mode);
+
+int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id);
+void kmstest_set_vt_graphics_mode(void);
+void kmstest_restore_vt_mode(void);
+
+struct kmstest_connector_config {
+ drmModeCrtc *crtc;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ drmModeModeInfo default_mode;
+ int crtc_idx;
+ int pipe;
+};
+
+/**
+ * kmstest_force_connector_state:
+ * @FORCE_CONNECTOR_UNSPECIFIED: Unspecified
+ * @FORCE_CONNECTOR_ON: On
+ * @FORCE_CONNECTOR_DIGITAL: Digital
+ * @FORCE_CONNECTOR_OFF: Off
+ */
+enum kmstest_force_connector_state {
+ FORCE_CONNECTOR_UNSPECIFIED,
+ FORCE_CONNECTOR_ON,
+ FORCE_CONNECTOR_DIGITAL,
+ FORCE_CONNECTOR_OFF
+};
+
+bool kmstest_force_connector(int fd, drmModeConnector *connector,
+ enum kmstest_force_connector_state state);
+void kmstest_edid_add_3d(const unsigned char *edid, size_t length, unsigned char *new_edid_ptr[], size_t *new_length);
+void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
+ const unsigned char *edid, size_t length);
+
+bool kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
+ drmModeModeInfo *mode);
+bool kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
+ unsigned long crtc_idx_mask,
+ struct kmstest_connector_config *config);
+void kmstest_free_connector_config(struct kmstest_connector_config *config);
+
+void kmstest_set_connector_dpms(int fd, drmModeConnector *connector, int mode);
+bool kmstest_get_property(int drm_fd, uint32_t object_id, uint32_t object_type,
+ const char *name, uint32_t *prop_id, uint64_t *value,
+ drmModePropertyPtr *prop);
+void kmstest_unset_all_crtcs(int drm_fd, drmModeResPtr resources);
+
+/*
+ * A small modeset API
+ */
+
+/* High-level kms api with igt_ prefix */
+enum igt_commit_style {
+ COMMIT_LEGACY = 0,
+ COMMIT_UNIVERSAL,
+ /* We'll add atomic here eventually. */
+};
+
+typedef struct igt_display igt_display_t;
+typedef struct igt_pipe igt_pipe_t;
+typedef uint32_t igt_fixed_t; /* 16.16 fixed point */
+
+typedef enum {
+ /* this maps to the kernel API */
+ IGT_ROTATION_0 = 1 << 0,
+ IGT_ROTATION_90 = 1 << 1,
+ IGT_ROTATION_180 = 1 << 2,
+ IGT_ROTATION_270 = 1 << 3,
+} igt_rotation_t;
+
+typedef struct {
+ /*< private >*/
+ igt_pipe_t *pipe;
+ int index;
+ /* capabilities */
+ unsigned int is_primary : 1;
+ unsigned int is_cursor : 1;
+ /* state tracking */
+ unsigned int fb_changed : 1;
+ unsigned int position_changed : 1;
+ unsigned int panning_changed : 1;
+ unsigned int rotation_changed : 1;
+ /*
+ * drm_plane can be NULL for primary and cursor planes (when not
+ * using the atomic modeset API)
+ */
+ drmModePlane *drm_plane;
+ struct igt_fb *fb;
+
+ uint32_t rotation_property;
+
+ /* position within pipe_src_w x pipe_src_h */
+ int crtc_x, crtc_y;
+ /* size within pipe_src_w x pipe_src_h */
+ int crtc_w, crtc_h;
+ /* panning offset within the fb */
+ unsigned int pan_x, pan_y;
+ igt_rotation_t rotation;
+} igt_plane_t;
+
+struct igt_pipe {
+ igt_display_t *display;
+ enum pipe pipe;
+ bool enabled;
+#define IGT_MAX_PLANES 4
+ int n_planes;
+ igt_plane_t planes[IGT_MAX_PLANES];
+};
+
+typedef struct {
+ /*< private >*/
+ igt_display_t *display;
+ uint32_t id; /* KMS id */
+ struct kmstest_connector_config config;
+ char *name;
+ bool valid;
+ unsigned long pending_crtc_idx_mask;
+} igt_output_t;
+
+struct igt_display {
+ int drm_fd;
+ int log_shift;
+ int n_pipes;
+ int n_outputs;
+ unsigned long pipes_in_use;
+ igt_output_t *outputs;
+ igt_pipe_t pipes[I915_MAX_PIPES];
+ bool has_universal_planes;
+};
+
+void igt_display_init(igt_display_t *display, int drm_fd);
+void igt_display_fini(igt_display_t *display);
+int igt_display_commit2(igt_display_t *display, enum igt_commit_style s);
+int igt_display_commit(igt_display_t *display);
+int igt_display_try_commit2(igt_display_t *display, enum igt_commit_style s);
+int igt_display_get_n_pipes(igt_display_t *display);
+
+const char *igt_output_name(igt_output_t *output);
+drmModeModeInfo *igt_output_get_mode(igt_output_t *output);
+void igt_output_set_pipe(igt_output_t *output, enum pipe pipe);
+igt_plane_t *igt_output_get_plane(igt_output_t *output, enum igt_plane plane);
+
+static inline bool igt_plane_supports_rotation(igt_plane_t *plane)
+{
+ return plane->rotation_property != 0;
+}
+
+void igt_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb);
+void igt_plane_set_position(igt_plane_t *plane, int x, int y);
+void igt_plane_set_size(igt_plane_t *plane, int w, int h);
+void igt_plane_set_panning(igt_plane_t *plane, int x, int y);
+void igt_plane_set_rotation(igt_plane_t *plane, igt_rotation_t rotation);
+
+void igt_wait_for_vblank(int drm_fd, enum pipe pipe);
+
+#define for_each_connected_output(display, output) \
+ for (int i__ = 0; i__ < (display)->n_outputs; i__++) \
+ if ((output = &(display)->outputs[i__]), output->valid)
+
+#define for_each_pipe(display, pipe) \
+ for (pipe = 0; pipe < igt_display_get_n_pipes(display); pipe++) \
+
+/*
+ * Can be used with igt_output_set_pipe() to mean we don't care about the pipe
+ * that should drive this output
+ */
+#define PIPE_ANY (-1)
+
+#define IGT_FIXED(i,f) ((i) << 16 | (f))
+
+void igt_enable_connectors(void);
+void igt_reset_connectors(void);
+
+#define EDID_LENGTH 128
+const unsigned char* igt_kms_get_base_edid(void);
+
+
+#endif /* __IGT_KMS_H__ */
+
diff --git a/lib/intel_batchbuffer.c b/lib/intel_batchbuffer.c
new file mode 100644
index 0000000..c70f6d8
--- /dev/null
+++ b/lib/intel_batchbuffer.c
@@ -0,0 +1,532 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "drm.h"
+#include "drmtest.h"
+#include "intel_batchbuffer.h"
+#include "intel_bufmgr.h"
+#include "intel_chipset.h"
+#include "intel_reg.h"
+#include "rendercopy.h"
+#include "media_fill.h"
+#include <i915_drm.h>
+
+/**
+ * SECTION:intel_batchbuffer
+ * @short_description: Batchbuffer and blitter support
+ * @title: intel batchbuffer
+ * @include: intel_batchbuffer.h
+ *
+ * This library provides some basic support for batchbuffers and using the
+ * blitter engine based upon libdrm. A new batchbuffer is allocated with
+ * intel_batchbuffer_alloc() and for simple blitter commands submitted with
+ * intel_batchbuffer_flush().
+ *
+ * It also provides some convenient macros to easily emit commands into
+ * batchbuffers. All those macros presume that a pointer to a #intel_batchbuffer
+ * structure called batch is in scope. The basic macros are #BEGIN_BATCH,
+ * #OUT_BATCH, #OUT_RELOC and #ADVANCE_BATCH.
+ *
+ * Note that this library's header pulls in the [i-g-t core](intel-gpu-tools-i-g-t-core.html)
+ * library as a dependency.
+ */
+
+/**
+ * intel_batchbuffer_reset:
+ * @batch: batchbuffer object
+ *
+ * Resets @batch by allocating a new gem buffer object as backing storage.
+ */
+void
+intel_batchbuffer_reset(struct intel_batchbuffer *batch)
+{
+ if (batch->bo != NULL) {
+ drm_intel_bo_unreference(batch->bo);
+ batch->bo = NULL;
+ }
+
+ batch->bo = drm_intel_bo_alloc(batch->bufmgr, "batchbuffer",
+ BATCH_SZ, 4096);
+
+ memset(batch->buffer, 0, sizeof(batch->buffer));
+ batch->ctx = NULL;
+
+ batch->ptr = batch->buffer;
+ batch->end = NULL;
+}
+
+/**
+ * intel_batchbuffer_alloc:
+ * @bufmgr: libdrm buffer manager
+ * @devid: pci device id of the drm device
+ *
+ * Allocates a new batchbuffer object. @devid must be supplied since libdrm
+ * doesn't expose it directly.
+ *
+ * Returns: The allocated and initialized batchbuffer object.
+ */
+struct intel_batchbuffer *
+intel_batchbuffer_alloc(drm_intel_bufmgr *bufmgr, uint32_t devid)
+{
+ struct intel_batchbuffer *batch = calloc(sizeof(*batch), 1);
+
+ batch->bufmgr = bufmgr;
+ batch->devid = devid;
+ batch->gen = intel_gen(devid);
+ intel_batchbuffer_reset(batch);
+
+ return batch;
+}
+
+/**
+ * intel_batchbuffer_free:
+ * @batch: batchbuffer object
+ *
+ * Releases all resource of the batchbuffer object @batch.
+ */
+void
+intel_batchbuffer_free(struct intel_batchbuffer *batch)
+{
+ drm_intel_bo_unreference(batch->bo);
+ batch->bo = NULL;
+ free(batch);
+}
+
+#define CMD_POLY_STIPPLE_OFFSET 0x7906
+
+static unsigned int
+flush_on_ring_common(struct intel_batchbuffer *batch, int ring)
+{
+ unsigned int used = batch->ptr - batch->buffer;
+
+ if (used == 0)
+ return 0;
+
+ if (IS_GEN5(batch->devid)) {
+ /* emit gen5 w/a without batch space checks - we reserve that
+ * already. */
+ *(uint32_t *) (batch->ptr) = CMD_POLY_STIPPLE_OFFSET << 16;
+ batch->ptr += 4;
+ *(uint32_t *) (batch->ptr) = 0;
+ batch->ptr += 4;
+ }
+
+ /* Round batchbuffer usage to 2 DWORDs. */
+ if ((used & 4) == 0) {
+ *(uint32_t *) (batch->ptr) = 0; /* noop */
+ batch->ptr += 4;
+ }
+
+ /* Mark the end of the buffer. */
+ *(uint32_t *)(batch->ptr) = MI_BATCH_BUFFER_END; /* noop */
+ batch->ptr += 4;
+ return batch->ptr - batch->buffer;
+}
+
+/**
+ * intel_batchbuffer_flush_on_ring:
+ * @batch: batchbuffer object
+ * @ring: execbuf ring flag
+ *
+ * Submits the batch for execution on @ring.
+ */
+void
+intel_batchbuffer_flush_on_ring(struct intel_batchbuffer *batch, int ring)
+{
+ unsigned int used = flush_on_ring_common(batch, ring);
+ drm_intel_context *ctx;
+
+ if (used == 0)
+ return;
+
+ do_or_die(drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer));
+
+ batch->ptr = NULL;
+
+ /* XXX bad kernel API */
+ ctx = batch->ctx;
+ if (ring != I915_EXEC_RENDER)
+ ctx = NULL;
+ do_or_die(drm_intel_gem_bo_context_exec(batch->bo, ctx, used, ring));
+
+ intel_batchbuffer_reset(batch);
+}
+
+void
+intel_batchbuffer_set_context(struct intel_batchbuffer *batch,
+ drm_intel_context *context)
+{
+ batch->ctx = context;
+}
+
+/**
+ * intel_batchbuffer_flush_with_context:
+ * @batch: batchbuffer object
+ * @context: libdrm hardware context object
+ *
+ * Submits the batch for execution on the render engine with the supplied
+ * hardware context.
+ */
+void
+intel_batchbuffer_flush_with_context(struct intel_batchbuffer *batch,
+ drm_intel_context *context)
+{
+ int ret;
+ unsigned int used = flush_on_ring_common(batch, I915_EXEC_RENDER);
+
+ if (used == 0)
+ return;
+
+ ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer);
+ igt_assert(ret == 0);
+
+ batch->ptr = NULL;
+
+ ret = drm_intel_gem_bo_context_exec(batch->bo, context, used,
+ I915_EXEC_RENDER);
+ igt_assert(ret == 0);
+
+ intel_batchbuffer_reset(batch);
+}
+
+/**
+ * intel_batchbuffer_flush:
+ * @batch: batchbuffer object
+ *
+ * Submits the batch for execution on the blitter engine, selecting the right
+ * ring depending upon the hardware platform.
+ */
+void
+intel_batchbuffer_flush(struct intel_batchbuffer *batch)
+{
+ int ring = 0;
+ if (HAS_BLT_RING(batch->devid))
+ ring = I915_EXEC_BLT;
+ intel_batchbuffer_flush_on_ring(batch, ring);
+}
+
+
+/**
+ * intel_batchbuffer_emit_reloc:
+ * @batch: batchbuffer object
+ * @buffer: relocation target libdrm buffer object
+ * @delta: delta value to add to @buffer's gpu address
+ * @read_domains: gem domain bits for the relocation
+ * @write_domain: gem domain bit for the relocation
+ * @fenced: whether this gpu access requires fences
+ *
+ * Emits both a libdrm relocation entry pointing at @buffer and the pre-computed
+ * DWORD of @batch's presumed gpu address plus the supplied @delta into @batch.
+ *
+ * Note that @fenced is only relevant if @buffer is actually tiled.
+ *
+ * This is the only way buffers get added to the validate list.
+ */
+void
+intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch,
+ drm_intel_bo *buffer, uint64_t delta,
+ uint32_t read_domains, uint32_t write_domain,
+ int fenced)
+{
+ uint64_t offset;
+ int ret;
+
+ if (batch->ptr - batch->buffer > BATCH_SZ)
+ igt_info("bad relocation ptr %p map %p offset %d size %d\n",
+ batch->ptr, batch->buffer,
+ (int)(batch->ptr - batch->buffer), BATCH_SZ);
+
+ if (fenced)
+ ret = drm_intel_bo_emit_reloc_fence(batch->bo, batch->ptr - batch->buffer,
+ buffer, delta,
+ read_domains, write_domain);
+ else
+ ret = drm_intel_bo_emit_reloc(batch->bo, batch->ptr - batch->buffer,
+ buffer, delta,
+ read_domains, write_domain);
+
+ offset = buffer->offset64;
+ offset += delta;
+ intel_batchbuffer_emit_dword(batch, offset);
+ if (batch->gen >= 8)
+ intel_batchbuffer_emit_dword(batch, offset >> 32);
+ igt_assert(ret == 0);
+}
+
+/**
+ * intel_batchbuffer_data:
+ * @batch: batchbuffer object
+ * @data: pointer to the data to write into the batchbuffer
+ * @bytes: number of bytes to write into the batchbuffer
+ *
+ * This transfers the given @data into the batchbuffer. Note that the length
+ * must be DWORD aligned, i.e. multiples of 32bits.
+ */
+void
+intel_batchbuffer_data(struct intel_batchbuffer *batch,
+ const void *data, unsigned int bytes)
+{
+ igt_assert((bytes & 3) == 0);
+ intel_batchbuffer_require_space(batch, bytes);
+ memcpy(batch->ptr, data, bytes);
+ batch->ptr += bytes;
+}
+
+/**
+ * intel_blt_copy:
+ * @batch: batchbuffer object
+ * @src_bo: source libdrm buffer object
+ * @src_x1: source pixel x-coordination
+ * @src_y1: source pixel y-coordination
+ * @src_pitch: @src_bo's pitch in bytes
+ * @dst_bo: destination libdrm buffer object
+ * @dst_x1: destination pixel x-coordination
+ * @dst_y1: destination pixel y-coordination
+ * @dst_pitch: @dst_bo's pitch in bytes
+ * @width: width of the copied rectangle
+ * @height: height of the copied rectangle
+ * @bpp: bits per pixel
+ *
+ * This emits a 2D copy operation using blitter commands into the supplied batch
+ * buffer object.
+ */
+void
+intel_blt_copy(struct intel_batchbuffer *batch,
+ drm_intel_bo *src_bo, int src_x1, int src_y1, int src_pitch,
+ drm_intel_bo *dst_bo, int dst_x1, int dst_y1, int dst_pitch,
+ int width, int height, int bpp)
+{
+ const int gen = batch->gen;
+ uint32_t src_tiling, dst_tiling, swizzle;
+ uint32_t cmd_bits = 0;
+ uint32_t br13_bits;
+
+#define CHECK_RANGE(x) ((x) >= 0 && (x) < (1 << 15))
+ igt_assert(CHECK_RANGE(src_x1) && CHECK_RANGE(src_y1) &&
+ CHECK_RANGE(dst_x1) && CHECK_RANGE(dst_y1) &&
+ CHECK_RANGE(width) && CHECK_RANGE(height) &&
+ CHECK_RANGE(src_x1 + width) && CHECK_RANGE(src_y1 + height)
+ && CHECK_RANGE(dst_x1 + width) && CHECK_RANGE(dst_y1 +
+ height) &&
+ CHECK_RANGE(src_pitch) && CHECK_RANGE(dst_pitch));
+#undef CHECK_RANGE
+ igt_assert(bpp*(src_x1 + width) <= 8*src_pitch);
+ igt_assert(bpp*(dst_x1 + width) <= 8*dst_pitch);
+ igt_assert(src_pitch * (src_y1 + height) <= src_bo->size);
+ igt_assert(dst_pitch * (dst_y1 + height) <= dst_bo->size);
+
+ drm_intel_bo_get_tiling(src_bo, &src_tiling, &swizzle);
+ drm_intel_bo_get_tiling(dst_bo, &dst_tiling, &swizzle);
+
+ if (gen >= 4 && src_tiling != I915_TILING_NONE) {
+ src_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED;
+ }
+
+ if (gen >= 4 && dst_tiling != I915_TILING_NONE) {
+ dst_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_DST_TILED;
+ }
+
+ br13_bits = 0;
+ switch (bpp) {
+ case 8:
+ break;
+ case 16: /* supporting only RGB565, not ARGB1555 */
+ br13_bits |= 1 << 24;
+ break;
+ case 32:
+ br13_bits |= 3 << 24;
+ cmd_bits |= XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB;
+ break;
+ default:
+ igt_fail(1);
+ }
+
+ BLIT_COPY_BATCH_START(cmd_bits);
+ OUT_BATCH((br13_bits) |
+ (0xcc << 16) | /* copy ROP */
+ dst_pitch);
+ OUT_BATCH((dst_y1 << 16) | dst_x1); /* dst x1,y1 */
+ OUT_BATCH(((dst_y1 + height) << 16) | (dst_x1 + width)); /* dst x2,y2 */
+ OUT_RELOC_FENCED(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH((src_y1 << 16) | src_x1); /* src x1,y1 */
+ OUT_BATCH(src_pitch);
+ OUT_RELOC_FENCED(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+#define CMD_POLY_STIPPLE_OFFSET 0x7906
+ if (gen == 5) {
+ BEGIN_BATCH(2, 0);
+ OUT_BATCH(CMD_POLY_STIPPLE_OFFSET << 16);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+
+ if (gen >= 6 && src_bo == dst_bo) {
+ BEGIN_BATCH(3, 0);
+ OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+
+ intel_batchbuffer_flush(batch);
+}
+
+/**
+ * intel_copy_bo:
+ * @batch: batchbuffer object
+ * @src_bo: source libdrm buffer object
+ * @dst_bo: destination libdrm buffer object
+ * @size: size of the copy range in bytes
+ *
+ * This emits a copy operation using blitter commands into the supplied batch
+ * buffer object. A total of @size bytes from the start of @src_bo is copied
+ * over to @dst_bo. Note that @size must be page-aligned.
+ */
+void
+intel_copy_bo(struct intel_batchbuffer *batch,
+ drm_intel_bo *dst_bo, drm_intel_bo *src_bo,
+ long int size)
+{
+ igt_assert(size % 4096 == 0);
+
+ intel_blt_copy(batch,
+ src_bo, 0, 0, 4096,
+ dst_bo, 0, 0, 4096,
+ 4096/4, size/4096, 32);
+}
+
+/**
+ * igt_buf_width:
+ * @buf: the i-g-t buffer object
+ *
+ * Computes the widht in 32-bit pixels of the given buffer.
+ *
+ * Returns:
+ * The width of the buffer.
+ */
+unsigned igt_buf_width(struct igt_buf *buf)
+{
+ return buf->stride/sizeof(uint32_t);
+}
+
+/**
+ * igt_buf_height:
+ * @buf: the i-g-t buffer object
+ *
+ * Computes the height in 32-bit pixels of the given buffer.
+ *
+ * Returns:
+ * The height of the buffer.
+ */
+unsigned igt_buf_height(struct igt_buf *buf)
+{
+ return buf->size/buf->stride;
+}
+
+/**
+ * igt_get_render_copyfunc:
+ * @devid: pci device id
+ *
+ * Returns:
+ *
+ * The platform-specific render copy function pointer for the device
+ * specified with @devid. Will return NULL when no render copy function is
+ * implemented.
+ */
+igt_render_copyfunc_t igt_get_render_copyfunc(int devid)
+{
+ igt_render_copyfunc_t copy = NULL;
+
+ if (IS_GEN2(devid))
+ copy = gen2_render_copyfunc;
+ else if (IS_GEN3(devid))
+ copy = gen3_render_copyfunc;
+ else if (IS_GEN6(devid))
+ copy = gen6_render_copyfunc;
+ else if (IS_GEN7(devid))
+ copy = gen7_render_copyfunc;
+ else if (IS_GEN8(devid))
+ copy = gen8_render_copyfunc;
+ else if (IS_GEN9(devid))
+ copy = gen9_render_copyfunc;
+
+ return copy;
+}
+
+/**
+ * igt_get_media_fillfunc:
+ * @devid: pci device id
+ *
+ * Returns:
+ *
+ * The platform-specific media fill function pointer for the device specified
+ * with @devid. Will return NULL when no media fill function is implemented.
+ */
+igt_fillfunc_t igt_get_media_fillfunc(int devid)
+{
+ igt_fillfunc_t fill = NULL;
+
+ if (IS_GEN9(devid))
+ fill = gen9_media_fillfunc;
+ else if (IS_BROADWELL(devid))
+ fill = gen8_media_fillfunc;
+ else if (IS_GEN7(devid))
+ fill = gen7_media_fillfunc;
+ else if (IS_CHERRYVIEW(devid))
+ fill = gen8lp_media_fillfunc;
+
+ return fill;
+}
+
+/**
+ * igt_get_gpgpu_fillfunc:
+ * @devid: pci device id
+ *
+ * Returns:
+ *
+ * The platform-specific gpgpu fill function pointer for the device specified
+ * with @devid. Will return NULL when no gpgpu fill function is implemented.
+ */
+igt_fillfunc_t igt_get_gpgpu_fillfunc(int devid)
+{
+ igt_fillfunc_t fill = NULL;
+
+ if (IS_GEN7(devid))
+ fill = gen7_gpgpu_fillfunc;
+
+ return fill;
+}
diff --git a/lib/intel_batchbuffer.h b/lib/intel_batchbuffer.h
new file mode 100644
index 0000000..12f7be1
--- /dev/null
+++ b/lib/intel_batchbuffer.h
@@ -0,0 +1,268 @@
+#ifndef INTEL_BATCHBUFFER_H
+#define INTEL_BATCHBUFFER_H
+
+#include <stdint.h>
+#include <intel_bufmgr.h>
+#include "igt_core.h"
+#include "intel_reg.h"
+
+#define BATCH_SZ 4096
+#define BATCH_RESERVED 16
+
+struct intel_batchbuffer {
+ drm_intel_bufmgr *bufmgr;
+ uint32_t devid;
+ int gen;
+
+ drm_intel_context *ctx;
+ drm_intel_bo *bo;
+
+ uint8_t buffer[BATCH_SZ];
+ uint8_t *ptr, *end;
+ uint8_t *state;
+};
+
+struct intel_batchbuffer *intel_batchbuffer_alloc(drm_intel_bufmgr *bufmgr,
+ uint32_t devid);
+
+void intel_batchbuffer_set_context(struct intel_batchbuffer *batch,
+ drm_intel_context *ctx);
+
+
+void intel_batchbuffer_free(struct intel_batchbuffer *batch);
+
+
+void intel_batchbuffer_flush(struct intel_batchbuffer *batch);
+void intel_batchbuffer_flush_on_ring(struct intel_batchbuffer *batch, int ring);
+void intel_batchbuffer_flush_with_context(struct intel_batchbuffer *batch,
+ drm_intel_context *context);
+
+void intel_batchbuffer_reset(struct intel_batchbuffer *batch);
+
+void intel_batchbuffer_data(struct intel_batchbuffer *batch,
+ const void *data, unsigned int bytes);
+
+void intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch,
+ drm_intel_bo *buffer,
+ uint64_t delta,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ int fenced);
+
+/* Inline functions - might actually be better off with these
+ * non-inlined. Certainly better off switching all command packets to
+ * be passed as structs rather than dwords, but that's a little bit of
+ * work...
+ */
+#pragma GCC diagnostic ignored "-Winline"
+static inline unsigned int
+intel_batchbuffer_space(struct intel_batchbuffer *batch)
+{
+ return (BATCH_SZ - BATCH_RESERVED) - (batch->ptr - batch->buffer);
+}
+
+
+static inline void
+intel_batchbuffer_emit_dword(struct intel_batchbuffer *batch, uint32_t dword)
+{
+ igt_assert(intel_batchbuffer_space(batch) >= 4);
+ *(uint32_t *) (batch->ptr) = dword;
+ batch->ptr += 4;
+}
+
+static inline void
+intel_batchbuffer_require_space(struct intel_batchbuffer *batch,
+ unsigned int sz)
+{
+ igt_assert(sz < BATCH_SZ - BATCH_RESERVED);
+ if (intel_batchbuffer_space(batch) < sz)
+ intel_batchbuffer_flush(batch);
+}
+
+/**
+ * BEGIN_BATCH:
+ * @n: number of DWORDS to emit
+ * @r: number of RELOCS to emit
+ *
+ * Prepares a batch to emit @n DWORDS, flushing it if there's not enough space
+ * available.
+ *
+ * This macro needs a pointer to an #intel_batchbuffer structure called batch in
+ * scope.
+ */
+#define BEGIN_BATCH(n, r) do { \
+ int __n = (n); \
+ igt_assert(batch->end == NULL); \
+ if (batch->gen >= 8) __n += r; \
+ __n *= 4; \
+ intel_batchbuffer_require_space(batch, __n); \
+ batch->end = batch->ptr + __n; \
+} while (0)
+
+/**
+ * OUT_BATCH:
+ * @d: DWORD to emit
+ *
+ * Emits @d into a batch.
+ *
+ * This macro needs a pointer to an #intel_batchbuffer structure called batch in
+ * scope.
+ */
+#define OUT_BATCH(d) intel_batchbuffer_emit_dword(batch, d)
+
+/**
+ * OUT_RELOC_FENCED:
+ * @buf: relocation target libdrm buffer object
+ * @read_domains: gem domain bits for the relocation
+ * @write_domain: gem domain bit for the relocation
+ * @delta: delta value to add to @buffer's gpu address
+ *
+ * Emits a fenced relocation into a batch.
+ *
+ * This macro needs a pointer to an #intel_batchbuffer structure called batch in
+ * scope.
+ */
+#define OUT_RELOC_FENCED(buf, read_domains, write_domain, delta) do { \
+ igt_assert((delta) >= 0); \
+ intel_batchbuffer_emit_reloc(batch, buf, delta, \
+ read_domains, write_domain, 1); \
+} while (0)
+
+/**
+ * OUT_RELOC:
+ * @buf: relocation target libdrm buffer object
+ * @read_domains: gem domain bits for the relocation
+ * @write_domain: gem domain bit for the relocation
+ * @delta: delta value to add to @buffer's gpu address
+ *
+ * Emits a normal, unfenced relocation into a batch.
+ *
+ * This macro needs a pointer to an #intel_batchbuffer structure called batch in
+ * scope.
+ */
+#define OUT_RELOC(buf, read_domains, write_domain, delta) do { \
+ igt_assert((delta) >= 0); \
+ intel_batchbuffer_emit_reloc(batch, buf, delta, \
+ read_domains, write_domain, 0); \
+} while (0)
+
+/**
+ * ADVANCE_BATCH:
+ *
+ * Completes the batch command emission sequence started with #BEGIN_BATCH.
+ *
+ * This macro needs a pointer to an #intel_batchbuffer structure called batch in
+ * scope.
+ */
+#define ADVANCE_BATCH() do { \
+ igt_assert(batch->ptr == batch->end); \
+ batch->end = NULL; \
+} while(0)
+
+#define BLIT_COPY_BATCH_START(flags) do { \
+ BEGIN_BATCH(8, 2); \
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD | \
+ XY_SRC_COPY_BLT_WRITE_ALPHA | \
+ XY_SRC_COPY_BLT_WRITE_RGB | \
+ (flags) | \
+ (6 + 2*(batch->gen >= 8))); \
+} while(0)
+
+#define COLOR_BLIT_COPY_BATCH_START(flags) do { \
+ BEGIN_BATCH(6, 1); \
+ OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | \
+ COLOR_BLT_WRITE_ALPHA | \
+ XY_COLOR_BLT_WRITE_RGB | \
+ (4 + (batch->gen >= 8))); \
+} while(0)
+
+void
+intel_blt_copy(struct intel_batchbuffer *batch,
+ drm_intel_bo *src_bo, int src_x1, int src_y1, int src_pitch,
+ drm_intel_bo *dst_bo, int dst_x1, int dst_y1, int dst_pitch,
+ int width, int height, int bpp);
+void intel_copy_bo(struct intel_batchbuffer *batch,
+ drm_intel_bo *dst_bo, drm_intel_bo *src_bo,
+ long int size);
+
+/**
+ * igt_buf:
+ * @bo: underlying libdrm buffer object
+ * @stride: stride of the buffer
+ * @tiling: tiling mode bits
+ * @data: pointer to the memory mapping of the buffer
+ * @size: size of the buffer object
+ *
+ * This is a i-g-t buffer object wrapper structure which augments the baseline
+ * libdrm buffer object with suitable data needed by the render copy and the
+ * fill functions.
+ */
+struct igt_buf {
+ drm_intel_bo *bo;
+ uint32_t stride;
+ uint32_t tiling;
+ uint32_t *data;
+ uint32_t size;
+ /*< private >*/
+ unsigned num_tiles;
+};
+
+unsigned igt_buf_width(struct igt_buf *buf);
+unsigned igt_buf_height(struct igt_buf *buf);
+
+/**
+ * igt_render_copyfunc_t:
+ * @batch: batchbuffer object
+ * @context: libdrm hardware context to use
+ * @src: source i-g-t buffer object
+ * @src_x: source pixel x-coordination
+ * @src_y: source pixel y-coordination
+ * @width: width of the copied rectangle
+ * @height: height of the copied rectangle
+ * @dst: destination i-g-t buffer object
+ * @dst_x: destination pixel x-coordination
+ * @dst_y: destination pixel y-coordination
+ *
+ * This is the type of the per-platform render copy functions. The
+ * platform-specific implementation can be obtained by calling
+ * igt_get_render_copyfunc().
+ *
+ * A render copy function will emit a batchbuffer to the kernel which executes
+ * the specified blit copy operation using the render engine. @context is
+ * optional and can be NULL.
+ */
+typedef void (*igt_render_copyfunc_t)(struct intel_batchbuffer *batch,
+ drm_intel_context *context,
+ struct igt_buf *src, unsigned src_x, unsigned src_y,
+ unsigned width, unsigned height,
+ struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
+
+igt_render_copyfunc_t igt_get_render_copyfunc(int devid);
+
+/**
+ * igt_fillfunc_t:
+ * @batch: batchbuffer object
+ * @dst: destination i-g-t buffer object
+ * @x: destination pixel x-coordination
+ * @y: destination pixel y-coordination
+ * @width: width of the filled rectangle
+ * @height: height of the filled rectangle
+ * @color: fill color to use
+ *
+ * This is the type of the per-platform fill functions using media
+ * or gpgpu pipeline. The platform-specific implementation can be obtained
+ * by calling igt_get_media_fillfunc() or igt_get_gpgpu_fillfunc().
+ *
+ * A fill function will emit a batchbuffer to the kernel which executes
+ * the specified blit fill operation using the media/gpgpu engine.
+ */
+typedef void (*igt_fillfunc_t)(struct intel_batchbuffer *batch,
+ struct igt_buf *dst,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ uint8_t color);
+
+igt_fillfunc_t igt_get_media_fillfunc(int devid);
+igt_fillfunc_t igt_get_gpgpu_fillfunc(int devid);
+
+#endif
diff --git a/lib/intel_chipset.c b/lib/intel_chipset.c
new file mode 100644
index 0000000..3b3e03b
--- /dev/null
+++ b/lib/intel_chipset.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright © 2008 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include "i915_drm.h"
+
+#include "intel_chipset.h"
+#include "igt_core.h"
+
+/**
+ * SECTION:intel_chipset
+ * @short_description: Feature macros and chipset helpers
+ * @title: intel chipset
+ * @include: intel_chipset.h
+ *
+ * This library mostly provides feature macros which use raw pci device ids. It
+ * also provides a few more helper functions to handle pci devices, chipset
+ * detection and related issues.
+ */
+
+/**
+ * intel_pch:
+ *
+ * Global variable to keep track of the pch type. Can either be set manually or
+ * detected at runtime with intel_check_pch().
+ */
+enum pch_type intel_pch;
+
+/**
+ * intel_get_pci_device:
+ *
+ * Looks up the main graphics pci device using libpciaccess.
+ *
+ * Returns:
+ * The pci_device, exits the program on any failures.
+ */
+struct pci_device *
+intel_get_pci_device(void)
+{
+ struct pci_device *pci_dev;
+ int error;
+
+ error = pci_system_init();
+ igt_fail_on_f(error != 0,
+ "Couldn't initialize PCI system\n");
+
+ /* Grab the graphics card. Try the canonical slot first, then
+ * walk the entire PCI bus for a matching device. */
+ pci_dev = pci_device_find_by_slot(0, 0, 2, 0);
+ if (pci_dev == NULL || pci_dev->vendor_id != 0x8086) {
+ struct pci_device_iterator *iter;
+ struct pci_id_match match;
+
+ match.vendor_id = 0x8086; /* Intel */
+ match.device_id = PCI_MATCH_ANY;
+ match.subvendor_id = PCI_MATCH_ANY;
+ match.subdevice_id = PCI_MATCH_ANY;
+
+ match.device_class = 0x3 << 16;
+ match.device_class_mask = 0xff << 16;
+
+ match.match_data = 0;
+
+ iter = pci_id_match_iterator_create(&match);
+ pci_dev = pci_device_next(iter);
+ pci_iterator_destroy(iter);
+ }
+ if (pci_dev == NULL)
+ errx(1, "Couldn't find graphics card");
+
+ error = pci_device_probe(pci_dev);
+ igt_fail_on_f(error != 0,
+ "Couldn't probe graphics card\n");
+
+ if (pci_dev->vendor_id != 0x8086)
+ errx(1, "Graphics card is non-intel");
+
+ return pci_dev;
+}
+
+extern uint16_t __drm_device_id;
+
+/**
+ * intel_get_drm_devid:
+ * @fd: open i915 drm file descriptor
+ *
+ * Queries the kernel for the pci device id corresponding to the drm file
+ * descriptor.
+ *
+ * Returns:
+ * The devid, exits the program on any failures.
+ */
+uint32_t
+intel_get_drm_devid(int fd)
+{
+ const char *override;
+
+ igt_assert(__drm_device_id);
+
+ override = getenv("INTEL_DEVID_OVERRIDE");
+ if (override)
+ return strtol(override, NULL, 0);
+ else
+ return __drm_device_id;
+}
+
+/**
+ * intel_gen:
+ * @devid: pci device id
+ *
+ * Computes the Intel GFX generation for the give device id.
+ *
+ * Returns:
+ * The GFX generation on successful lookup, -1 on failure.
+ */
+int intel_gen(uint32_t devid)
+{
+ if (IS_GEN2(devid))
+ return 2;
+ if (IS_GEN3(devid))
+ return 3;
+ if (IS_GEN4(devid))
+ return 4;
+ if (IS_GEN5(devid))
+ return 5;
+ if (IS_GEN6(devid))
+ return 6;
+ if (IS_GEN7(devid))
+ return 7;
+ if (IS_GEN8(devid))
+ return 8;
+ if (IS_GEN9(devid))
+ return 9;
+
+ return -1;
+}
+
+/**
+ * intel_check_pch:
+ *
+ * Detects the PCH chipset type of the running systems and fills in the results
+ * into the global #intel_pch varaible.
+ */
+void
+intel_check_pch(void)
+{
+ struct pci_device *pch_dev;
+
+ pch_dev = pci_device_find_by_slot(0, 0, 31, 0);
+ if (pch_dev == NULL)
+ return;
+
+ if (pch_dev->vendor_id != 0x8086)
+ return;
+
+ switch (pch_dev->device_id & 0xff00) {
+ case 0x3b00:
+ intel_pch = PCH_IBX;
+ break;
+ case 0x1c00:
+ case 0x1e00:
+ intel_pch = PCH_CPT;
+ break;
+ case 0x8c00:
+ case 0x9c00:
+ intel_pch = PCH_LPT;
+ break;
+ default:
+ intel_pch = PCH_NONE;
+ return;
+ }
+}
diff --git a/lib/intel_chipset.h b/lib/intel_chipset.h
new file mode 100644
index 0000000..e3ce603
--- /dev/null
+++ b/lib/intel_chipset.h
@@ -0,0 +1,444 @@
+/*
+ * 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>
+ *
+ */
+
+#ifndef _INTEL_CHIPSET_H
+#define _INTEL_CHIPSET_H
+
+#include <pciaccess.h>
+
+struct pci_device *intel_get_pci_device(void);
+uint32_t intel_get_drm_devid(int fd);
+int intel_gen(uint32_t devid);
+
+extern enum pch_type intel_pch;
+
+enum pch_type {
+ PCH_NONE,
+ PCH_IBX,
+ PCH_CPT,
+ PCH_LPT,
+};
+
+void intel_check_pch(void);
+
+#define HAS_IBX (intel_pch == PCH_IBX)
+#define HAS_CPT (intel_pch == PCH_CPT)
+#define HAS_LPT (intel_pch == PCH_LPT)
+
+/* Exclude chipset #defines, they just add noise */
+#ifndef __GTK_DOC_IGNORE__
+
+#define PCI_CHIP_I810 0x7121
+#define PCI_CHIP_I810_DC100 0x7123
+#define PCI_CHIP_I810_E 0x7125
+#define PCI_CHIP_I815 0x1132
+
+#define PCI_CHIP_I830_M 0x3577
+#define PCI_CHIP_845_G 0x2562
+#define PCI_CHIP_I855_GM 0x3582
+#define PCI_CHIP_I865_G 0x2572
+
+#define PCI_CHIP_I915_G 0x2582
+#define PCI_CHIP_E7221_G 0x258A
+#define PCI_CHIP_I915_GM 0x2592
+#define PCI_CHIP_I945_G 0x2772
+#define PCI_CHIP_I945_GM 0x27A2
+#define PCI_CHIP_I945_GME 0x27AE
+
+#define PCI_CHIP_Q35_G 0x29B2
+#define PCI_CHIP_G33_G 0x29C2
+#define PCI_CHIP_Q33_G 0x29D2
+
+#define PCI_CHIP_IGD_GM 0xA011
+#define PCI_CHIP_IGD_G 0xA001
+
+#define IS_IGDGM(devid) ((devid) == PCI_CHIP_IGD_GM)
+#define IS_IGDG(devid) ((devid) == PCI_CHIP_IGD_G)
+#define IS_IGD(devid) (IS_IGDG(devid) || IS_IGDGM(devid))
+
+#define PCI_CHIP_I965_G 0x29A2
+#define PCI_CHIP_I965_Q 0x2992
+#define PCI_CHIP_I965_G_1 0x2982
+#define PCI_CHIP_I946_GZ 0x2972
+#define PCI_CHIP_I965_GM 0x2A02
+#define PCI_CHIP_I965_GME 0x2A12
+
+#define PCI_CHIP_GM45_GM 0x2A42
+
+#define PCI_CHIP_IGD_E_G 0x2E02
+#define PCI_CHIP_Q45_G 0x2E12
+#define PCI_CHIP_G45_G 0x2E22
+#define PCI_CHIP_G41_G 0x2E32
+
+#define PCI_CHIP_ILD_G 0x0042
+#define PCI_CHIP_ILM_G 0x0046
+
+#define PCI_CHIP_SANDYBRIDGE_GT1 0x0102 /* desktop */
+#define PCI_CHIP_SANDYBRIDGE_GT2 0x0112
+#define PCI_CHIP_SANDYBRIDGE_GT2_PLUS 0x0122
+#define PCI_CHIP_SANDYBRIDGE_M_GT1 0x0106 /* mobile */
+#define PCI_CHIP_SANDYBRIDGE_M_GT2 0x0116
+#define PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS 0x0126
+#define PCI_CHIP_SANDYBRIDGE_S 0x010A /* server */
+
+#define PCI_CHIP_IVYBRIDGE_GT1 0x0152 /* desktop */
+#define PCI_CHIP_IVYBRIDGE_GT2 0x0162
+#define PCI_CHIP_IVYBRIDGE_M_GT1 0x0156 /* mobile */
+#define PCI_CHIP_IVYBRIDGE_M_GT2 0x0166
+#define PCI_CHIP_IVYBRIDGE_S 0x015a /* server */
+#define PCI_CHIP_IVYBRIDGE_S_GT2 0x016a /* server */
+
+#define PCI_CHIP_HASWELL_GT1 0x0402 /* Desktop */
+#define PCI_CHIP_HASWELL_GT2 0x0412
+#define PCI_CHIP_HASWELL_GT3 0x0422
+#define PCI_CHIP_HASWELL_M_GT1 0x0406 /* Mobile */
+#define PCI_CHIP_HASWELL_M_GT2 0x0416
+#define PCI_CHIP_HASWELL_M_GT3 0x0426
+#define PCI_CHIP_HASWELL_S_GT1 0x040A /* Server */
+#define PCI_CHIP_HASWELL_S_GT2 0x041A
+#define PCI_CHIP_HASWELL_S_GT3 0x042A
+#define PCI_CHIP_HASWELL_B_GT1 0x040B /* Reserved */
+#define PCI_CHIP_HASWELL_B_GT2 0x041B
+#define PCI_CHIP_HASWELL_B_GT3 0x042B
+#define PCI_CHIP_HASWELL_E_GT1 0x040E /* Reserved */
+#define PCI_CHIP_HASWELL_E_GT2 0x041E
+#define PCI_CHIP_HASWELL_E_GT3 0x042E
+#define PCI_CHIP_HASWELL_SDV_GT1 0x0C02 /* Desktop */
+#define PCI_CHIP_HASWELL_SDV_GT2 0x0C12
+#define PCI_CHIP_HASWELL_SDV_GT3 0x0C22
+#define PCI_CHIP_HASWELL_SDV_M_GT1 0x0C06 /* Mobile */
+#define PCI_CHIP_HASWELL_SDV_M_GT2 0x0C16
+#define PCI_CHIP_HASWELL_SDV_M_GT3 0x0C26
+#define PCI_CHIP_HASWELL_SDV_S_GT1 0x0C0A /* Server */
+#define PCI_CHIP_HASWELL_SDV_S_GT2 0x0C1A
+#define PCI_CHIP_HASWELL_SDV_S_GT3 0x0C2A
+#define PCI_CHIP_HASWELL_SDV_B_GT1 0x0C0B /* Reserved */
+#define PCI_CHIP_HASWELL_SDV_B_GT2 0x0C1B
+#define PCI_CHIP_HASWELL_SDV_B_GT3 0x0C2B
+#define PCI_CHIP_HASWELL_SDV_E_GT1 0x0C0E /* Reserved */
+#define PCI_CHIP_HASWELL_SDV_E_GT2 0x0C1E
+#define PCI_CHIP_HASWELL_SDV_E_GT3 0x0C2E
+#define PCI_CHIP_HASWELL_ULT_GT1 0x0A02 /* Desktop */
+#define PCI_CHIP_HASWELL_ULT_GT2 0x0A12
+#define PCI_CHIP_HASWELL_ULT_GT3 0x0A22
+#define PCI_CHIP_HASWELL_ULT_M_GT1 0x0A06 /* Mobile */
+#define PCI_CHIP_HASWELL_ULT_M_GT2 0x0A16
+#define PCI_CHIP_HASWELL_ULT_M_GT3 0x0A26
+#define PCI_CHIP_HASWELL_ULT_S_GT1 0x0A0A /* Server */
+#define PCI_CHIP_HASWELL_ULT_S_GT2 0x0A1A
+#define PCI_CHIP_HASWELL_ULT_S_GT3 0x0A2A
+#define PCI_CHIP_HASWELL_ULT_B_GT1 0x0A0B /* Reserved */
+#define PCI_CHIP_HASWELL_ULT_B_GT2 0x0A1B
+#define PCI_CHIP_HASWELL_ULT_B_GT3 0x0A2B
+#define PCI_CHIP_HASWELL_ULT_E_GT1 0x0A0E /* Reserved */
+#define PCI_CHIP_HASWELL_ULT_E_GT2 0x0A1E
+#define PCI_CHIP_HASWELL_ULT_E_GT3 0x0A2E
+#define PCI_CHIP_HASWELL_CRW_GT1 0x0D02 /* Desktop */
+#define PCI_CHIP_HASWELL_CRW_GT2 0x0D12
+#define PCI_CHIP_HASWELL_CRW_GT3 0x0D22
+#define PCI_CHIP_HASWELL_CRW_M_GT1 0x0D06 /* Mobile */
+#define PCI_CHIP_HASWELL_CRW_M_GT2 0x0D16
+#define PCI_CHIP_HASWELL_CRW_M_GT3 0x0D26
+#define PCI_CHIP_HASWELL_CRW_S_GT1 0x0D0A /* Server */
+#define PCI_CHIP_HASWELL_CRW_S_GT2 0x0D1A
+#define PCI_CHIP_HASWELL_CRW_S_GT3 0x0D2A
+#define PCI_CHIP_HASWELL_CRW_B_GT1 0x0D0B /* Reserved */
+#define PCI_CHIP_HASWELL_CRW_B_GT2 0x0D1B
+#define PCI_CHIP_HASWELL_CRW_B_GT3 0x0D2B
+#define PCI_CHIP_HASWELL_CRW_E_GT1 0x0D0E /* Reserved */
+#define PCI_CHIP_HASWELL_CRW_E_GT2 0x0D1E
+#define PCI_CHIP_HASWELL_CRW_E_GT3 0x0D2E
+#define BDW_SPARE 0x2
+#define BDW_ULT 0x6
+#define BDW_HALO 0xb
+#define BDW_SERVER 0xa
+#define BDW_WORKSTATION 0xd
+#define BDW_ULX 0xe
+
+#define PCI_CHIP_VALLEYVIEW_PO 0x0f30 /* VLV PO board */
+#define PCI_CHIP_VALLEYVIEW_1 0x0f31
+#define PCI_CHIP_VALLEYVIEW_2 0x0f32
+#define PCI_CHIP_VALLEYVIEW_3 0x0f33
+
+#define PCI_CHIP_CHERRYVIEW_0 0x22b0
+#define PCI_CHIP_CHERRYVIEW_1 0x22b1
+#define PCI_CHIP_CHERRYVIEW_2 0x22b2
+#define PCI_CHIP_CHERRYVIEW_3 0x22b3
+
+#define PCI_CHIP_SKYLAKE_ULT_GT2 0x1916
+#define PCI_CHIP_SKYLAKE_ULT_GT1 0x1906
+#define PCI_CHIP_SKYLAKE_ULT_GT3 0x1926
+#define PCI_CHIP_SKYLAKE_ULT_GT2F 0x1921
+#define PCI_CHIP_SKYLAKE_ULX_GT1 0x190E
+#define PCI_CHIP_SKYLAKE_ULX_GT2 0x191E
+#define PCI_CHIP_SKYLAKE_DT_GT2 0x1912
+#define PCI_CHIP_SKYLAKE_DT_GT1 0x1902
+#define PCI_CHIP_SKYLAKE_HALO_GT2 0x191B
+#define PCI_CHIP_SKYLAKE_HALO_GT3 0x192B
+#define PCI_CHIP_SKYLAKE_HALO_GT1 0x190B
+#define PCI_CHIP_SKYLAKE_SRV_GT2 0x191A
+#define PCI_CHIP_SKYLAKE_SRV_GT3 0x192A
+#define PCI_CHIP_SKYLAKE_SRV_GT1 0x190A
+#define PCI_CHIP_SKYLAKE_WKS_GT2 0x191D
+
+#endif /* __GTK_DOC_IGNORE__ */
+
+#define IS_MOBILE(devid) ((devid) == PCI_CHIP_I855_GM || \
+ (devid) == PCI_CHIP_I915_GM || \
+ (devid) == PCI_CHIP_I945_GM || \
+ (devid) == PCI_CHIP_I945_GME || \
+ (devid) == PCI_CHIP_I965_GM || \
+ (devid) == PCI_CHIP_I965_GME || \
+ (devid) == PCI_CHIP_GM45_GM || IS_IGD(devid) || \
+ (devid) == PCI_CHIP_IVYBRIDGE_M_GT1 || \
+ (devid) == PCI_CHIP_IVYBRIDGE_M_GT2)
+
+#define IS_G45(devid) ((devid) == PCI_CHIP_IGD_E_G || \
+ (devid) == PCI_CHIP_Q45_G || \
+ (devid) == PCI_CHIP_G45_G || \
+ (devid) == PCI_CHIP_G41_G)
+#define IS_GM45(devid) ((devid) == PCI_CHIP_GM45_GM)
+#define IS_G4X(devid) (IS_G45(devid) || IS_GM45(devid))
+
+#define IS_ILD(devid) ((devid) == PCI_CHIP_ILD_G)
+#define IS_ILM(devid) ((devid) == PCI_CHIP_ILM_G)
+
+#define IS_915(devid) ((devid) == PCI_CHIP_I915_G || \
+ (devid) == PCI_CHIP_E7221_G || \
+ (devid) == PCI_CHIP_I915_GM)
+
+#define IS_945GM(devid) ((devid) == PCI_CHIP_I945_GM || \
+ (devid) == PCI_CHIP_I945_GME)
+
+#define IS_945(devid) ((devid) == PCI_CHIP_I945_G || \
+ (devid) == PCI_CHIP_I945_GM || \
+ (devid) == PCI_CHIP_I945_GME || \
+ IS_G33(devid))
+
+#define IS_G33(devid) ((devid) == PCI_CHIP_G33_G || \
+ (devid) == PCI_CHIP_Q33_G || \
+ (devid) == PCI_CHIP_Q35_G || IS_IGD(devid))
+
+#define IS_GEN2(devid) ((devid) == PCI_CHIP_I830_M || \
+ (devid) == PCI_CHIP_845_G || \
+ (devid) == PCI_CHIP_I855_GM || \
+ (devid) == PCI_CHIP_I865_G)
+
+#define IS_GEN3(devid) (IS_945(devid) || IS_915(devid))
+
+#define IS_GEN4(devid) ((devid) == PCI_CHIP_I965_G || \
+ (devid) == PCI_CHIP_I965_Q || \
+ (devid) == PCI_CHIP_I965_G_1 || \
+ (devid) == PCI_CHIP_I965_GM || \
+ (devid) == PCI_CHIP_I965_GME || \
+ (devid) == PCI_CHIP_I946_GZ || \
+ IS_G4X(devid))
+
+#define IS_GEN5(devid) (IS_ILD(devid) || IS_ILM(devid))
+
+#define IS_GEN6(devid) ((devid) == PCI_CHIP_SANDYBRIDGE_GT1 || \
+ (devid) == PCI_CHIP_SANDYBRIDGE_GT2 || \
+ (devid) == PCI_CHIP_SANDYBRIDGE_GT2_PLUS || \
+ (devid) == PCI_CHIP_SANDYBRIDGE_M_GT1 || \
+ (devid) == PCI_CHIP_SANDYBRIDGE_M_GT2 || \
+ (devid) == PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS || \
+ (devid) == PCI_CHIP_SANDYBRIDGE_S)
+
+#define IS_GEN7(devid) (IS_IVYBRIDGE(devid) || \
+ IS_HASWELL(devid) || \
+ IS_VALLEYVIEW(devid))
+
+#define IS_IVYBRIDGE(devid) ((devid) == PCI_CHIP_IVYBRIDGE_GT1 || \
+ (devid) == PCI_CHIP_IVYBRIDGE_GT2 || \
+ (devid) == PCI_CHIP_IVYBRIDGE_M_GT1 || \
+ (devid) == PCI_CHIP_IVYBRIDGE_M_GT2 || \
+ (devid) == PCI_CHIP_IVYBRIDGE_S || \
+ (devid) == PCI_CHIP_IVYBRIDGE_S_GT2)
+
+#define IS_VALLEYVIEW(devid) ((devid) == PCI_CHIP_VALLEYVIEW_PO || \
+ (devid) == PCI_CHIP_VALLEYVIEW_1 || \
+ (devid) == PCI_CHIP_VALLEYVIEW_2 || \
+ (devid) == PCI_CHIP_VALLEYVIEW_3)
+
+#define IS_HSW_GT1(devid) ((devid) == PCI_CHIP_HASWELL_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_M_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_S_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_B_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_E_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_M_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_S_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_B_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_E_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_M_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_S_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_B_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_E_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_M_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_S_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_B_GT1 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_E_GT1)
+#define IS_HSW_GT2(devid) ((devid) == PCI_CHIP_HASWELL_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_M_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_S_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_B_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_E_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_M_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_S_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_B_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_E_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_M_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_S_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_B_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_E_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_M_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_S_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_B_GT2 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_E_GT2)
+#define IS_HSW_GT3(devid) ((devid) == PCI_CHIP_HASWELL_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_M_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_S_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_B_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_E_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_M_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_S_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_B_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_SDV_E_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_M_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_S_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_B_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_ULT_E_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_M_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_S_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_B_GT3 || \
+ (devid) == PCI_CHIP_HASWELL_CRW_E_GT3)
+
+#define IS_HASWELL(devid) (IS_HSW_GT1(devid) || \
+ IS_HSW_GT2(devid) || \
+ IS_HSW_GT3(devid))
+
+#define IS_BROADWELL(devid) ((((devid) & 0xff00) != 0x1600) ? 0 : \
+ ((((devid) & 0x00f0) >> 4) > 3) ? 0 : \
+ (((devid) & 0x000f) == BDW_SPARE) ? 1 : \
+ (((devid) & 0x000f) == BDW_ULT) ? 1 : \
+ (((devid) & 0x000f) == BDW_HALO) ? 1 : \
+ (((devid) & 0x000f) == BDW_SERVER) ? 1 : \
+ (((devid) & 0x000f) == BDW_WORKSTATION) ? 1 : \
+ (((devid) & 0x000f) == BDW_ULX) ? 1 : 0)
+
+#define IS_CHERRYVIEW(devid) ((devid) == PCI_CHIP_CHERRYVIEW_0 || \
+ (devid) == PCI_CHIP_CHERRYVIEW_1 || \
+ (devid) == PCI_CHIP_CHERRYVIEW_2 || \
+ (devid) == PCI_CHIP_CHERRYVIEW_3)
+
+#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_HALO_GT1 || \
+ (devid) == PCI_CHIP_SKYLAKE_SRV_GT1)
+
+#define IS_SKL_GT2(devid) ((devid) == PCI_CHIP_SKYLAKE_ULT_GT2 || \
+ (devid) == PCI_CHIP_SKYLAKE_ULT_GT2F || \
+ (devid) == PCI_CHIP_SKYLAKE_ULX_GT2 || \
+ (devid) == PCI_CHIP_SKYLAKE_DT_GT2 || \
+ (devid) == PCI_CHIP_SKYLAKE_HALO_GT2 || \
+ (devid) == PCI_CHIP_SKYLAKE_SRV_GT2 || \
+ (devid) == PCI_CHIP_SKYLAKE_WKS_GT2)
+
+#define IS_SKL_GT3(devid) ((devid) == PCI_CHIP_SKYLAKE_ULT_GT3 || \
+ (devid) == PCI_CHIP_SKYLAKE_HALO_GT3 || \
+ (devid) == PCI_CHIP_SKYLAKE_SRV_GT3)
+
+#define IS_SKYLAKE(devid) (IS_SKL_GT1(devid) || \
+ IS_SKL_GT2(devid) || \
+ IS_SKL_GT3(devid))
+
+#define IS_GEN9(devid) IS_SKYLAKE(devid)
+
+#define IS_965(devid) (IS_GEN4(devid) || \
+ IS_GEN5(devid) || \
+ IS_GEN6(devid) || \
+ IS_GEN7(devid) || \
+ IS_GEN8(devid) || \
+ IS_GEN9(devid))
+
+#define IS_9XX(devid) (IS_GEN3(devid) || \
+ IS_GEN4(devid) || \
+ IS_GEN5(devid) || \
+ IS_GEN6(devid) || \
+ IS_GEN7(devid) || \
+ IS_GEN8(devid) || \
+ IS_GEN9(devid))
+
+#define IS_INTEL(devid) (IS_GEN2(devid) || \
+ IS_GEN3(devid) || \
+ IS_GEN4(devid) || \
+ IS_GEN5(devid) || \
+ IS_GEN6(devid) || \
+ IS_GEN7(devid) || \
+ IS_GEN8(devid) || \
+ IS_GEN9(devid))
+
+#define HAS_PCH_SPLIT(devid) (IS_GEN5(devid) || \
+ IS_GEN6(devid) || \
+ IS_IVYBRIDGE(devid) || IS_HASWELL(devid) || \
+ IS_GEN8(devid) || \
+ IS_GEN9(devid))
+
+#define HAS_BLT_RING(devid) (IS_GEN6(devid) || \
+ IS_GEN7(devid) || \
+ IS_GEN8(devid) || \
+ IS_GEN9(devid))
+
+#define HAS_BSD_RING(devid) (IS_GEN5(devid) || \
+ IS_GEN6(devid) || \
+ IS_GEN7(devid) || \
+ IS_GEN8(devid) || \
+ IS_GEN9(devid))
+
+#define IS_BROADWATER(devid) ((devid) == PCI_CHIP_I946_GZ || \
+ (devid) == PCI_CHIP_I965_G_1 || \
+ (devid) == PCI_CHIP_I965_Q || \
+ (devid) == PCI_CHIP_I965_G)
+
+#define IS_CRESTLINE(devid) ((devid) == PCI_CHIP_I965_GM || \
+ (devid) == PCI_CHIP_I965_GME)
+
+#define HAS_VEBOX_RING(devid) (IS_HASWELL(devid))
+
+#endif /* _INTEL_CHIPSET_H */
diff --git a/lib/intel_io.h b/lib/intel_io.h
new file mode 100644
index 0000000..8293353
--- /dev/null
+++ b/lib/intel_io.h
@@ -0,0 +1,85 @@
+/*
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#ifndef INTEL_GPU_TOOLS_H
+#define INTEL_GPU_TOOLS_H
+
+#include <stdint.h>
+#include <pciaccess.h>
+
+/* register access helpers from intel_mmio.c */
+extern void *mmio;
+void intel_mmio_use_pci_bar(struct pci_device *pci_dev);
+void intel_mmio_use_dump_file(char *file);
+
+int intel_register_access_init(struct pci_device *pci_dev, int safe);
+void intel_register_access_fini(void);
+uint32_t intel_register_read(uint32_t reg);
+void intel_register_write(uint32_t reg, uint32_t val);
+int intel_register_access_needs_fakewake(void);
+
+uint32_t INREG(uint32_t reg);
+void OUTREG(uint32_t reg, uint32_t val);
+
+/* sideband access functions from intel_iosf.c */
+uint32_t intel_dpio_reg_read(uint32_t reg, int phy);
+void intel_dpio_reg_write(uint32_t reg, uint32_t val, int phy);
+uint32_t intel_flisdsi_reg_read(uint32_t reg);
+void intel_flisdsi_reg_write(uint32_t reg, uint32_t val);
+uint32_t intel_iosf_sb_read(uint32_t port, uint32_t reg);
+void intel_iosf_sb_write(uint32_t port, uint32_t reg, uint32_t val);
+
+int intel_punit_read(uint8_t addr, uint32_t *val);
+int intel_punit_write(uint8_t addr, uint32_t val);
+int intel_nc_read(uint8_t addr, uint32_t *val);
+int intel_nc_write(uint8_t addr, uint32_t val);
+
+/* register maps from intel_reg_map.c */
+#ifndef __GTK_DOC_IGNORE__
+
+#define INTEL_RANGE_RSVD (0<<0) /* Shouldn't be read or written */
+#define INTEL_RANGE_READ (1<<0)
+#define INTEL_RANGE_WRITE (1<<1)
+#define INTEL_RANGE_RW (INTEL_RANGE_READ | INTEL_RANGE_WRITE)
+#define INTEL_RANGE_END (1<<31)
+
+struct intel_register_range {
+ uint32_t base;
+ uint32_t size;
+ uint32_t flags;
+};
+
+struct intel_register_map {
+ struct intel_register_range *map;
+ uint32_t top;
+ uint32_t alignment_mask;
+};
+struct intel_register_map intel_get_register_map(uint32_t devid);
+struct intel_register_range *intel_get_register_range(struct intel_register_map map, uint32_t offset, uint32_t mode);
+#endif /* __GTK_DOC_IGNORE__ */
+
+#endif /* INTEL_GPU_TOOLS_H */
diff --git a/lib/intel_reg.h b/lib/intel_reg.h
new file mode 100644
index 0000000..ade1c0c
--- /dev/null
+++ b/lib/intel_reg.h
@@ -0,0 +1,3600 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_reg.h,v 1.13 2003/02/06 04:18:04 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+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, 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 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.
+
+**************************************************************************/
+
+/* @file
+ * Register names and fields for Intel graphics.
+ */
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ * Eric Anholt <eric@anholt.net>
+ *
+ * based on the i740 driver by
+ * Kevin E. Martin <kevin@precisioninsight.com>
+ *
+ *
+ */
+
+#ifndef _I810_REG_H
+#define _I810_REG_H
+
+/* I/O register offsets
+ */
+#define SRX 0x3C4 /* p208 */
+#define GRX 0x3CE /* p213 */
+#define ARX 0x3C0 /* p224 */
+
+/* VGA Color Palette Registers */
+#define DACMASK 0x3C6 /* p232 */
+#define DACSTATE 0x3C7 /* p232 */
+#define DACRX 0x3C7 /* p233 */
+#define DACWX 0x3C8 /* p233 */
+#define DACDATA 0x3C9 /* p233 */
+
+/* CRT Controller Registers (CRX) */
+#define START_ADDR_HI 0x0C /* p246 */
+#define START_ADDR_LO 0x0D /* p247 */
+#define VERT_SYNC_END 0x11 /* p249 */
+#define EXT_VERT_TOTAL 0x30 /* p257 */
+#define EXT_VERT_DISPLAY 0x31 /* p258 */
+#define EXT_VERT_SYNC_START 0x32 /* p259 */
+#define EXT_VERT_BLANK_START 0x33 /* p260 */
+#define EXT_HORIZ_TOTAL 0x35 /* p261 */
+#define EXT_HORIZ_BLANK 0x39 /* p261 */
+#define EXT_START_ADDR 0x40 /* p262 */
+#define EXT_START_ADDR_ENABLE 0x80
+#define EXT_OFFSET 0x41 /* p263 */
+#define EXT_START_ADDR_HI 0x42 /* p263 */
+#define INTERLACE_CNTL 0x70 /* p264 */
+#define INTERLACE_ENABLE 0x80
+#define INTERLACE_DISABLE 0x00
+
+/* Miscellaneous Output Register
+ */
+#define MSR_R 0x3CC /* p207 */
+#define MSR_W 0x3C2 /* p207 */
+#define IO_ADDR_SELECT 0x01
+
+#define MDA_BASE 0x3B0 /* p207 */
+#define CGA_BASE 0x3D0 /* p207 */
+
+/* CR80 - IO Control, p264
+ */
+#define IO_CTNL 0x80
+#define EXTENDED_ATTR_CNTL 0x02
+#define EXTENDED_CRTC_CNTL 0x01
+
+/* GR10 - Address mapping, p221
+ */
+#define ADDRESS_MAPPING 0x10
+#define PAGE_TO_LOCAL_MEM_ENABLE 0x10
+#define GTT_MEM_MAP_ENABLE 0x08
+#define PACKED_MODE_ENABLE 0x04
+#define LINEAR_MODE_ENABLE 0x02
+#define PAGE_MAPPING_ENABLE 0x01
+
+#define HOTKEY_VBIOS_SWITCH_BLOCK 0x80
+#define HOTKEY_SWITCH 0x20
+#define HOTKEY_TOGGLE 0x10
+
+/* Blitter control, p378
+ */
+#define BITBLT_CNTL 0x7000c
+#define COLEXP_MODE 0x30
+#define COLEXP_8BPP 0x00
+#define COLEXP_16BPP 0x10
+#define COLEXP_24BPP 0x20
+#define COLEXP_RESERVED 0x30
+#define BITBLT_STATUS 0x01
+
+#define CHDECMISC 0x10111
+#define DCC 0x10200
+#define C0DRB0 0x10200
+#define C0DRB1 0x10202
+#define C0DRB2 0x10204
+#define C0DRB3 0x10206
+#define C0DRA01 0x10208
+#define C0DRA23 0x1020a
+#define C1DRB0 0x10600
+#define C1DRB1 0x10602
+#define C1DRB2 0x10604
+#define C1DRB3 0x10606
+#define C1DRA01 0x10608
+#define C1DRA23 0x1060a
+
+/* p375.
+ */
+#define DISPLAY_CNTL 0x70008
+#define VGA_WRAP_MODE 0x02
+#define VGA_WRAP_AT_256KB 0x00
+#define VGA_NO_WRAP 0x02
+#define GUI_MODE 0x01
+#define STANDARD_VGA_MODE 0x00
+#define HIRES_MODE 0x01
+
+/* p375
+ */
+#define PIXPIPE_CONFIG_0 0x70009
+#define DAC_8_BIT 0x80
+#define DAC_6_BIT 0x00
+#define HW_CURSOR_ENABLE 0x10
+#define EXTENDED_PALETTE 0x01
+
+/* p375
+ */
+#define PIXPIPE_CONFIG_1 0x7000a
+#define DISPLAY_COLOR_MODE 0x0F
+#define DISPLAY_VGA_MODE 0x00
+#define DISPLAY_8BPP_MODE 0x02
+#define DISPLAY_15BPP_MODE 0x04
+#define DISPLAY_16BPP_MODE 0x05
+#define DISPLAY_24BPP_MODE 0x06
+#define DISPLAY_32BPP_MODE 0x07
+
+/* p375
+ */
+#define PIXPIPE_CONFIG_2 0x7000b
+#define DISPLAY_GAMMA_ENABLE 0x08
+#define DISPLAY_GAMMA_DISABLE 0x00
+#define OVERLAY_GAMMA_ENABLE 0x04
+#define OVERLAY_GAMMA_DISABLE 0x00
+
+
+/* p380
+ */
+#define DISPLAY_BASE 0x70020
+#define DISPLAY_BASE_MASK 0x03fffffc
+
+
+/* Cursor control registers, pp383-384
+ */
+/* Desktop (845G, 865G) */
+#define CURSOR_CONTROL 0x70080
+#define CURSOR_ENABLE 0x80000000
+#define CURSOR_GAMMA_ENABLE 0x40000000
+#define CURSOR_STRIDE_MASK 0x30000000
+#define CURSOR_FORMAT_SHIFT 24
+#define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT)
+#define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT)
+#define CURSOR_FORMAT_3C (0x01 << CURSOR_FORMAT_SHIFT)
+#define CURSOR_FORMAT_4C (0x02 << CURSOR_FORMAT_SHIFT)
+#define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT)
+#define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT)
+
+/* Mobile and i810 */
+#define CURSOR_A_CONTROL CURSOR_CONTROL
+#define CURSOR_ORIGIN_SCREEN 0x00 /* i810 only */
+#define CURSOR_ORIGIN_DISPLAY 0x1 /* i810 only */
+#define CURSOR_MODE 0x27
+#define CURSOR_MODE_DISABLE 0x00
+#define CURSOR_MODE_32_4C_AX 0x01 /* i810 only */
+#define CURSOR_MODE_64_3C 0x04
+#define CURSOR_MODE_64_4C_AX 0x05
+#define CURSOR_MODE_64_4C 0x06
+#define CURSOR_MODE_64_32B_AX 0x07
+#define CURSOR_MODE_64_ARGB_AX (0x20 | CURSOR_MODE_64_32B_AX)
+#define MCURSOR_PIPE_SELECT (1 << 28)
+#define MCURSOR_PIPE_A 0x00
+#define MCURSOR_PIPE_B (1 << 28)
+#define MCURSOR_GAMMA_ENABLE (1 << 26)
+#define MCURSOR_MEM_TYPE_LOCAL (1 << 25)
+
+
+#define CURSOR_BASEADDR 0x70084
+#define CURSOR_A_BASE CURSOR_BASEADDR
+#define CURSOR_BASEADDR_MASK 0x1FFFFF00
+#define CURSOR_A_POSITION 0x70088
+#define CURSOR_POS_SIGN 0x8000
+#define CURSOR_POS_MASK 0x007FF
+#define CURSOR_X_SHIFT 0
+#define CURSOR_Y_SHIFT 16
+#define CURSOR_X_LO 0x70088
+#define CURSOR_X_HI 0x70089
+#define CURSOR_X_POS 0x00
+#define CURSOR_X_NEG 0x80
+#define CURSOR_Y_LO 0x7008A
+#define CURSOR_Y_HI 0x7008B
+#define CURSOR_Y_POS 0x00
+#define CURSOR_Y_NEG 0x80
+
+#define CURSOR_A_PALETTE0 0x70090
+#define CURSOR_A_PALETTE1 0x70094
+#define CURSOR_A_PALETTE2 0x70098
+#define CURSOR_A_PALETTE3 0x7009C
+
+#define CURSOR_SIZE 0x700A0
+#define CURSOR_SIZE_MASK 0x3FF
+#define CURSOR_SIZE_HSHIFT 0
+#define CURSOR_SIZE_VSHIFT 12
+
+#define CURSOR_B_CONTROL 0x700C0
+#define CURSOR_B_BASE 0x700C4
+#define CURSOR_B_POSITION 0x700C8
+#define CURSOR_B_PALETTE0 0x700D0
+#define CURSOR_B_PALETTE1 0x700D4
+#define CURSOR_B_PALETTE2 0x700D8
+#define CURSOR_B_PALETTE3 0x700DC
+
+
+/* Similar registers exist in Device 0 on the i810 (pp55-65), but I'm
+ * not sure they refer to local (graphics) memory.
+ *
+ * These details are for the local memory control registers,
+ * (pp301-310). The test machines are not equiped with local memory,
+ * so nothing is tested. Only a single row seems to be supported.
+ */
+#define DRAM_ROW_TYPE 0x3000
+#define DRAM_ROW_0 0x01
+#define DRAM_ROW_0_SDRAM 0x01
+#define DRAM_ROW_0_EMPTY 0x00
+#define DRAM_ROW_CNTL_LO 0x3001
+#define DRAM_PAGE_MODE_CTRL 0x10
+#define DRAM_RAS_TO_CAS_OVRIDE 0x08
+#define DRAM_CAS_LATENCY 0x04
+#define DRAM_RAS_TIMING 0x02
+#define DRAM_RAS_PRECHARGE 0x01
+#define DRAM_ROW_CNTL_HI 0x3002
+#define DRAM_REFRESH_RATE 0x18
+#define DRAM_REFRESH_DISABLE 0x00
+#define DRAM_REFRESH_60HZ 0x08
+#define DRAM_REFRESH_FAST_TEST 0x10
+#define DRAM_REFRESH_RESERVED 0x18
+#define DRAM_SMS 0x07
+#define DRAM_SMS_NORMAL 0x00
+#define DRAM_SMS_NOP_ENABLE 0x01
+#define DRAM_SMS_ABPCE 0x02
+#define DRAM_SMS_MRCE 0x03
+#define DRAM_SMS_CBRCE 0x04
+
+/* p307
+ */
+#define DPMS_SYNC_SELECT 0x5002
+#define VSYNC_CNTL 0x08
+#define VSYNC_ON 0x00
+#define VSYNC_OFF 0x08
+#define HSYNC_CNTL 0x02
+#define HSYNC_ON 0x00
+#define HSYNC_OFF 0x02
+
+#define GPIOA 0x5010
+#define GPIOB 0x5014
+#define GPIOC 0x5018
+#define GPIOD 0x501c
+#define GPIOE 0x5020
+#define GPIOF 0x5024
+#define GPIOG 0x5028
+#define GPIOH 0x502c
+# define GPIO_CLOCK_DIR_MASK (1 << 0)
+# define GPIO_CLOCK_DIR_IN (0 << 1)
+# define GPIO_CLOCK_DIR_OUT (1 << 1)
+# define GPIO_CLOCK_VAL_MASK (1 << 2)
+# define GPIO_CLOCK_VAL_OUT (1 << 3)
+# define GPIO_CLOCK_VAL_IN (1 << 4)
+# define GPIO_CLOCK_PULLUP_DISABLE (1 << 5)
+# define GPIO_DATA_DIR_MASK (1 << 8)
+# define GPIO_DATA_DIR_IN (0 << 9)
+# define GPIO_DATA_DIR_OUT (1 << 9)
+# define GPIO_DATA_VAL_MASK (1 << 10)
+# define GPIO_DATA_VAL_OUT (1 << 11)
+# define GPIO_DATA_VAL_IN (1 << 12)
+# define GPIO_DATA_PULLUP_DISABLE (1 << 13)
+
+/* GMBus registers for hardware-assisted (non-bitbanging) I2C access */
+#define GMBUS0 0x5100
+#define GMBUS1 0x5104
+#define GMBUS2 0x5108
+#define GMBUS3 0x510c
+#define GMBUS4 0x5110
+#define GMBUS5 0x5120
+
+/* p317, 319
+ */
+#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */
+#define VCLK2_VCO_N 0x600a
+#define VCLK2_VCO_DIV_SEL 0x6012
+
+#define VCLK_DIVISOR_VGA0 0x6000
+#define VCLK_DIVISOR_VGA1 0x6004
+#define VCLK_POST_DIV 0x6010
+/* Selects a post divisor of 4 instead of 2. */
+# define VGA1_PD_P2_DIV_4 (1 << 15)
+/* Overrides the p2 post divisor field */
+# define VGA1_PD_P1_DIV_2 (1 << 13)
+# define VGA1_PD_P1_SHIFT 8
+/* P1 value is 2 greater than this field */
+# define VGA1_PD_P1_MASK (0x1f << 8)
+/* Selects a post divisor of 4 instead of 2. */
+# define VGA0_PD_P2_DIV_4 (1 << 7)
+/* Overrides the p2 post divisor field */
+# define VGA0_PD_P1_DIV_2 (1 << 5)
+# define VGA0_PD_P1_SHIFT 0
+/* P1 value is 2 greater than this field */
+# define VGA0_PD_P1_MASK (0x1f << 0)
+
+#define POST_DIV_SELECT 0x70
+#define POST_DIV_1 0x00
+#define POST_DIV_2 0x10
+#define POST_DIV_4 0x20
+#define POST_DIV_8 0x30
+#define POST_DIV_16 0x40
+#define POST_DIV_32 0x50
+#define VCO_LOOP_DIV_BY_4M 0x00
+#define VCO_LOOP_DIV_BY_16M 0x04
+
+
+/* Instruction Parser Mode Register
+ * - p281
+ * - 2 new bits.
+ */
+#define INST_PM 0x20c0
+#define AGP_SYNC_PACKET_FLUSH_ENABLE 0x20 /* reserved */
+#define SYNC_PACKET_FLUSH_ENABLE 0x10
+#define TWO_D_INST_DISABLE 0x08
+#define THREE_D_INST_DISABLE 0x04
+#define STATE_VAR_UPDATE_DISABLE 0x02
+#define PAL_STIP_DISABLE 0x01
+#define GEN6_GLOBAL_DEBUG_ENABLE 0x10
+
+
+#define MEMMODE 0x20dc
+
+
+/* Instruction parser error register. p279
+ */
+#define IPEIR 0x2088
+#define IPEHR 0x208C
+
+#define INSTDONE 0x2090
+#define NOP_ID 0x2094
+
+#define SCPD0 0x209c /* debug */
+#define INST_PS 0x20c4
+#define IPEIR_I965 0x2064 /* i965 */
+#define IPEHR_I965 0x2068 /* i965 */
+#define INSTDONE_I965 0x206c
+#define GEN6_INSTDONE_1 0x206c
+#define INST_PS_I965 0x2070
+
+/* Current active ring head address:
+ */
+#define ACTHD_I965 0x2074
+#define ACTHD 0x20C8
+
+/* Current primary/secondary DMA fetch addresses:
+ */
+#define DMA_FADD_P 0x2078
+#define DMA_FADD_S 0x20d4
+#define INSTDONE_1 0x207c
+#define GEN6_INSTDONE_2 0x207c
+
+#define CACHE_MODE_0 0x2120
+#define CACHE_MODE_1 0x2124
+#define MI_MODE 0x209c
+#define MI_DISPLAY_POWER_DOWN 0x20e0
+#define MI_ARB_STATE 0x20e4
+#define MI_RDRET_STATE 0x20fc
+
+/* Start addresses for each of the primary rings:
+ */
+#define PR0_STR 0x20f0
+#define PR1_STR 0x20f4
+#define PR2_STR 0x20f8
+
+#define WIZ_CTL 0x7c00
+#define WIZ_CTL_SINGLE_SUBSPAN (1<<6)
+#define WIZ_CTL_IGNORE_STALLS (1<<5)
+
+#define SVG_WORK_CTL 0x7408
+
+#define TS_CTL 0x7e00
+#define TS_MUX_ERR_CODE (0<<8)
+#define TS_MUX_URB_0 (1<<8)
+#define TS_MUX_DISPATCH_ID_0 (10<<8)
+#define TS_MUX_ERR_CODE_VALID (15<<8)
+#define TS_MUX_TID_0 (16<<8)
+#define TS_MUX_EUID_0 (18<<8)
+#define TS_MUX_FFID_0 (22<<8)
+#define TS_MUX_EOT (26<<8)
+#define TS_MUX_SIDEBAND_0 (27<<8)
+#define TS_SNAP_ALL_CHILD (1<<2)
+#define TS_SNAP_ALL_ROOT (1<<1)
+#define TS_SNAP_ENABLE (1<<0)
+
+#define TS_DEBUG_DATA 0x7e0c
+
+#define TD_CTL 0x8000
+#define TD_CTL2 0x8004
+
+
+#define ECOSKPD 0x21d0
+#define EXCC 0x2028
+
+/* I965 debug regs:
+ */
+#define IA_VERTICES_COUNT_QW 0x2310
+#define IA_PRIMITIVES_COUNT_QW 0x2318
+#define VS_INVOCATION_COUNT_QW 0x2320
+#define GS_INVOCATION_COUNT_QW 0x2328
+#define GS_PRIMITIVES_COUNT_QW 0x2330
+#define CL_INVOCATION_COUNT_QW 0x2338
+#define CL_PRIMITIVES_COUNT_QW 0x2340
+#define PS_INVOCATION_COUNT_QW 0x2348
+#define PS_DEPTH_COUNT_QW 0x2350
+#define TIMESTAMP_QW 0x2358
+#define CLKCMP_QW 0x2360
+
+
+
+
+
+
+/* General error reporting regs, p296
+ */
+#define EIR 0x20B0
+#define EMR 0x20B4
+#define ESR 0x20B8
+# define ERR_VERTEX_MAX (1 << 5) /* lpt/cst */
+# define ERR_PGTBL_ERROR (1 << 4)
+# define ERR_DISPLAY_OVERLAY_UNDERRUN (1 << 3)
+# define ERR_MAIN_MEMORY_REFRESH (1 << 1)
+# define ERR_INSTRUCTION_ERROR (1 << 0)
+
+
+/* Interrupt Control Registers
+ * - new bits for i810
+ * - new register hwstam (mask)
+ */
+#define HWS_PGA 0x2080
+#define PWRCTXA 0x2088 /* 965GM+ only */
+#define PWRCTX_EN (1<<0)
+#define HWSTAM 0x2098 /* p290 */
+#define IER 0x20a0 /* p291 */
+#define IIR 0x20a4 /* p292 */
+#define IMR 0x20a8 /* p293 */
+#define ISR 0x20ac /* p294 */
+#define HW_ERROR 0x8000
+#define SYNC_STATUS_TOGGLE 0x1000
+#define DPY_0_FLIP_PENDING 0x0800
+#define DPY_1_FLIP_PENDING 0x0400 /* not implemented on i810 */
+#define OVL_0_FLIP_PENDING 0x0200
+#define OVL_1_FLIP_PENDING 0x0100 /* not implemented on i810 */
+#define DPY_0_VBLANK 0x0080
+#define DPY_0_EVENT 0x0040
+#define DPY_1_VBLANK 0x0020 /* not implemented on i810 */
+#define DPY_1_EVENT 0x0010 /* not implemented on i810 */
+#define HOST_PORT_EVENT 0x0008 /* */
+#define CAPTURE_EVENT 0x0004 /* */
+#define USER_DEFINED 0x0002
+#define BREAKPOINT 0x0001
+
+
+#define INTR_RESERVED (0x6000 | \
+ DPY_1_FLIP_PENDING | \
+ OVL_1_FLIP_PENDING | \
+ DPY_1_VBLANK | \
+ DPY_1_EVENT | \
+ HOST_PORT_EVENT | \
+ CAPTURE_EVENT )
+
+/* FIFO Watermark and Burst Length Control Register
+ *
+ * - different offset and contents on i810 (p299) (fewer bits per field)
+ * - some overlay fields added
+ * - what does it all mean?
+ */
+#define FWATER_BLC 0x20d8
+#define FWATER_BLC2 0x20dc
+#define MM_BURST_LENGTH 0x00700000
+#define MM_FIFO_WATERMARK 0x0001F000
+#define LM_BURST_LENGTH 0x00000700
+#define LM_FIFO_WATERMARK 0x0000001F
+
+
+/* Fence/Tiling ranges [0..7]
+ */
+#define FENCE 0x2000
+#define FENCE_NR 8
+
+#define FENCE_NEW 0x3000
+#define FENCE_NEW_NR 16
+
+#define FENCE_LINEAR 0
+#define FENCE_XMAJOR 1
+#define FENCE_YMAJOR 2
+
+#define I915G_FENCE_START_MASK 0x0ff00000
+
+#define I830_FENCE_START_MASK 0x07f80000
+
+#define FENCE_START_MASK 0x03F80000
+#define FENCE_X_MAJOR 0x00000000
+#define FENCE_Y_MAJOR 0x00001000
+#define FENCE_SIZE_MASK 0x00000700
+#define FENCE_SIZE_512K 0x00000000
+#define FENCE_SIZE_1M 0x00000100
+#define FENCE_SIZE_2M 0x00000200
+#define FENCE_SIZE_4M 0x00000300
+#define FENCE_SIZE_8M 0x00000400
+#define FENCE_SIZE_16M 0x00000500
+#define FENCE_SIZE_32M 0x00000600
+#define FENCE_SIZE_64M 0x00000700
+#define I915G_FENCE_SIZE_1M 0x00000000
+#define I915G_FENCE_SIZE_2M 0x00000100
+#define I915G_FENCE_SIZE_4M 0x00000200
+#define I915G_FENCE_SIZE_8M 0x00000300
+#define I915G_FENCE_SIZE_16M 0x00000400
+#define I915G_FENCE_SIZE_32M 0x00000500
+#define I915G_FENCE_SIZE_64M 0x00000600
+#define I915G_FENCE_SIZE_128M 0x00000700
+#define I965_FENCE_X_MAJOR 0x00000000
+#define I965_FENCE_Y_MAJOR 0x00000002
+#define FENCE_PITCH_1 0x00000000
+#define FENCE_PITCH_2 0x00000010
+#define FENCE_PITCH_4 0x00000020
+#define FENCE_PITCH_8 0x00000030
+#define FENCE_PITCH_16 0x00000040
+#define FENCE_PITCH_32 0x00000050
+#define FENCE_PITCH_64 0x00000060
+#define FENCE_VALID 0x00000001
+
+#define FENCE_REG_SANDYBRIDGE_0 0x100000
+
+/* Registers to control page table, p274
+ */
+#define PGETBL_CTL 0x2020
+#define PGETBL_ADDR_MASK 0xFFFFF000
+#define PGETBL_ENABLE_MASK 0x00000001
+#define PGETBL_ENABLED 0x00000001
+/* Added in 965G, this field has the actual size of the global GTT */
+#define PGETBL_SIZE_MASK 0x0000000e
+#define PGETBL_SIZE_512KB (0 << 1)
+#define PGETBL_SIZE_256KB (1 << 1)
+#define PGETBL_SIZE_128KB (2 << 1)
+#define PGETBL_SIZE_1MB (3 << 1)
+#define PGETBL_SIZE_2MB (4 << 1)
+#define PGETBL_SIZE_1_5MB (5 << 1)
+#define G33_PGETBL_SIZE_MASK (3 << 8)
+#define G33_PGETBL_SIZE_1M (1 << 8)
+#define G33_PGETBL_SIZE_2M (2 << 8)
+
+#define I830_PTE_BASE 0x10000
+#define PTE_ADDRESS_MASK 0xfffff000
+#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
+#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
+#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */
+#define PTE_MAPPING_TYPE_CACHED (3 << 1)
+#define PTE_MAPPING_TYPE_MASK (3 << 1)
+#define PTE_VALID (1 << 0)
+
+/* @defgroup PGE_ERR
+ * @{
+ */
+/* Page table debug register for i845 */
+#define PGE_ERR 0x2024
+#define PGE_ERR_ADDR_MASK 0xFFFFF000
+#define PGE_ERR_ID_MASK 0x00000038
+#define PGE_ERR_CAPTURE 0x00000000
+#define PGE_ERR_OVERLAY 0x00000008
+#define PGE_ERR_DISPLAY 0x00000010
+#define PGE_ERR_HOST 0x00000018
+#define PGE_ERR_RENDER 0x00000020
+#define PGE_ERR_BLITTER 0x00000028
+#define PGE_ERR_MAPPING 0x00000030
+#define PGE_ERR_CMD_PARSER 0x00000038
+#define PGE_ERR_TYPE_MASK 0x00000007
+#define PGE_ERR_INV_TABLE 0x00000000
+#define PGE_ERR_INV_PTE 0x00000001
+#define PGE_ERR_MIXED_TYPES 0x00000002
+#define PGE_ERR_PAGE_MISS 0x00000003
+#define PGE_ERR_ILLEGAL_TRX 0x00000004
+#define PGE_ERR_LOCAL_MEM 0x00000005
+#define PGE_ERR_TILED 0x00000006
+/* @} */
+
+/* @defgroup PGTBL_ER
+ * @{
+ */
+/* Page table debug register for i945 */
+# define PGTBL_ER 0x2024
+# define PGTBL_ERR_MT_TILING (1 << 27)
+# define PGTBL_ERR_MT_GTT_PTE (1 << 26)
+# define PGTBL_ERR_LC_TILING (1 << 25)
+# define PGTBL_ERR_LC_GTT_PTE (1 << 24)
+# define PGTBL_ERR_BIN_VERTEXDATA_GTT_PTE (1 << 23)
+# define PGTBL_ERR_BIN_INSTRUCTION_GTT_PTE (1 << 22)
+# define PGTBL_ERR_CS_VERTEXDATA_GTT_PTE (1 << 21)
+# define PGTBL_ERR_CS_INSTRUCTION_GTT_PTE (1 << 20)
+# define PGTBL_ERR_CS_GTT (1 << 19)
+# define PGTBL_ERR_OVERLAY_TILING (1 << 18)
+# define PGTBL_ERR_OVERLAY_GTT_PTE (1 << 16)
+# define PGTBL_ERR_DISPC_TILING (1 << 14)
+# define PGTBL_ERR_DISPC_GTT_PTE (1 << 12)
+# define PGTBL_ERR_DISPB_TILING (1 << 10)
+# define PGTBL_ERR_DISPB_GTT_PTE (1 << 8)
+# define PGTBL_ERR_DISPA_TILING (1 << 6)
+# define PGTBL_ERR_DISPA_GTT_PTE (1 << 4)
+# define PGTBL_ERR_HOST_PTE_DATA (1 << 1)
+# define PGTBL_ERR_HOST_GTT_PTE (1 << 0)
+/* @} */
+
+/* Ring buffer registers, p277, overview p19
+ */
+#define LP_RING 0x2030
+#define HP_RING 0x2040
+
+#define RING_TAIL 0x00
+#define TAIL_ADDR 0x000FFFF8
+#define I830_TAIL_MASK 0x001FFFF8
+
+#define RING_HEAD 0x04
+#define HEAD_WRAP_COUNT 0xFFE00000
+#define HEAD_WRAP_ONE 0x00200000
+#define HEAD_ADDR 0x001FFFFC
+#define I830_HEAD_MASK 0x001FFFFC
+
+#define RING_START 0x08
+#define START_ADDR 0x03FFFFF8
+#define I830_RING_START_MASK 0xFFFFF000
+
+#define RING_LEN 0x0C
+#define RING_NR_PAGES 0x001FF000
+#define I830_RING_NR_PAGES 0x001FF000
+#define RING_REPORT_MASK 0x00000006
+#define RING_REPORT_64K 0x00000002
+#define RING_REPORT_128K 0x00000004
+#define RING_NO_REPORT 0x00000000
+#define RING_VALID_MASK 0x00000001
+#define RING_VALID 0x00000001
+#define RING_INVALID 0x00000000
+
+
+
+/* BitBlt Instructions
+ *
+ * There are many more masks & ranges yet to add.
+ */
+#define BR00_BITBLT_CLIENT 0x40000000
+#define BR00_OP_COLOR_BLT 0x10000000
+#define BR00_OP_SRC_COPY_BLT 0x10C00000
+#define BR00_OP_FULL_BLT 0x11400000
+#define BR00_OP_MONO_SRC_BLT 0x11800000
+#define BR00_OP_MONO_SRC_COPY_BLT 0x11000000
+#define BR00_OP_MONO_PAT_BLT 0x11C00000
+#define BR00_OP_MONO_SRC_COPY_IMMEDIATE_BLT (0x61 << 22)
+#define BR00_OP_TEXT_IMMEDIATE_BLT 0xc000000
+
+
+#define BR00_TPCY_DISABLE 0x00000000
+#define BR00_TPCY_ENABLE 0x00000010
+
+#define BR00_TPCY_ROP 0x00000000
+#define BR00_TPCY_NO_ROP 0x00000020
+#define BR00_TPCY_EQ 0x00000000
+#define BR00_TPCY_NOT_EQ 0x00000040
+
+#define BR00_PAT_MSB_FIRST 0x00000000 /* ? */
+
+#define BR00_PAT_VERT_ALIGN 0x000000e0
+
+#define BR00_LENGTH 0x0000000F
+
+#define BR09_DEST_ADDR 0x03FFFFFF
+
+#define BR11_SOURCE_PITCH 0x00003FFF
+
+#define BR12_SOURCE_ADDR 0x03FFFFFF
+
+#define BR13_SOLID_PATTERN 0x80000000
+#define BR13_RIGHT_TO_LEFT 0x40000000
+#define BR13_LEFT_TO_RIGHT 0x00000000
+#define BR13_MONO_TRANSPCY 0x20000000
+#define BR13_MONO_PATN_TRANS 0x10000000
+#define BR13_USE_DYN_DEPTH 0x04000000
+#define BR13_DYN_8BPP 0x00000000
+#define BR13_DYN_16BPP 0x01000000
+#define BR13_DYN_24BPP 0x02000000
+#define BR13_ROP_MASK 0x00FF0000
+#define BR13_DEST_PITCH 0x0000FFFF
+#define BR13_PITCH_SIGN_BIT 0x00008000
+
+#define BR14_DEST_HEIGHT 0xFFFF0000
+#define BR14_DEST_WIDTH 0x0000FFFF
+
+#define BR15_PATTERN_ADDR 0x03FFFFFF
+
+#define BR16_SOLID_PAT_COLOR 0x00FFFFFF
+#define BR16_BACKGND_PAT_CLR 0x00FFFFFF
+
+#define BR17_FGND_PAT_CLR 0x00FFFFFF
+
+#define BR18_SRC_BGND_CLR 0x00FFFFFF
+#define BR19_SRC_FGND_CLR 0x00FFFFFF
+
+
+/* Instruction parser instructions
+ */
+
+#define INST_PARSER_CLIENT 0x00000000
+#define INST_OP_FLUSH 0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
+
+
+/* Registers in the i810 host-pci bridge pci config space which affect
+ * the i810 graphics operations.
+ */
+#define SMRAM_MISCC 0x70
+#define GMS 0x000000c0
+#define GMS_DISABLE 0x00000000
+#define GMS_ENABLE_BARE 0x00000040
+#define GMS_ENABLE_512K 0x00000080
+#define GMS_ENABLE_1M 0x000000c0
+#define USMM 0x00000030
+#define USMM_DISABLE 0x00000000
+#define USMM_TSEG_ZERO 0x00000010
+#define USMM_TSEG_512K 0x00000020
+#define USMM_TSEG_1M 0x00000030
+#define GFX_MEM_WIN_SIZE 0x00010000
+#define GFX_MEM_WIN_32M 0x00010000
+#define GFX_MEM_WIN_64M 0x00000000
+
+/* Overkill? I don't know. Need to figure out top of mem to make the
+ * SMRAM calculations come out. Linux seems to have problems
+ * detecting it all on its own, so this seems a reasonable double
+ * check to any user supplied 'mem=...' boot param.
+ *
+ * ... unfortunately this reg doesn't work according to spec on the
+ * test hardware.
+ */
+#define WHTCFG_PAMR_DRP 0x50
+#define SYS_DRAM_ROW_0_SHIFT 16
+#define SYS_DRAM_ROW_1_SHIFT 20
+#define DRAM_MASK 0x0f
+#define DRAM_VALUE_0 0
+#define DRAM_VALUE_1 8
+/* No 2 value defined */
+#define DRAM_VALUE_3 16
+#define DRAM_VALUE_4 16
+#define DRAM_VALUE_5 24
+#define DRAM_VALUE_6 32
+#define DRAM_VALUE_7 32
+#define DRAM_VALUE_8 48
+#define DRAM_VALUE_9 64
+#define DRAM_VALUE_A 64
+#define DRAM_VALUE_B 96
+#define DRAM_VALUE_C 128
+#define DRAM_VALUE_D 128
+#define DRAM_VALUE_E 192
+#define DRAM_VALUE_F 256 /* nice one, geezer */
+#define LM_FREQ_MASK 0x10
+#define LM_FREQ_133 0x10
+#define LM_FREQ_100 0x00
+
+
+
+
+/* These are 3d state registers, but the state is invarient, so we let
+ * the X server handle it:
+ */
+
+
+
+/* GFXRENDERSTATE_COLOR_CHROMA_KEY, p135
+ */
+#define GFX_OP_COLOR_CHROMA_KEY ((0x3<<29)|(0x1d<<24)|(0x2<<16)|0x1)
+#define CC1_UPDATE_KILL_WRITE (1<<28)
+#define CC1_ENABLE_KILL_WRITE (1<<27)
+#define CC1_DISABLE_KILL_WRITE 0
+#define CC1_UPDATE_COLOR_IDX (1<<26)
+#define CC1_UPDATE_CHROMA_LOW (1<<25)
+#define CC1_UPDATE_CHROMA_HI (1<<24)
+#define CC1_CHROMA_LOW_MASK ((1<<24)-1)
+#define CC2_COLOR_IDX_SHIFT 24
+#define CC2_COLOR_IDX_MASK (0xff<<24)
+#define CC2_CHROMA_HI_MASK ((1<<24)-1)
+
+
+#define GFX_CMD_CONTEXT_SEL ((0<<29)|(0x5<<23))
+#define CS_UPDATE_LOAD (1<<17)
+#define CS_UPDATE_USE (1<<16)
+#define CS_UPDATE_LOAD (1<<17)
+#define CS_LOAD_CTX0 0
+#define CS_LOAD_CTX1 (1<<8)
+#define CS_USE_CTX0 0
+#define CS_USE_CTX1 (1<<0)
+
+/* I810 LCD/TV registers */
+#define LCD_TV_HTOTAL 0x60000
+#define LCD_TV_C 0x60018
+#define LCD_TV_OVRACT 0x6001C
+
+#define LCD_TV_ENABLE (1 << 31)
+#define LCD_TV_VGAMOD (1 << 28)
+
+/* I830 CRTC registers */
+#define HTOTAL_A 0x60000
+#define HBLANK_A 0x60004
+#define HSYNC_A 0x60008
+#define VTOTAL_A 0x6000c
+#define VBLANK_A 0x60010
+#define VSYNC_A 0x60014
+#define PIPEASRC 0x6001c
+#define BCLRPAT_A 0x60020
+#define VSYNCSHIFT_A 0x60028
+
+#define HTOTAL_B 0x61000
+#define HBLANK_B 0x61004
+#define HSYNC_B 0x61008
+#define VTOTAL_B 0x6100c
+#define VBLANK_B 0x61010
+#define VSYNC_B 0x61014
+#define PIPEBSRC 0x6101c
+#define BCLRPAT_B 0x61020
+#define VSYNCSHIFT_B 0x61028
+
+#define HTOTAL_C 0x62000
+#define HBLANK_C 0x62004
+#define HSYNC_C 0x62008
+#define VTOTAL_C 0x6200c
+#define VBLANK_C 0x62010
+#define VSYNC_C 0x62014
+#define PIPECSRC 0x6201c
+#define BCLRPAT_C 0x62020
+#define VSYNCSHIFT_C 0x62028
+
+#define HTOTAL_EDP 0x6F000
+#define HBLANK_EDP 0x6F004
+#define HSYNC_EDP 0x6F008
+#define VTOTAL_EDP 0x6F00c
+#define VBLANK_EDP 0x6F010
+#define VSYNC_EDP 0x6F014
+#define VSYNCSHIFT_EDP 0x6F028
+
+#define PP_STATUS 0x61200
+# define PP_ON (1 << 31)
+/*
+ * Indicates that all dependencies of the panel are on:
+ *
+ * - PLL enabled
+ * - pipe enabled
+ * - LVDS/DVOB/DVOC on
+ */
+# define PP_READY (1 << 30)
+# define PP_SEQUENCE_NONE (0 << 28)
+# define PP_SEQUENCE_ON (1 << 28)
+# define PP_SEQUENCE_OFF (2 << 28)
+# define PP_SEQUENCE_MASK 0x30000000
+
+#define PP_CONTROL 0x61204
+# define POWER_DOWN_ON_RESET (1 << 1)
+# define POWER_TARGET_ON (1 << 0)
+
+#define PP_ON_DELAYS 0x61208
+#define PP_OFF_DELAYS 0x6120c
+#define PP_DIVISOR 0x61210
+
+#define PFIT_CONTROL 0x61230
+# define PFIT_ENABLE (1 << 31)
+/* Pre-965 */
+# define VERT_INTERP_DISABLE (0 << 10)
+# define VERT_INTERP_BILINEAR (1 << 10)
+# define VERT_INTERP_MASK (3 << 10)
+# define VERT_AUTO_SCALE (1 << 9)
+# define HORIZ_INTERP_DISABLE (0 << 6)
+# define HORIZ_INTERP_BILINEAR (1 << 6)
+# define HORIZ_INTERP_MASK (3 << 6)
+# define HORIZ_AUTO_SCALE (1 << 5)
+# define PANEL_8TO6_DITHER_ENABLE (1 << 3)
+/* 965+ */
+# define PFIT_PIPE_MASK (3 << 29)
+# define PFIT_PIPE_SHIFT 29
+# define PFIT_SCALING_MODE_MASK (7 << 26)
+# define PFIT_SCALING_AUTO (0 << 26)
+# define PFIT_SCALING_PROGRAMMED (1 << 26)
+# define PFIT_SCALING_PILLAR (2 << 26)
+# define PFIT_SCALING_LETTER (3 << 26)
+# define PFIT_FILTER_SELECT_MASK (3 << 24)
+# define PFIT_FILTER_FUZZY (0 << 24)
+# define PFIT_FILTER_CRISP (1 << 24)
+# define PFIT_FILTER_MEDIAN (2 << 24)
+
+#define PFIT_PGM_RATIOS 0x61234
+/* Pre-965 */
+# define PFIT_VERT_SCALE_SHIFT 20
+# define PFIT_VERT_SCALE_MASK 0xfff00000
+# define PFIT_HORIZ_SCALE_SHIFT 4
+# define PFIT_HORIZ_SCALE_MASK 0x0000fff0
+/* 965+ */
+# define PFIT_VERT_SCALE_SHIFT_965 16
+# define PFIT_VERT_SCALE_MASK_965 0x1fff0000
+# define PFIT_HORIZ_SCALE_SHIFT_965 0
+# define PFIT_HORIZ_SCALE_MASK_965 0x00001fff
+
+#define DPLL_A 0x06014
+#define DPLL_B 0x06018
+# define DPLL_VCO_ENABLE (1 << 31)
+# define DPLL_DVO_HIGH_SPEED (1 << 30)
+# define DPLL_SYNCLOCK_ENABLE (1 << 29)
+# define DPLL_VGA_MODE_DIS (1 << 28)
+# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */
+# define DPLLB_MODE_LVDS (2 << 26) /* i915 */
+# define DPLL_MODE_MASK (3 << 26)
+# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
+# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
+# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */
+# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
+# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
+# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
+# define DPLL_FPA01_P1_POST_DIV_MASK_IGD 0x00ff8000 /* IGD */
+/*
+ * The i830 generation, in DAC/serial mode, defines p1 as two plus this
+ * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set.
+ */
+# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
+/*
+ * The i830 generation, in LVDS mode, defines P1 as the bit number set within
+ * this field (only one bit may be set).
+ */
+# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000
+# define DPLL_FPA01_P1_POST_DIV_SHIFT 16
+# define DPLL_FPA01_P1_POST_DIV_SHIFT_IGD 15
+# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */
+# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */
+# define PLL_REF_INPUT_DREFCLK (0 << 13)
+# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */
+# define PLL_REF_INPUT_SUPER_SSC (1 << 13) /* Ironlake: 120M SSC */
+# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */
+# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
+# define PLL_REF_INPUT_MASK (3 << 13)
+# define PLL_REF_INPUT_DMICLK (5 << 13) /* Ironlake: DMI refclk */
+# define PLL_LOAD_PULSE_PHASE_SHIFT 9
+/*
+ * Parallel to Serial Load Pulse phase selection.
+ * Selects the phase for the 10X DPLL clock for the PCIe
+ * digital display port. The range is 4 to 13; 10 or more
+ * is just a flip delay. The default is 6
+ */
+# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
+# define DISPLAY_RATE_SELECT_FPA1 (1 << 8)
+/* Ironlake */
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT 9
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK (7 << 9)
+# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x)-1)<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT)
+# define DPLL_FPA1_P1_POST_DIV_SHIFT 0
+# define DPLL_FPA1_P1_POST_DIV_MASK 0xff
+
+/*
+ * SDVO multiplier for 945G/GM. Not used on 965.
+ *
+ * \sa DPLL_MD_UDI_MULTIPLIER_MASK
+ */
+# define SDVO_MULTIPLIER_MASK 0x000000ff
+# define SDVO_MULTIPLIER_SHIFT_HIRES 4
+# define SDVO_MULTIPLIER_SHIFT_VGA 0
+
+/* @defgroup DPLL_MD
+ * @{
+ */
+/* Pipe A SDVO/UDI clock multiplier/divider register for G965. */
+#define DPLL_A_MD 0x0601c
+/* Pipe B SDVO/UDI clock multiplier/divider register for G965. */
+#define DPLL_B_MD 0x06020
+/*
+ * UDI pixel divider, controlling how many pixels are stuffed into a packet.
+ *
+ * Value is pixels minus 1. Must be set to 1 pixel for SDVO.
+ */
+# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000
+# define DPLL_MD_UDI_DIVIDER_SHIFT 24
+/* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
+# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000
+# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16
+/*
+ * SDVO/UDI pixel multiplier.
+ *
+ * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
+ * clock rate is 10 times the DPLL clock. At low resolution/refresh rate
+ * modes, the bus rate would be below the limits, so SDVO allows for stuffing
+ * dummy bytes in the datastream at an increased clock rate, with both sides of
+ * the link knowing how many bytes are fill.
+ *
+ * So, for a mode with a dotclock of 65Mhz, we would want to double the clock
+ * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be
+ * set to 130Mhz, and the SDVO multiplier set to 2x in this register and
+ * through an SDVO command.
+ *
+ * This register field has values of multiplication factor minus 1, with
+ * a maximum multiplier of 5 for SDVO.
+ */
+# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00
+# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8
+/* SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
+ * This best be set to the default value (3) or the CRT won't work. No,
+ * I don't entirely understand what this does...
+ */
+# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
+# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
+/* @} */
+
+#define DPLL_TEST 0x606c
+# define DPLLB_TEST_SDVO_DIV_1 (0 << 22)
+# define DPLLB_TEST_SDVO_DIV_2 (1 << 22)
+# define DPLLB_TEST_SDVO_DIV_4 (2 << 22)
+# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22)
+# define DPLLB_TEST_N_BYPASS (1 << 19)
+# define DPLLB_TEST_M_BYPASS (1 << 18)
+# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16)
+# define DPLLA_TEST_N_BYPASS (1 << 3)
+# define DPLLA_TEST_M_BYPASS (1 << 2)
+# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
+
+#define D_STATE 0x6104
+#define DSPCLK_GATE_D 0x6200
+# define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */
+# define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */
+# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */
+# define VRDUNIT_CLOCK_GATE_DISABLE (1 << 27) /* 965 */
+# define AUDUNIT_CLOCK_GATE_DISABLE (1 << 26) /* 965 */
+# define DPUNIT_A_CLOCK_GATE_DISABLE (1 << 25) /* 965 */
+# define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24) /* 965 */
+# define TVRUNIT_CLOCK_GATE_DISABLE (1 << 23) /* 915-945 */
+# define TVCUNIT_CLOCK_GATE_DISABLE (1 << 22) /* 915-945 */
+# define TVFUNIT_CLOCK_GATE_DISABLE (1 << 21) /* 915-945 */
+# define TVEUNIT_CLOCK_GATE_DISABLE (1 << 20) /* 915-945 */
+# define DVSUNIT_CLOCK_GATE_DISABLE (1 << 19) /* 915-945 */
+# define DSSUNIT_CLOCK_GATE_DISABLE (1 << 18) /* 915-945 */
+# define DDBUNIT_CLOCK_GATE_DISABLE (1 << 17) /* 915-945 */
+# define DPRUNIT_CLOCK_GATE_DISABLE (1 << 16) /* 915-945 */
+# define DPFUNIT_CLOCK_GATE_DISABLE (1 << 15) /* 915-945 */
+# define DPBMUNIT_CLOCK_GATE_DISABLE (1 << 14) /* 915-945 */
+# define DPLSUNIT_CLOCK_GATE_DISABLE (1 << 13) /* 915-945 */
+# define DPLUNIT_CLOCK_GATE_DISABLE (1 << 12) /* 915-945 */
+# define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11)
+# define DPBUNIT_CLOCK_GATE_DISABLE (1 << 10)
+# define DCUNIT_CLOCK_GATE_DISABLE (1 << 9)
+# define DPUNIT_CLOCK_GATE_DISABLE (1 << 8)
+# define VRUNIT_CLOCK_GATE_DISABLE (1 << 7) /* 915+: reserved */
+# define OVHUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 830-865 */
+# define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 915-945 */
+# define OVFUNIT_CLOCK_GATE_DISABLE (1 << 5)
+# define OVBUNIT_CLOCK_GATE_DISABLE (1 << 4)
+/*
+ * This bit must be set on the 830 to prevent hangs when turning off the
+ * overlay scaler.
+ */
+# define OVRUNIT_CLOCK_GATE_DISABLE (1 << 3)
+# define OVCUNIT_CLOCK_GATE_DISABLE (1 << 2)
+# define OVUUNIT_CLOCK_GATE_DISABLE (1 << 1)
+# define ZVUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 830 */
+# define OVLUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 845,865 */
+
+#define RENCLK_GATE_D1 0x6204
+# define BLITTER_CLOCK_GATE_DISABLE (1 << 13) /* 945GM only */
+# define MPEG_CLOCK_GATE_DISABLE (1 << 12) /* 945GM only */
+# define PC_FE_CLOCK_GATE_DISABLE (1 << 11)
+# define PC_BE_CLOCK_GATE_DISABLE (1 << 10)
+# define WINDOWER_CLOCK_GATE_DISABLE (1 << 9)
+# define INTERPOLATOR_CLOCK_GATE_DISABLE (1 << 8)
+# define COLOR_CALCULATOR_CLOCK_GATE_DISABLE (1 << 7)
+# define MOTION_COMP_CLOCK_GATE_DISABLE (1 << 6)
+# define MAG_CLOCK_GATE_DISABLE (1 << 5)
+/* This bit must be unset on 855,865 */
+# define MECI_CLOCK_GATE_DISABLE (1 << 4)
+# define DCMP_CLOCK_GATE_DISABLE (1 << 3)
+# define MEC_CLOCK_GATE_DISABLE (1 << 2)
+# define MECO_CLOCK_GATE_DISABLE (1 << 1)
+/* This bit must be set on 855,865. */
+# define SV_CLOCK_GATE_DISABLE (1 << 0)
+# define I915_MPEG_CLOCK_GATE_DISABLE (1 << 16)
+# define I915_VLD_IP_PR_CLOCK_GATE_DISABLE (1 << 15)
+# define I915_MOTION_COMP_CLOCK_GATE_DISABLE (1 << 14)
+# define I915_BD_BF_CLOCK_GATE_DISABLE (1 << 13)
+# define I915_SF_SE_CLOCK_GATE_DISABLE (1 << 12)
+# define I915_WM_CLOCK_GATE_DISABLE (1 << 11)
+# define I915_IZ_CLOCK_GATE_DISABLE (1 << 10)
+# define I915_PI_CLOCK_GATE_DISABLE (1 << 9)
+# define I915_DI_CLOCK_GATE_DISABLE (1 << 8)
+# define I915_SH_SV_CLOCK_GATE_DISABLE (1 << 7)
+# define I915_PL_DG_QC_FT_CLOCK_GATE_DISABLE (1 << 6)
+# define I915_SC_CLOCK_GATE_DISABLE (1 << 5)
+# define I915_FL_CLOCK_GATE_DISABLE (1 << 4)
+# define I915_DM_CLOCK_GATE_DISABLE (1 << 3)
+# define I915_PS_CLOCK_GATE_DISABLE (1 << 2)
+# define I915_CC_CLOCK_GATE_DISABLE (1 << 1)
+# define I915_BY_CLOCK_GATE_DISABLE (1 << 0)
+
+# define I965_RCZ_CLOCK_GATE_DISABLE (1 << 30)
+/* This bit must always be set on 965G/965GM */
+# define I965_RCC_CLOCK_GATE_DISABLE (1 << 29)
+# define I965_RCPB_CLOCK_GATE_DISABLE (1 << 28)
+# define I965_DAP_CLOCK_GATE_DISABLE (1 << 27)
+# define I965_ROC_CLOCK_GATE_DISABLE (1 << 26)
+# define I965_GW_CLOCK_GATE_DISABLE (1 << 25)
+# define I965_TD_CLOCK_GATE_DISABLE (1 << 24)
+/* This bit must always be set on 965G */
+# define I965_ISC_CLOCK_GATE_DISABLE (1 << 23)
+# define I965_IC_CLOCK_GATE_DISABLE (1 << 22)
+# define I965_EU_CLOCK_GATE_DISABLE (1 << 21)
+# define I965_IF_CLOCK_GATE_DISABLE (1 << 20)
+# define I965_TC_CLOCK_GATE_DISABLE (1 << 19)
+# define I965_SO_CLOCK_GATE_DISABLE (1 << 17)
+# define I965_FBC_CLOCK_GATE_DISABLE (1 << 16)
+# define I965_MARI_CLOCK_GATE_DISABLE (1 << 15)
+# define I965_MASF_CLOCK_GATE_DISABLE (1 << 14)
+# define I965_MAWB_CLOCK_GATE_DISABLE (1 << 13)
+# define I965_EM_CLOCK_GATE_DISABLE (1 << 12)
+# define I965_UC_CLOCK_GATE_DISABLE (1 << 11)
+# define I965_SI_CLOCK_GATE_DISABLE (1 << 6)
+# define I965_MT_CLOCK_GATE_DISABLE (1 << 5)
+# define I965_PL_CLOCK_GATE_DISABLE (1 << 4)
+# define I965_DG_CLOCK_GATE_DISABLE (1 << 3)
+# define I965_QC_CLOCK_GATE_DISABLE (1 << 2)
+# define I965_FT_CLOCK_GATE_DISABLE (1 << 1)
+# define I965_DM_CLOCK_GATE_DISABLE (1 << 0)
+
+#define RENCLK_GATE_D2 0x6208
+#define VF_UNIT_CLOCK_GATE_DISABLE (1 << 9)
+#define GS_UNIT_CLOCK_GATE_DISABLE (1 << 7)
+#define CL_UNIT_CLOCK_GATE_DISABLE (1 << 6)
+#define RAMCLK_GATE_D 0x6210 /* CRL only */
+#define DEUC 0x6214 /* CRL only */
+
+/*
+ * This is a PCI config space register to manipulate backlight brightness
+ * It is used when the BLM_LEGACY_MODE is turned on. When enabled, the first
+ * byte of this config register sets brightness within the range from
+ * 0 to 0xff
+ */
+#define LEGACY_BACKLIGHT_BRIGHTNESS 0xf4
+
+#define BLC_PWM_CTL 0x61254
+#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
+#define BACKLIGHT_MODULATION_FREQ_SHIFT2 (16)
+/*
+ * This is the most significant 15 bits of the number of backlight cycles in a
+ * complete cycle of the modulated backlight control.
+ *
+ * The actual value is this field multiplied by two.
+ */
+#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17)
+#define BACKLIGHT_MODULATION_FREQ_MASK2 (0xffff << 16)
+#define BLM_LEGACY_MODE (1 << 16)
+
+/*
+ * This is the number of cycles out of the backlight modulation cycle for which
+ * the backlight is on.
+ *
+ * This field must be no greater than the number of cycles in the complete
+ * backlight modulation cycle.
+ */
+#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
+#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
+
+/* On 965+ backlight control is in another register */
+#define BLC_PWM_CTL2 0x61250
+#define BLM_LEGACY_MODE2 (1 << 30)
+
+#define BLM_CTL 0x61260
+#define BLM_THRESHOLD_0 0x61270
+#define BLM_THRESHOLD_1 0x61274
+#define BLM_THRESHOLD_2 0x61278
+#define BLM_THRESHOLD_3 0x6127c
+#define BLM_THRESHOLD_4 0x61280
+#define BLM_THRESHOLD_5 0x61284
+
+#define BLM_ACCUMULATOR_0 0x61290
+#define BLM_ACCUMULATOR_1 0x61294
+#define BLM_ACCUMULATOR_2 0x61298
+#define BLM_ACCUMULATOR_3 0x6129c
+#define BLM_ACCUMULATOR_4 0x612a0
+#define BLM_ACCUMULATOR_5 0x612a4
+
+#define FPA0 0x06040
+#define FPA1 0x06044
+#define FPB0 0x06048
+#define FPB1 0x0604c
+# define FP_N_DIV_MASK 0x003f0000
+# define FP_N_IGD_DIV_MASK 0x00ff0000
+# define FP_N_DIV_SHIFT 16
+# define FP_M1_DIV_MASK 0x00003f00
+# define FP_M1_DIV_SHIFT 8
+# define FP_M2_DIV_MASK 0x0000003f
+# define FP_M2_IGD_DIV_MASK 0x000000ff
+# define FP_M2_DIV_SHIFT 0
+
+#define PORT_HOTPLUG_EN 0x61110
+# define HDMIB_HOTPLUG_INT_EN (1 << 29)
+# define HDMIC_HOTPLUG_INT_EN (1 << 28)
+# define HDMID_HOTPLUG_INT_EN (1 << 27)
+# define SDVOB_HOTPLUG_INT_EN (1 << 26)
+# define SDVOC_HOTPLUG_INT_EN (1 << 25)
+# define TV_HOTPLUG_INT_EN (1 << 18)
+# define CRT_HOTPLUG_INT_EN (1 << 9)
+# define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8)
+/* must use period 64 on GM45 according to docs */
+# define CRT_HOTPLUG_ACTIVATION_PERIOD_64 (1 << 8)
+# define CRT_HOTPLUG_DAC_ON_TIME_2M (0 << 7)
+# define CRT_HOTPLUG_DAC_ON_TIME_4M (1 << 7)
+# define CRT_HOTPLUG_VOLTAGE_COMPARE_40 (0 << 5)
+# define CRT_HOTPLUG_VOLTAGE_COMPARE_50 (1 << 5)
+# define CRT_HOTPLUG_VOLTAGE_COMPARE_60 (2 << 5)
+# define CRT_HOTPLUG_VOLTAGE_COMPARE_70 (3 << 5)
+# define CRT_HOTPLUG_VOLTAGE_COMPARE_MASK (3 << 5)
+# define CRT_HOTPLUG_DETECT_DELAY_1G (0 << 4)
+# define CRT_HOTPLUG_DETECT_DELAY_2G (1 << 4)
+# define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
+# define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2)
+# define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
+# define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */
+
+#define PORT_HOTPLUG_STAT 0x61114
+# define HDMIB_HOTPLUG_INT_STATUS (1 << 29)
+# define HDMIC_HOTPLUG_INT_STATUS (1 << 28)
+# define HDMID_HOTPLUG_INT_STATUS (1 << 27)
+# define CRT_HOTPLUG_INT_STATUS (1 << 11)
+# define TV_HOTPLUG_INT_STATUS (1 << 10)
+# define CRT_HOTPLUG_MONITOR_MASK (3 << 8)
+# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8)
+# define CRT_HOTPLUG_MONITOR_MONO (2 << 8)
+# define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
+# define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
+# define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
+
+#define SDVOB 0x61140
+#define SDVOC 0x61160
+#define SDVO_ENABLE (1 << 31)
+#define SDVO_PIPE_B_SELECT (1 << 30)
+#define SDVO_STALL_SELECT (1 << 29)
+#define SDVO_INTERRUPT_ENABLE (1 << 26)
+
+#define DISPLAY_HOTPLUG_CTL 0x61164
+/*
+ * 915G/GM SDVO pixel multiplier.
+ *
+ * Programmed value is multiplier - 1, up to 5x.
+ *
+ * \sa DPLL_MD_UDI_MULTIPLIER_MASK
+ */
+#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
+#define SDVO_PORT_MULTIPLY_SHIFT 23
+#define SDVO_PHASE_SELECT_MASK (15 << 19)
+#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
+#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
+#define SDVOC_GANG_MODE (1 << 16)
+#define SDVO_ENCODING_SDVO (0x0 << 10)
+#define SDVO_ENCODING_HDMI (0x2 << 10)
+/* Requird for HDMI operation */
+#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9)
+#define SDVO_BORDER_ENABLE (1 << 7)
+#define SDVO_AUDIO_ENABLE (1 << 6)
+/* New with 965, default is to be set */
+#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4)
+/* New with 965, default is to be set */
+#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3)
+/* 915/945 only, read-only bit */
+#define SDVOB_PCIE_CONCURRENCY (1 << 3)
+#define SDVO_DETECTED (1 << 2)
+/* Bits to be preserved when writing */
+#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14))
+#define SDVOC_PRESERVE_MASK (1 << 17)
+
+#define UDIB_SVB_SHB_CODES 0x61144
+#define UDIB_SHA_BLANK_CODES 0x61148
+#define UDIB_START_END_FILL_CODES 0x6114c
+
+
+#define SDVOUDI 0x61150
+
+#define I830_HTOTAL_MASK 0xfff0000
+#define I830_HACTIVE_MASK 0x7ff
+
+#define I830_HBLANKEND_MASK 0xfff0000
+#define I830_HBLANKSTART_MASK 0xfff
+
+#define I830_HSYNCEND_MASK 0xfff0000
+#define I830_HSYNCSTART_MASK 0xfff
+
+#define I830_VTOTAL_MASK 0xfff0000
+#define I830_VACTIVE_MASK 0x7ff
+
+#define I830_VBLANKEND_MASK 0xfff0000
+#define I830_VBLANKSTART_MASK 0xfff
+
+#define I830_VSYNCEND_MASK 0xfff0000
+#define I830_VSYNCSTART_MASK 0xfff
+
+#define I830_PIPEA_HORZ_MASK 0x7ff0000
+#define I830_PIPEA_VERT_MASK 0x7ff
+
+#define ADPA 0x61100
+#define ADPA_DAC_ENABLE (1<<31)
+#define ADPA_DAC_DISABLE 0
+#define ADPA_PIPE_SELECT_MASK (1<<30)
+#define ADPA_PIPE_A_SELECT 0
+#define ADPA_PIPE_B_SELECT (1<<30)
+#define ADPA_USE_VGA_HVPOLARITY (1<<15)
+#define ADPA_SETS_HVPOLARITY 0
+#define ADPA_VSYNC_CNTL_DISABLE (1<<11)
+#define ADPA_VSYNC_CNTL_ENABLE 0
+#define ADPA_HSYNC_CNTL_DISABLE (1<<10)
+#define ADPA_HSYNC_CNTL_ENABLE 0
+#define ADPA_VSYNC_ACTIVE_HIGH (1<<4)
+#define ADPA_VSYNC_ACTIVE_LOW 0
+#define ADPA_HSYNC_ACTIVE_HIGH (1<<3)
+#define ADPA_HSYNC_ACTIVE_LOW 0
+
+#define PCH_DSP_CHICKEN1 0x42000
+#define PCH_DSP_CHICKEN2 0x42004
+#define PCH_DSP_CHICKEN3 0x4200c
+#define PCH_DSPCLK_GATE_D 0x42020
+#define PCH_DSPRAMCLK_GATE_D 0x42024
+#define PCH_3DCGDIS0 0x46020
+#define PCH_3DCGDIS1 0x46024
+#define PCH_3DRAMCGDIS0 0x46028
+#define SOUTH_DSPCLK_GATE_D 0xc2020
+
+#define CPU_eDP_A 0x64000
+#define PCH_DP_B 0xe4100
+#define PCH_DP_C 0xe4200
+#define PCH_DP_D 0xe4300
+
+#define DVOA 0x61120
+#define DVOB 0x61140
+#define DVOC 0x61160
+#define DVO_ENABLE (1 << 31)
+#define DVO_PIPE_B_SELECT (1 << 30)
+#define DVO_PIPE_STALL_UNUSED (0 << 28)
+#define DVO_PIPE_STALL (1 << 28)
+#define DVO_PIPE_STALL_TV (2 << 28)
+#define DVO_PIPE_STALL_MASK (3 << 28)
+#define DVO_USE_VGA_SYNC (1 << 15)
+#define DVO_DATA_ORDER_I740 (0 << 14)
+#define DVO_DATA_ORDER_FP (1 << 14)
+#define DVO_VSYNC_DISABLE (1 << 11)
+#define DVO_HSYNC_DISABLE (1 << 10)
+#define DVO_VSYNC_TRISTATE (1 << 9)
+#define DVO_HSYNC_TRISTATE (1 << 8)
+#define DVO_BORDER_ENABLE (1 << 7)
+#define DVO_DATA_ORDER_GBRG (1 << 6)
+#define DVO_DATA_ORDER_RGGB (0 << 6)
+#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6)
+#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6)
+#define DVO_VSYNC_ACTIVE_HIGH (1 << 4)
+#define DVO_HSYNC_ACTIVE_HIGH (1 << 3)
+#define DVO_BLANK_ACTIVE_HIGH (1 << 2)
+#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */
+#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */
+#define DVO_PRESERVE_MASK (0x7<<24)
+
+#define DVOA_SRCDIM 0x61124
+#define DVOB_SRCDIM 0x61144
+#define DVOC_SRCDIM 0x61164
+#define DVO_SRCDIM_HORIZONTAL_SHIFT 12
+#define DVO_SRCDIM_VERTICAL_SHIFT 0
+
+/* @defgroup LVDS
+ * @{
+ */
+/*
+ * This register controls the LVDS output enable, pipe selection, and data
+ * format selection.
+ *
+ * All of the clock/data pairs are force powered down by power sequencing.
+ */
+#define LVDS 0x61180
+/*
+ * Enables the LVDS port. This bit must be set before DPLLs are enabled, as
+ * the DPLL semantics change when the LVDS is assigned to that pipe.
+ */
+# define LVDS_PORT_EN (1 << 31)
+/* Selects pipe B for LVDS data. Must be set on pre-965. */
+# define LVDS_PIPEB_SELECT (1 << 30)
+
+/* on 965, dithering is enabled in this register, not PFIT_CONTROL */
+# define LVDS_DITHER_ENABLE (1 << 25)
+
+/*
+ * Selects between .0 and .1 formats:
+ *
+ * 0 = 1x18.0, 2x18.0, 1x24.0 or 2x24.0
+ * 1 = 1x24.1 or 2x24.1
+ */
+# define LVDS_DATA_FORMAT_DOT_ONE (1 << 24)
+
+/* Using LE instead of HS on second channel control signal */
+# define LVDS_LE_CONTROL_ENABLE (1 << 23)
+
+/* Using LF instead of VS on second channel control signal */
+# define LVDS_LF_CONTROL_ENABLE (1 << 22)
+
+/* invert vsync signal polarity */
+# define LVDS_VSYNC_POLARITY_INVERT (1 << 21)
+
+/* invert hsync signal polarity */
+# define LVDS_HSYNC_POLARITY_INVERT (1 << 20)
+
+/* invert display enable signal polarity */
+# define LVDS_DE_POLARITY_INVERT (1 << 19)
+
+/*
+ * Control signals for second channel, ignored in single channel modes
+ */
+
+/* send DE, HS, VS on second channel */
+# define LVDS_SECOND_CHANNEL_DE_HS_VS (0 << 17)
+
+# define LVDS_SECOND_CHANNEL_RESERVED (1 << 17)
+
+/* Send zeros instead of DE, HS, VS on second channel */
+# define LVDS_SECOND_CHANNEL_ZEROS (2 << 17)
+
+/* Set DE=0, HS=LE, VS=LF on second channel */
+# define LVDS_SECOND_CHANNEL_HS_VS (3 << 17)
+
+/*
+ * Send duplicate data for channel reserved bits, otherwise send zeros
+ */
+# define LVDS_CHANNEL_DUP_RESERVED (1 << 16)
+
+/*
+ * Enable border for unscaled (or aspect-scaled) display
+ */
+# define LVDS_BORDER_ENABLE (1 << 15)
+
+/*
+ * Tri-state the LVDS buffers when powered down, otherwise
+ * they are set to 0V
+ */
+# define LVDS_POWER_DOWN_TRI_STATE (1 << 10)
+
+/*
+ * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
+ * pixel.
+ */
+# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8)
+# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8)
+# define LVDS_A0A2_CLKA_POWER_UP (3 << 8)
+/*
+ * Controls the A3 data pair, which contains the additional LSBs for 24 bit
+ * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
+ * on.
+ */
+# define LVDS_A3_POWER_MASK (3 << 6)
+# define LVDS_A3_POWER_DOWN (0 << 6)
+# define LVDS_A3_POWER_UP (3 << 6)
+/*
+ * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP
+ * is set.
+ */
+# define LVDS_CLKB_POWER_MASK (3 << 4)
+# define LVDS_CLKB_POWER_DOWN (0 << 4)
+# define LVDS_CLKB_POWER_UP (3 << 4)
+
+/*
+ * Controls the B0-B3 data pairs. This must be set to match the DPLL p2
+ * setting for whether we are in dual-channel mode. The B3 pair will
+ * additionally only be powered up when LVDS_A3_POWER_UP is set.
+ */
+# define LVDS_B0B3_POWER_MASK (3 << 2)
+# define LVDS_B0B3_POWER_DOWN (0 << 2)
+# define LVDS_B0B3_POWER_UP (3 << 2)
+
+/* @} */
+
+#define DP_B 0x64100
+#define DPB_AUX_CH_CTL 0x64110
+#define DPB_AUX_CH_DATA1 0x64114
+#define DPB_AUX_CH_DATA2 0x64118
+#define DPB_AUX_CH_DATA3 0x6411c
+#define DPB_AUX_CH_DATA4 0x64120
+#define DPB_AUX_CH_DATA5 0x64124
+
+#define DP_C 0x64200
+#define DPC_AUX_CH_CTL 0x64210
+#define DPC_AUX_CH_DATA1 0x64214
+#define DPC_AUX_CH_DATA2 0x64218
+#define DPC_AUX_CH_DATA3 0x6421c
+#define DPC_AUX_CH_DATA4 0x64220
+#define DPC_AUX_CH_DATA5 0x64224
+
+#define DP_D 0x64300
+#define DPD_AUX_CH_CTL 0x64310
+#define DPD_AUX_CH_DATA1 0x64314
+#define DPD_AUX_CH_DATA2 0x64318
+#define DPD_AUX_CH_DATA3 0x6431c
+#define DPD_AUX_CH_DATA4 0x64320
+#define DPD_AUX_CH_DATA5 0x64324
+
+/*
+ * Two channel clock control. Turn this on if you need clkb for two channel mode
+ * Overridden by global LVDS power sequencing
+ */
+
+/* clkb off */
+# define LVDS_CLKB_POWER_DOWN (0 << 4)
+
+/* powered up, but clkb forced to 0 */
+# define LVDS_CLKB_POWER_PARTIAL (1 << 4)
+
+/* clock B running */
+# define LVDS_CLKB_POWER_UP (3 << 4)
+
+/*
+ * Two channel mode B0-B2 control. Sets state when power is on.
+ * Set to POWER_DOWN in single channel mode, other settings enable
+ * two channel mode. The CLKB power control controls whether that clock
+ * is enabled during two channel mode.
+ *
+ */
+/* Everything is off, including B3 and CLKB */
+# define LVDS_B_POWER_DOWN (0 << 2)
+
+/* B0, B1, B2 and data lines forced to 0. timing is active */
+# define LVDS_B_POWER_PARTIAL (1 << 2)
+
+/* data lines active (both timing and colour) */
+# define LVDS_B_POWER_UP (3 << 2)
+
+/* @defgroup TV_CTL
+ * @{
+ */
+#define TV_CTL 0x68000
+/* Enables the TV encoder */
+# define TV_ENC_ENABLE (1 << 31)
+/* Sources the TV encoder input from pipe B instead of A. */
+# define TV_ENC_PIPEB_SELECT (1 << 30)
+/* Outputs composite video (DAC A only) */
+# define TV_ENC_OUTPUT_COMPOSITE (0 << 28)
+/* Outputs SVideo video (DAC B/C) */
+# define TV_ENC_OUTPUT_SVIDEO (1 << 28)
+/* Outputs Component video (DAC A/B/C) */
+# define TV_ENC_OUTPUT_COMPONENT (2 << 28)
+/* Outputs Composite and SVideo (DAC A/B/C) */
+# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE (3 << 28)
+# define TV_TRILEVEL_SYNC (1 << 21)
+/* Enables slow sync generation (945GM only) */
+# define TV_SLOW_SYNC (1 << 20)
+/* Selects 4x oversampling for 480i and 576p */
+# define TV_OVERSAMPLE_4X (0 << 18)
+/* Selects 2x oversampling for 720p and 1080i */
+# define TV_OVERSAMPLE_2X (1 << 18)
+/* Selects no oversampling for 1080p */
+# define TV_OVERSAMPLE_NONE (2 << 18)
+/* Selects 8x oversampling */
+# define TV_OVERSAMPLE_8X (3 << 18)
+/* Selects progressive mode rather than interlaced */
+# define TV_PROGRESSIVE (1 << 17)
+/* Sets the colorburst to PAL mode. Required for non-M PAL modes. */
+# define TV_PAL_BURST (1 << 16)
+/* Field for setting delay of Y compared to C */
+# define TV_YC_SKEW_MASK (7 << 12)
+/* Enables a fix for 480p/576p standard definition modes on the 915GM only */
+# define TV_ENC_SDP_FIX (1 << 11)
+/*
+ * Enables a fix for the 915GM only.
+ *
+ * Not sure what it does.
+ */
+# define TV_ENC_C0_FIX (1 << 10)
+/* Bits that must be preserved by software */
+# define TV_CTL_SAVE ((1 << 11) | (3 << 9) | (7 << 6) | 0xf)
+# define TV_FUSE_STATE_MASK (3 << 4)
+/* Read-only state that reports all features enabled */
+# define TV_FUSE_STATE_ENABLED (0 << 4)
+/* Read-only state that reports that Macrovision is disabled in hardware*/
+# define TV_FUSE_STATE_NO_MACROVISION (1 << 4)
+/* Read-only state that reports that TV-out is disabled in hardware. */
+# define TV_FUSE_STATE_DISABLED (2 << 4)
+/* Normal operation */
+# define TV_TEST_MODE_NORMAL (0 << 0)
+/* Encoder test pattern 1 - combo pattern */
+# define TV_TEST_MODE_PATTERN_1 (1 << 0)
+/* Encoder test pattern 2 - full screen vertical 75% color bars */
+# define TV_TEST_MODE_PATTERN_2 (2 << 0)
+/* Encoder test pattern 3 - full screen horizontal 75% color bars */
+# define TV_TEST_MODE_PATTERN_3 (3 << 0)
+/* Encoder test pattern 4 - random noise */
+# define TV_TEST_MODE_PATTERN_4 (4 << 0)
+/* Encoder test pattern 5 - linear color ramps */
+# define TV_TEST_MODE_PATTERN_5 (5 << 0)
+/*
+ * This test mode forces the DACs to 50% of full output.
+ *
+ * This is used for load detection in combination with TVDAC_SENSE_MASK
+ */
+# define TV_TEST_MODE_MONITOR_DETECT (7 << 0)
+# define TV_TEST_MODE_MASK (7 << 0)
+/* @} */
+
+/* @defgroup TV_DAC
+ * @{
+ */
+#define TV_DAC 0x68004
+/*
+ * Reports that DAC state change logic has reported change (RO).
+ *
+ * This gets cleared when TV_DAC_STATE_EN is cleared
+*/
+# define TVDAC_STATE_CHG (1 << 31)
+# define TVDAC_SENSE_MASK (7 << 28)
+/* Reports that DAC A voltage is above the detect threshold */
+# define TVDAC_A_SENSE (1 << 30)
+/* Reports that DAC B voltage is above the detect threshold */
+# define TVDAC_B_SENSE (1 << 29)
+/* Reports that DAC C voltage is above the detect threshold */
+# define TVDAC_C_SENSE (1 << 28)
+/*
+ * Enables DAC state detection logic, for load-based TV detection.
+ *
+ * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set
+ * to off, for load detection to work.
+ */
+# define TVDAC_STATE_CHG_EN (1 << 27)
+/* Sets the DAC A sense value to high */
+# define TVDAC_A_SENSE_CTL (1 << 26)
+/* Sets the DAC B sense value to high */
+# define TVDAC_B_SENSE_CTL (1 << 25)
+/* Sets the DAC C sense value to high */
+# define TVDAC_C_SENSE_CTL (1 << 24)
+/* Overrides the ENC_ENABLE and DAC voltage levels */
+# define DAC_CTL_OVERRIDE (1 << 7)
+/* Sets the slew rate. Must be preserved in software */
+# define ENC_TVDAC_SLEW_FAST (1 << 6)
+# define DAC_A_1_3_V (0 << 4)
+# define DAC_A_1_1_V (1 << 4)
+# define DAC_A_0_7_V (2 << 4)
+# define DAC_A_OFF (3 << 4)
+# define DAC_B_1_3_V (0 << 2)
+# define DAC_B_1_1_V (1 << 2)
+# define DAC_B_0_7_V (2 << 2)
+# define DAC_B_OFF (3 << 2)
+# define DAC_C_1_3_V (0 << 0)
+# define DAC_C_1_1_V (1 << 0)
+# define DAC_C_0_7_V (2 << 0)
+# define DAC_C_OFF (3 << 0)
+/* @} */
+
+/*
+ * CSC coefficients are stored in a floating point format with 9 bits of
+ * mantissa and 2 or 3 bits of exponent. The exponent is represented as 2*-n,
+ * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
+ * -1 (0x3) being the only legal negative value.
+ */
+#define TV_CSC_Y 0x68010
+# define TV_RY_MASK 0x07ff0000
+# define TV_RY_SHIFT 16
+# define TV_GY_MASK 0x00000fff
+# define TV_GY_SHIFT 0
+
+#define TV_CSC_Y2 0x68014
+# define TV_BY_MASK 0x07ff0000
+# define TV_BY_SHIFT 16
+/*
+ * Y attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AY_MASK 0x000003ff
+# define TV_AY_SHIFT 0
+
+#define TV_CSC_U 0x68018
+# define TV_RU_MASK 0x07ff0000
+# define TV_RU_SHIFT 16
+# define TV_GU_MASK 0x000007ff
+# define TV_GU_SHIFT 0
+
+#define TV_CSC_U2 0x6801c
+# define TV_BU_MASK 0x07ff0000
+# define TV_BU_SHIFT 16
+/*
+ * U attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AU_MASK 0x000003ff
+# define TV_AU_SHIFT 0
+
+#define TV_CSC_V 0x68020
+# define TV_RV_MASK 0x0fff0000
+# define TV_RV_SHIFT 16
+# define TV_GV_MASK 0x000007ff
+# define TV_GV_SHIFT 0
+
+#define TV_CSC_V2 0x68024
+# define TV_BV_MASK 0x07ff0000
+# define TV_BV_SHIFT 16
+/*
+ * V attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AV_MASK 0x000007ff
+# define TV_AV_SHIFT 0
+
+/* @defgroup TV_CSC_KNOBS
+ * @{
+ */
+#define TV_CLR_KNOBS 0x68028
+/* 2s-complement brightness adjustment */
+# define TV_BRIGHTNESS_MASK 0xff000000
+# define TV_BRIGHTNESS_SHIFT 24
+/* Contrast adjustment, as a 2.6 unsigned floating point number */
+# define TV_CONTRAST_MASK 0x00ff0000
+# define TV_CONTRAST_SHIFT 16
+/* Saturation adjustment, as a 2.6 unsigned floating point number */
+# define TV_SATURATION_MASK 0x0000ff00
+# define TV_SATURATION_SHIFT 8
+/* Hue adjustment, as an integer phase angle in degrees */
+# define TV_HUE_MASK 0x000000ff
+# define TV_HUE_SHIFT 0
+/* @} */
+
+/* @defgroup TV_CLR_LEVEL
+ * @{
+ */
+#define TV_CLR_LEVEL 0x6802c
+/* Controls the DAC level for black */
+# define TV_BLACK_LEVEL_MASK 0x01ff0000
+# define TV_BLACK_LEVEL_SHIFT 16
+/* Controls the DAC level for blanking */
+# define TV_BLANK_LEVEL_MASK 0x000001ff
+# define TV_BLANK_LEVEL_SHIFT 0
+/* @} */
+
+/* @defgroup TV_H_CTL_1
+ * @{
+ */
+#define TV_H_CTL_1 0x68030
+/* Number of pixels in the hsync. */
+# define TV_HSYNC_END_MASK 0x1fff0000
+# define TV_HSYNC_END_SHIFT 16
+/* Total number of pixels minus one in the line (display and blanking). */
+# define TV_HTOTAL_MASK 0x00001fff
+# define TV_HTOTAL_SHIFT 0
+/* @} */
+
+/* @defgroup TV_H_CTL_2
+ * @{
+ */
+#define TV_H_CTL_2 0x68034
+/* Enables the colorburst (needed for non-component color) */
+# define TV_BURST_ENA (1 << 31)
+/* Offset of the colorburst from the start of hsync, in pixels minus one. */
+# define TV_HBURST_START_SHIFT 16
+# define TV_HBURST_START_MASK 0x1fff0000
+/* Length of the colorburst */
+# define TV_HBURST_LEN_SHIFT 0
+# define TV_HBURST_LEN_MASK 0x0001fff
+/* @} */
+
+/* @defgroup TV_H_CTL_3
+ * @{
+ */
+#define TV_H_CTL_3 0x68038
+/* End of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_END_SHIFT 16
+# define TV_HBLANK_END_MASK 0x1fff0000
+/* Start of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_START_SHIFT 0
+# define TV_HBLANK_START_MASK 0x0001fff
+/* @} */
+
+/* @defgroup TV_V_CTL_1
+ * @{
+ */
+#define TV_V_CTL_1 0x6803c
+/* XXX */
+# define TV_NBR_END_SHIFT 16
+# define TV_NBR_END_MASK 0x07ff0000
+/* XXX */
+# define TV_VI_END_F1_SHIFT 8
+# define TV_VI_END_F1_MASK 0x00003f00
+/* XXX */
+# define TV_VI_END_F2_SHIFT 0
+# define TV_VI_END_F2_MASK 0x0000003f
+/* @} */
+
+/* @defgroup TV_V_CTL_2
+ * @{
+ */
+#define TV_V_CTL_2 0x68040
+/* Length of vsync, in half lines */
+# define TV_VSYNC_LEN_MASK 0x07ff0000
+# define TV_VSYNC_LEN_SHIFT 16
+/* Offset of the start of vsync in field 1, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F1_MASK 0x00007f00
+# define TV_VSYNC_START_F1_SHIFT 8
+/*
+ * Offset of the start of vsync in field 2, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F2_MASK 0x0000007f
+# define TV_VSYNC_START_F2_SHIFT 0
+/* @} */
+
+/* @defgroup TV_V_CTL_3
+ * @{
+ */
+#define TV_V_CTL_3 0x68044
+/* Enables generation of the equalization signal */
+# define TV_EQUAL_ENA (1 << 31)
+/* Length of vsync, in half lines */
+# define TV_VEQ_LEN_MASK 0x007f0000
+# define TV_VEQ_LEN_SHIFT 16
+/* Offset of the start of equalization in field 1, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F1_MASK 0x0007f00
+# define TV_VEQ_START_F1_SHIFT 8
+/*
+ * Offset of the start of equalization in field 2, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F2_MASK 0x000007f
+# define TV_VEQ_START_F2_SHIFT 0
+/* @} */
+
+/* @defgroup TV_V_CTL_4
+ * @{
+ */
+#define TV_V_CTL_4 0x68048
+/*
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F1_MASK 0x003f0000
+# define TV_VBURST_START_F1_SHIFT 16
+/*
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F1_MASK 0x000000ff
+# define TV_VBURST_END_F1_SHIFT 0
+/* @} */
+
+/* @defgroup TV_V_CTL_5
+ * @{
+ */
+#define TV_V_CTL_5 0x6804c
+/*
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F2_MASK 0x003f0000
+# define TV_VBURST_START_F2_SHIFT 16
+/*
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F2_MASK 0x000000ff
+# define TV_VBURST_END_F2_SHIFT 0
+/* @} */
+
+/* @defgroup TV_V_CTL_6
+ * @{
+ */
+#define TV_V_CTL_6 0x68050
+/*
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F3_MASK 0x003f0000
+# define TV_VBURST_START_F3_SHIFT 16
+/*
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F3_MASK 0x000000ff
+# define TV_VBURST_END_F3_SHIFT 0
+/* @} */
+
+/* @defgroup TV_V_CTL_7
+ * @{
+ */
+#define TV_V_CTL_7 0x68054
+/*
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F4_MASK 0x003f0000
+# define TV_VBURST_START_F4_SHIFT 16
+/*
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F4_MASK 0x000000ff
+# define TV_VBURST_END_F4_SHIFT 0
+/* @} */
+
+/* @defgroup TV_SC_CTL_1
+ * @{
+ */
+#define TV_SC_CTL_1 0x68060
+/* Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA1_EN (1 << 31)
+/* Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA2_EN (1 << 30)
+/* Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA3_EN (1 << 29)
+/* Sets the subcarrier DDA to reset frequency every other field */
+# define TV_SC_RESET_EVERY_2 (0 << 24)
+/* Sets the subcarrier DDA to reset frequency every fourth field */
+# define TV_SC_RESET_EVERY_4 (1 << 24)
+/* Sets the subcarrier DDA to reset frequency every eighth field */
+# define TV_SC_RESET_EVERY_8 (2 << 24)
+/* Sets the subcarrier DDA to never reset the frequency */
+# define TV_SC_RESET_NEVER (3 << 24)
+/* Sets the peak amplitude of the colorburst.*/
+# define TV_BURST_LEVEL_MASK 0x00ff0000
+# define TV_BURST_LEVEL_SHIFT 16
+/* Sets the increment of the first subcarrier phase generation DDA */
+# define TV_SCDDA1_INC_MASK 0x00000fff
+# define TV_SCDDA1_INC_SHIFT 0
+/* @} */
+
+/* @defgroup TV_SC_CTL_2
+ * @{
+ */
+#define TV_SC_CTL_2 0x68064
+/* Sets the rollover for the second subcarrier phase generation DDA */
+# define TV_SCDDA2_SIZE_MASK 0x7fff0000
+# define TV_SCDDA2_SIZE_SHIFT 16
+/* Sets the increent of the second subcarrier phase generation DDA */
+# define TV_SCDDA2_INC_MASK 0x00007fff
+# define TV_SCDDA2_INC_SHIFT 0
+/* @} */
+
+/* @defgroup TV_SC_CTL_3
+ * @{
+ */
+#define TV_SC_CTL_3 0x68068
+/* Sets the rollover for the third subcarrier phase generation DDA */
+# define TV_SCDDA3_SIZE_MASK 0x7fff0000
+# define TV_SCDDA3_SIZE_SHIFT 16
+/* Sets the increent of the third subcarrier phase generation DDA */
+# define TV_SCDDA3_INC_MASK 0x00007fff
+# define TV_SCDDA3_INC_SHIFT 0
+/* @} */
+
+/* @defgroup TV_WIN_POS
+ * @{
+ */
+#define TV_WIN_POS 0x68070
+/* X coordinate of the display from the start of horizontal active */
+# define TV_XPOS_MASK 0x1fff0000
+# define TV_XPOS_SHIFT 16
+/* Y coordinate of the display from the start of vertical active (NBR) */
+# define TV_YPOS_MASK 0x00000fff
+# define TV_YPOS_SHIFT 0
+/* @} */
+
+/* @defgroup TV_WIN_SIZE
+ * @{
+ */
+#define TV_WIN_SIZE 0x68074
+/* Horizontal size of the display window, measured in pixels*/
+# define TV_XSIZE_MASK 0x1fff0000
+# define TV_XSIZE_SHIFT 16
+/*
+ * Vertical size of the display window, measured in pixels.
+ *
+ * Must be even for interlaced modes.
+ */
+# define TV_YSIZE_MASK 0x00000fff
+# define TV_YSIZE_SHIFT 0
+/* @} */
+
+/* @defgroup TV_FILTER_CTL_1
+ * @{
+ */
+#define TV_FILTER_CTL_1 0x68080
+/*
+ * Enables automatic scaling calculation.
+ *
+ * If set, the rest of the registers are ignored, and the calculated values can
+ * be read back from the register.
+ */
+# define TV_AUTO_SCALE (1 << 31)
+/*
+ * Disables the vertical filter.
+ *
+ * This is required on modes more than 1024 pixels wide */
+# define TV_V_FILTER_BYPASS (1 << 29)
+/* Enables adaptive vertical filtering */
+# define TV_VADAPT (1 << 28)
+# define TV_VADAPT_MODE_MASK (3 << 26)
+/* Selects the least adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_LEAST (0 << 26)
+/* Selects the moderately adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MODERATE (1 << 26)
+/* Selects the most adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MOST (3 << 26)
+/*
+ * Sets the horizontal scaling factor.
+ *
+ * This should be the fractional part of the horizontal scaling factor divided
+ * by the oversampling rate. TV_HSCALE should be less than 1, and set to:
+ *
+ * (src width - 1) / ((oversample * dest width) - 1)
+ */
+# define TV_HSCALE_FRAC_MASK 0x00003fff
+# define TV_HSCALE_FRAC_SHIFT 0
+/* @} */
+
+/* @defgroup TV_FILTER_CTL_2
+ * @{
+ */
+#define TV_FILTER_CTL_2 0x68084
+/*
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1)
+ */
+# define TV_VSCALE_INT_MASK 0x00038000
+# define TV_VSCALE_INT_SHIFT 15
+/*
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * \sa TV_VSCALE_INT_MASK
+ */
+# define TV_VSCALE_FRAC_MASK 0x00007fff
+# define TV_VSCALE_FRAC_SHIFT 0
+/* @} */
+
+/* @defgroup TV_FILTER_CTL_3
+ * @{
+ */
+#define TV_FILTER_CTL_3 0x68088
+/*
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1))
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ */
+# define TV_VSCALE_IP_INT_MASK 0x00038000
+# define TV_VSCALE_IP_INT_SHIFT 15
+/*
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ *
+ * \sa TV_VSCALE_IP_INT_MASK
+ */
+# define TV_VSCALE_IP_FRAC_MASK 0x00007fff
+# define TV_VSCALE_IP_FRAC_SHIFT 0
+/* @} */
+
+/* @defgroup TV_CC_CONTROL
+ * @{
+ */
+#define TV_CC_CONTROL 0x68090
+# define TV_CC_ENABLE (1 << 31)
+/*
+ * Specifies which field to send the CC data in.
+ *
+ * CC data is usually sent in field 0.
+ */
+# define TV_CC_FID_MASK (1 << 27)
+# define TV_CC_FID_SHIFT 27
+/* Sets the horizontal position of the CC data. Usually 135. */
+# define TV_CC_HOFF_MASK 0x03ff0000
+# define TV_CC_HOFF_SHIFT 16
+/* Sets the vertical position of the CC data. Usually 21 */
+# define TV_CC_LINE_MASK 0x0000003f
+# define TV_CC_LINE_SHIFT 0
+/* @} */
+
+/* @defgroup TV_CC_DATA
+ * @{
+ */
+#define TV_CC_DATA 0x68094
+# define TV_CC_RDY (1 << 31)
+/* Second word of CC data to be transmitted. */
+# define TV_CC_DATA_2_MASK 0x007f0000
+# define TV_CC_DATA_2_SHIFT 16
+/* First word of CC data to be transmitted. */
+# define TV_CC_DATA_1_MASK 0x0000007f
+# define TV_CC_DATA_1_SHIFT 0
+/* @}
+ */
+
+/* @{ */
+#define TV_H_LUMA_0 0x68100
+#define TV_H_LUMA_59 0x681ec
+#define TV_H_CHROMA_0 0x68200
+#define TV_H_CHROMA_59 0x682ec
+#define TV_V_LUMA_0 0x68300
+#define TV_V_LUMA_42 0x683a8
+#define TV_V_CHROMA_0 0x68400
+#define TV_V_CHROMA_42 0x684a8
+/* @} */
+
+#define PIPEA_DSL 0x70000
+
+#define PIPEACONF 0x70008
+#define PIPEACONF_ENABLE (1<<31)
+#define PIPEACONF_DISABLE 0
+#define PIPEACONF_DOUBLE_WIDE (1<<30)
+#define I965_PIPECONF_ACTIVE (1<<30)
+#define PIPEACONF_SINGLE_WIDE 0
+#define PIPEACONF_PIPE_UNLOCKED 0
+#define PIPEACONF_PIPE_LOCKED (1<<25)
+#define PIPEACONF_PALETTE 0
+#define PIPEACONF_GAMMA (1<<24)
+#define PIPECONF_FORCE_BORDER (1<<25)
+#define PIPECONF_PROGRESSIVE (0 << 21)
+#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
+#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
+/* ironlake: gamma */
+#define PIPECONF_PALETTE_8BIT (0<<24)
+#define PIPECONF_PALETTE_10BIT (1<<24)
+#define PIPECONF_PALETTE_12BIT (2<<24)
+#define PIPECONF_FORCE_BORDER (1<<25)
+#define PIPECONF_PROGRESSIVE (0 << 21)
+#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
+#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
+/* ironlake */
+#define PIPECONF_MSA_TIMING_DELAY (0<<18) /* for eDP */
+#define PIPECONF_NO_DYNAMIC_RATE_CHANGE (0 << 16)
+#define PIPECONF_NO_ROTATION (0<<14)
+#define PIPECONF_FULL_COLOR_RANGE (0<<13)
+#define PIPECONF_CE_COLOR_RANGE (1<<13)
+#define PIPECONF_COLOR_SPACE_RGB (0<<11)
+#define PIPECONF_COLOR_SPACE_YUV601 (1<<11)
+#define PIPECONF_COLOR_SPACE_YUV709 (2<<11)
+#define PIPECONF_CONNECT_DEFAULT (0<<9)
+#define PIPECONF_8BPP (0<<5)
+#define PIPECONF_10BPP (1<<5)
+#define PIPECONF_6BPP (2<<5)
+#define PIPECONF_12BPP (3<<5)
+#define PIPECONF_ENABLE_DITHER (1<<4)
+#define PIPECONF_DITHER_SPATIAL (0<<2)
+#define PIPECONF_DITHER_ST1 (1<<2)
+#define PIPECONF_DITHER_ST2 (2<<2)
+#define PIPECONF_DITHER_TEMPORAL (3<<2)
+
+#define PIPEAGCMAXRED 0x70010
+#define PIPEAGCMAXGREEN 0x70014
+#define PIPEAGCMAXBLUE 0x70018
+#define PIPEASTAT 0x70024
+# define FIFO_UNDERRUN (1 << 31)
+# define CRC_ERROR_ENABLE (1 << 29)
+# define CRC_DONE_ENABLE (1 << 28)
+# define GMBUS_EVENT_ENABLE (1 << 27)
+# define VSYNC_INT_ENABLE (1 << 25)
+# define DLINE_COMPARE_ENABLE (1 << 24)
+# define DPST_EVENT_ENABLE (1 << 23)
+# define LBLC_EVENT_ENABLE (1 << 22)
+# define OFIELD_INT_ENABLE (1 << 21)
+# define EFIELD_INT_ENABLE (1 << 20)
+# define SVBLANK_INT_ENABLE (1 << 18)
+# define VBLANK_INT_ENABLE (1 << 17)
+# define OREG_UPDATE_ENABLE (1 << 16)
+# define CRC_ERROR_INT_STATUS (1 << 13)
+# define CRC_DONE_INT_STATUS (1 << 12)
+# define GMBUS_INT_STATUS (1 << 11)
+# define VSYNC_INT_STATUS (1 << 9)
+# define DLINE_COMPARE_STATUS (1 << 8)
+# define DPST_EVENT_STATUS (1 << 7)
+# define LBLC_EVENT_STATUS (1 << 6)
+# define OFIELD_INT_STATUS (1 << 5)
+# define EFIELD_INT_STATUS (1 << 4)
+# define SVBLANK_INT_STATUS (1 << 2)
+# define VBLANK_INT_STATUS (1 << 1)
+# define OREG_UPDATE_STATUS (1 << 0)
+
+#define FW_BLC 0x020d8
+#define FW_BLC2 0x020dc
+#define FW_BLC_SELF 0x020e0 /* 915+ only */
+
+#define DSPARB 0x70030
+#define DSPARB_CSTART_SHIFT 7
+#define DSPARB_BSTART_SHIFT 0
+#define DSPARB_BEND_SHIFT 9 /* on 855 */
+#define DSPARB_AEND_SHIFT 0
+#define DSPFW1 0x70034
+#define DSPFW2 0x70038
+#define DSPFW3 0x7003c
+/*
+ * The two pipe frame counter registers are not synchronized, so
+ * reading a stable value is somewhat tricky. The following code
+ * should work:
+ *
+ * do {
+ * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> PIPE_FRAME_HIGH_SHIFT;
+ * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> PIPE_FRAME_LOW_SHIFT);
+ * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> PIPE_FRAME_HIGH_SHIFT);
+ * } while (high1 != high2);
+ * frame = (high1 << 8) | low1;
+ */
+#define PIPEAFRAMEHIGH 0x70040
+#define PIPE_FRAME_HIGH_MASK 0x0000ffff
+#define PIPE_FRAME_HIGH_SHIFT 0
+#define PIPEAFRAMEPIXEL 0x70044
+#define PIPE_FRAME_LOW_MASK 0xff000000
+#define PIPE_FRAME_LOW_SHIFT 24
+/*
+ * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register
+ * and is 24 bits wide.
+ */
+#define PIPE_PIXEL_MASK 0x00ffffff
+#define PIPE_PIXEL_SHIFT 0
+/*
+ * g4x+ frame/flip counters
+ */
+#define PIPEAFRMCOUNT_G4X 0x70040
+#define PIPEAFLIPCOUNT_G4X 0x70044
+/*
+ * Computing GMCH M and N values.
+ *
+ * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes
+ *
+ * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz)
+ *
+ * The GMCH value is used internally
+ */
+#define PIPEA_GMCH_DATA_M 0x70050
+
+/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
+#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25)
+#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25
+
+#define PIPE_GMCH_DATA_M_MASK (0xffffff)
+
+#define PIPEA_GMCH_DATA_N 0x70054
+#define PIPE_GMCH_DATA_N_MASK (0xffffff)
+
+/*
+ * Computing Link M and N values.
+ *
+ * Link M / N = pixel_clock / ls_clk
+ *
+ * (the DP spec calls pixel_clock the 'strm_clk')
+ *
+ * The Link value is transmitted in the Main Stream
+ * Attributes and VB-ID.
+ */
+
+#define PIPEA_DP_LINK_M 0x70060
+#define PIPEA_DP_LINK_M_MASK (0xffffff)
+
+#define PIPEA_DP_LINK_N 0x70064
+#define PIPEA_DP_LINK_N_MASK (0xffffff)
+
+#define PIPEB_DSL 0x71000
+
+#define PIPEBCONF 0x71008
+
+#define PIPEBGCMAXRED 0x71010
+#define PIPEBGCMAXGREEN 0x71014
+#define PIPEBGCMAXBLUE 0x71018
+#define PIPEBSTAT 0x71024
+#define PIPEBFRAMEHIGH 0x71040
+#define PIPEBFRAMEPIXEL 0x71044
+#define PIPEBFRMCOUNT_G4X 0x71040
+#define PIPEBFLIPCOUNT_G4X 0x71044
+
+#define PIPEB_GMCH_DATA_M 0x71050
+#define PIPEB_GMCH_DATA_N 0x71054
+#define PIPEB_DP_LINK_M 0x71060
+#define PIPEB_DP_LINK_N 0x71064
+
+#define PIPEC_DSL 0x72000
+
+#define PIPECCONF 0x72008
+
+#define PIPECGCMAXRED 0x72010
+#define PIPECGCMAXGREEN 0x72014
+#define PIPECGCMAXBLUE 0x72018
+#define PIPECSTAT 0x72024
+#define PIPECFRMCOUNT_G4X 0x72040
+#define PIPECFLIPCOUNT_G4X 0x72044
+
+#define PIPEC_GMCH_DATA_M 0x72050
+#define PIPEC_GMCH_DATA_N 0x72054
+#define PIPEC_DP_LINK_M 0x72060
+#define PIPEC_DP_LINK_N 0x72064
+
+#define PIPEEDPCONF 0x7F008
+
+#define DSPACNTR 0x70180
+#define DSPBCNTR 0x71180
+#define DSPCCNTR 0x72180
+#define DISPLAY_PLANE_ENABLE (1<<31)
+#define DISPLAY_PLANE_DISABLE 0
+#define DISPLAY_PLANE_TILED (1<<10)
+#define DISPPLANE_GAMMA_ENABLE (1<<30)
+#define DISPPLANE_GAMMA_DISABLE 0
+#define DISPPLANE_PIXFORMAT_MASK (0xf<<26)
+#define DISPPLANE_8BPP (0x2<<26)
+#define DISPPLANE_15_16BPP (0x4<<26)
+#define DISPPLANE_16BPP (0x5<<26)
+#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26)
+#define DISPPLANE_32BPP (0x7<<26)
+#define DISPPLANE_STEREO_ENABLE (1<<25)
+#define DISPPLANE_STEREO_DISABLE 0
+#define DISPPLANE_SEL_PIPE_MASK (1<<24)
+#define DISPPLANE_SEL_PIPE_A 0
+#define DISPPLANE_SEL_PIPE_B (1<<24)
+#define DISPPLANE_SRC_KEY_ENABLE (1<<22)
+#define DISPPLANE_SRC_KEY_DISABLE 0
+#define DISPPLANE_LINE_DOUBLE (1<<20)
+#define DISPPLANE_NO_LINE_DOUBLE 0
+#define DISPPLANE_STEREO_POLARITY_FIRST 0
+#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
+/* plane B only */
+#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15)
+#define DISPPLANE_ALPHA_TRANS_DISABLE 0
+#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0
+#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1)
+
+#define DSPABASE 0x70184
+#define DSPASTRIDE 0x70188
+
+#define DSPBBASE 0x71184
+#define DSPBADDR DSPBBASE
+#define DSPBSTRIDE 0x71188
+
+#define DSPCBASE 0x72184
+#define DSPCADDR DSPCBASE
+#define DSPCSTRIDE 0x72188
+
+#define DSPAKEYVAL 0x70194
+#define DSPAKEYMASK 0x70198
+
+#define DSPAPOS 0x7018C /* reserved */
+#define DSPASIZE 0x70190
+#define DSPBPOS 0x7118C
+#define DSPBSIZE 0x71190
+
+#define DSPASURF 0x7019C
+#define DSPATILEOFF 0x701A4
+#define DSPASURFLIVE 0x701AC
+
+#define DSPBSURF 0x7119C
+#define DSPBTILEOFF 0x711A4
+#define DSPBSURFLIVE 0x711AC
+
+#define DSPCSURF 0x7219C
+#define DSPCTILEOFF 0x721A4
+#define DSPCSURFLIVE 0x721AC
+
+#define VGACNTRL 0x71400
+# define VGA_DISP_DISABLE (1 << 31)
+# define VGA_2X_MODE (1 << 30)
+# define VGA_PIPE_B_SELECT (1 << 29)
+
+/* Various masks for reserved bits, etc. */
+#define I830_FWATER1_MASK (~((1<<11)|(1<<10)|(1<<9)| \
+ (1<<8)|(1<<26)|(1<<25)|(1<<24)|(1<<5)|(1<<4)|(1<<3)| \
+ (1<<2)|(1<<1)|1|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)))
+#define I830_FWATER2_MASK ~(0)
+
+#define DV0A_RESERVED ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<16)|(1<<5)|(1<<1)|1)
+#define DV0B_RESERVED ((1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<16)|(1<<5)|(1<<1)|1)
+#define VGA0_N_DIVISOR_MASK ((1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16))
+#define VGA0_M1_DIVISOR_MASK ((1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8))
+#define VGA0_M2_DIVISOR_MASK ((1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1)
+#define VGA0_M1M2N_RESERVED ~(VGA0_N_DIVISOR_MASK|VGA0_M1_DIVISOR_MASK|VGA0_M2_DIVISOR_MASK)
+#define VGA0_POSTDIV_MASK ((1<<7)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1)
+#define VGA1_POSTDIV_MASK ((1<<15)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8))
+#define VGA_POSTDIV_RESERVED ~(VGA0_POSTDIV_MASK|VGA1_POSTDIV_MASK|(1<<7)|(1<<15))
+#define DPLLA_POSTDIV_MASK ((1<<23)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16))
+#define DPLLA_RESERVED ((1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<22)|(1<<15)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1)
+#define ADPA_RESERVED ((1<<2)|(1<<1)|1|(1<<9)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16))
+#define SUPER_WORD 32
+#define BURST_A_MASK ((1<<11)|(1<<10)|(1<<9)|(1<<8))
+#define BURST_B_MASK ((1<<26)|(1<<25)|(1<<24))
+#define WATER_A_MASK ((1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1)
+#define WATER_B_MASK ((1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16))
+#define WATER_RESERVED ((1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<23)|(1<<22)|(1<<21)|(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<7)|(1<<6))
+#define PIPEACONF_RESERVED ((1<<29)|(1<<28)|(1<<27)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)|0xffff)
+#define PIPEBCONF_RESERVED ((1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)|0xffff)
+#define DSPACNTR_RESERVED ((1<<23)|(1<<19)|(1<<17)|(1<<16)|0xffff)
+#define DSPBCNTR_RESERVED ((1<<23)|(1<<19)|(1<<17)|(1<<16)|0x7ffe)
+
+#define I830_GMCH_CTRL 0x52
+
+#define I830_GMCH_ENABLED 0x4
+#define I830_GMCH_MEM_MASK 0x1
+#define I830_GMCH_MEM_64M 0x1
+#define I830_GMCH_MEM_128M 0
+
+#define I830_GMCH_GMS_MASK 0x70
+#define I830_GMCH_GMS_DISABLED 0x00
+#define I830_GMCH_GMS_LOCAL 0x10
+#define I830_GMCH_GMS_STOLEN_512 0x20
+#define I830_GMCH_GMS_STOLEN_1024 0x30
+#define I830_GMCH_GMS_STOLEN_8192 0x40
+
+#define I830_RDRAM_CHANNEL_TYPE 0x03010
+#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5)
+#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3)
+
+#define I855_GMCH_GMS_MASK (0xF << 4)
+#define I855_GMCH_GMS_DISABLED 0x00
+#define I855_GMCH_GMS_STOLEN_1M (0x1 << 4)
+#define I855_GMCH_GMS_STOLEN_4M (0x2 << 4)
+#define I855_GMCH_GMS_STOLEN_8M (0x3 << 4)
+#define I855_GMCH_GMS_STOLEN_16M (0x4 << 4)
+#define I855_GMCH_GMS_STOLEN_32M (0x5 << 4)
+#define I915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
+#define I915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
+#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4)
+#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4)
+#define INTEL_GMCH_GMS_STOLEN_96M (0xa << 4)
+#define INTEL_GMCH_GMS_STOLEN_160M (0xb << 4)
+#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4)
+#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4)
+
+
+#define I85X_CAPID 0x44
+#define I85X_VARIANT_MASK 0x7
+#define I85X_VARIANT_SHIFT 5
+#define I855_GME 0x0
+#define I855_GM 0x4
+#define I852_GME 0x2
+#define I852_GM 0x5
+
+#define I915_GCFGC 0xf0
+#define I915_LOW_FREQUENCY_ENABLE (1 << 7)
+#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
+#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4)
+#define I915_DISPLAY_CLOCK_MASK (7 << 4)
+
+#define I855_HPLLCC 0xc0
+#define I855_CLOCK_CONTROL_MASK (3 << 0)
+#define I855_CLOCK_133_200 (0 << 0)
+#define I855_CLOCK_100_200 (1 << 0)
+#define I855_CLOCK_100_133 (2 << 0)
+#define I855_CLOCK_166_250 (3 << 0)
+
+/* BLT commands */
+#define COLOR_BLT_CMD ((2<<29)|(0x40<<22)|(0x3))
+#define COLOR_BLT_WRITE_ALPHA (1<<21)
+#define COLOR_BLT_WRITE_RGB (1<<20)
+
+#define XY_COLOR_BLT_CMD_NOLEN ((2<<29)|(0x50<<22))
+#define XY_COLOR_BLT_WRITE_ALPHA (1<<21)
+#define XY_COLOR_BLT_WRITE_RGB (1<<20)
+#define XY_COLOR_BLT_TILED (1<<11)
+
+#define XY_SETUP_CLIP_BLT_CMD ((2<<29)|(3<<22)|1)
+
+#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22))
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+#define XY_SRC_COPY_BLT_SRC_TILED (1<<15)
+#define XY_SRC_COPY_BLT_DST_TILED (1<<11)
+
+#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|0x4)
+#define SRC_COPY_BLT_WRITE_ALPHA (1<<21)
+#define SRC_COPY_BLT_WRITE_RGB (1<<20)
+
+#define XY_PAT_BLT_IMMEDIATE ((2<<29)|(0x72<<22))
+
+#define XY_MONO_PAT_BLT_CMD ((0x2<<29)|(0x52<<22)|0x7)
+#define XY_MONO_PAT_VERT_SEED ((1<<10)|(1<<9)|(1<<8))
+#define XY_MONO_PAT_HORT_SEED ((1<<14)|(1<<13)|(1<<12))
+#define XY_MONO_PAT_BLT_WRITE_ALPHA (1<<21)
+#define XY_MONO_PAT_BLT_WRITE_RGB (1<<20)
+
+#define XY_MONO_SRC_BLT_CMD ((0x2<<29)|(0x54<<22)|(0x6))
+#define XY_MONO_SRC_BLT_WRITE_ALPHA (1<<21)
+#define XY_MONO_SRC_BLT_WRITE_RGB (1<<20)
+
+#define MI_STORE_DWORD_IMM ((0x20<<23)|2)
+#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
+
+#define MI_SET_CONTEXT (0x18<<23)
+#define CTXT_NO_RESTORE (1)
+#define CTXT_PALETTE_SAVE_DISABLE (1<<3)
+#define CTXT_PALETTE_RESTORE_DISABLE (1<<2)
+
+/* Dword 0 */
+#define MI_VERTEX_BUFFER (0x17<<23)
+#define MI_VERTEX_BUFFER_IDX(x) (x<<20)
+#define MI_VERTEX_BUFFER_PITCH(x) (x<<13)
+#define MI_VERTEX_BUFFER_WIDTH(x) (x<<6)
+/* Dword 1 */
+#define MI_VERTEX_BUFFER_DISABLE (1)
+
+/* Overlay Flip */
+#define MI_OVERLAY_FLIP (0x11<<23)
+#define MI_OVERLAY_FLIP_CONTINUE (0<<21)
+#define MI_OVERLAY_FLIP_ON (1<<21)
+#define MI_OVERLAY_FLIP_OFF (2<<21)
+
+/* Wait for Events */
+#define MI_WAIT_FOR_EVENT (0x03<<23)
+#define MI_WAIT_FOR_PIPEB_SVBLANK (1<<18)
+#define MI_WAIT_FOR_PIPEA_SVBLANK (1<<17)
+#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16)
+#define MI_WAIT_FOR_PIPEB_VBLANK (1<<7)
+#define MI_WAIT_FOR_PIPEA_VBLANK (1<<3)
+#define MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW (1<<5)
+#define MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW (1<<1)
+
+#define MI_LOAD_SCAN_LINES_INCL (0x12<<23)
+#define MI_LOAD_REGISTER_IMM ((0x22 << 23) | 1)
+
+/* Flush */
+#define MI_FLUSH (0x04<<23)
+#define MI_WRITE_DIRTY_STATE (1<<4)
+#define MI_END_SCENE (1<<3)
+#define MI_GLOBAL_SNAPSHOT_COUNT_RESET (1<<3)
+#define MI_INHIBIT_RENDER_CACHE_FLUSH (1<<2)
+#define MI_STATE_INSTRUCTION_CACHE_FLUSH (1<<1)
+#define MI_INVALIDATE_MAP_CACHE (1<<0)
+/* broadwater flush bits */
+#define BRW_MI_GLOBAL_SNAPSHOT_RESET (1 << 3)
+
+/* Noop */
+#define MI_NOOP 0x00
+#define MI_NOOP_WRITE_ID (1<<22)
+#define MI_NOOP_ID_MASK (1<<22 - 1)
+
+#define STATE3D_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x01<<16))
+
+/* Batch */
+#define MI_BATCH_BUFFER ((0x30 << 23) | 1)
+#define MI_BATCH_BUFFER_START (0x31 << 23)
+#define MI_BATCH_BUFFER_END (0xA << 23)
+#define MI_BATCH_NON_SECURE (1)
+#define MI_BATCH_NON_SECURE_I965 (1 << 8)
+#define MI_BATCH_NON_SECURE_HSW (1<<13) /* Additional bit for RCS */
+
+#define MAX_DISPLAY_PIPES 2
+
+typedef enum {
+ CrtIndex = 0,
+ TvIndex,
+ DfpIndex,
+ LfpIndex,
+ Crt2Index,
+ Tv2Index,
+ Dfp2Index,
+ Lfp2Index,
+ NumDisplayTypes
+} DisplayType;
+
+/* What's connected to the pipes (as reported by the BIOS) */
+#define PIPE_ACTIVE_MASK 0xff
+#define PIPE_CRT_ACTIVE (1 << CrtIndex)
+#define PIPE_TV_ACTIVE (1 << TvIndex)
+#define PIPE_DFP_ACTIVE (1 << DfpIndex)
+#define PIPE_LCD_ACTIVE (1 << LfpIndex)
+#define PIPE_CRT2_ACTIVE (1 << Crt2Index)
+#define PIPE_TV2_ACTIVE (1 << Tv2Index)
+#define PIPE_DFP2_ACTIVE (1 << Dfp2Index)
+#define PIPE_LCD2_ACTIVE (1 << Lfp2Index)
+
+#define PIPE_SIZED_DISP_MASK (PIPE_DFP_ACTIVE | \
+ PIPE_LCD_ACTIVE | \
+ PIPE_DFP2_ACTIVE)
+
+#define PIPE_A_SHIFT 0
+#define PIPE_B_SHIFT 8
+#define PIPE_SHIFT(n) ((n) == 0 ? \
+ PIPE_A_SHIFT : PIPE_B_SHIFT)
+
+/*
+ * Some BIOS scratch area registers. The 845 (and 830?) store the amount
+ * of video memory available to the BIOS in SWF1.
+ */
+
+#define SWF0 0x71410
+#define SWF1 0x71414
+#define SWF2 0x71418
+#define SWF3 0x7141c
+#define SWF4 0x71420
+#define SWF5 0x71424
+#define SWF6 0x71428
+
+/*
+ * 855 scratch registers.
+ */
+#define SWF00 0x70410
+#define SWF01 0x70414
+#define SWF02 0x70418
+#define SWF03 0x7041c
+#define SWF04 0x70420
+#define SWF05 0x70424
+#define SWF06 0x70428
+
+#define SWF10 SWF0
+#define SWF11 SWF1
+#define SWF12 SWF2
+#define SWF13 SWF3
+#define SWF14 SWF4
+#define SWF15 SWF5
+#define SWF16 SWF6
+
+#define SWF30 0x72414
+#define SWF31 0x72418
+#define SWF32 0x7241c
+
+/*
+ * Overlay registers. These are overlay registers accessed via MMIO.
+ * Those loaded via the overlay register page are defined in i830_video.c.
+ */
+#define OVADD 0x30000
+
+#define DOVSTA 0x30008
+#define OC_BUF (0x3<<20)
+
+#define OGAMC5 0x30010
+#define OGAMC4 0x30014
+#define OGAMC3 0x30018
+#define OGAMC2 0x3001c
+#define OGAMC1 0x30020
+#define OGAMC0 0x30024
+
+
+/*
+ * Palette registers
+ */
+#define PALETTE_A 0x0a000
+#define PALETTE_B 0x0a800
+
+/* Framebuffer compression */
+#define FBC_CFB_BASE 0x03200 /* 4k page aligned */
+#define FBC_LL_BASE 0x03204 /* 4k page aligned */
+#define FBC_CONTROL 0x03208
+#define FBC_CTL_EN (1<<31)
+#define FBC_CTL_PERIODIC (1<<30)
+#define FBC_CTL_INTERVAL_SHIFT (16)
+#define FBC_CTL_UNCOMPRESSIBLE (1<<14)
+#define FBC_CTL_STRIDE_SHIFT (5)
+#define FBC_CTL_FENCENO (1<<0)
+#define FBC_COMMAND 0x0320c
+#define FBC_CMD_COMPRESS (1<<0)
+#define FBC_STATUS 0x03210
+#define FBC_STAT_COMPRESSING (1<<31)
+#define FBC_STAT_COMPRESSED (1<<30)
+#define FBC_STAT_MODIFIED (1<<29)
+#define FBC_STAT_CURRENT_LINE (1<<0)
+#define FBC_CONTROL2 0x03214
+#define FBC_CTL_FENCE_DBL (0<<4)
+#define FBC_CTL_IDLE_IMM (0<<2)
+#define FBC_CTL_IDLE_FULL (1<<2)
+#define FBC_CTL_IDLE_LINE (2<<2)
+#define FBC_CTL_IDLE_DEBUG (3<<2)
+#define FBC_CTL_CPU_FENCE (1<<1)
+#define FBC_CTL_PLANEA (0<<0)
+#define FBC_CTL_PLANEB (1<<0)
+#define FBC_FENCE_OFF 0x0321b
+#define FBC_MOD_NUM 0x03220
+#define FBC_TAG_DEBUG 0x03300
+
+#define FBC_LL_SIZE (1536)
+#define FBC_LL_PAD (32)
+
+/* Framebuffer compression version 2 */
+#define DPFC_CB_BASE 0x3200
+#define DPFC_CONTROL 0x3208
+#define DPFC_CTL_EN (1<<31)
+#define DPFC_CTL_PLANEA (0<<30)
+#define DPFC_CTL_PLANEB (1<<30)
+#define DPFC_CTL_FENCE_EN (1<<29)
+#define DPFC_CTL_LIMIT_1X (0<<6)
+#define DPFC_CTL_LIMIT_2X (1<<6)
+#define DPFC_CTL_LIMIT_4X (2<<6)
+#define DPFC_RECOMP_CTL 0x320c
+#define DPFC_RECOMP_STALL_EN (1<<27)
+#define DPFC_RECOMP_STALL_WM_SHIFT (16)
+#define DPFC_RECOMP_STALL_WM_MASK (0x07ff0000)
+#define DPFC_RECOMP_TIMER_COUNT_SHIFT (0)
+#define DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f)
+#define DPFC_STATUS 0x3210
+#define DPFC_INVAL_SEG_SHIFT (16)
+#define DPFC_INVAL_SEG_MASK (0x07ff0000)
+#define DPFC_COMP_SEG_SHIFT (0)
+#define DPFC_COMP_SEG_MASK (0x000003ff)
+#define DPFC_STATUS2 0x3214
+#define DPFC_FENCE_YOFF 0x3218
+
+#define PEG_BAND_GAP_DATA 0x14d68
+
+#define MCHBAR_RENDER_STANDBY 0x111B8
+#define RENDER_STANDBY_ENABLE (1 << 30)
+
+
+/* Ironlake */
+
+/* warmup time in us */
+#define WARMUP_PCH_REF_CLK_SSC_MOD 1
+#define WARMUP_PCH_FDI_RECEIVER_PLL 25
+#define WARMUP_PCH_DPLL 50
+#define WARMUP_CPU_DP_PLL 20
+#define WARMUP_CPU_FDI_TRANSMITTER_PLL 10
+#define WARMUP_DMI_LATENCY 20
+#define FDI_TRAIN_PATTERN_1_TIME 0.5
+#define FDI_TRAIN_PATTERN_2_TIME 1.5
+#define FDI_ONE_IDLE_PATTERN_TIME 31
+
+#define CPU_VGACNTRL 0x41000
+
+#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030
+#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4)
+#define DIGITAL_PORTA_SHORT_PULSE_2MS (0 << 2)
+#define DIGITAL_PORTA_SHORT_PULSE_4_5MS (1 << 2)
+#define DIGITAL_PORTA_SHORT_PULSE_6MS (2 << 2)
+#define DIGITAL_PORTA_SHORT_PULSE_100MS (3 << 2)
+#define DIGITAL_PORTA_NO_DETECT (0 << 0)
+#define DIGITAL_PORTA_LONG_PULSE_DETECT_MASK (1 << 1)
+#define DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK (1 << 0)
+
+/* refresh rate hardware control */
+#define RR_HW_CTL 0x45300
+#define RR_HW_LOW_POWER_FRAMES_MASK 0xff
+#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00
+
+#define FDI_PLL_BIOS_0 0x46000
+#define FDI_PLL_BIOS_1 0x46004
+#define FDI_PLL_BIOS_2 0x46008
+#define DISPLAY_PORT_PLL_BIOS_0 0x4600c
+#define DISPLAY_PORT_PLL_BIOS_1 0x46010
+#define DISPLAY_PORT_PLL_BIOS_2 0x46014
+
+#define FDI_PLL_FREQ_CTL 0x46030
+#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24)
+#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00
+#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff
+
+#define PIPEA_DATA_M1 0x60030
+#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
+#define TU_SIZE_MASK 0x7e000000
+#define PIPEA_DATA_M1_OFFSET 0
+#define PIPEA_DATA_N1 0x60034
+#define PIPEA_DATA_N1_OFFSET 0
+
+#define PIPEA_DATA_M2 0x60038
+#define PIPEA_DATA_M2_OFFSET 0
+#define PIPEA_DATA_N2 0x6003c
+#define PIPEA_DATA_N2_OFFSET 0
+
+#define PIPEA_LINK_M1 0x60040
+#define PIPEA_LINK_M1_OFFSET 0
+#define PIPEA_LINK_N1 0x60044
+#define PIPEA_LINK_N1_OFFSET 0
+
+#define PIPEA_LINK_M2 0x60048
+#define PIPEA_LINK_M2_OFFSET 0
+#define PIPEA_LINK_N2 0x6004c
+#define PIPEA_LINK_N2_OFFSET 0
+
+/* PIPEB timing regs are same start from 0x61000 */
+
+#define PIPEB_DATA_M1 0x61030
+#define PIPEB_DATA_N1 0x61034
+
+#define PIPEB_DATA_M2 0x61038
+#define PIPEB_DATA_N2 0x6103c
+
+#define PIPEB_LINK_M1 0x61040
+#define PIPEB_LINK_N1 0x61044
+
+#define PIPEB_LINK_M2 0x61048
+#define PIPEB_LINK_N2 0x6104c
+
+/* PIPEC timing regs */
+
+#define PIPEC_DATA_M1 0x62030
+#define PIPEC_DATA_N1 0x62034
+
+#define PIPEC_DATA_M2 0x62038
+#define PIPEC_DATA_N2 0x6203c
+
+#define PIPEC_LINK_M1 0x62040
+#define PIPEC_LINK_N1 0x62044
+
+#define PIPEC_LINK_M2 0x62048
+#define PIPEC_LINK_N2 0x6204c
+
+#define PIPEEDP_DATA_M1 0x6F030
+#define PIPEEDP_DATA_N1 0x6F034
+
+#define PIPEEDP_LINK_M1 0x6F040
+#define PIPEEDP_LINK_N1 0x6F044
+
+/* PIPECONF for pipe A/B addr is same */
+
+/* cusor A is only connected to pipe A,
+ cursor B is connected to pipe B. Otherwise no change. */
+
+/* Plane A/B, DSPACNTR/DSPBCNTR addr not changed */
+
+/* CPU panel fitter */
+#define PFA_CTL_1 0x68080
+#define PFB_CTL_1 0x68880
+#define PFC_CTL_1 0x69080
+#define PF_ENABLE (1<<31)
+#define PFA_CTL_2 0x68084
+#define PFB_CTL_2 0x68884
+#define PFC_CTL_2 0x69084
+#define PFA_CTL_3 0x68088
+#define PFB_CTL_3 0x68888
+#define PFC_CTL_3 0x69088
+#define PFA_CTL_4 0x68090
+#define PFB_CTL_4 0x68890
+#define PFC_CTL_4 0x69090
+
+#define PFA_WIN_POS 0x68070
+#define PFB_WIN_POS 0x68870
+#define PFC_WIN_POS 0x69070
+#define PFA_WIN_SIZE 0x68074
+#define PFB_WIN_SIZE 0x68874
+#define PFC_WIN_SIZE 0x69074
+
+/* legacy palette */
+#define LGC_PALETTE_A 0x4a000
+#define LGC_PALETTE_B 0x4a800
+
+/* interrupts */
+#define DE_MASTER_IRQ_CONTROL (1 << 31)
+#define DE_SPRITEB_FLIP_DONE (1 << 29)
+#define DE_SPRITEA_FLIP_DONE (1 << 28)
+#define DE_PLANEB_FLIP_DONE (1 << 27)
+#define DE_PLANEA_FLIP_DONE (1 << 26)
+#define DE_PCU_EVENT (1 << 25)
+#define DE_GTT_FAULT (1 << 24)
+#define DE_POISON (1 << 23)
+#define DE_PERFORM_COUNTER (1 << 22)
+#define DE_PCH_EVENT (1 << 21)
+#define DE_AUX_CHANNEL_A (1 << 20)
+#define DE_DP_A_HOTPLUG (1 << 19)
+#define DE_GSE (1 << 18)
+#define DE_PIPEB_VBLANK (1 << 15)
+#define DE_PIPEB_EVEN_FIELD (1 << 14)
+#define DE_PIPEB_ODD_FIELD (1 << 13)
+#define DE_PIPEB_LINE_COMPARE (1 << 12)
+#define DE_PIPEB_VSYNC (1 << 11)
+#define DE_PIPEB_FIFO_UNDERRUN (1 << 8)
+#define DE_PIPEA_VBLANK (1 << 7)
+#define DE_PIPEA_EVEN_FIELD (1 << 6)
+#define DE_PIPEA_ODD_FIELD (1 << 5)
+#define DE_PIPEA_LINE_COMPARE (1 << 4)
+#define DE_PIPEA_VSYNC (1 << 3)
+#define DE_PIPEA_FIFO_UNDERRUN (1 << 0)
+
+#define DEISR 0x44000
+#define DEIMR 0x44004
+#define DEIIR 0x44008
+#define DEIER 0x4400c
+
+#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + 0x10 * (pipe))
+#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + 0x10 * (pipe))
+#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + 0x10 * (pipe))
+#define GEN8_DE_PIPE_IER(pipe) (0x4440c + 0x10 * (pipe))
+
+/* GT interrupt */
+#define GT_SYNC_STATUS (1 << 2)
+#define GT_USER_INTERRUPT (1 << 0)
+
+#define GTISR 0x44010
+#define GTIMR 0x44014
+#define GTIIR 0x44018
+#define GTIER 0x4401c
+
+/* PCH */
+
+/* south display engine interrupt */
+#define SDE_CRT_HOTPLUG (1 << 11)
+#define SDE_PORTD_HOTPLUG (1 << 10)
+#define SDE_PORTC_HOTPLUG (1 << 9)
+#define SDE_PORTB_HOTPLUG (1 << 8)
+#define SDE_SDVOB_HOTPLUG (1 << 6)
+
+#define SDEISR 0xc4000
+#define SDEIMR 0xc4004
+#define SDEIIR 0xc4008
+#define SDEIER 0xc400c
+
+/* digital port hotplug */
+#define PCH_PORT_HOTPLUG 0xc4030
+#define PORTD_HOTPLUG_ENABLE (1 << 20)
+#define PORTD_PULSE_DURATION_2ms (0)
+#define PORTD_PULSE_DURATION_4_5ms (1 << 18)
+#define PORTD_PULSE_DURATION_6ms (2 << 18)
+#define PORTD_PULSE_DURATION_100ms (3 << 18)
+#define PORTD_HOTPLUG_NO_DETECT (0)
+#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16)
+#define PORTD_HOTPLUG_LONG_DETECT (1 << 17)
+#define PORTC_HOTPLUG_ENABLE (1 << 12)
+#define PORTC_PULSE_DURATION_2ms (0)
+#define PORTC_PULSE_DURATION_4_5ms (1 << 10)
+#define PORTC_PULSE_DURATION_6ms (2 << 10)
+#define PORTC_PULSE_DURATION_100ms (3 << 10)
+#define PORTC_HOTPLUG_NO_DETECT (0)
+#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8)
+#define PORTC_HOTPLUG_LONG_DETECT (1 << 9)
+#define PORTB_HOTPLUG_ENABLE (1 << 4)
+#define PORTB_PULSE_DURATION_2ms (0)
+#define PORTB_PULSE_DURATION_4_5ms (1 << 2)
+#define PORTB_PULSE_DURATION_6ms (2 << 2)
+#define PORTB_PULSE_DURATION_100ms (3 << 2)
+#define PORTB_HOTPLUG_NO_DETECT (0)
+#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
+#define PORTB_HOTPLUG_LONG_DETECT (1 << 1)
+
+#define PCH_GPIOA 0xc5010
+#define PCH_GPIOB 0xc5014
+#define PCH_GPIOC 0xc5018
+#define PCH_GPIOD 0xc501c
+#define PCH_GPIOE 0xc5020
+#define PCH_GPIOF 0xc5024
+#define PCH_GMBUS0 0xc5100
+#define PCH_GMBUS1 0xc5104
+#define PCH_GMBUS2 0xc5108
+#define PCH_GMBUS3 0xc510c
+#define PCH_GMBUS4 0xc5110
+#define PCH_GMBUS5 0xc5120
+
+#define PCH_DPLL_A 0xc6014
+#define PCH_DPLL_B 0xc6018
+
+#define PCH_FPA0 0xc6040
+#define PCH_FPA1 0xc6044
+#define PCH_FPB0 0xc6048
+#define PCH_FPB1 0xc604c
+
+#define PCH_DPLL_TEST 0xc606c
+
+#define PCH_DREF_CONTROL 0xC6200
+#define DREF_CONTROL_MASK 0x7fc3
+#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13)
+#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13)
+#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13)
+#define DREF_SSC_SOURCE_DISABLE (0<<11)
+#define DREF_SSC_SOURCE_ENABLE (2<<11)
+#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9)
+#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9)
+#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7)
+#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7)
+#define DREF_SSC4_DOWNSPREAD (0<<6)
+#define DREF_SSC4_CENTERSPREAD (1<<6)
+#define DREF_SSC1_DISABLE (0<<1)
+#define DREF_SSC1_ENABLE (1<<1)
+#define DREF_SSC4_DISABLE (0)
+#define DREF_SSC4_ENABLE (1)
+
+#define PCH_RAWCLK_FREQ 0xc6204
+#define FDL_TP1_TIMER_SHIFT 12
+#define FDL_TP1_TIMER_MASK (3<<12)
+#define FDL_TP2_TIMER_SHIFT 10
+#define FDL_TP2_TIMER_MASK (3<<10)
+#define RAWCLK_FREQ_MASK 0x3ff
+
+#define PCH_DPLL_TMR_CFG 0xc6208
+
+#define PCH_SSC4_PARMS 0xc6210
+#define PCH_SSC4_AUX_PARMS 0xc6214
+
+/* CPT */
+#define PCH_DPLL_ANALOG_CTL 0xc6300
+
+#define PCH_DPLL_SEL 0xc7000
+#define TRANSA_DPLL_ENABLE (1<<3)
+#define TRANSA_DPLLA_SEL (0)
+#define TRANSA_DPLLB_SEL (1<<0)
+#define TRANSB_DPLL_ENABLE (1<<7)
+#define TRANSB_DPLLA_SEL (0<<4)
+#define TRANSB_DPLLB_SEL (1<<4)
+#define TRANSC_DPLL_ENABLE (1<<11)
+#define TRANSC_DPLLA_SEL (0<<8)
+#define TRANSC_DPLLB_SEL (1<<8)
+
+/* transcoder */
+
+#define TRANS_HTOTAL_A 0xe0000
+#define TRANS_HTOTAL_SHIFT 16
+#define TRANS_HACTIVE_SHIFT 0
+#define TRANS_HBLANK_A 0xe0004
+#define TRANS_HBLANK_END_SHIFT 16
+#define TRANS_HBLANK_START_SHIFT 0
+#define TRANS_HSYNC_A 0xe0008
+#define TRANS_HSYNC_END_SHIFT 16
+#define TRANS_HSYNC_START_SHIFT 0
+#define TRANS_VTOTAL_A 0xe000c
+#define TRANS_VTOTAL_SHIFT 16
+#define TRANS_VACTIVE_SHIFT 0
+#define TRANS_VBLANK_A 0xe0010
+#define TRANS_VBLANK_END_SHIFT 16
+#define TRANS_VBLANK_START_SHIFT 0
+#define TRANS_VSYNC_A 0xe0014
+#define TRANS_VSYNC_END_SHIFT 16
+#define TRANS_VSYNC_START_SHIFT 0
+#define TRANS_VSYNCSHIFT_A 0xe0028
+
+#define TRANSA_DATA_M1 0xe0030
+#define TRANSA_DATA_N1 0xe0034
+#define TRANSA_DATA_M2 0xe0038
+#define TRANSA_DATA_N2 0xe003c
+#define TRANSA_DP_LINK_M1 0xe0040
+#define TRANSA_DP_LINK_N1 0xe0044
+#define TRANSA_DP_LINK_M2 0xe0048
+#define TRANSA_DP_LINK_N2 0xe004c
+
+#define TRANS_HTOTAL_B 0xe1000
+#define TRANS_HBLANK_B 0xe1004
+#define TRANS_HSYNC_B 0xe1008
+#define TRANS_VTOTAL_B 0xe100c
+#define TRANS_VBLANK_B 0xe1010
+#define TRANS_VSYNC_B 0xe1014
+#define TRANS_VSYNCSHIFT_B 0xe1028
+
+#define TRANSB_DATA_M1 0xe1030
+#define TRANSB_DATA_N1 0xe1034
+#define TRANSB_DATA_M2 0xe1038
+#define TRANSB_DATA_N2 0xe103c
+#define TRANSB_DP_LINK_M1 0xe1040
+#define TRANSB_DP_LINK_N1 0xe1044
+#define TRANSB_DP_LINK_M2 0xe1048
+#define TRANSB_DP_LINK_N2 0xe104c
+
+#define TRANS_HTOTAL_C 0xe2000
+#define TRANS_HBLANK_C 0xe2004
+#define TRANS_HSYNC_C 0xe2008
+#define TRANS_VTOTAL_C 0xe200c
+#define TRANS_VBLANK_C 0xe2010
+#define TRANS_VSYNC_C 0xe2014
+#define TRANS_VSYNCSHIFT_C 0xe2028
+
+#define TRANSC_DATA_M1 0xe2030
+#define TRANSC_DATA_N1 0xe2034
+#define TRANSC_DATA_M2 0xe2038
+#define TRANSC_DATA_N2 0xe203c
+#define TRANSC_DP_LINK_M1 0xe2040
+#define TRANSC_DP_LINK_N1 0xe2044
+#define TRANSC_DP_LINK_M2 0xe2048
+#define TRANSC_DP_LINK_N2 0xe204c
+
+#define TRANSACONF 0xf0008
+#define TRANSBCONF 0xf1008
+#define TRANSCCONF 0xf2008
+#define TRANS_DISABLE (0<<31)
+#define TRANS_ENABLE (1<<31)
+#define TRANS_STATE_MASK (1<<30)
+#define TRANS_STATE_DISABLE (0<<30)
+#define TRANS_STATE_ENABLE (1<<30)
+#define TRANS_FSYNC_DELAY_HB1 (0<<27)
+#define TRANS_FSYNC_DELAY_HB2 (1<<27)
+#define TRANS_FSYNC_DELAY_HB3 (2<<27)
+#define TRANS_FSYNC_DELAY_HB4 (3<<27)
+#define TRANS_DP_AUDIO_ONLY (1<<26)
+#define TRANS_DP_VIDEO_AUDIO (0<<26)
+#define TRANS_PROGRESSIVE (0<<21)
+#define TRANS_8BPC (0<<5)
+#define TRANS_10BPC (1<<5)
+#define TRANS_6BPC (2<<5)
+#define TRANS_12BPC (3<<5)
+
+#define FDI_RXA_CHICKEN 0xc200c
+#define FDI_RXB_CHICKEN 0xc2010
+#define FDI_RX_PHASE_SYNC_POINTER_ENABLE (1)
+
+/* CPU: FDI_TX */
+#define FDI_TXA_CTL 0x60100
+#define FDI_TXB_CTL 0x61100
+#define FDI_TXC_CTL 0x62100
+#define FDI_TX_DISABLE (0<<31)
+#define FDI_TX_ENABLE (1<<31)
+#define FDI_LINK_TRAIN_PATTERN_1 (0<<28)
+#define FDI_LINK_TRAIN_PATTERN_2 (1<<28)
+#define FDI_LINK_TRAIN_PATTERN_IDLE (2<<28)
+#define FDI_LINK_TRAIN_NONE (3<<28)
+#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0<<25)
+#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1<<25)
+#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2<<25)
+#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3<<25)
+#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22)
+#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22)
+#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2<<22)
+#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3<<22)
+/* ILK always use 400mV 0dB for voltage swing and pre-emphasis level.
+ SNB has different settings. */
+/* SNB A-stepping */
+#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38<<22)
+#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02<<22)
+#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22)
+#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22)
+/* SNB B-stepping */
+#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x0<<22)
+#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a<<22)
+#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22)
+#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22)
+#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f<<22)
+#define FDI_DP_PORT_WIDTH_X1 (0<<19)
+#define FDI_DP_PORT_WIDTH_X2 (1<<19)
+#define FDI_DP_PORT_WIDTH_X3 (2<<19)
+#define FDI_DP_PORT_WIDTH_X4 (3<<19)
+#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18)
+/* Ironlake: hardwired to 1 */
+#define FDI_TX_PLL_ENABLE (1<<14)
+/* both Tx and Rx */
+#define FDI_SCRAMBLING_ENABLE (0<<7)
+#define FDI_SCRAMBLING_DISABLE (1<<7)
+
+/* Additional cpu TX control regs, from ivb bspec */
+#define DPAFE_BMFUNC 0x6c024
+#define DPAFE_DL_IREFCAL0 0x6c02c
+#define DPAFE_DL_IREFCAL1 0x6c030
+#define DPAFE_DP_IREFCAL 0x6c034
+
+/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
+#define FDI_RXA_CTL 0xf000c
+#define FDI_RXB_CTL 0xf100c
+#define FDI_RXC_CTL 0xf200c
+#define FDI_RX_ENABLE (1<<31)
+#define FDI_RX_DISABLE (0<<31)
+/* train, dp width same as FDI_TX */
+#define FDI_DP_PORT_WIDTH_X8 (7<<19)
+#define FDI_8BPC (0<<16)
+#define FDI_10BPC (1<<16)
+#define FDI_6BPC (2<<16)
+#define FDI_12BPC (3<<16)
+#define FDI_LINK_REVERSE_OVERWRITE (1<<15)
+#define FDI_DMI_LINK_REVERSE_MASK (1<<14)
+#define FDI_RX_PLL_ENABLE (1<<13)
+#define FDI_FS_ERR_CORRECT_ENABLE (1<<11)
+#define FDI_FE_ERR_CORRECT_ENABLE (1<<10)
+#define FDI_FS_ERR_REPORT_ENABLE (1<<9)
+#define FDI_FE_ERR_REPORT_ENABLE (1<<8)
+#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6)
+#define FDI_SEL_RAWCLK (0<<4)
+#define FDI_SEL_PCDCLK (1<<4)
+/* CPT */
+#define FDI_AUTO_TRAINING (1<<10)
+#define FDI_LINK_TRAIN_PATTERN_1_CPT (0<<8)
+#define FDI_LINK_TRAIN_PATTERN_2_CPT (1<<8)
+#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8)
+#define FDI_LINK_TRAIN_NORMAL_CPT (3<<8)
+#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8)
+
+#define FDI_RXA_MISC 0xf0010
+#define FDI_RXB_MISC 0xf1010
+#define FDI_RXC_MISC 0xf2010
+#define FDI_RXA_TUSIZE1 0xf0030
+#define FDI_RXA_TUSIZE2 0xf0038
+#define FDI_RXB_TUSIZE1 0xf1030
+#define FDI_RXB_TUSIZE2 0xf1038
+#define FDI_RXC_TUSIZE1 0xf2030
+#define FDI_RXC_TUSIZE2 0xf2038
+
+/* FDI_RX interrupt register format */
+#define FDI_RX_INTER_LANE_ALIGN (1<<10)
+#define FDI_RX_SYMBOL_LOCK (1<<9) /* train 2 */
+#define FDI_RX_BIT_LOCK (1<<8) /* train 1 */
+#define FDI_RX_TRAIN_PATTERN_2_FAIL (1<<7)
+#define FDI_RX_FS_CODE_ERR (1<<6)
+#define FDI_RX_FE_CODE_ERR (1<<5)
+#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1<<4)
+#define FDI_RX_HDCP_LINK_FAIL (1<<3)
+#define FDI_RX_PIXEL_FIFO_OVERFLOW (1<<2)
+#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1)
+#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0)
+
+#define FDI_RXA_IIR 0xf0014
+#define FDI_RXA_IMR 0xf0018
+#define FDI_RXB_IIR 0xf1014
+#define FDI_RXB_IMR 0xf1018
+
+#define FDI_PLL_CTL_1 0xfe000
+#define FDI_PLL_CTL_2 0xfe004
+
+/* CRT */
+#define PCH_ADPA 0xe1100
+#define ADPA_TRANS_SELECT_MASK (1<<30)
+#define ADPA_TRANS_A_SELECT 0
+#define ADPA_TRANS_B_SELECT (1<<30)
+/* HPD is here */
+#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */
+#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24)
+#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24)
+#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
+#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24)
+#define ADPA_CRT_HOTPLUG_ENABLE (1<<23)
+#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22)
+#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22)
+#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21)
+#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21)
+#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20)
+#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18)
+#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17)
+#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17)
+#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
+/* polarity control not changed */
+
+/* or SDVOB */
+#define HDMIB 0xe1140
+#define PORT_ENABLE (1 << 31)
+#define TRANSCODER_A (0)
+#define TRANSCODER_B (1 << 30)
+#define COLOR_FORMAT_8bpc (0)
+#define COLOR_FORMAT_12bpc (3 << 26)
+#define SDVOB_HOTPLUG_ENABLE (1 << 23)
+#define SDVO_ENCODING (0)
+#define TMDS_ENCODING (2 << 10)
+#define NULL_PACKET_VSYNC_ENABLE (1 << 9)
+#define SDVOB_BORDER_ENABLE (1 << 7)
+#define AUDIO_ENABLE (1 << 6)
+#define VSYNC_ACTIVE_HIGH (1 << 4)
+#define HSYNC_ACTIVE_HIGH (1 << 3)
+#define PORT_DETECTED (1 << 2)
+
+#define HDMIC 0xe1150
+#define HDMID 0xe1160
+#define PCH_LVDS 0xe1180
+
+/* Since IVB, the old _CTL2 is now _CTL and the old _CTL is now _DATA. */
+#define BLC_PWM_CPU_CTL2 0x48250
+#define BLC_PWM2_CPU_CTL2 0x48350
+#define PWM_ENABLE (1 << 31)
+#define PWM_PIPE_A (0 << 29)
+#define PWM_PIPE_B (1 << 29)
+#define BLC_PWM_CPU_CTL 0x48254
+#define BLC_PWM2_CPU_CTL 0x48354
+#define BLC_MISC_CTL 0x48360
+
+#define UTIL_PIN_CTL 0x48400
+
+#define BLC_PWM_PCH_CTL1 0xc8250
+#define PWM_PCH_ENABLE (1 << 31)
+#define PWM_POLARITY_ACTIVE_LOW (1 << 29)
+#define PWM_POLARITY_ACTIVE_HIGH (0 << 29)
+#define PWM_POLARITY_ACTIVE_LOW2 (1 << 28)
+#define PWM_POLARITY_ACTIVE_HIGH2 (0 << 28)
+
+#define BLC_PWM_PCH_CTL2 0xc8254
+
+#define PCH_PP_STATUS 0xc7200
+#define PCH_PP_CONTROL 0xc7204
+#define EDP_FORCE_VDD (1 << 3)
+#define EDP_BLC_ENABLE (1 << 2)
+#define PANEL_POWER_RESET (1 << 1)
+#define PANEL_POWER_OFF (0 << 0)
+#define PANEL_POWER_ON (1 << 0)
+#define PCH_PP_ON_DELAYS 0xc7208
+#define EDP_PANEL (1 << 30)
+#define PCH_PP_OFF_DELAYS 0xc720c
+#define PCH_PP_DIVISOR 0xc7210
+
+#define AUD_CONFIG 0x62000
+#define AUD_DEBUG 0x62010
+#define AUD_VID_DID 0x62020
+#define AUD_RID 0x62024
+#define AUD_SUBN_CNT 0x62028
+#define AUD_FUNC_GRP 0x62040
+#define AUD_SUBN_CNT2 0x62044
+#define AUD_GRP_CAP 0x62048
+#define AUD_PWRST 0x6204c
+#define AUD_SUPPWR 0x62050
+#define AUD_SID 0x62054
+#define AUD_OUT_CWCAP 0x62070
+#define AUD_OUT_PCMSIZE 0x62074
+#define AUD_OUT_STR 0x62078
+#define AUD_OUT_DIG_CNVT 0x6207c
+#define AUD_OUT_CH_STR 0x62080
+#define AUD_OUT_STR_DESC 0x62084
+#define AUD_PINW_CAP 0x620a0
+#define AUD_PIN_CAP 0x620a4
+#define AUD_PINW_CONNLNG 0x620a8
+#define AUD_PINW_CONNLST 0x620ac
+#define AUD_PINW_CNTR 0x620b0
+#define AUD_PINW_UNSOLRESP 0x620b8
+#define AUD_CNTL_ST 0x620b4
+#define AUD_PINW_CONFIG 0x620bc
+#define AUD_HDMIW_STATUS 0x620d4
+#define AUD_HDMIW_HDMIEDID 0x6210c
+#define AUD_HDMIW_INFOFR 0x62118
+#define AUD_CONV_CHCNT 0x62120
+#define AUD_CTS_ENABLE 0x62128
+
+#define VIDEO_DIP_CTL 0x61170
+#define VIDEO_DIP_DATA 0x61178
+
+/* CPT */
+#define TRANS_DP_CTL_A 0xe0300
+#define TRANS_DP_CTL_B 0xe1300
+#define TRANS_DP_CTL_C 0xe2300
+#define TRANS_DP_OUTPUT_ENABLE (1<<31)
+#define TRANS_DP_PORT_SEL_B (0<<29)
+#define TRANS_DP_PORT_SEL_C (1<<29)
+#define TRANS_DP_PORT_SEL_D (2<<29)
+#define TRANS_DP_PORT_SEL_MASK (3<<29)
+#define TRANS_DP_AUDIO_ONLY (1<<26)
+#define TRANS_DP_ENH_FRAMING (1<<18)
+#define TRANS_DP_8BPC (0<<9)
+#define TRANS_DP_10BPC (1<<9)
+#define TRANS_DP_6BPC (2<<9)
+#define TRANS_DP_12BPC (3<<9)
+#define TRANS_DP_VSYNC_ACTIVE_HIGH (1<<4)
+#define TRANS_DP_VSYNC_ACTIVE_LOW 0
+#define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3)
+#define TRANS_DP_HSYNC_ACTIVE_LOW 0
+
+/* Debug regs */
+#define GEN6_TD_CTL 0x7000 /* <= GEN5 was at 0x8000 */
+#define GEN6_TD_CTL_FORCE_TD_BKPT (1<<4)
+
+/* Port debugging
+ */
+
+#define PORT_DBG 0x42308
+#define PORT_DBG_DRRS_HW_STATE_OFF (0<<30)
+#define PORT_DBG_DRRS_HW_STATE_LOW (1<<30)
+#define PORT_DBG_DRRS_HW_STATE_HIGH (2<<30)
+
+/* RC6 residence counters
+ */
+#define RC6_RESIDENCY_TIME 0x138108
+#define RC6p_RESIDENCY_TIME 0x13810C
+#define RC6pp_RESIDENCY_TIME 0x138110
+
+#define GEN6_RPNSWREQ 0xA008
+#define GEN6_RC_VIDEO_FREQ 0xA00C
+#define GEN6_RC_CONTROL 0xA090
+#define GEN6_RP_DOWN_TIMEOUT 0xA010
+#define GEN6_RP_INTERRUPT_LIMITS 0xA014
+#define GEN6_RPSTAT1 0xA01C
+#define GEN6_RP_CONTROL 0xA024
+#define GEN6_RP_UP_THRESHOLD 0xA02C
+#define GEN6_RP_DOWN_THRESHOLD 0xA030
+#define GEN6_RP_CUR_UP_EI 0xA050
+#define GEN6_RP_CUR_UP 0xA054
+#define GEN6_RP_PREV_UP 0xA058
+#define GEN6_RP_CUR_DOWN_EI 0xA05C
+#define GEN6_RP_CUR_DOWN 0xA060
+#define GEN6_RP_PREV_DOWN 0xA064
+#define GEN6_RP_UP_EI 0xA068
+#define GEN6_RP_DOWN_EI 0xA06C
+#define GEN6_RP_IDLE_HYSTERSIS 0xA070
+#define GEN6_RC_STATE 0xA094
+#define GEN6_RC1_WAKE_RATE_LIMIT 0xA098
+#define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C
+#define GEN6_RC6pp_WAKE_RATE_LIMIT 0xA0A0
+#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8
+#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC
+#define GEN6_RC_SLEEP 0xA0B0
+#define GEN6_RC1e_THRESHOLD 0xA0B4
+#define GEN6_RC6_THRESHOLD 0xA0B8
+#define GEN6_RC6p_THRESHOLD 0xA0BC
+#define GEN6_RC6pp_THRESHOLD 0xA0C0
+#define GEN6_PMINTRMSK 0xA168
+#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8
+#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC
+#define GEN6_PMIER 0x4402C
+#define GEN6_PMIMR 0x44024 /* rps_lock */
+#define GEN6_PMINTRMSK 0xA168
+
+/* Haswell-related items */
+
+/* HSW Power Wells */
+#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */
+#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */
+#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */
+#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */
+#define HSW_PWR_WELL_ENABLE_REQUEST (1<<31)
+#define HSW_PWR_WELL_STATE_ENABLED (1<<30)
+#define HSW_PWR_WELL_CTL5 0x45410
+#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31)
+#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20)
+#define HSW_PWR_WELL_FORCE_ON (1<<19)
+#define HSW_PWR_WELL_CTL6 0x45414
+
+/* Per-pipe DDI Function Control */
+#define PIPE_DDI_FUNC_CTL_A 0x60400
+#define PIPE_DDI_FUNC_CTL_B 0x61400
+#define PIPE_DDI_FUNC_CTL_C 0x62400
+#define PIPE_DDI_FUNC_CTL_EDP 0x6F400
+#define DDI_FUNC_CTL(pipe) _PIPE(pipe, \
+ PIPE_DDI_FUNC_CTL_A, \
+ PIPE_DDI_FUNC_CTL_B)
+#define PIPE_DDI_FUNC_ENABLE (1<<31)
+/* Those bits are ignored by pipe EDP since it can only connect to DDI A */
+#define PIPE_DDI_PORT_MASK (0xf<<28)
+#define PIPE_DDI_SELECT_PORT(x) ((x)<<28)
+#define PIPE_DDI_MODE_SELECT_HDMI (0<<24)
+#define PIPE_DDI_MODE_SELECT_DVI (1<<24)
+#define PIPE_DDI_MODE_SELECT_DP_SST (2<<24)
+#define PIPE_DDI_MODE_SELECT_DP_MST (3<<24)
+#define PIPE_DDI_MODE_SELECT_FDI (4<<24)
+#define PIPE_DDI_BPC_8 (0<<20)
+#define PIPE_DDI_BPC_10 (1<<20)
+#define PIPE_DDI_BPC_6 (2<<20)
+#define PIPE_DDI_BPC_12 (3<<20)
+#define PIPE_DDI_BFI_ENABLE (1<<4)
+#define PIPE_DDI_PORT_WIDTH_X1 (0<<1)
+#define PIPE_DDI_PORT_WIDTH_X2 (1<<1)
+#define PIPE_DDI_PORT_WIDTH_X4 (3<<1)
+
+/* DisplayPort Transport Control */
+#define DP_TP_CTL_A 0x64040
+#define DP_TP_CTL_B 0x64140
+#define DP_TP_CTL_C 0x64240
+#define DP_TP_CTL_D 0x64340
+#define DP_TP_CTL_E 0x64440
+#define DP_TP_CTL_ENABLE (1<<31)
+#define DP_TP_CTL_MODE_SST (0<<27)
+#define DP_TP_CTL_MODE_MST (1<<27)
+#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18)
+#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15)
+#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8)
+#define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8)
+#define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8)
+#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8)
+
+/* DisplayPort Transport Status */
+#define DP_TP_STATUS_A 0x64044
+#define DP_TP_STATUS_B 0x64144
+#define DP_TP_STATUS_C 0x64244
+#define DP_TP_STATUS_D 0x64344
+#define DP_TP_STATUS_E 0x64444
+#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12)
+
+/* DDI Buffer Control */
+#define DDI_BUF_CTL_A 0x64000
+#define DDI_BUF_CTL_B 0x64100
+#define DDI_BUF_CTL_C 0x64200
+#define DDI_BUF_CTL_D 0x64300
+#define DDI_BUF_CTL_E 0x64400
+#define DDI_BUF_CTL_ENABLE (1<<31)
+#define DDI_BUF_EMP_400MV_0DB_HSW (0<<24) /* Sel0 */
+#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */
+#define DDI_BUF_EMP_400MV_6DB_HSW (2<<24) /* Sel2 */
+#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */
+#define DDI_BUF_EMP_600MV_0DB_HSW (4<<24) /* Sel4 */
+#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */
+#define DDI_BUF_EMP_600MV_6DB_HSW (6<<24) /* Sel6 */
+#define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */
+#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */
+#define DDI_BUF_EMP_MASK (0xf<<24)
+#define DDI_BUF_IS_IDLE (1<<7)
+#define DDI_PORT_WIDTH_X1 (0<<1)
+#define DDI_PORT_WIDTH_X2 (1<<1)
+#define DDI_PORT_WIDTH_X4 (3<<1)
+#define DDI_INIT_DISPLAY_DETECTED (1<<0)
+
+/* LPT PIXCLK_GATE */
+#define PIXCLK_GATE 0xC6020
+#define PIXCLK_GATE_UNGATE 1<<0
+#define PIXCLK_GATE_GATE 0<<0
+
+/* SPLL */
+#define SPLL_CTL 0x46020
+#define SPLL_PLL_ENABLE (1<<31)
+#define SPLL_PLL_SCC (1<<28)
+#define SPLL_PLL_NON_SCC (2<<28)
+#define SPLL_PLL_FREQ_810MHz (0<<26)
+#define SPLL_PLL_FREQ_1350MHz (1<<26)
+
+/* WRPLL */
+#define WRPLL_CTL1 0x46040
+#define WRPLL_CTL2 0x46060
+#define WRPLL_PLL_ENABLE (1<<31)
+#define WRPLL_PLL_SELECT_SSC (0x01<<28)
+#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28)
+#define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28)
+/* WRPLL divider programming */
+#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0)
+#define WRPLL_DIVIDER_POST(x) ((x)<<8)
+#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16)
+
+/* Port clock selection */
+#define PORT_CLK_SEL_A 0x46100
+#define PORT_CLK_SEL_B 0x46104
+#define PORT_CLK_SEL_C 0x46108
+#define PORT_CLK_SEL_D 0x4610C
+#define PORT_CLK_SEL_E 0x46110
+#define PORT_CLK_SEL_LCPLL_2700 (0<<29)
+#define PORT_CLK_SEL_LCPLL_1350 (1<<29)
+#define PORT_CLK_SEL_LCPLL_810 (2<<29)
+#define PORT_CLK_SEL_SPLL (3<<29)
+#define PORT_CLK_SEL_WRPLL1 (4<<29)
+#define PORT_CLK_SEL_WRPLL2 (5<<29)
+
+/* Pipe clock selection */
+#define PIPE_CLK_SEL_A 0x46140
+#define PIPE_CLK_SEL_B 0x46144
+#define PIPE_CLK_SEL_C 0x46148
+/* For each pipe, we need to select the corresponding port clock */
+#define PIPE_CLK_SEL_DISABLED (0x0<<29)
+#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29)
+
+/* LCPLL Control */
+#define LCPLL_CTL 0x130040
+#define LCPLL_PLL_DISABLE (1<<31)
+#define LCPLL_PLL_LOCK (1<<30)
+#define LCPLL_CD_CLOCK_DISABLE (1<<25)
+#define LCPLL_CD2X_CLOCK_DISABLE (1<<23)
+
+/* Pipe WM_LINETIME - watermark line time */
+#define WM_PIPE_A 0x45100
+#define WM_PIPE_B 0x45104
+#define WM_PIPE_C 0x45200
+#define WM_LP1 0x45108
+#define WM_LP2 0x4510C
+#define WM_LP3 0x45110
+#define WM_LP1_SPR 0x45120
+#define WM_LP2_SPR 0x45124
+#define WM_LP3_SPR 0x45128
+#define WM_MISC 0x45260
+#define WM_SR_CNT 0x45264
+#define WM_DBG 0x45280
+#define PIPE_WM_LINETIME_A 0x45270
+#define PIPE_WM_LINETIME_B 0x45274
+#define PIPE_WM_LINETIME_C 0x45278
+#define PIPE_WM_LINETIME_MASK (0x1ff)
+#define PIPE_WM_LINETIME_TIME(x) ((x))
+#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16)
+#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16)
+
+/* SFUSE_STRAP */
+#define SFUSE_STRAP 0xc2014
+#define SFUSE_STRAP_DDIB_DETECTED (1<<2)
+#define SFUSE_STRAP_DDIC_DETECTED (1<<1)
+#define SFUSE_STRAP_DDID_DETECTED (1<<0)
+
+/* Valleyview related items */
+#define VLV_DISPLAY_BASE 0x180000
+
+/*
+ * IOSF sideband
+ */
+#define VLV_IOSF_DOORBELL_REQ (VLV_DISPLAY_BASE + 0x2100)
+#define IOSF_DEVFN_SHIFT 24
+#define IOSF_OPCODE_SHIFT 16
+#define IOSF_PORT_SHIFT 8
+#define IOSF_BYTE_ENABLES_SHIFT 4
+#define IOSF_BAR_SHIFT 1
+#define IOSF_SB_BUSY (1<<0)
+#define IOSF_PORT_BUNIT 0x3
+#define IOSF_PORT_PUNIT 0x4
+#define IOSF_PORT_NC 0x11
+#define IOSF_PORT_DPIO 0x12
+#define IOSF_PORT_DPIO_2 0x1a
+#define IOSF_PORT_GPIO_NC 0x13
+#define IOSF_PORT_CCK 0x14
+#define IOSF_PORT_CCU 0xA9
+#define IOSF_PORT_GPS_CORE 0x48
+#define IOSF_PORT_FLISDSI 0x1B
+#define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104)
+#define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108)
+
+#endif /* _I810_REG_H */
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
new file mode 100644
index 0000000..66c90de
--- /dev/null
+++ b/lib/ioctl_wrappers.c
@@ -0,0 +1,1144 @@
+/*
+ * Copyright © 2007, 2011, 2013, 2014 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>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef ANDROID
+#define _GNU_SOURCE
+#else
+#include <libgen.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <pciaccess.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <termios.h>
+#include <errno.h>
+
+#include "drmtest.h"
+#include "i915_drm.h"
+#include "intel_chipset.h"
+#include "intel_io.h"
+#include "igt_debugfs.h"
+#include "config.h"
+
+#include "ioctl_wrappers.h"
+
+/**
+ * SECTION:ioctl_wrappers
+ * @short_description: ioctl wrappers and related functions
+ * @title: ioctl wrappers
+ * @include: ioctl_wrappers.h
+ *
+ * This helper library contains simple functions to wrap the raw drm/i915 kernel
+ * ioctls. The normal versions never pass any error codes to the caller and use
+ * igt_assert() to check for error conditions instead. For some ioctls raw
+ * wrappers which do pass on error codes are available. These raw wrappers have
+ * a __ prefix.
+ *
+ * For wrappers which check for feature bits there can also be two versions: The
+ * normal one simply returns a boolean to the caller. But when skipping the
+ * testcase entirely is the right action then it's better to use igt_skip()
+ * directly in the wrapper. Such functions have _require_ in their name to
+ * distinguish them.
+ */
+
+/**
+ * gem_handle_to_libdrm_bo:
+ * @bufmgr: libdrm buffer manager instance
+ * @fd: open i915 drm file descriptor
+ * @name: buffer name in libdrm
+ * @handle: gem buffer object handle
+ *
+ * This helper function imports a raw gem buffer handle into the libdrm buffer
+ * manager.
+ *
+ * Returns: The imported libdrm buffer manager object.
+ */
+drm_intel_bo *
+gem_handle_to_libdrm_bo(drm_intel_bufmgr *bufmgr, int fd, const char *name, uint32_t handle)
+{
+ struct drm_gem_flink flink;
+ int ret;
+ drm_intel_bo *bo;
+
+ memset(&flink, 0, sizeof(handle));
+ flink.handle = handle;
+ ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+ igt_assert(ret == 0);
+ errno = 0;
+
+ bo = drm_intel_bo_gem_create_from_name(bufmgr, name, flink.name);
+ igt_assert(bo);
+
+ return bo;
+}
+
+/**
+ * gem_get_tiling:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @tiling: (out) tiling mode of the gem buffer
+ * @swizzle: (out) bit 6 swizzle mode
+ *
+ * This wraps the GET_TILING ioctl.
+ */
+void
+gem_get_tiling(int fd, uint32_t handle, uint32_t *tiling, uint32_t *swizzle)
+{
+ struct drm_i915_gem_get_tiling get_tiling;
+ int ret;
+
+ memset(&get_tiling, 0, sizeof(get_tiling));
+ get_tiling.handle = handle;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);
+ igt_assert(ret == 0);
+
+ *tiling = get_tiling.tiling_mode;
+ *swizzle = get_tiling.swizzle_mode;
+}
+
+int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
+{
+ struct drm_i915_gem_set_tiling st;
+ int ret;
+
+ memset(&st, 0, sizeof(st));
+ do {
+ st.handle = handle;
+ st.tiling_mode = tiling;
+ st.stride = tiling ? stride : 0;
+
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &st);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+ if (ret != 0)
+ return -errno;
+
+ errno = 0;
+ igt_assert(st.tiling_mode == tiling);
+ return 0;
+}
+
+/**
+ * gem_set_tiling:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @tiling: tiling mode bits
+ * @stride: stride of the buffer when using a tiled mode, otherwise must be 0
+ *
+ * This wraps the SET_TILING ioctl.
+ */
+void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
+{
+ igt_assert(__gem_set_tiling(fd, handle, tiling, stride) == 0);
+}
+
+struct local_drm_i915_gem_caching {
+ uint32_t handle;
+ uint32_t caching;
+};
+
+#define LOCAL_DRM_I915_GEM_SET_CACHEING 0x2f
+#define LOCAL_DRM_I915_GEM_GET_CACHEING 0x30
+#define LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING \
+ DRM_IOW(DRM_COMMAND_BASE + LOCAL_DRM_I915_GEM_SET_CACHEING, struct local_drm_i915_gem_caching)
+#define LOCAL_DRM_IOCTL_I915_GEM_GET_CACHEING \
+ DRM_IOWR(DRM_COMMAND_BASE + LOCAL_DRM_I915_GEM_GET_CACHEING, struct local_drm_i915_gem_caching)
+
+/**
+ * gem_set_caching:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @caching: caching mode bits
+ *
+ * This wraps the SET_CACHING ioctl. Note that this function internally calls
+ * igt_require() when SET_CACHING isn't available, hence automatically skips the
+ * test. Therefore always extract test logic which uses this into its own
+ * subtest.
+ */
+void gem_set_caching(int fd, uint32_t handle, uint32_t caching)
+{
+ struct local_drm_i915_gem_caching arg;
+ int ret;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = handle;
+ arg.caching = caching;
+ ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING, &arg);
+
+ igt_assert(ret == 0 || (errno == ENOTTY || errno == EINVAL));
+ igt_require(ret == 0);
+ errno = 0;
+}
+
+/**
+ * gem_get_caching:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This wraps the GET_CACHING ioctl.
+ *
+ * Returns: The current caching mode bits.
+ */
+uint32_t gem_get_caching(int fd, uint32_t handle)
+{
+ struct local_drm_i915_gem_caching arg;
+ int ret;
+
+ arg.handle = handle;
+ arg.caching = 0;
+ ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_GET_CACHEING, &arg);
+ igt_assert(ret == 0);
+ errno = 0;
+
+ return arg.caching;
+}
+
+/**
+ * gem_open:
+ * @fd: open i915 drm file descriptor
+ * @name: flink buffer name
+ *
+ * This wraps the GEM_OPEN ioctl, which is used to import an flink name.
+ *
+ * Returns: gem file-private buffer handle of the open object.
+ */
+uint32_t gem_open(int fd, uint32_t name)
+{
+ struct drm_gem_open open_struct;
+ int ret;
+
+ memset(&open_struct, 0, sizeof(open_struct));
+ open_struct.name = name;
+ ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open_struct);
+ igt_assert(ret == 0);
+ igt_assert(open_struct.handle != 0);
+ errno = 0;
+
+ return open_struct.handle;
+}
+
+/**
+ * gem_flink:
+ * @fd: open i915 drm file descriptor
+ * @handle: file-private gem buffer object handle
+ *
+ * This wraps the GEM_FLINK ioctl, which is used to export a gem buffer object
+ * into the device-global flink namespace. See gem_open() for opening such a
+ * buffer name on a different i915 drm file descriptor.
+ *
+ * Returns: The created flink buffer name.
+ */
+uint32_t gem_flink(int fd, uint32_t handle)
+{
+ struct drm_gem_flink flink;
+ int ret;
+
+ memset(&flink, 0, sizeof(flink));
+ flink.handle = handle;
+ ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+ igt_assert(ret == 0);
+ errno = 0;
+
+ return flink.name;
+}
+
+/**
+ * gem_close:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This wraps the GEM_CLOSE ioctl, which to release a file-private gem buffer
+ * handle.
+ */
+void gem_close(int fd, uint32_t handle)
+{
+ struct drm_gem_close close_bo;
+
+ memset(&close_bo, 0, sizeof(close_bo));
+ close_bo.handle = handle;
+ do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+}
+
+/**
+ * gem_write:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @offset: offset within the buffer of the subrange
+ * @buf: pointer to the data to write into the buffer
+ * @length: size of the subrange
+ *
+ * This wraps the PWRITE ioctl, which is to upload a linear data to a subrange
+ * of a gem buffer object.
+ */
+void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t length)
+{
+ struct drm_i915_gem_pwrite gem_pwrite;
+
+ memset(&gem_pwrite, 0, sizeof(gem_pwrite));
+ gem_pwrite.handle = handle;
+ gem_pwrite.offset = offset;
+ gem_pwrite.size = length;
+ gem_pwrite.data_ptr = (uintptr_t)buf;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
+}
+
+/**
+ * gem_read:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @offset: offset within the buffer of the subrange
+ * @buf: pointer to the data to read into
+ * @length: size of the subrange
+ *
+ * This wraps the PREAD ioctl, which is to download a linear data to a subrange
+ * of a gem buffer object.
+ */
+void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t length)
+{
+ struct drm_i915_gem_pread gem_pread;
+
+ memset(&gem_pread, 0, sizeof(gem_pread));
+ gem_pread.handle = handle;
+ gem_pread.offset = offset;
+ gem_pread.size = length;
+ gem_pread.data_ptr = (uintptr_t)buf;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
+}
+
+/**
+ * gem_set_domain:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @read_domains: gem domain bits for read access
+ * @write_domain: gem domain bit for write access
+ *
+ * This wraps the SET_DOMAIN ioctl, which is used to control the coherency of
+ * the gem buffer object between the cpu and gtt mappings. It is also use to
+ * synchronize with outstanding rendering in general, but for that use-case
+ * please have a look at gem_sync().
+ */
+void gem_set_domain(int fd, uint32_t handle,
+ uint32_t read_domains, uint32_t write_domain)
+{
+ struct drm_i915_gem_set_domain set_domain;
+
+ memset(&set_domain, 0, sizeof(set_domain));
+ set_domain.handle = handle;
+ set_domain.read_domains = read_domains;
+ set_domain.write_domain = write_domain;
+
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
+}
+
+/**
+ * gem_sync:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This is a wrapper around gem_set_domain() which simply blocks for any
+ * outstanding rendering to complete.
+ */
+void gem_sync(int fd, uint32_t handle)
+{
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+}
+
+uint32_t __gem_create(int fd, int size)
+{
+ struct drm_i915_gem_create create;
+ int ret;
+
+ memset(&create, 0, sizeof(create));
+ create.handle = 0;
+ create.size = size;
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+
+ if (ret < 0)
+ return 0;
+
+ errno = 0;
+ return create.handle;
+}
+
+/**
+ * gem_create:
+ * @fd: open i915 drm file descriptor
+ * @size: desired size of the buffer
+ *
+ * This wraps the GEM_CREATE ioctl, which allocates a new gem buffer object of
+ * @size.
+ *
+ * Returns: The file-private handle of the created buffer object
+ */
+uint32_t gem_create(int fd, int size)
+{
+ struct drm_i915_gem_create create;
+
+ memset(&create, 0, sizeof(create));
+ create.handle = 0;
+ create.size = size;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+ igt_assert(create.handle);
+
+ return create.handle;
+}
+
+/**
+ * gem_execbuf:
+ * @fd: open i915 drm file descriptor
+ * @execbuf: execbuffer data structure
+ *
+ * This wraps the EXECBUFFER2 ioctl, which submits a batchbuffer for the gpu to
+ * run.
+ */
+void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
+{
+ int ret;
+
+ ret = drmIoctl(fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ execbuf);
+ igt_assert(ret == 0);
+ errno = 0;
+}
+
+/**
+ * gem_mmap__gtt:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @size: size of the gem buffer
+ * @prot: memory protection bits as used by mmap()
+ *
+ * This functions wraps up procedure to establish a memory mapping through the
+ * GTT.
+ *
+ * Returns: A pointer to the created memory mapping.
+ */
+void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot)
+{
+ struct drm_i915_gem_mmap_gtt mmap_arg;
+ void *ptr;
+
+ memset(&mmap_arg, 0, sizeof(mmap_arg));
+ mmap_arg.handle = handle;
+ if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
+ return NULL;
+
+ ptr = mmap64(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
+ if (ptr == MAP_FAILED)
+ ptr = NULL;
+ else
+ errno = 0;
+
+ return ptr;
+}
+
+struct local_i915_gem_mmap_v2 {
+ uint32_t handle;
+ uint32_t pad;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t addr_ptr;
+ uint64_t flags;
+#define I915_MMAP_WC 0x1
+};
+#define LOCAL_IOCTL_I915_GEM_MMAP_v2 DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct local_i915_gem_mmap_v2)
+
+bool gem_mmap__has_wc(int fd)
+{
+ static int has_wc = -1;
+
+ if (has_wc == -1) {
+ struct drm_i915_getparam gp;
+ int val = -1;
+
+ has_wc = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = 30; /* MMAP_VERSION */
+ gp.value = &val;
+
+ /* Do we have the new mmap_ioctl? */
+ ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ if (val >= 1) {
+ struct local_i915_gem_mmap_v2 arg;
+
+ /* Does this device support wc-mmaps ? */
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = gem_create(fd, 4096);
+ arg.offset = 0;
+ arg.size = 4096;
+ arg.flags = I915_MMAP_WC;
+ has_wc = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_MMAP_v2, &arg) == 0;
+ gem_close(fd, arg.handle);
+ }
+ errno = 0;
+ }
+
+ return has_wc > 0;
+}
+
+/**
+ * gem_mmap__wc:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @offset: offset in the gem buffer of te mmap arena
+ * @size: size of the mmap arena
+ * @prot: memory protection bits as used by mmap()
+ *
+ * This functions wraps up procedure to establish a memory mapping through
+ * direct cpu access, bypassing the gpu and cpu caches completely and also
+ * bypassing the GTT system agent (i.e. there is no automatic tiling of
+ * the mmapping through the fence registers).
+ *
+ * Returns: A pointer to the created memory mapping.
+ */
+void *gem_mmap__wc(int fd, uint32_t handle, int offset, int size, int prot)
+{
+ struct local_i915_gem_mmap_v2 arg;
+
+ if (!gem_mmap__has_wc(fd)) {
+ errno = ENOSYS;
+ return NULL;
+ }
+
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = handle;
+ arg.offset = offset;
+ arg.size = size;
+ arg.flags = I915_MMAP_WC;
+ if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_MMAP_v2, &arg))
+ return NULL;
+
+ errno = 0;
+ return (void *)(uintptr_t)arg.addr_ptr;
+}
+
+/**
+ * gem_mmap__cpu:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @offset: offset in the gem buffer of te mmap arena
+ * @size: size of the mmap arena
+ * @prot: memory protection bits as used by mmap()
+ *
+ * This functions wraps up procedure to establish a memory mapping through
+ * direct cpu access, bypassing the gpu completely.
+ *
+ * Returns: A pointer to the created memory mapping.
+ */
+void *gem_mmap__cpu(int fd, uint32_t handle, int offset, int size, int prot)
+{
+ struct drm_i915_gem_mmap mmap_arg;
+
+ memset(&mmap_arg, 0, sizeof(mmap_arg));
+ mmap_arg.handle = handle;
+ mmap_arg.offset = offset;
+ mmap_arg.size = size;
+ if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))
+ return NULL;
+
+ errno = 0;
+ return (void *)(uintptr_t)mmap_arg.addr_ptr;
+}
+
+/**
+ * gem_madvise:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @state: desired madvise state
+ *
+ * This is a wraps the MADVISE ioctl, which is used in libdrm to implement
+ * opportunistic buffer object caching. Objects in the cache are set to DONTNEED
+ * (internally in the kernel tracked as purgeable objects). When such a cached
+ * object is in need again it must be set back to WILLNEED before first use.
+ *
+ * Returns: When setting the madvise state to WILLNEED this returns whether the
+ * backing storage was still available or not.
+ */
+int gem_madvise(int fd, uint32_t handle, int state)
+{
+ struct drm_i915_gem_madvise madv;
+
+ memset(&madv, 0, sizeof(madv));
+ madv.handle = handle;
+ madv.madv = state;
+ madv.retained = 1;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);
+
+ return madv.retained;
+}
+
+/**
+ * gem_context_create:
+ * @fd: open i915 drm file descriptor
+ *
+ * This is a wraps the CONTEXT_CREATE ioctl, which is used to allocate a new
+ * hardware context. Not that similarly to gem_set_caching() this wrapper calls
+ * igt_require() internally to correctly skip on kernels and platforms where hw
+ * context support is not available.
+ *
+ * Returns: The id of the allocated hw context.
+ */
+uint32_t gem_context_create(int fd)
+{
+ struct drm_i915_gem_context_create create;
+ int ret;
+
+ memset(&create, 0, sizeof(create));
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);
+ igt_require(ret == 0 || (errno != ENODEV && errno != EINVAL));
+ igt_assert(ret == 0);
+ errno = 0;
+
+ return create.ctx_id;
+}
+
+int __gem_context_destroy(int fd, uint32_t ctx_id)
+{
+ struct drm_i915_gem_context_destroy destroy;
+ int ret;
+
+ memset(&destroy, 0, sizeof(destroy));
+ destroy.ctx_id = ctx_id;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &destroy);
+ if (ret)
+ return -errno;
+ return 0;
+}
+
+/**
+ * gem_context_destroy:
+ * @fd: open i915 drm file descriptor
+ * @ctx_id: i915 hw context id
+ *
+ * This is a wraps the CONTEXT_DESTROY ioctl, which is used to free a hardware
+ * context.
+ */
+void gem_context_destroy(int fd, uint32_t ctx_id)
+{
+ struct drm_i915_gem_context_destroy destroy;
+
+ memset(&destroy, 0, sizeof(destroy));
+ destroy.ctx_id = ctx_id;
+
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &destroy);
+}
+
+/**
+ * gem_context_get_param:
+ * @fd: open i915 drm file descriptor
+ * @p: i915 hw context parameter
+ *
+ * This is a wraps the CONTEXT_GET_PARAM ioctl, which is used to free a hardware
+ * context. Not that similarly to gem_set_caching() this wrapper calls
+ * igt_require() internally to correctly skip on kernels and platforms where hw
+ * context parameter support is not available.
+ */
+void gem_context_get_param(int fd, struct local_i915_gem_context_param *p)
+{
+#define LOCAL_I915_GEM_CONTEXT_GETPARAM 0x34
+#define LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_GETPARAM, struct local_i915_gem_context_param)
+ do_ioctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM, p);
+}
+
+/**
+ * gem_context_set_param:
+ * @fd: open i915 drm file descriptor
+ * @p: i915 hw context parameter
+ *
+ * This is a wraps the CONTEXT_SET_PARAM ioctl, which is used to free a hardware
+ * context. Not that similarly to gem_set_caching() this wrapper calls
+ * igt_require() internally to correctly skip on kernels and platforms where hw
+ * context parameter support is not available.
+ */
+void gem_context_set_param(int fd, struct local_i915_gem_context_param *p)
+{
+#define LOCAL_I915_GEM_CONTEXT_SETPARAM 0x35
+#define LOCAL_IOCTL_I915_GEM_CONTEXT_SETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_SETPARAM, struct local_i915_gem_context_param)
+ do_ioctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_SETPARAM, p);
+}
+
+/**
+ * gem_context_require_param:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether hw context parameter support for @param
+ * is available. Automatically skips through igt_require() if not.
+ */
+void gem_context_require_param(int fd, uint64_t param)
+{
+ struct local_i915_gem_context_param p;
+
+ p.context = 0;
+ p.param = param;
+ p.value = 0;
+ p.size = 0;
+
+ igt_require(drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p) == 0);
+}
+
+/**
+ * gem_sw_finish:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This is a wraps the SW_FINISH ioctl, which is used to flush out frontbuffer
+ * rendering done through the direct cpu memory mappings. Shipping userspace
+ * does _not_ call this after frontbuffer rendering through gtt memory mappings.
+ */
+void gem_sw_finish(int fd, uint32_t handle)
+{
+ struct drm_i915_gem_sw_finish finish;
+
+ memset(&finish, 0, sizeof(finish));
+ finish.handle = handle;
+
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_SW_FINISH, &finish);
+}
+
+/**
+ * gem_bo_busy:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This is a wraps the BUSY ioctl, which tells whether a buffer object is still
+ * actively used by the gpu in a execbuffer.
+ *
+ * Returns: The busy state of the buffer object.
+ */
+bool gem_bo_busy(int fd, uint32_t handle)
+{
+ struct drm_i915_gem_busy busy;
+
+ memset(&busy, 0, sizeof(busy));
+ busy.handle = handle;
+
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
+
+ return !!busy.busy;
+}
+
+
+/* feature test helpers */
+
+/**
+ * gem_uses_aliasing_ppgtt:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to check whether the kernel internally uses ppgtt to
+ * execute batches. The /aliasing/ in the function name is a bit a misnomer,
+ * this driver parameter is also true when full ppgtt address spaces are
+ * available since for batchbuffer construction only ppgtt or global gtt is
+ * relevant.
+ *
+ * Returns: Whether batches are run through ppgtt.
+ */
+bool gem_uses_aliasing_ppgtt(int fd)
+{
+ struct drm_i915_getparam gp;
+ int val = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = 18; /* HAS_ALIASING_PPGTT */
+ gp.value = &val;
+
+ if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
+ return 0;
+
+ errno = 0;
+ return val;
+}
+
+/**
+ * gem_available_fences:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the kernel for the number of available fences
+ * usable in a batchbuffer. Only relevant for pre-gen4.
+ *
+ * Returns: The number of available fences.
+ */
+int gem_available_fences(int fd)
+{
+ struct drm_i915_getparam gp;
+ int val = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = I915_PARAM_NUM_FENCES_AVAIL;
+ gp.value = &val;
+
+ if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
+ return 0;
+
+ errno = 0;
+ return val;
+}
+
+bool gem_has_llc(int fd)
+{
+ struct drm_i915_getparam gp;
+ int val = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = I915_PARAM_HAS_LLC;
+ gp.value = &val;
+
+ if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
+ return 0;
+
+ errno = 0;
+ return val;
+}
+
+/**
+ * gem_get_num_rings:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the number of available rings. This is useful in
+ * test loops which need to step through all rings and similar logic.
+ *
+ * For more explicit tests of ring availability see gem_has_enable_ring() and
+ * the ring specific versions like gem_has_bsd().
+ *
+ * Returns: The number of available rings.
+ */
+int gem_get_num_rings(int fd)
+{
+ int num_rings = 1; /* render ring is always available */
+
+ if (gem_has_bsd(fd))
+ num_rings++;
+ else
+ goto skip;
+
+ if (gem_has_blt(fd))
+ num_rings++;
+ else
+ goto skip;
+
+ if (gem_has_vebox(fd))
+ num_rings++;
+ else
+ goto skip;
+
+
+skip:
+ return num_rings;
+}
+
+/**
+ * gem_has_enable_ring:
+ * @fd: open i915 drm file descriptor
+ * @param: ring flag bit as used in gem_execbuf()
+ *
+ * Feature test macro to query whether a specific ring is available.
+ *
+ * Returns: Whether the ring is available or not.
+ */
+bool gem_has_enable_ring(int fd,int param)
+{
+ drm_i915_getparam_t gp;
+ int tmp = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.value = &tmp;
+ gp.param = param;
+
+ if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
+ return false;
+
+ errno = 0;
+ return tmp > 0;
+}
+
+/**
+ * gem_has_bsd:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether the BSD ring is available. This is simply
+ * a specific version of gem_has_enable_ring() for the BSD ring.
+ *
+ * Note that recent Bspec calls this the VCS ring for Video Command Submission.
+ *
+ * Returns: Whether the BSD ring is available or not.
+ */
+bool gem_has_bsd(int fd)
+{
+ return gem_has_enable_ring(fd,I915_PARAM_HAS_BSD);
+}
+
+/**
+ * gem_has_blt:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether the blitter ring is available. This is simply
+ * a specific version of gem_has_enable_ring() for the blitter ring.
+ *
+ * Note that recent Bspec calls this the BCS ring for Blitter Command Submission.
+ *
+ * Returns: Whether the blitter ring is available or not.
+ */
+bool gem_has_blt(int fd)
+{
+ return gem_has_enable_ring(fd,I915_PARAM_HAS_BLT);
+}
+
+#define LOCAL_I915_PARAM_HAS_VEBOX 22
+/**
+ * gem_has_vebox:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether the vebox ring is available. This is simply
+ * a specific version of gem_has_enable_ring() for the vebox ring.
+ *
+ * Note that recent Bspec calls this the VECS ring for Video Enhancement Command
+ * Submission.
+ *
+ * Returns: Whether the vebox ring is available or not.
+ */
+bool gem_has_vebox(int fd)
+{
+ return gem_has_enable_ring(fd,LOCAL_I915_PARAM_HAS_VEBOX);
+}
+
+#define LOCAL_I915_PARAM_HAS_BSD2 31
+/**
+ * gem_has_bsd2:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether the BSD2 ring is available. This is simply
+ * a specific version of gem_has_enable_ring() for the BSD2 ring.
+ *
+ * Note that recent Bspec calls this the VCS ring for Video Command Submission.
+ *
+ * Returns: Whether the BSD ring is avaible or not.
+ */
+bool gem_has_bsd2(int fd)
+{
+ return gem_has_enable_ring(fd,LOCAL_I915_PARAM_HAS_BSD2);
+}
+/**
+ * gem_available_aperture_size:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the kernel for the available gpu aperture size
+ * usable in a batchbuffer.
+ *
+ * Returns: The available gtt address space size.
+ */
+uint64_t gem_available_aperture_size(int fd)
+{
+ struct drm_i915_gem_get_aperture aperture;
+
+ memset(&aperture, 0, sizeof(aperture));
+ aperture.aper_size = 256*1024*1024;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
+
+ return aperture.aper_available_size;
+}
+
+/**
+ * gem_aperture_size:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the kernel for the total gpu aperture size.
+ *
+ * Returns: The total gtt address space size.
+ */
+uint64_t gem_aperture_size(int fd)
+{
+ struct drm_i915_gem_get_aperture aperture;
+
+ memset(&aperture, 0, sizeof(aperture));
+ aperture.aper_size = 256*1024*1024;
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
+
+ return aperture.aper_size;
+}
+
+/**
+ * gem_mappable_aperture_size:
+ *
+ * Feature test macro to query the kernel for the mappable gpu aperture size.
+ * This is the area available for GTT memory mappings.
+ *
+ * Returns: The mappable gtt address space size.
+ */
+uint64_t gem_mappable_aperture_size(void)
+{
+ struct pci_device *pci_dev = intel_get_pci_device();
+ int bar;
+
+ if (intel_gen(pci_dev->device_id) < 3)
+ bar = 0;
+ else
+ bar = 2;
+
+ return pci_dev->regions[bar].size;
+}
+
+/**
+ * gem_require_caching:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether buffer object caching control is
+ * available. Automatically skips through igt_require() if not.
+ */
+void gem_require_caching(int fd)
+{
+ struct local_drm_i915_gem_caching arg;
+ int ret;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = gem_create(fd, 4096);
+ igt_assert(arg.handle != 0);
+
+ arg.caching = 0;
+ ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING, &arg);
+ gem_close(fd, arg.handle);
+
+ igt_require(ret == 0);
+ errno = 0;
+}
+
+/**
+ * gem_require_ring:
+ * @fd: open i915 drm file descriptor
+ * @ring_id: ring flag bit as used in gem_execbuf()
+ *
+ * Feature test macro to query whether a specific ring is available.
+ * In contrast to gem_has_enable_ring() this automagically skips if the ring
+ * isn't available by calling igt_require().
+ */
+void gem_require_ring(int fd, int ring_id)
+{
+ switch (ring_id) {
+ case I915_EXEC_RENDER:
+ return;
+ case I915_EXEC_BLT:
+ igt_require(HAS_BLT_RING(intel_get_drm_devid(fd)));
+ return;
+ case I915_EXEC_BSD:
+ igt_require(HAS_BSD_RING(intel_get_drm_devid(fd)));
+ return;
+#ifdef I915_EXEC_VEBOX
+ case I915_EXEC_VEBOX:
+ igt_require(gem_has_vebox(fd));
+ return;
+#endif
+ default:
+ igt_assert(0);
+ return;
+ }
+}
+
+/* prime */
+
+/**
+ * prime_handle_to_fd:
+ * @fd: open i915 drm file descriptor
+ * @handle: file-private gem buffer object handle
+ *
+ * This wraps the PRIME_HANDLE_TO_FD ioctl, which is used to export a gem buffer
+ * object into a global (i.e. potentially cross-device) dma-buf file-descriptor
+ * handle.
+ *
+ * Returns: The created dma-buf fd handle.
+ */
+int prime_handle_to_fd(int fd, uint32_t handle)
+{
+ struct drm_prime_handle args;
+
+ memset(&args, 0, sizeof(args));
+ args.handle = handle;
+ args.flags = DRM_CLOEXEC;
+ args.fd = -1;
+
+ do_ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
+
+ return args.fd;
+}
+
+/**
+ * prime_fd_to_handle:
+ * @fd: open i915 drm file descriptor
+ * @dma_buf_fd: dma-buf fd handle
+ *
+ * This wraps the PRIME_FD_TO_HANDLE ioctl, which is used to import a dma-buf
+ * file-descriptor into a gem buffer object.
+ *
+ * Returns: The created gem buffer object handle.
+ */
+uint32_t prime_fd_to_handle(int fd, int dma_buf_fd)
+{
+ struct drm_prime_handle args;
+
+ memset(&args, 0, sizeof(args));
+ args.fd = dma_buf_fd;
+ args.flags = 0;
+ args.handle = 0;
+
+ do_ioctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
+
+ return args.handle;
+}
+
+/**
+ * prime_get_size:
+ * @dma_buf_fd: dma-buf fd handle
+ *
+ * This wraps the lseek() protocol used to query the invariant size of a
+ * dma-buf. Not all kernels support this, which is check with igt_require() and
+ * so will result in automagic test skipping.
+ *
+ * Returns: The lifetime-invariant size of the dma-buf object.
+ */
+off_t prime_get_size(int dma_buf_fd)
+{
+ off_t ret;
+
+ ret = lseek(dma_buf_fd, 0, SEEK_END);
+ igt_assert(ret >= 0 || errno == ESPIPE);
+ igt_require(ret >= 0);
+ errno = 0;
+
+ return ret;
+}
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
new file mode 100644
index 0000000..7c0c87e
--- /dev/null
+++ b/lib/ioctl_wrappers.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright © 2007,2014 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>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+
+#ifndef IOCTL_WRAPPERS_H
+#define IOCTL_WRAPPERS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <intel_bufmgr.h>
+#include <i915_drm.h>
+
+/* libdrm interfacing */
+drm_intel_bo * gem_handle_to_libdrm_bo(drm_intel_bufmgr *bufmgr, int fd,
+ const char *name, uint32_t handle);
+
+/* ioctl_wrappers.c:
+ *
+ * ioctl wrappers and similar stuff for bare metal testing */
+void gem_get_tiling(int fd, uint32_t handle, uint32_t *tiling, uint32_t *swizzle);
+void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
+int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
+
+void gem_set_caching(int fd, uint32_t handle, uint32_t caching);
+uint32_t gem_get_caching(int fd, uint32_t handle);
+uint32_t gem_flink(int fd, uint32_t handle);
+uint32_t gem_open(int fd, uint32_t name);
+void gem_close(int fd, uint32_t handle);
+void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t length);
+void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t length);
+void gem_set_domain(int fd, uint32_t handle,
+ uint32_t read_domains, uint32_t write_domain);
+void gem_sync(int fd, uint32_t handle);
+uint32_t __gem_create(int fd, int size);
+uint32_t gem_create(int fd, int size);
+void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf);
+
+void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot);
+void *gem_mmap__cpu(int fd, uint32_t handle, int offset, int size, int prot);
+
+bool gem_mmap__has_wc(int fd);
+void *gem_mmap__wc(int fd, uint32_t handle, int offset, int size, int prot);
+
+/**
+ * gem_require_mmap_wc:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether direct (i.e. cpu access path, bypassing
+ * the gtt) write-combine memory mappings are available. Automatically skips
+ * through igt_require() if not.
+ */
+#define gem_require_mmap_wc(fd) igt_require(gem_mmap__has_wc(fd))
+
+/**
+ * gem_mmap:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @size: size of the gem buffer
+ * @prot: memory protection bits as used by mmap()
+ *
+ * This functions wraps up procedure to establish a memory mapping through the
+ * GTT.
+ *
+ * This is a simple convenience alias to gem_mmap__gtt()
+ *
+ * Returns: A pointer to the created memory mapping.
+ */
+#define gem_mmap(fd, handle, size, prot) gem_mmap__gtt(fd, handle, size, prot)
+
+int gem_madvise(int fd, uint32_t handle, int state);
+
+uint32_t gem_context_create(int fd);
+void gem_context_destroy(int fd, uint32_t ctx_id);
+int __gem_context_destroy(int fd, uint32_t ctx_id);
+struct local_i915_gem_context_param {
+ uint32_t context;
+ uint32_t size;
+ uint64_t param;
+#define LOCAL_CONTEXT_PARAM_BAN_PERIOD 0x1
+ uint64_t value;
+};
+void gem_context_require_param(int fd, uint64_t param);
+void gem_context_get_param(int fd, struct local_i915_gem_context_param *p);
+void gem_context_set_param(int fd, struct local_i915_gem_context_param *p);
+
+void gem_sw_finish(int fd, uint32_t handle);
+
+bool gem_bo_busy(int fd, uint32_t handle);
+
+/* feature test helpers */
+bool gem_has_llc(int fd);
+int gem_get_num_rings(int fd);
+bool gem_has_enable_ring(int fd,int param);
+bool gem_has_bsd(int fd);
+bool gem_has_blt(int fd);
+bool gem_has_vebox(int fd);
+bool gem_has_bsd2(int fd);
+bool gem_uses_aliasing_ppgtt(int fd);
+int gem_available_fences(int fd);
+uint64_t gem_available_aperture_size(int fd);
+uint64_t gem_aperture_size(int fd);
+uint64_t gem_mappable_aperture_size(void);
+
+/* check functions which auto-skip tests by calling igt_skip() */
+void gem_require_caching(int fd);
+void gem_require_ring(int fd, int ring_id);
+
+/* prime */
+int prime_handle_to_fd(int fd, uint32_t handle);
+uint32_t prime_fd_to_handle(int fd, int dma_buf_fd);
+off_t prime_get_size(int dma_buf_fd);
+
+#endif /* IOCTL_WRAPPERS_H */
diff --git a/lib/media_fill.h b/lib/media_fill.h
new file mode 100644
index 0000000..2a30055
--- /dev/null
+++ b/lib/media_fill.h
@@ -0,0 +1,42 @@
+#ifndef RENDE_MEDIA_FILL_H
+#define RENDE_MEDIA_FILL_H
+
+#include <stdint.h>
+#include "intel_batchbuffer.h"
+
+void
+gen8_media_fillfunc(struct intel_batchbuffer *batch,
+ struct igt_buf *dst,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ uint8_t color);
+
+void
+gen7_media_fillfunc(struct intel_batchbuffer *batch,
+ struct igt_buf *dst,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ uint8_t color);
+
+void
+gen8lp_media_fillfunc(struct intel_batchbuffer *batch,
+ struct igt_buf *dst,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ uint8_t color);
+
+void
+gen9_media_fillfunc(struct intel_batchbuffer *batch,
+ struct igt_buf *dst,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ uint8_t color);
+
+void
+gen7_gpgpu_fillfunc(struct intel_batchbuffer *batch,
+ struct igt_buf *dst,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ uint8_t color);
+
+#endif /* RENDE_MEDIA_FILL_H */
diff --git a/lib/rendercopy.h b/lib/rendercopy.h
new file mode 100644
index 0000000..fdc3cab
--- /dev/null
+++ b/lib/rendercopy.h
@@ -0,0 +1,55 @@
+#include "intel_batchbuffer.h"
+
+
+static inline void emit_vertex_2s(struct intel_batchbuffer *batch,
+ int16_t x, int16_t y)
+{
+ OUT_BATCH((uint16_t)y << 16 | (uint16_t)x);
+}
+
+static inline void emit_vertex(struct intel_batchbuffer *batch,
+ float f)
+{
+ union { float f; uint32_t ui; } u;
+ u.f = f;
+ OUT_BATCH(u.ui);
+}
+
+static inline void emit_vertex_normalized(struct intel_batchbuffer *batch,
+ float f, float total)
+{
+ union { float f; uint32_t ui; } u;
+ u.f = f / total;
+ OUT_BATCH(u.ui);
+}
+
+void gen9_render_copyfunc(struct intel_batchbuffer *batch,
+ drm_intel_context *context,
+ struct igt_buf *src, unsigned src_x, unsigned src_y,
+ unsigned width, unsigned height,
+ struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
+void gen8_render_copyfunc(struct intel_batchbuffer *batch,
+ drm_intel_context *context,
+ struct igt_buf *src, unsigned src_x, unsigned src_y,
+ unsigned width, unsigned height,
+ struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
+void gen7_render_copyfunc(struct intel_batchbuffer *batch,
+ drm_intel_context *context,
+ struct igt_buf *src, unsigned src_x, unsigned src_y,
+ unsigned width, unsigned height,
+ struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
+void gen6_render_copyfunc(struct intel_batchbuffer *batch,
+ drm_intel_context *context,
+ struct igt_buf *src, unsigned src_x, unsigned src_y,
+ unsigned width, unsigned height,
+ struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
+void gen3_render_copyfunc(struct intel_batchbuffer *batch,
+ drm_intel_context *context,
+ struct igt_buf *src, unsigned src_x, unsigned src_y,
+ unsigned width, unsigned height,
+ struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
+void gen2_render_copyfunc(struct intel_batchbuffer *batch,
+ drm_intel_context *context,
+ struct igt_buf *src, unsigned src_x, unsigned src_y,
+ unsigned width, unsigned height,
+ struct igt_buf *dst, unsigned dst_x, unsigned dst_y);
diff --git a/m4/ax_pkg_swig.m4 b/m4/ax_pkg_swig.m4
new file mode 100644
index 0000000..d836eec
--- /dev/null
+++ b/m4/ax_pkg_swig.m4
@@ -0,0 +1,135 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
+#
+# DESCRIPTION
+#
+# This macro searches for a SWIG installation on your system. If found,
+# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
+# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
+#
+# You can use the optional first argument to check if the version of the
+# available SWIG is greater than or equal to the value of the argument. It
+# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
+# the first N is mandatory.) If the version argument is given (e.g.
+# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
+# or higher.
+#
+# As usual, action-if-found is executed if SWIG is found, otherwise
+# action-if-not-found is executed.
+#
+# In configure.in, use as:
+#
+# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
+# AX_SWIG_ENABLE_CXX
+# AX_SWIG_MULTI_MODULE_SUPPORT
+# AX_SWIG_PYTHON
+#
+# LICENSE
+#
+# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
+# Copyright (c) 2008 Alan W. Irwin
+# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright (c) 2008 Andrew Collier
+# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 11
+
+AC_DEFUN([AX_PKG_SWIG],[
+ # Ubuntu has swig 2.0 as /usr/bin/swig2.0
+ AC_PATH_PROGS([SWIG],[swig swig2.0])
+ if test -z "$SWIG" ; then
+ m4_ifval([$3],[$3],[:])
+ elif test -n "$1" ; then
+ AC_MSG_CHECKING([SWIG version])
+ [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
+ AC_MSG_RESULT([$swig_version])
+ if test -n "$swig_version" ; then
+ # Calculate the required version number components
+ [required=$1]
+ [required_major=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_major" ; then
+ [required_major=0]
+ fi
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+ [required_minor=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_minor" ; then
+ [required_minor=0]
+ fi
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+ [required_patch=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_patch" ; then
+ [required_patch=0]
+ fi
+ # Calculate the available version number components
+ [available=$swig_version]
+ [available_major=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_major" ; then
+ [available_major=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_minor=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_minor" ; then
+ [available_minor=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_patch=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_patch" ; then
+ [available_patch=0]
+ fi
+ # Convert the version tuple into a single number for easier comparison.
+ # Using base 100 should be safe since SWIG internally uses BCD values
+ # to encode its version number.
+ required_swig_vernum=`expr $required_major \* 10000 \
+ \+ $required_minor \* 100 \+ $required_patch`
+ available_swig_vernum=`expr $available_major \* 10000 \
+ \+ $available_minor \* 100 \+ $available_patch`
+
+ if test $available_swig_vernum -lt $required_swig_vernum; then
+ AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
+ SWIG=''
+ m4_ifval([$3],[$3],[])
+ else
+ AC_MSG_CHECKING([for SWIG library])
+ SWIG_LIB=`$SWIG -swiglib`
+ AC_MSG_RESULT([$SWIG_LIB])
+ m4_ifval([$2],[$2],[])
+ fi
+ else
+ AC_MSG_WARN([cannot determine SWIG version])
+ SWIG=''
+ m4_ifval([$3],[$3],[])
+ fi
+ fi
+ AC_SUBST([SWIG_LIB])
+])
diff --git a/m4/ax_python_devel.m4 b/m4/ax_python_devel.m4
new file mode 100644
index 0000000..cf2163c
--- /dev/null
+++ b/m4/ax_python_devel.m4
@@ -0,0 +1,324 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PYTHON_DEVEL([version])
+#
+# DESCRIPTION
+#
+# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
+# in your configure.ac.
+#
+# This macro checks for Python and tries to get the include path to
+# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS)
+# output variables. It also exports $(PYTHON_EXTRA_LIBS) and
+# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
+#
+# You can search for some particular version of Python by passing a
+# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
+# note that you *have* to pass also an operator along with the version to
+# match, and pay special attention to the single quotes surrounding the
+# version number. Don't use "PYTHON_VERSION" for this: that environment
+# variable is declared as precious and thus reserved for the end-user.
+#
+# This macro should work for all versions of Python >= 2.1.0. As an end
+# user, you can disable the check for the python version by setting the
+# PYTHON_NOVERSIONCHECK environment variable to something else than the
+# empty string.
+#
+# If you need to use this macro for an older Python version, please
+# contact the authors. We're always open for feedback.
+#
+# LICENSE
+#
+# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
+# Copyright (c) 2009 Alan W. Irwin
+# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright (c) 2009 Andrew Collier
+# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
+# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
+# Copyright (c) 2013 Daniel Mullner <muellner@math.stanford.edu>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 16
+
+AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
+AC_DEFUN([AX_PYTHON_DEVEL],[
+ #
+ # Allow the use of a (user set) custom python version
+ #
+ AC_ARG_VAR([PYTHON_VERSION],[The installed Python
+ version to use, for example '2.3'. This string
+ will be appended to the Python interpreter
+ canonical name.])
+
+ AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
+ if test -z "$PYTHON"; then
+ AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
+ PYTHON_VERSION=""
+ fi
+
+ #
+ # Check for a version of Python >= 2.1.0
+ #
+ AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
+ ac_supports_python_ver=`$PYTHON -c "import sys; \
+ ver = sys.version.split ()[[0]]; \
+ print (ver >= '2.1.0')"`
+ if test "$ac_supports_python_ver" != "True"; then
+ if test -z "$PYTHON_NOVERSIONCHECK"; then
+ AC_MSG_RESULT([no])
+ AC_MSG_FAILURE([
+This version of the AC@&t@_PYTHON_DEVEL macro
+doesn't work properly with versions of Python before
+2.1.0. You may need to re-run configure, setting the
+variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG,
+PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
+Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
+to something else than an empty string.
+])
+ else
+ AC_MSG_RESULT([skip at user request])
+ fi
+ else
+ AC_MSG_RESULT([yes])
+ fi
+
+ #
+ # if the macro parameter ``version'' is set, honour it
+ #
+ if test -n "$1"; then
+ AC_MSG_CHECKING([for a version of Python $1])
+ ac_supports_python_ver=`$PYTHON -c "import sys; \
+ ver = sys.version.split ()[[0]]; \
+ print (ver $1)"`
+ if test "$ac_supports_python_ver" = "True"; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([this package requires Python $1.
+If you have it installed, but it isn't the default Python
+interpreter in your system path, please pass the PYTHON_VERSION
+variable to configure. See ``configure --help'' for reference.
+])
+ PYTHON_VERSION=""
+ fi
+ fi
+
+ #
+ # Check if you have distutils, else fail
+ #
+ AC_MSG_CHECKING([for the distutils Python package])
+ ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
+ if test -z "$ac_distutils_result"; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([cannot import Python module "distutils".
+Please check your Python installation. The error was:
+$ac_distutils_result])
+ PYTHON_VERSION=""
+ fi
+
+ #
+ # Check for Python include path
+ #
+ AC_MSG_CHECKING([for Python include path])
+ if test -z "$PYTHON_CPPFLAGS"; then
+ python_path=`$PYTHON -c "import distutils.sysconfig; \
+ print (distutils.sysconfig.get_python_inc ());"`
+ plat_python_path=`$PYTHON -c "import distutils.sysconfig; \
+ print (distutils.sysconfig.get_python_inc (plat_specific=1));"`
+ if test -n "${python_path}"; then
+ if test "${plat_python_path}" != "${python_path}"; then
+ python_path="-I$python_path -I$plat_python_path"
+ else
+ python_path="-I$python_path"
+ fi
+ fi
+ PYTHON_CPPFLAGS=$python_path
+ fi
+ AC_MSG_RESULT([$PYTHON_CPPFLAGS])
+ AC_SUBST([PYTHON_CPPFLAGS])
+
+ #
+ # Check for Python library path
+ #
+ AC_MSG_CHECKING([for Python library path])
+ if test -z "$PYTHON_LDFLAGS"; then
+ # (makes two attempts to ensure we've got a version number
+ # from the interpreter)
+ ac_python_version=`cat<<EOD | $PYTHON -
+
+# join all versioning strings, on some systems
+# major/minor numbers could be in different list elements
+from distutils.sysconfig import *
+e = get_config_var('VERSION')
+if e is not None:
+ print(e)
+EOD`
+
+ if test -z "$ac_python_version"; then
+ if test -n "$PYTHON_VERSION"; then
+ ac_python_version=$PYTHON_VERSION
+ else
+ ac_python_version=`$PYTHON -c "import sys; \
+ print (sys.version[[:3]])"`
+ fi
+ fi
+
+ # Make the versioning information available to the compiler
+ AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
+ [If available, contains the Python version number currently in use.])
+
+ # First, the library directory:
+ ac_python_libdir=`cat<<EOD | $PYTHON -
+
+# There should be only one
+import distutils.sysconfig
+e = distutils.sysconfig.get_config_var('LIBDIR')
+if e is not None:
+ print (e)
+EOD`
+
+ # Now, for the library:
+ ac_python_library=`cat<<EOD | $PYTHON -
+
+import distutils.sysconfig
+c = distutils.sysconfig.get_config_vars()
+if 'LDVERSION' in c:
+ print ('python'+c[['LDVERSION']])
+else:
+ print ('python'+c[['VERSION']])
+EOD`
+
+ # This small piece shamelessly adapted from PostgreSQL python macro;
+ # credits goes to momjian, I think. I'd like to put the right name
+ # in the credits, if someone can point me in the right direction... ?
+ #
+ if test -n "$ac_python_libdir" -a -n "$ac_python_library"
+ then
+ # use the official shared library
+ ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
+ PYTHON_LDFLAGS="-L$ac_python_libdir -l$ac_python_library"
+ else
+ # old way: use libpython from python_configdir
+ ac_python_libdir=`$PYTHON -c \
+ "from distutils.sysconfig import get_python_lib as f; \
+ import os; \
+ print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
+ PYTHON_LDFLAGS="-L$ac_python_libdir -lpython$ac_python_version"
+ fi
+
+ if test -z "PYTHON_LDFLAGS"; then
+ AC_MSG_ERROR([
+ Cannot determine location of your Python DSO. Please check it was installed with
+ dynamic libraries enabled, or try setting PYTHON_LDFLAGS by hand.
+ ])
+ fi
+ fi
+ AC_MSG_RESULT([$PYTHON_LDFLAGS])
+ AC_SUBST([PYTHON_LDFLAGS])
+
+ #
+ # Check for site packages
+ #
+ AC_MSG_CHECKING([for Python site-packages path])
+ if test -z "$PYTHON_SITE_PKG"; then
+ PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
+ print (distutils.sysconfig.get_python_lib(0,0));"`
+ fi
+ AC_MSG_RESULT([$PYTHON_SITE_PKG])
+ AC_SUBST([PYTHON_SITE_PKG])
+
+ #
+ # libraries which must be linked in when embedding
+ #
+ AC_MSG_CHECKING(python extra libraries)
+ if test -z "$PYTHON_EXTRA_LIBS"; then
+ PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
+ conf = distutils.sysconfig.get_config_var; \
+ print (conf('LIBS'))"`
+ fi
+ AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
+ AC_SUBST(PYTHON_EXTRA_LIBS)
+
+ #
+ # linking flags needed when embedding
+ #
+ AC_MSG_CHECKING(python extra linking flags)
+ if test -z "$PYTHON_EXTRA_LDFLAGS"; then
+ PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
+ conf = distutils.sysconfig.get_config_var; \
+ print (conf('LINKFORSHARED'))"`
+ fi
+ AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
+ AC_SUBST(PYTHON_EXTRA_LDFLAGS)
+
+ #
+ # final check to see if everything compiles alright
+ #
+ AC_MSG_CHECKING([consistency of all components of python development environment])
+ # save current global flags
+ ac_save_LIBS="$LIBS"
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ LIBS="$ac_save_LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS $PYTHON_EXTRA_LIBS"
+ CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
+ AC_LANG_PUSH([C])
+ AC_LINK_IFELSE([
+ AC_LANG_PROGRAM([[#include <Python.h>]],
+ [[Py_Initialize();]])
+ ],[pythonexists=yes],[pythonexists=no])
+ AC_LANG_POP([C])
+ # turn back to default flags
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+
+ AC_MSG_RESULT([$pythonexists])
+
+ if test ! "x$pythonexists" = "xyes"; then
+ AC_MSG_FAILURE([
+ Could not link test program to Python. Maybe the main Python library has been
+ installed in some non-standard library path. If so, pass it to configure,
+ via the LDFLAGS environment variable.
+ Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
+ ============================================================================
+ ERROR!
+ You probably have to install the development version of the Python package
+ for your distribution. The exact name of this package varies among them.
+ ============================================================================
+ ])
+ PYTHON_VERSION=""
+ fi
+
+ #
+ # all done!
+ #
+])
diff --git a/m4/ax_swig_python.m4 b/m4/ax_swig_python.m4
new file mode 100644
index 0000000..bf22558
--- /dev/null
+++ b/m4/ax_swig_python.m4
@@ -0,0 +1,64 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_swig_python.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_SWIG_PYTHON([use-shadow-classes = {no, yes}])
+#
+# DESCRIPTION
+#
+# Checks for Python and provides the $(AX_SWIG_PYTHON_CPPFLAGS), and
+# $(AX_SWIG_PYTHON_OPT) output variables.
+#
+# $(AX_SWIG_PYTHON_OPT) contains all necessary SWIG options to generate
+# code for Python. Shadow classes are enabled unless the value of the
+# optional first argument is exactly 'no'. If you need multi module
+# support (provided by the AX_SWIG_MULTI_MODULE_SUPPORT macro) use
+# $(AX_SWIG_PYTHON_LIBS) to link against the appropriate library. It
+# contains the SWIG Python runtime library that is needed by the type
+# check system for example.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
+# Copyright (c) 2008 Alan W. Irwin
+# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright (c) 2008 Andrew Collier
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 10
+
+AU_ALIAS([SWIG_PYTHON], [AX_SWIG_PYTHON])
+AC_DEFUN([AX_SWIG_PYTHON],[
+ AC_REQUIRE([AX_PKG_SWIG])
+ AC_REQUIRE([AX_PYTHON_DEVEL])
+ test "x$1" != "xno" || swig_shadow=" -noproxy"
+ AC_SUBST([AX_SWIG_PYTHON_OPT],[-python$swig_shadow])
+ AC_SUBST([AX_SWIG_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS])
+])
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..7b4dd94
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,154 @@
+# Please keep sorted alphabetically
+core_get_client_auth
+core_getclient
+core_getstats
+core_getversion
+drm_import_export
+drm_read
+drm_vma_limiter
+drm_vma_limiter_cached
+drm_vma_limiter_cpu
+drm_vma_limiter_gtt
+drv_hangman
+drv_suspend
+gem_alive
+gem_bad_address
+gem_bad_batch
+gem_bad_blit
+gem_bad_length
+gem_bad_reloc
+gem_basic
+gem_caching
+gem_close_race
+gem_concurrent_blit
+gem_cpu_reloc
+gem_cs_prefetch
+gem_cs_tlb
+gem_ctx_bad_destroy
+gem_ctx_bad_exec
+gem_ctx_basic
+gem_ctx_create
+gem_ctx_exec
+gem_ctx_thrash
+gem_ctx_param_basic
+gem_double_irq_loop
+gem_dummy_reloc_loop
+gem_evict_alignment
+gem_evict_everything
+gem_exec_bad_domains
+gem_exec_big
+gem_exec_blt
+gem_exec_faulting_reloc
+gem_exec_lut_handle
+gem_exec_nop
+gem_exec_params
+gem_exec_parse
+gem_fd_exhaustion
+gem_fence_thrash
+gem_fence_upload
+gem_fenced_exec_thrash
+gem_flink
+gem_flink_race
+gem_gpgpu_fill
+gem_gtt_cpu_tlb
+gem_gtt_hog
+gem_gtt_speed
+gem_hang
+gem_hangcheck_forcewake
+gem_largeobject
+gem_linear_blits
+gem_lut_handle
+gem_madvise
+gem_media_fill
+gem_mmap
+gem_mmap_gtt
+gem_mmap_wc
+gem_mmap_offset_exhaustion
+gem_multi_bsd_sync_loop
+gem_non_secure_batch
+gem_partial_pwrite_pread
+gem_persistent_relocs
+gem_pin
+gem_pipe_control_store_loop
+gem_ppgtt
+gem_pread
+gem_pread_after_blit
+gem_pwrite
+gem_pwrite_pread
+gem_readwrite
+gem_reg_read
+gem_reloc_overflow
+gem_reloc_vs_gpu
+gem_render_copy
+gem_render_copy_redux
+gem_render_linear_blits
+gem_render_tiled_blits
+gem_reset_stats
+gem_ring_sync_copy
+gem_ring_sync_loop
+gem_ringfill
+gem_seqno_wrap
+gem_set_tiling_vs_blt
+gem_set_tiling_vs_gtt
+gem_set_tiling_vs_pwrite
+gem_storedw_batches_loop
+gem_storedw_loop_blt
+gem_storedw_loop_bsd
+gem_storedw_loop_render
+gem_storedw_loop_vebox
+gem_stress
+gem_threaded_access_tiled
+gem_tiled_blits
+gem_tiled_fence_blits
+gem_tiled_partial_pwrite_pread
+gem_tiled_pread
+gem_tiled_pread_pwrite
+gem_tiled_swapping
+gem_tiled_wb
+gem_tiled_wc
+gem_tiling_max_stride
+gem_unfence_active_buffers
+gem_unref_active_buffers
+gem_userptr_blits
+gem_wait
+gem_write_read_ring_switch
+gem_workarounds
+gen3_mixed_blits
+gen3_render_linear_blits
+gen3_render_mixed_blits
+gen3_render_tiledx_blits
+gen3_render_tiledy_blits
+gen7_forcewake_mt
+kms_3d
+kms_addfb
+kms_cursor_crc
+kms_fbc_crc
+kms_fence_pin_leak
+kms_flip
+kms_flip_event_leak
+kms_flip_tiling
+kms_force_connector
+kms_mmio_vs_cs_flip
+kms_pipe_crc_basic
+kms_plane
+kms_psr_sink_crc
+kms_pwrite_crc
+kms_render
+kms_rotation_crc
+kms_setmode
+kms_sink_crc_basic
+kms_universal_plane
+multi-tests.txt
+pm_lpsp
+pm_psr
+pm_rc6_residency
+pm_rpm
+pm_rps
+prime_nv_api
+prime_nv_pcopy
+prime_nv_test
+prime_self_import
+prime_udl
+single-tests.txt
+template
+testdisplay
diff --git a/tests/1080p-left.png b/tests/1080p-left.png
new file mode 100644
index 0000000..67653ec
--- /dev/null
+++ b/tests/1080p-left.png
Binary files differ
diff --git a/tests/1080p-right.png b/tests/1080p-right.png
new file mode 100644
index 0000000..d973565
--- /dev/null
+++ b/tests/1080p-right.png
Binary files differ
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..006555e
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,23 @@
+include Makefile.sources
+
+if BUILD_TESTS
+
+EXTRA_PROGRAMS = $(TESTS_progs) $(TESTS_progs_M) $(HANG)
+EXTRA_DIST = $(TESTS_scripts) $(TESTS_scripts_M) $(scripts) $(IMAGES) $(common_files)
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) \
+ -I$(srcdir)/.. \
+ -I$(srcdir)/../lib \
+ -include "$(srcdir)/../lib/check-ndebug.h" \
+ -DIGT_DATADIR=\""$(abs_srcdir)"\" \
+ $(NULL)
+
+LDADD = ../lib/libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS)
+
+LDADD += $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(GLIB_LIBS)
+AM_CFLAGS += $(CAIRO_CFLAGS) $(LIBUDEV_CFLAGS) $(GLIB_CFLAGS)
+
+endif
+
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
new file mode 100644
index 0000000..623a748
--- /dev/null
+++ b/tests/Makefile.sources
@@ -0,0 +1,16 @@
+noinst_PROGRAMS = \
+ $(TESTS_progs) \
+ $(NULL)
+
+TESTS_progs = \
+ $(NULL)
+
+IMAGES = pass.png 1080p-left.png 1080p-right.png
+
+testdisplay_SOURCES = \
+ testdisplay.c \
+ testdisplay.h \
+ testdisplay_hotplug.c \
+ $(NULL)
+
+TESTS_progs += testdisplay
diff --git a/tests/pass.png b/tests/pass.png
new file mode 100644
index 0000000..36a5236
--- /dev/null
+++ b/tests/pass.png
Binary files differ
diff --git a/tests/template.c b/tests/template.c
new file mode 100644
index 0000000..24fd850
--- /dev/null
+++ b/tests/template.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2013 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:
+ *
+ */
+
+#include "drmtest.h"
+
+/*
+ * Note that test function (and code called by them) should generally not return
+ * a variable indicating success/failure. Instead use the igt_require/igt_assert
+ * macros to skip out of the entire subtest.
+ *
+ * Also, helper functions should only return a status code if the callers have a
+ * real need to differentiate. If the only thing they do is call igt_assert or a
+ * similar macro then it'll result in simpler code when the check is moved
+ * completely into the helper.
+ */
+static void test_A(int fd)
+{
+}
+
+static void test_B(int fd)
+{
+}
+
+/*
+ * Variables which are written to in igt_fixtures/subtest blocks need to be
+ * allocated outside of the relevant function scope, otherwise gcc will wreak
+ * havoc (since these magic blocks use setjmp/longjmp internally).
+ *
+ * Common practice is to put variables used in the main test function into
+ * global scope, but only right above the main function itself (to avoid leaking
+ * it into other functions).
+ */
+
+int drm_fd;
+
+igt_main
+{
+ igt_fixture {
+ drm_fd = drm_open_any();
+ igt_require(drm_fd >= 0);
+
+ /* Set up other interesting stuff shared by all tests. */
+ }
+
+ igt_subtest("A")
+ test_A(drm_fd);
+ igt_subtest("B")
+ test_B(drm_fd);
+ /*
+ * Note that subtest names can be programatically generated. See the
+ * various uses of igt_subtest_f for a few neat ideas.
+ */
+
+ igt_fixture {
+ close(drm_fd);
+ }
+}
diff --git a/tests/testdisplay.c b/tests/testdisplay.c
new file mode 100644
index 0000000..35a39f9
--- /dev/null
+++ b/tests/testdisplay.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2010 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * 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.
+ */
+
+/*
+ * This program is intended for testing of display functionality. It should
+ * allow for testing of
+ * - hotplug
+ * - mode setting
+ * - clone & twin modes
+ * - panel fitting
+ * - test patterns & pixel generators
+ * Additional programs can test the detected outputs against VBT provided
+ * device lists (both docked & undocked).
+ *
+ * TODO:
+ * - pixel generator in transcoder
+ * - test pattern reg in pipe
+ * - test patterns on outputs (e.g. TV)
+ * - handle hotplug (leaks crtcs, can't handle clones)
+ * - allow mode force
+ * - expose output specific controls
+ * - e.g. DDC-CI brightness
+ * - HDMI controls
+ * - panel brightness
+ * - DP commands (e.g. poweroff)
+ * - verify outputs against VBT/physical connectors
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <cairo.h>
+#include <errno.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <strings.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "drmtest.h"
+#include "testdisplay.h"
+#include "igt_kms.h"
+
+#include <stdlib.h>
+#include <signal.h>
+
+
+static int tio_fd;
+struct termios saved_tio;
+
+drmModeRes *resources;
+int drm_fd, modes;
+int test_all_modes = 0, test_preferred_mode = 0;
+
+unsigned int tiling = I915_TILING_X; //tiling = I915_TILING_NONE;
+int sleep_between_modes = 5;
+uint32_t depth = 24, stride, bpp = 32;
+
+drmModeModeInfo force_timing;
+
+int crtc_x, crtc_y, crtc_w, crtc_h, width, height;
+unsigned int plane_fb_id;
+unsigned int plane_crtc_id;
+unsigned int plane_id;
+int plane_width, plane_height;
+static const uint32_t SPRITE_COLOR_KEY = 0x00aaaaaa;
+
+/*
+ * Mode setting with the kernel interfaces is a bit of a chore.
+ * First you have to find the connector in question and make sure the
+ * requested mode is available.
+ * Then you need to find the encoder attached to that connector so you
+ * can bind it with a free crtc.
+ */
+struct connector {
+ uint32_t id;
+ int mode_valid;
+ drmModeModeInfo mode;
+ drmModeEncoder *encoder;
+ drmModeConnector *connector;
+ int crtc;
+ int crtc_idx;
+ int pipe;
+};
+
+static void connector_find_preferred_mode(uint32_t connector_id,
+ unsigned long crtc_idx_mask,
+ int mode_num, struct connector *c)
+{
+ struct kmstest_connector_config config;
+
+ if (!kmstest_get_connector_config(drm_fd, connector_id, crtc_idx_mask,
+ &config)) {
+ c->mode_valid = 0;
+ return;
+ }
+
+ c->connector = config.connector;
+ c->encoder = config.encoder;
+ c->crtc = config.crtc->crtc_id;
+ c->crtc_idx = config.crtc_idx;
+ c->pipe = config.pipe;
+
+ if (mode_num != -1) {
+ igt_assert(mode_num < config.connector->count_modes);
+ c->mode = config.connector->modes[mode_num];
+ } else {
+ c->mode = config.default_mode;
+ }
+ c->mode_valid = 1;
+}
+
+static void paint_image(cairo_t *cr, const char *file)
+{
+ int img_x, img_y, img_w, img_h, img_w_o, img_h_o;
+ double img_w_scale, img_h_scale;
+
+ cairo_surface_t *image;
+
+ img_y = height * (0.10 );
+ img_h = height * 0.08 * 4;
+ img_w = img_h;
+
+ img_x = (width / 2) - (img_w / 2);
+
+ image = cairo_image_surface_create_from_png(file);
+
+ img_w_o = cairo_image_surface_get_width(image);
+ img_h_o = cairo_image_surface_get_height(image);
+
+ cairo_translate(cr, img_x, img_y);
+
+ img_w_scale = (double)img_w / (double)img_w_o;
+ img_h_scale = (double)img_h / (double)img_h_o;
+ cairo_scale(cr, img_w_scale, img_h_scale);
+
+ cairo_set_source_surface(cr, image, 0, 0);
+ cairo_scale(cr, 1, 1);
+
+ cairo_paint(cr);
+ cairo_surface_destroy(image);
+}
+
+static void paint_output_info(struct connector *c, struct igt_fb *fb)
+{
+ cairo_t *cr = igt_get_cairo_ctx(drm_fd, fb);
+ int l_width = fb->width;
+ int l_height = fb->height;
+ double str_width;
+ double x, y, top_y;
+ double max_width;
+ int i;
+
+ paint_image(cr, IGT_DATADIR"/pass.png");
+
+ igt_assert(!cairo_status(cr));
+
+ cairo_destroy(cr);
+}
+
+static void
+set_mode(struct connector *c)
+{
+ unsigned int fb_id = 0;
+ struct igt_fb fb_info[2] = { };
+ int j, test_mode_num, current_fb = 0, old_fb = -1;
+
+ test_mode_num = 1;
+ if (test_all_modes)
+ test_mode_num = c->connector->count_modes;
+
+
+
+ width = c->mode.hdisplay;
+ height = c->mode.vdisplay;
+
+ fb_id = igt_create_fb(drm_fd, width, height,
+ igt_bpp_depth_to_drm_format(bpp, depth),
+ tiling, &fb_info[current_fb]);
+ paint_output_info(c, &fb_info[current_fb]);
+
+ kmstest_dump_mode(&c->mode);
+ if (drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0,
+ &c->id, 1, &c->mode)) {
+ igt_warn("failed to set mode (%dx%d@%dHz): %s\n", width, height, c->mode.vrefresh, strerror(errno));
+ }
+
+ if (old_fb != -1)
+ igt_remove_fb(drm_fd, &fb_info[old_fb]);
+ old_fb = current_fb;
+ current_fb = 1 - current_fb;
+
+ if (sleep_between_modes && test_all_modes)
+ sleep(sleep_between_modes);
+
+
+ if (test_all_modes)
+ igt_remove_fb(drm_fd, &fb_info[old_fb]);
+
+ drmModeFreeEncoder(c->encoder);
+ drmModeFreeConnector(c->connector);
+}
+
+/*
+ * Re-probe outputs and light up as many as possible.
+ *
+ * On Intel, we have two CRTCs that we can drive independently with
+ * different timings and scanout buffers.
+ *
+ * Each connector has a corresponding encoder, except in the SDVO case
+ * where an encoder may have multiple connectors.
+ */
+int update_display(void)
+{
+ struct connector *connectors;
+ int c;
+
+ resources = drmModeGetResources(drm_fd);
+ if (!resources) {
+ igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
+ return 0;
+ }
+
+ connectors = calloc(resources->count_connectors,
+ sizeof(struct connector));
+ if (!connectors)
+ return 0;
+
+ if (test_preferred_mode || test_all_modes ) {
+ unsigned long crtc_idx_mask = -1UL;
+
+ /* Find any connected displays */
+ for (c = 0; c < resources->count_connectors; c++) {
+ struct connector *connector = &connectors[c];
+
+ connector->id = resources->connectors[c];
+
+ connector_find_preferred_mode(connector->id,
+ crtc_idx_mask,
+ -1,
+ connector);
+ if (!connector->mode_valid)
+ continue;
+
+ set_mode(connector);
+
+ if (test_preferred_mode )
+ crtc_idx_mask &= ~(1 << connector->crtc_idx);
+
+ }
+ }
+
+ free(connectors);
+ drmModeFreeResources(resources);
+ return 1;
+}
+
+static char optstr[] = "3hiaf:s:d:p:mrto:j:";
+
+static void __attribute__((noreturn)) usage(char *name, char opt)
+{
+ igt_info("usage: %s [-hiasdpmtf]\n", name);
+ igt_info("\t-i\tdump info\n");
+ igt_info("\t-a\ttest all modes\n");
+ igt_info("\t-s\t<duration>\tsleep between each mode test\n");
+ igt_info("\t-d\t<depth>\tbit depth of scanout buffer\n");
+ igt_info("\t-p\t<planew,h>,<crtcx,y>,<crtcw,h> test overlay plane\n");
+ igt_info("\t-m\ttest the preferred mode\n");
+ igt_info("\t-3\ttest all 3D modes\n");
+ igt_info("\t-t\tuse a tiled framebuffer\n");
+ igt_info("\t-j\tdo dpms off, optional arg to select dpms leve (1-3)\n");
+ igt_info("\t-r\tprint a QR code on the screen whose content is \"pass\" for the automatic test\n");
+ igt_info("\t-o\t<id of the display>,<number of the mode>\tonly test specified mode on the specified display\n");
+ igt_info("\t-f\t<clock MHz>,<hdisp>,<hsync-start>,<hsync-end>,<htotal>,\n");
+ igt_info("\t\t<vdisp>,<vsync-start>,<vsync-end>,<vtotal>\n");
+ igt_info("\t\ttest force mode\n");
+ igt_info("\tDefault is to test all modes.\n");
+ exit((opt != 'h') ? -1 : 0);
+}
+
+#define dump_resource(res) if (res) dump_##res()
+
+static void cleanup_and_exit(int ret)
+{
+ close(drm_fd);
+ exit(ret);
+}
+
+static gboolean input_event(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ gchar buf[2];
+ gsize count;
+
+ count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf));
+ if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) {
+ cleanup_and_exit(0);
+ }
+
+ return TRUE;
+}
+
+static void enter_exec_path( char **argv )
+{
+ char *exec_path = NULL;
+ char *pos = NULL;
+ short len_path = 0;
+ int ret;
+
+ len_path = strlen( argv[0] );
+ exec_path = (char*) malloc(len_path);
+
+ memcpy(exec_path, argv[0], len_path);
+ pos = strrchr(exec_path, '/');
+ if (pos != NULL)
+ *(pos+1) = '\0';
+
+ ret = chdir(exec_path);
+ igt_assert(ret == 0);
+ free(exec_path);
+}
+
+static void restore_termio_mode(int sig)
+{
+ tcsetattr(tio_fd, TCSANOW, &saved_tio);
+ close(tio_fd);
+}
+
+static void set_termio_mode(void)
+{
+ struct termios tio;
+
+ /* don't attempt to set terminal attributes if not in the foreground
+ * process group */
+ if (getpgrp() != tcgetpgrp(STDOUT_FILENO))
+ return;
+
+ tio_fd = dup(STDIN_FILENO);
+ tcgetattr(tio_fd, &saved_tio);
+ igt_install_exit_handler(restore_termio_mode);
+ tio = saved_tio;
+ tio.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(tio_fd, TCSANOW, &tio);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int ret = 0;
+ GIOChannel *stdinchannel;
+ GMainLoop *mainloop;
+ float force_clock;
+ struct option long_opts[] = {
+ {"help", 0, 0, 'h'},
+ { 0, 0, 0, 0 }
+ };
+
+ igt_skip_on_simulation();
+
+ enter_exec_path( argv );
+
+ while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'a':
+ test_all_modes = 1;
+ break;
+ case 'f':
+ if(sscanf(optarg,"%f,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu",
+ &force_clock,&force_timing.hdisplay, &force_timing.hsync_start,&force_timing.hsync_end,&force_timing.htotal,
+ &force_timing.vdisplay, &force_timing.vsync_start, &force_timing.vsync_end, &force_timing.vtotal)!= 9)
+ usage(argv[0], c);
+ force_timing.clock = force_clock*1000;
+
+ break;
+ case 's':
+ sleep_between_modes = atoi(optarg);
+ break;
+ case 'd':
+ depth = atoi(optarg);
+ igt_info("using depth %d\n", depth);
+ break;
+ case 'm':
+ test_preferred_mode = 1;
+ break;
+ default:
+ /* fall through */
+ case 'h':
+ usage(argv[0], c);
+ break;
+ }
+ }
+
+ set_termio_mode();
+
+ if (!test_all_modes && !test_preferred_mode )
+ test_all_modes = 1;
+
+ drm_fd = drm_open_any();
+
+ kmstest_set_vt_graphics_mode();
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+ if (!mainloop) {
+ igt_warn("failed to create glib mainloop\n");
+ ret = -1;
+ goto out_close;
+ }
+
+ if (!testdisplay_setup_hotplug()) {
+ igt_warn("failed to initialize hotplug support\n");
+ goto out_mainloop;
+ }
+
+ stdinchannel = g_io_channel_unix_new(0);
+ if (!stdinchannel) {
+ igt_warn("failed to create stdin GIO channel\n");
+ goto out_hotplug;
+ }
+
+ ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event,
+ NULL);
+ if (ret < 0) {
+ igt_warn("failed to add watch on stdin GIO channel\n");
+ goto out_stdio;
+ }
+
+ ret = 0;
+
+ if (!update_display()) {
+ ret = 1;
+ goto out_stdio;
+ }
+
+ if (test_all_modes)
+ goto out_stdio;
+
+ g_main_loop_run(mainloop);
+
+out_stdio:
+ g_io_channel_shutdown(stdinchannel, TRUE, NULL);
+out_hotplug:
+ testdisplay_cleanup_hotplug();
+out_mainloop:
+ g_main_loop_unref(mainloop);
+out_close:
+ close(drm_fd);
+
+ igt_assert(ret == 0);
+
+ igt_exit();
+}
diff --git a/tests/testdisplay.h b/tests/testdisplay.h
new file mode 100644
index 0000000..962e621
--- /dev/null
+++ b/tests/testdisplay.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+
+extern int drm_fd;
+
+gboolean testdisplay_setup_hotplug(void);
+void testdisplay_cleanup_hotplug(void);
+
+/* called by the hotplug code */
+int update_display(void);
diff --git a/tests/testdisplay_hotplug.c b/tests/testdisplay_hotplug.c
new file mode 100644
index 0000000..6e33ef3
--- /dev/null
+++ b/tests/testdisplay_hotplug.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2010 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "testdisplay.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "igt_core.h"
+
+#if HAVE_UDEV
+#include <libudev.h>
+static struct udev_monitor *uevent_monitor;
+static struct udev *udev;
+static GIOChannel *udevchannel;
+
+static gboolean hotplug_event(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ struct udev_device *dev;
+ dev_t udev_devnum;
+ struct stat s;
+ const char *hotplug;
+
+ dev = udev_monitor_receive_device(uevent_monitor);
+ if (!dev)
+ goto out;
+
+ udev_devnum = udev_device_get_devnum(dev);
+ fstat(drm_fd, &s);
+
+ hotplug = udev_device_get_property_value(dev, "HOTPLUG");
+
+ if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
+ hotplug && atoi(hotplug) == 1)
+ update_display();
+
+ udev_device_unref(dev);
+out:
+ return TRUE;
+}
+
+
+gboolean testdisplay_setup_hotplug(void)
+{
+ int ret;
+
+ udev = udev_new();
+ if (!udev) {
+ igt_warn("failed to create udev object\n");
+ goto out;
+ }
+
+ uevent_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (!uevent_monitor) {
+ igt_warn("failed to create udev event monitor\n");
+ goto out;
+ }
+
+ ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor,
+ "drm",
+ "drm_minor");
+ if (ret < 0) {
+ igt_warn("failed to filter for drm events\n");
+ goto out;
+ }
+
+ ret = udev_monitor_enable_receiving(uevent_monitor);
+ if (ret < 0) {
+ igt_warn("failed to enable udev event reception\n");
+ goto out;
+ }
+
+ udevchannel =
+ g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor));
+ if (!udevchannel) {
+ igt_warn("failed to create udev GIO channel\n");
+ goto out;
+ }
+
+ ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event,
+ udev);
+ if (ret < 0) {
+ igt_warn("failed to add watch on udev GIO channel\n");
+ goto out;
+ }
+
+ return TRUE;
+
+out:
+ testdisplay_cleanup_hotplug();
+ return FALSE;
+}
+
+void testdisplay_cleanup_hotplug(void)
+{
+ if (udevchannel)
+ g_io_channel_shutdown(udevchannel, TRUE, NULL);
+ if (uevent_monitor)
+ udev_monitor_unref(uevent_monitor);
+ if (udev)
+ udev_unref(udev);
+}
+#else
+gboolean testdisplay_setup_hotplug(void)
+{
+ igt_warn("no hotplug support on this platform\n");
+ return TRUE;
+}
+
+void testdisplay_cleanup_hotplug(void)
+{
+}
+#endif