Module Name:    xsrc
Committed By:   mrg
Date:           Sun Nov  1 09:57:41 UTC 2020

Modified Files:
        xsrc/external/mit/libdrm/dist: xf86atomic.h xf86drm.c xf86drm.h
            xf86drmMode.c xf86drmMode.h
        xsrc/external/mit/libdrm/dist/include/drm: drm.h
        xsrc/external/mit/libdrm/dist/intel: intel_bufmgr_gem.c
        xsrc/external/mit/libdrm/dist/tests/modetest: modetest.c
Added Files:
        xsrc/external/mit/libdrm/dist: Android.mk
        xsrc/external/mit/libdrm/dist/freedreno: Android.mk
        xsrc/external/mit/libdrm/dist/intel: Android.mk
        xsrc/external/mit/libdrm/dist/libkms: Android.mk
        xsrc/external/mit/libdrm/dist/nouveau: Android.mk
        xsrc/external/mit/libdrm/dist/radeon: Android.mk
        xsrc/external/mit/libdrm/dist/tests/modetest: Android.mk
Removed Files:
        xsrc/external/mit/libdrm/dist: Makefile.am Makefile.in aclocal.m4
            config.h.in configure configure.ac
        xsrc/external/mit/libdrm/dist/amdgpu: Makefile.am Makefile.in
            amdgpu-symbol-check
        xsrc/external/mit/libdrm/dist/build-aux: compile config.guess
            config.sub depcomp install-sh ltmain.sh missing test-driver
        xsrc/external/mit/libdrm/dist/data: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/etnaviv: Makefile.am Makefile.in
            etnaviv-symbol-check
        xsrc/external/mit/libdrm/dist/exynos: Makefile.am Makefile.in
            exynos-symbol-check
        xsrc/external/mit/libdrm/dist/freedreno: Makefile.am Makefile.in
            freedreno-symbol-check
        xsrc/external/mit/libdrm/dist/intel: Makefile.am Makefile.in
            intel-symbol-check
        xsrc/external/mit/libdrm/dist/intel/tests: gen4-3d.batch.sh
            gen5-3d.batch.sh gen6-3d.batch.sh gen7-2d-copy.batch.sh
            gen7-3d.batch.sh gm45-3d.batch.sh
        xsrc/external/mit/libdrm/dist/libkms: Makefile.am Makefile.in
            kms-symbol-check
        xsrc/external/mit/libdrm/dist/m4: libtool.m4 ltoptions.m4 ltsugar.m4
            ltversion.m4 lt~obsolete.m4
        xsrc/external/mit/libdrm/dist/man: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/nouveau: Makefile.am Makefile.in
            nouveau-symbol-check
        xsrc/external/mit/libdrm/dist/omap: Makefile.am Makefile.in
            omap-symbol-check
        xsrc/external/mit/libdrm/dist/radeon: Makefile.am Makefile.in
            radeon-symbol-check
        xsrc/external/mit/libdrm/dist/tegra: Makefile.am Makefile.in
            tegra-symbol-check
        xsrc/external/mit/libdrm/dist/tests: Makefile.am Makefile.in random.c
        xsrc/external/mit/libdrm/dist/tests/amdgpu: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/etnaviv: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/exynos: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/kms: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/kmstest: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/modeprint: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/modetest: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/nouveau: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/proptest: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/radeon: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/tegra: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/util: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/tests/vbltest: Makefile.am Makefile.in
        xsrc/external/mit/libdrm/dist/vc4: Makefile.am Makefile.in

Log Message:
merge libdrm 2.4.102.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.3 xsrc/external/mit/libdrm/dist/Android.mk
cvs rdiff -u -r1.1.1.12 -r0 xsrc/external/mit/libdrm/dist/Makefile.am
cvs rdiff -u -r1.1.1.15 -r0 xsrc/external/mit/libdrm/dist/Makefile.in
cvs rdiff -u -r1.1.1.16 -r0 xsrc/external/mit/libdrm/dist/aclocal.m4
cvs rdiff -u -r1.1.1.10 -r0 xsrc/external/mit/libdrm/dist/config.h.in
cvs rdiff -u -r1.1.1.19 -r0 xsrc/external/mit/libdrm/dist/configure \
    xsrc/external/mit/libdrm/dist/configure.ac
cvs rdiff -u -r1.13 -r1.14 xsrc/external/mit/libdrm/dist/xf86atomic.h
cvs rdiff -u -r1.25 -r1.26 xsrc/external/mit/libdrm/dist/xf86drm.c
cvs rdiff -u -r1.11 -r1.12 xsrc/external/mit/libdrm/dist/xf86drm.h
cvs rdiff -u -r1.15 -r1.16 xsrc/external/mit/libdrm/dist/xf86drmMode.c
cvs rdiff -u -r1.9 -r1.10 xsrc/external/mit/libdrm/dist/xf86drmMode.h
cvs rdiff -u -r1.1.1.4 -r0 xsrc/external/mit/libdrm/dist/amdgpu/Makefile.am
cvs rdiff -u -r1.1.1.6 -r0 xsrc/external/mit/libdrm/dist/amdgpu/Makefile.in
cvs rdiff -u -r1.1.1.8 -r0 \
    xsrc/external/mit/libdrm/dist/amdgpu/amdgpu-symbol-check
cvs rdiff -u -r1.1.1.5 -r0 xsrc/external/mit/libdrm/dist/build-aux/compile \
    xsrc/external/mit/libdrm/dist/build-aux/depcomp \
    xsrc/external/mit/libdrm/dist/build-aux/ltmain.sh
cvs rdiff -u -r1.1.1.10 -r0 \
    xsrc/external/mit/libdrm/dist/build-aux/config.guess \
    xsrc/external/mit/libdrm/dist/build-aux/config.sub
cvs rdiff -u -r1.1.1.4 -r0 xsrc/external/mit/libdrm/dist/build-aux/install-sh
cvs rdiff -u -r1.1.1.6 -r0 xsrc/external/mit/libdrm/dist/build-aux/missing \
    xsrc/external/mit/libdrm/dist/build-aux/test-driver
cvs rdiff -u -r1.1.1.2 -r0 xsrc/external/mit/libdrm/dist/data/Makefile.am
cvs rdiff -u -r1.1.1.3 -r0 xsrc/external/mit/libdrm/dist/data/Makefile.in
cvs rdiff -u -r1.1.1.2 -r0 xsrc/external/mit/libdrm/dist/etnaviv/Makefile.am
cvs rdiff -u -r1.1.1.5 -r0 xsrc/external/mit/libdrm/dist/etnaviv/Makefile.in
cvs rdiff -u -r1.1.1.6 -r0 \
    xsrc/external/mit/libdrm/dist/etnaviv/etnaviv-symbol-check
cvs rdiff -u -r1.1.1.4 -r0 xsrc/external/mit/libdrm/dist/exynos/Makefile.am
cvs rdiff -u -r1.1.1.10 -r0 xsrc/external/mit/libdrm/dist/exynos/Makefile.in
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/exynos/exynos-symbol-check
cvs rdiff -u -r0 -r1.3 xsrc/external/mit/libdrm/dist/freedreno/Android.mk
cvs rdiff -u -r1.1.1.7 -r0 \
    xsrc/external/mit/libdrm/dist/freedreno/Makefile.am
cvs rdiff -u -r1.1.1.10 -r0 \
    xsrc/external/mit/libdrm/dist/freedreno/Makefile.in
cvs rdiff -u -r1.1.1.6 -r0 \
    xsrc/external/mit/libdrm/dist/freedreno/freedreno-symbol-check
cvs rdiff -u -r1.12 -r1.13 xsrc/external/mit/libdrm/dist/include/drm/drm.h
cvs rdiff -u -r0 -r1.3 xsrc/external/mit/libdrm/dist/intel/Android.mk
cvs rdiff -u -r1.1.1.6 -r0 xsrc/external/mit/libdrm/dist/intel/Makefile.am \
    xsrc/external/mit/libdrm/dist/intel/intel-symbol-check
cvs rdiff -u -r1.1.1.14 -r0 xsrc/external/mit/libdrm/dist/intel/Makefile.in
cvs rdiff -u -r1.18 -r1.19 \
    xsrc/external/mit/libdrm/dist/intel/intel_bufmgr_gem.c
cvs rdiff -u -r1.1.1.1 -r0 \
    xsrc/external/mit/libdrm/dist/intel/tests/gen4-3d.batch.sh \
    xsrc/external/mit/libdrm/dist/intel/tests/gen5-3d.batch.sh \
    xsrc/external/mit/libdrm/dist/intel/tests/gen6-3d.batch.sh \
    xsrc/external/mit/libdrm/dist/intel/tests/gen7-2d-copy.batch.sh \
    xsrc/external/mit/libdrm/dist/intel/tests/gen7-3d.batch.sh \
    xsrc/external/mit/libdrm/dist/intel/tests/gm45-3d.batch.sh
cvs rdiff -u -r0 -r1.3 xsrc/external/mit/libdrm/dist/libkms/Android.mk
cvs rdiff -u -r1.1.1.8 -r0 xsrc/external/mit/libdrm/dist/libkms/Makefile.am
cvs rdiff -u -r1.1.1.14 -r0 xsrc/external/mit/libdrm/dist/libkms/Makefile.in
cvs rdiff -u -r1.1.1.4 -r0 \
    xsrc/external/mit/libdrm/dist/libkms/kms-symbol-check
cvs rdiff -u -r1.1.1.7 -r0 xsrc/external/mit/libdrm/dist/m4/libtool.m4
cvs rdiff -u -r1.1.1.3 -r0 xsrc/external/mit/libdrm/dist/m4/ltoptions.m4 \
    xsrc/external/mit/libdrm/dist/m4/ltsugar.m4 \
    xsrc/external/mit/libdrm/dist/m4/ltversion.m4 \
    xsrc/external/mit/libdrm/dist/m4/lt~obsolete.m4
cvs rdiff -u -r1.1.1.3 -r0 xsrc/external/mit/libdrm/dist/man/Makefile.am
cvs rdiff -u -r1.1.1.9 -r0 xsrc/external/mit/libdrm/dist/man/Makefile.in
cvs rdiff -u -r0 -r1.3 xsrc/external/mit/libdrm/dist/nouveau/Android.mk
cvs rdiff -u -r1.1.1.7 -r0 xsrc/external/mit/libdrm/dist/nouveau/Makefile.am
cvs rdiff -u -r1.1.1.14 -r0 xsrc/external/mit/libdrm/dist/nouveau/Makefile.in
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/nouveau/nouveau-symbol-check
cvs rdiff -u -r1.1.1.4 -r0 xsrc/external/mit/libdrm/dist/omap/Makefile.am \
    xsrc/external/mit/libdrm/dist/omap/omap-symbol-check
cvs rdiff -u -r1.1.1.10 -r0 xsrc/external/mit/libdrm/dist/omap/Makefile.in
cvs rdiff -u -r0 -r1.3 xsrc/external/mit/libdrm/dist/radeon/Android.mk
cvs rdiff -u -r1.1.1.7 -r0 xsrc/external/mit/libdrm/dist/radeon/Makefile.am
cvs rdiff -u -r1.1.1.14 -r0 xsrc/external/mit/libdrm/dist/radeon/Makefile.in
cvs rdiff -u -r1.1.1.4 -r0 \
    xsrc/external/mit/libdrm/dist/radeon/radeon-symbol-check
cvs rdiff -u -r1.1.1.3 -r0 xsrc/external/mit/libdrm/dist/tegra/Makefile.am
cvs rdiff -u -r1.1.1.8 -r0 xsrc/external/mit/libdrm/dist/tegra/Makefile.in
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/tegra/tegra-symbol-check
cvs rdiff -u -r1.1.1.9 -r0 xsrc/external/mit/libdrm/dist/tests/Makefile.am
cvs rdiff -u -r1.1.1.15 -r0 xsrc/external/mit/libdrm/dist/tests/Makefile.in
cvs rdiff -u -r1.1.1.1 -r0 xsrc/external/mit/libdrm/dist/tests/random.c
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/tests/amdgpu/Makefile.am
cvs rdiff -u -r1.1.1.7 -r0 \
    xsrc/external/mit/libdrm/dist/tests/amdgpu/Makefile.in
cvs rdiff -u -r1.1.1.3 -r0 \
    xsrc/external/mit/libdrm/dist/tests/etnaviv/Makefile.am
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/tests/etnaviv/Makefile.in
cvs rdiff -u -r1.1.1.6 -r0 \
    xsrc/external/mit/libdrm/dist/tests/exynos/Makefile.am
cvs rdiff -u -r1.1.1.10 -r0 \
    xsrc/external/mit/libdrm/dist/tests/exynos/Makefile.in
cvs rdiff -u -r1.1.1.2 -r0 \
    xsrc/external/mit/libdrm/dist/tests/kms/Makefile.am
cvs rdiff -u -r1.1.1.6 -r0 \
    xsrc/external/mit/libdrm/dist/tests/kms/Makefile.in
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/tests/kmstest/Makefile.am
cvs rdiff -u -r1.1.1.14 -r0 \
    xsrc/external/mit/libdrm/dist/tests/kmstest/Makefile.in
cvs rdiff -u -r1.1.1.6 -r0 \
    xsrc/external/mit/libdrm/dist/tests/modeprint/Makefile.am
cvs rdiff -u -r1.1.1.15 -r0 \
    xsrc/external/mit/libdrm/dist/tests/modeprint/Makefile.in
cvs rdiff -u -r0 -r1.3 \
    xsrc/external/mit/libdrm/dist/tests/modetest/Android.mk
cvs rdiff -u -r1.1.1.9 -r0 \
    xsrc/external/mit/libdrm/dist/tests/modetest/Makefile.am
cvs rdiff -u -r1.1.1.16 -r0 \
    xsrc/external/mit/libdrm/dist/tests/modetest/Makefile.in
cvs rdiff -u -r1.13 -r1.14 \
    xsrc/external/mit/libdrm/dist/tests/modetest/modetest.c
cvs rdiff -u -r1.1.1.3 -r0 \
    xsrc/external/mit/libdrm/dist/tests/nouveau/Makefile.am
cvs rdiff -u -r1.1.1.7 -r0 \
    xsrc/external/mit/libdrm/dist/tests/nouveau/Makefile.in
cvs rdiff -u -r1.1.1.4 -r0 \
    xsrc/external/mit/libdrm/dist/tests/proptest/Makefile.am
cvs rdiff -u -r1.1.1.8 -r0 \
    xsrc/external/mit/libdrm/dist/tests/proptest/Makefile.in
cvs rdiff -u -r1.1.1.4 -r0 \
    xsrc/external/mit/libdrm/dist/tests/radeon/Makefile.am
cvs rdiff -u -r1.1.1.10 -r0 \
    xsrc/external/mit/libdrm/dist/tests/radeon/Makefile.in
cvs rdiff -u -r1.1.1.3 -r0 \
    xsrc/external/mit/libdrm/dist/tests/tegra/Makefile.am
cvs rdiff -u -r1.1.1.8 -r0 \
    xsrc/external/mit/libdrm/dist/tests/tegra/Makefile.in
cvs rdiff -u -r1.1.1.1 -r0 \
    xsrc/external/mit/libdrm/dist/tests/util/Makefile.am
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/tests/util/Makefile.in
cvs rdiff -u -r1.1.1.5 -r0 \
    xsrc/external/mit/libdrm/dist/tests/vbltest/Makefile.am
cvs rdiff -u -r1.1.1.13 -r0 \
    xsrc/external/mit/libdrm/dist/tests/vbltest/Makefile.in
cvs rdiff -u -r1.1.1.2 -r0 xsrc/external/mit/libdrm/dist/vc4/Makefile.am
cvs rdiff -u -r1.1.1.6 -r0 xsrc/external/mit/libdrm/dist/vc4/Makefile.in

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: xsrc/external/mit/libdrm/dist/xf86atomic.h
diff -u xsrc/external/mit/libdrm/dist/xf86atomic.h:1.13 xsrc/external/mit/libdrm/dist/xf86atomic.h:1.14
--- xsrc/external/mit/libdrm/dist/xf86atomic.h:1.13	Mon Jul 15 05:42:34 2019
+++ xsrc/external/mit/libdrm/dist/xf86atomic.h	Sun Nov  1 09:57:37 2020
@@ -54,6 +54,7 @@ typedef struct {
 #endif
 
 #if HAVE_LIB_ATOMIC_OPS
+#define AO_REQUIRE_CAS
 #include <atomic_ops.h>
 
 #define HAS_ATOMIC_OPS 1

Index: xsrc/external/mit/libdrm/dist/xf86drm.c
diff -u xsrc/external/mit/libdrm/dist/xf86drm.c:1.25 xsrc/external/mit/libdrm/dist/xf86drm.c:1.26
--- xsrc/external/mit/libdrm/dist/xf86drm.c:1.25	Sun Feb 23 09:59:00 2020
+++ xsrc/external/mit/libdrm/dist/xf86drm.c	Sun Nov  1 09:57:37 2020
@@ -57,8 +57,16 @@
 #ifdef MAJOR_IN_SYSMACROS
 #include <sys/sysmacros.h>
 #endif
+#if HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
 #include <math.h>
 
+#if defined(__FreeBSD__)
+#include <sys/param.h>
+#include <sys/pciio.h>
+#endif
+
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
 /* Not all systems have MAP_FAILED defined */
@@ -71,7 +79,7 @@
 
 #include "util_math.h"
 
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#ifdef __DragonFly__
 #define DRM_MAJOR 145
 #endif
 
@@ -117,6 +125,9 @@ struct drm_pciinfo {
 
 static drmServerInfoPtr drm_server_info;
 
+static bool drmNodeIsDRM(int maj, int min);
+static char *drmGetMinorNameForFD(int fd, int type);
+
 drm_public void drmSetServerInfo(drmServerInfoPtr info)
 {
     drm_server_info = info;
@@ -515,8 +526,28 @@ static int drmGetMinorBase(int type)
     };
 }
 
-static int drmGetMinorType(int minor)
+static int drmGetMinorType(int major, int minor)
 {
+#ifdef __FreeBSD__
+    char name[SPECNAMELEN];
+    int id;
+
+    if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name)))
+        return -1;
+
+    if (sscanf(name, "drm/%d", &id) != 1) {
+        // If not in /dev/drm/ we have the type in the name
+        if (sscanf(name, "dri/card%d\n", &id) >= 1)
+           return DRM_NODE_PRIMARY;
+        else if (sscanf(name, "dri/control%d\n", &id) >= 1)
+           return DRM_NODE_CONTROL;
+        else if (sscanf(name, "dri/renderD%d\n", &id) >= 1)
+           return DRM_NODE_RENDER;
+        return -1;
+    }
+
+    minor = id;
+#endif
     int type = minor >> 6;
 
     if (minor < 0)
@@ -2748,6 +2779,19 @@ drm_public int drmIsMaster(int fd)
 
 drm_public char *drmGetDeviceNameFromFd(int fd)
 {
+#ifdef __FreeBSD__
+    struct stat sbuf;
+    int maj, min;
+    int nodetype;
+
+    if (fstat(fd, &sbuf))
+        return NULL;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+    nodetype = drmGetMinorType(maj, min);
+    return drmGetMinorNameForFD(fd, nodetype);
+#else
     char name[128];
     struct stat sbuf;
     dev_t d;
@@ -2770,6 +2814,7 @@ drm_public char *drmGetDeviceNameFromFd(
         return NULL;
 
     return strdup(name);
+#endif
 }
 
 static bool drmNodeIsDRM(int maj, int min)
@@ -2781,6 +2826,16 @@ static bool drmNodeIsDRM(int maj, int mi
     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
              maj, min);
     return stat(path, &sbuf) == 0;
+#elif __FreeBSD__
+    char name[SPECNAMELEN];
+
+    if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name)))
+      return 0;
+    /* Handle drm/ and dri/ as both are present in different FreeBSD version
+     * FreeBSD on amd64/i386/powerpc external kernel modules create node in
+     * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
+     * only device nodes in /dev/dri/ */
+    return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4));
 #else
     return maj == DRM_MAJOR;
 #endif
@@ -2802,7 +2857,7 @@ drm_public int drmGetNodeTypeFromFd(int 
         return -1;
     }
 
-    type = drmGetMinorType(min);
+    type = drmGetMinorType(maj, min);
     if (type == -1)
         errno = ENODEV;
     return type;
@@ -2884,6 +2939,49 @@ static char *drmGetMinorNameForFD(int fd
 
     closedir(sysdir);
     return NULL;
+#elif __FreeBSD__
+    struct stat sbuf;
+    char dname[SPECNAMELEN];
+    const char *mname;
+    char name[SPECNAMELEN];
+    int id, maj, min, nodetype, i;
+
+    if (fstat(fd, &sbuf))
+        return NULL;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+
+    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
+        return NULL;
+
+    if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname)))
+        return NULL;
+
+    /* Handle both /dev/drm and /dev/dri
+     * FreeBSD on amd64/i386/powerpc external kernel modules create node in
+     * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
+     * only device nodes in /dev/dri/ */
+
+    /* Get the node type represented by fd so we can deduce the target name */
+    nodetype = drmGetMinorType(maj, min);
+    if (nodetype == -1)
+        return (NULL);
+    mname = drmGetMinorName(type);
+
+    for (i = 0; i < SPECNAMELEN; i++) {
+        if (isalpha(dname[i]) == 0 && dname[i] != '/')
+           break;
+    }
+    if (dname[i] == '\0')
+        return (NULL);
+
+    id = (int)strtol(&dname[i], NULL, 10);
+    id -= drmGetMinorBase(nodetype);
+    snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname,
+         id + drmGetMinorBase(type));
+
+    return strdup(name);
 #else
     struct stat sbuf;
     char buf[PATH_MAX + 1];
@@ -2968,10 +3066,10 @@ sysfs_uevent_get(const char *path, const
 /* Little white lie to avoid major rework of the existing code */
 #define DRM_BUS_VIRTIO 0x10
 
-static int drmParseSubsystemType(int maj, int min)
-{
 #ifdef __linux__
-    char path[PATH_MAX + 1];
+static int get_subsystem_type(const char *device_path)
+{
+    char path[PATH_MAX + 1] = "";
     char link[PATH_MAX + 1] = "";
     char *name;
     struct {
@@ -2986,8 +3084,8 @@ static int drmParseSubsystemType(int maj
         { "/virtio", DRM_BUS_VIRTIO },
     };
 
-    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
-             maj, min);
+    strncpy(path, device_path, PATH_MAX);
+    strncat(path, "/subsystem", PATH_MAX);
 
     if (readlink(path, link, PATH_MAX) < 0)
         return -errno;
@@ -3002,6 +3100,29 @@ static int drmParseSubsystemType(int maj
     }
 
     return -EINVAL;
+}
+#endif
+
+static int drmParseSubsystemType(int maj, int min)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1] = "";
+    char real_path[PATH_MAX + 1] = "";
+    int subsystem_type;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+
+    subsystem_type = get_subsystem_type(path);
+    /* Try to get the parent (underlying) device type */
+    if (subsystem_type == DRM_BUS_VIRTIO) {
+        /* Assume virtio-pci on error */
+        if (!realpath(path, real_path))
+            return DRM_BUS_VIRTIO;
+        strncat(path, "/..", PATH_MAX);
+        subsystem_type = get_subsystem_type(path);
+        if (subsystem_type < 0)
+            return DRM_BUS_VIRTIO;
+     }
 #elif defined(__NetBSD__)
     int type, fd;
     drmSetVersion sv;
@@ -3069,6 +3190,7 @@ static int drmParseSubsystemType(int maj
 #endif
 }
 
+#ifdef __linux__
 static void
 get_pci_path(int maj, int min, char *pci_path)
 {
@@ -3084,6 +3206,67 @@ get_pci_path(int maj, int min, char *pci
     if (term && strncmp(term, "/virtio", 7) == 0)
         *term = 0;
 }
+#endif
+
+#ifdef __FreeBSD__
+static int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info)
+{
+    char dname[SPECNAMELEN];
+    char sysctl_name[16];
+    char sysctl_val[256];
+    size_t sysctl_len;
+    int id, type, nelem;
+    unsigned int rdev, majmin, domain, bus, dev, func;
+
+    rdev = makedev(maj, min);
+    if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname)))
+      return -EINVAL;
+
+    if (sscanf(dname, "drm/%d\n", &id) != 1)
+        return -EINVAL;
+    type = drmGetMinorType(maj, min);
+    if (type == -1)
+        return -EINVAL;
+
+    /* BUG: This above section is iffy, since it mandates that a driver will
+     * create both card and render node.
+     * If it does not, the next DRM device will create card#X and
+     * renderD#(128+X)-1.
+     * This is a possibility in FreeBSD but for now there is no good way for
+     * obtaining the info.
+     */
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+         break;
+    case DRM_NODE_CONTROL:
+         id -= 64;
+         break;
+    case DRM_NODE_RENDER:
+         id -= 128;
+          break;
+    }
+    if (id < 0)
+        return -EINVAL;
+
+    if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0)
+      return -EINVAL;
+    sysctl_len = sizeof(sysctl_val);
+    if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0))
+      return -EINVAL;
+
+    #define bus_fmt "pci:%04x:%02x:%02x.%u"
+
+    nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func);
+    if (nelem != 4)
+      return -EINVAL;
+    info->domain = domain;
+    info->bus = bus;
+    info->dev = dev;
+    info->func = func;
+
+    return 0;
+}
+#endif
 
 static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
 {
@@ -3181,7 +3364,7 @@ static int drmParsePciBusInfo(int maj, i
     struct drm_pciinfo pinfo;
     int fd, type;
 
-    type = drmGetMinorType(min);
+    type = drmGetMinorType(maj, min);
     if (type == -1)
         return -ENODEV;
 
@@ -3201,6 +3384,8 @@ static int drmParsePciBusInfo(int maj, i
     info->func = pinfo.func;
 
     return 0;
+#elif __FreeBSD__
+    return get_sysctl_pci_bus_info(maj, min, info);
 #else
 #warning "Missing implementation of drmParsePciBusInfo"
     return -EINVAL;
@@ -3389,7 +3574,7 @@ out:
     struct drm_pciinfo pinfo;
     int fd, type;
 
-    type = drmGetMinorType(min);
+    type = drmGetMinorType(maj, min);
     if (type == -1)
         return -ENODEV;
 
@@ -3410,6 +3595,48 @@ out:
     device->subdevice_id = pinfo.subdevice_id;
 
     return 0;
+#elif __FreeBSD__
+    drmPciBusInfo info;
+    struct pci_conf_io pc;
+    struct pci_match_conf patterns[1];
+    struct pci_conf results[1];
+    int fd, error;
+
+    if (get_sysctl_pci_bus_info(maj, min, &info) != 0)
+        return -EINVAL;
+
+    fd = open("/dev/pci", O_RDONLY, 0);
+    if (fd < 0)
+        return -errno;
+
+    bzero(&patterns, sizeof(patterns));
+    patterns[0].pc_sel.pc_domain = info.domain;
+    patterns[0].pc_sel.pc_bus = info.bus;
+    patterns[0].pc_sel.pc_dev = info.dev;
+    patterns[0].pc_sel.pc_func = info.func;
+    patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS
+                      | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
+    bzero(&pc, sizeof(struct pci_conf_io));
+    pc.num_patterns = 1;
+    pc.pat_buf_len = sizeof(patterns);
+    pc.patterns = patterns;
+    pc.match_buf_len = sizeof(results);
+    pc.matches = results;
+
+    if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) {
+        error = errno;
+        close(fd);
+        return -error;
+    }
+    close(fd);
+
+    device->vendor_id = results[0].pc_vendor;
+    device->device_id = results[0].pc_device;
+    device->subvendor_id = results[0].pc_subvendor;
+    device->subdevice_id = results[0].pc_subdevice;
+    device->revision_id = results[0].pc_revid;
+
+    return 0;
 #else
 #warning "Missing implementation of drmParsePciDeviceInfo"
     return -EINVAL;
@@ -3559,6 +3786,46 @@ free_device:
     return ret;
 }
 
+#ifdef __linux__
+static int drm_usb_dev_path(int maj, int min, char *path, size_t len)
+{
+    char *value, *tmp_path, *slash;
+
+    snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min);
+
+    value = sysfs_uevent_get(path, "DEVTYPE");
+    if (!value)
+        return -ENOENT;
+
+    if (strcmp(value, "usb_device") == 0)
+        return 0;
+    if (strcmp(value, "usb_interface") != 0)
+        return -ENOTSUP;
+
+    /* The parent of a usb_interface is a usb_device */
+
+    tmp_path = realpath(path, NULL);
+    if (!tmp_path)
+        return -errno;
+
+    slash = strrchr(tmp_path, '/');
+    if (!slash) {
+        free(tmp_path);
+        return -EINVAL;
+    }
+
+    *slash = '\0';
+
+    if (snprintf(path, len, "%s", tmp_path) >= (int)len) {
+        free(tmp_path);
+        return -EINVAL;
+    }
+
+    free(tmp_path);
+    return 0;
+}
+#endif
+
 static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
 {
 #ifdef __linux__
@@ -3566,7 +3833,9 @@ static int drmParseUsbBusInfo(int maj, i
     unsigned int bus, dev;
     int ret;
 
-    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+    ret = drm_usb_dev_path(maj, min, path, sizeof(path));
+    if (ret < 0)
+        return ret;
 
     value = sysfs_uevent_get(path, "BUSNUM");
     if (!value)
@@ -3605,7 +3874,9 @@ static int drmParseUsbDeviceInfo(int maj
     unsigned int vendor, product;
     int ret;
 
-    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+    ret = drm_usb_dev_path(maj, min, path, sizeof(path));
+    if (ret < 0)
+        return ret;
 
     value = sysfs_uevent_get(path, "PRODUCT");
     if (!value)
@@ -3979,7 +4250,7 @@ drm_public int drmGetDevice2(int fd, uin
     if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return -EINVAL;
 
-    node_type = drmGetMinorType(min);
+    node_type = drmGetMinorType(maj, min);
     if (node_type == -1)
         return -ENODEV;
 
@@ -4202,6 +4473,8 @@ drm_public char *drmGetDeviceNameFromFd2
     free(value);
 
     return strdup(path);
+#elif __FreeBSD__
+    return drmGetDeviceNameFromFd(fd);
 #else
     struct stat      sbuf;
     char             node[PATH_MAX + 1];
@@ -4218,7 +4491,7 @@ drm_public char *drmGetDeviceNameFromFd2
     if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
         return NULL;
 
-    node_type = drmGetMinorType(min);
+    node_type = drmGetMinorType(maj, min);
     if (node_type == -1)
         return NULL;
 
@@ -4424,6 +4697,21 @@ drm_public int drmSyncobjQuery(int fd, u
     return 0;
 }
 
+drm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points,
+				uint32_t handle_count, uint32_t flags)
+{
+    struct drm_syncobj_timeline_array args;
+
+    memclear(args);
+    args.handles = (uintptr_t)handles;
+    args.points = (uintptr_t)points;
+    args.count_handles = handle_count;
+    args.flags = flags;
+
+    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
+}
+
+
 drm_public int drmSyncobjTransfer(int fd,
 				  uint32_t dst_handle, uint64_t dst_point,
 				  uint32_t src_handle, uint64_t src_point,

Index: xsrc/external/mit/libdrm/dist/xf86drm.h
diff -u xsrc/external/mit/libdrm/dist/xf86drm.h:1.11 xsrc/external/mit/libdrm/dist/xf86drm.h:1.12
--- xsrc/external/mit/libdrm/dist/xf86drm.h:1.11	Sun Feb 23 09:59:00 2020
+++ xsrc/external/mit/libdrm/dist/xf86drm.h	Sun Nov  1 09:57:37 2020
@@ -490,6 +490,29 @@ do {	register unsigned int __old __asm("
 		: "cr0", "memory");			\
 	} while (0)
 
+# elif defined (__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
+	|| defined (__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \
+	|| defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) \
+	|| defined (__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
+	|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
+	|| defined(__ARM_ARCH_7EM__)
+       /* excluding ARMv4/ARMv5 and lower (lacking ldrex/strex support) */
+       #undef DRM_DEV_MODE
+       #define DRM_DEV_MODE     (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
+
+       #define DRM_CAS(lock,old,new,__ret)             \
+       do {                                            \
+               __asm__ __volatile__ (                  \
+                       "1: ldrex %0, [%1]\n"           \
+                       "   teq %0, %2\n"               \
+                       "   ite eq\n"                   \
+                       "   strexeq %0, %3, [%1]\n"     \
+                       "   movne   %0, #1\n"           \
+               : "=&r" (__ret)                         \
+               : "r" (lock), "r" (old), "r" (new)      \
+               : "cc","memory");                       \
+       } while (0)
+
 #endif /* architecture */
 #endif /* __GNUC__ >= 2 */
 
@@ -905,6 +928,8 @@ extern int drmSyncobjTimelineWait(int fd
 				  uint32_t *first_signaled);
 extern int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
 			   uint32_t handle_count);
+extern int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points,
+			    uint32_t handle_count, uint32_t flags);
 extern int drmSyncobjTransfer(int fd,
 			      uint32_t dst_handle, uint64_t dst_point,
 			      uint32_t src_handle, uint64_t src_point,

Index: xsrc/external/mit/libdrm/dist/xf86drmMode.c
diff -u xsrc/external/mit/libdrm/dist/xf86drmMode.c:1.15 xsrc/external/mit/libdrm/dist/xf86drmMode.c:1.16
--- xsrc/external/mit/libdrm/dist/xf86drmMode.c:1.15	Mon Jul 15 05:42:34 2019
+++ xsrc/external/mit/libdrm/dist/xf86drmMode.c	Sun Nov  1 09:57:37 2020
@@ -42,7 +42,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
-#ifdef HAVE_SYS_SYSCTL_H
+#if HAVE_SYS_SYSCTL_H
 #include <sys/sysctl.h>
 #endif
 #include <stdio.h>
@@ -683,6 +683,7 @@ drm_public void drmModeFreeProperty(drmM
 
 	drmFree(ptr->values);
 	drmFree(ptr->enums);
+	drmFree(ptr->blob_ids);
 	drmFree(ptr);
 }
 
@@ -800,21 +801,13 @@ drm_public int drmCheckModesettingSuppor
 	if (found)
 		return 0;
 #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
-	char kbusid[1024], sbusid[1024];
+	char sbusid[1024];
 	char oid[128];
-	int domain, bus, dev, func;
 	int i, modesetting, ret;
 	size_t len;
 
-	ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev,
-	    &func);
-	if (ret != 4)
-		return -EINVAL;
-	snprintf(kbusid, sizeof(kbusid), "pci:%04x:%02x:%02x.%d", domain, bus,
-	    dev, func);
-
 	/* How many GPUs do we expect in the machine ? */
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < 10; i++) {
 		snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i);
 		len = sizeof(sbusid);
 		ret = sysctlbyname(oid, sbusid, &len, NULL, 0);
@@ -823,7 +816,7 @@ drm_public int drmCheckModesettingSuppor
 				continue;
 			return -EINVAL;
 		}
-		if (strcmp(sbusid, kbusid) != 0)
+		if (strcmp(sbusid, busid) != 0)
 			continue;
 		snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i);
 		len = sizeof(modesetting);
@@ -1594,3 +1587,38 @@ drmModeRevokeLease(int fd, uint32_t less
 		return 0;
 	return -errno;
 }
+
+drm_public drmModeFB2Ptr
+drmModeGetFB2(int fd, uint32_t fb_id)
+{
+	struct drm_mode_fb_cmd2 get = {
+		.fb_id = fb_id,
+	};
+	drmModeFB2Ptr ret;
+	int err;
+
+	err = DRM_IOCTL(fd, DRM_IOCTL_MODE_GETFB2, &get);
+	if (err != 0)
+		return NULL;
+
+	ret = drmMalloc(sizeof(drmModeFB2));
+	if (!ret)
+		return NULL;
+
+	ret->fb_id = fb_id;
+	ret->width = get.width;
+	ret->height = get.height;
+	ret->pixel_format = get.pixel_format;
+	ret->flags = get.flags;
+	ret->modifier = get.modifier[0];
+	memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4);
+	memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4);
+	memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4);
+
+	return ret;
+}
+
+drm_public void drmModeFreeFB2(drmModeFB2Ptr ptr)
+{
+	drmFree(ptr);
+}

Index: xsrc/external/mit/libdrm/dist/xf86drmMode.h
diff -u xsrc/external/mit/libdrm/dist/xf86drmMode.h:1.9 xsrc/external/mit/libdrm/dist/xf86drmMode.h:1.10
--- xsrc/external/mit/libdrm/dist/xf86drmMode.h:1.9	Mon Jul 15 05:42:34 2019
+++ xsrc/external/mit/libdrm/dist/xf86drmMode.h	Sun Nov  1 09:57:37 2020
@@ -41,6 +41,8 @@ extern "C" {
 #endif
 
 #include <drm.h>
+#include <stddef.h>
+#include <stdint.h>
 
 /*
  * This is the interface for modesetting for drm.
@@ -160,6 +162,7 @@ extern "C" {
 #define DRM_MODE_CONNECTOR_VIRTUAL      15
 #define DRM_MODE_CONNECTOR_DSI          16
 #define DRM_MODE_CONNECTOR_DPI          17
+#define DRM_MODE_CONNECTOR_WRITEBACK    18
 
 #define DRM_MODE_PROP_PENDING   (1<<0)
 #define DRM_MODE_PROP_RANGE     (1<<1)
@@ -223,6 +226,19 @@ typedef struct _drmModeFB {
 	uint32_t handle;
 } drmModeFB, *drmModeFBPtr;
 
+typedef struct _drmModeFB2 {
+	uint32_t fb_id;
+	uint32_t width, height;
+	uint32_t pixel_format; /* fourcc code from drm_fourcc.h */
+	uint64_t modifier; /* applies to all buffers */
+	uint32_t flags;
+
+	/* per-plane GEM handle; may be duplicate entries for multiple planes */
+	uint32_t handles[4];
+	uint32_t pitches[4]; /* bytes */
+	uint32_t offsets[4]; /* bytes */
+} drmModeFB2, *drmModeFB2Ptr;
+
 typedef struct drm_clip_rect drmModeClip, *drmModeClipPtr;
 
 typedef struct _drmModePropertyBlob {
@@ -341,6 +357,7 @@ typedef struct _drmModePlaneRes {
 extern void drmModeFreeModeInfo( drmModeModeInfoPtr ptr );
 extern void drmModeFreeResources( drmModeResPtr ptr );
 extern void drmModeFreeFB( drmModeFBPtr ptr );
+extern void drmModeFreeFB2( drmModeFB2Ptr ptr );
 extern void drmModeFreeCrtc( drmModeCrtcPtr ptr );
 extern void drmModeFreeConnector( drmModeConnectorPtr ptr );
 extern void drmModeFreeEncoder( drmModeEncoderPtr ptr );
@@ -360,6 +377,7 @@ extern drmModeResPtr drmModeGetResources
  * Retrieve information about framebuffer bufferId
  */
 extern drmModeFBPtr drmModeGetFB(int fd, uint32_t bufferId);
+extern drmModeFB2Ptr drmModeGetFB2(int fd, uint32_t bufferId);
 
 /**
  * Creates a new framebuffer with an buffer object as its scanout buffer.

Index: xsrc/external/mit/libdrm/dist/include/drm/drm.h
diff -u xsrc/external/mit/libdrm/dist/include/drm/drm.h:1.12 xsrc/external/mit/libdrm/dist/include/drm/drm.h:1.13
--- xsrc/external/mit/libdrm/dist/include/drm/drm.h:1.12	Mon Jul 15 05:42:34 2019
+++ xsrc/external/mit/libdrm/dist/include/drm/drm.h	Sun Nov  1 09:57:38 2020
@@ -775,11 +775,12 @@ struct drm_syncobj_array {
 	__u32 pad;
 };
 
+#define DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED (1 << 0) /* last available point on timeline syncobj */
 struct drm_syncobj_timeline_array {
 	__u64 handles;
 	__u64 points;
 	__u32 count_handles;
-	__u32 pad;
+	__u32 flags;
 };
 
 
@@ -944,6 +945,8 @@ extern "C" {
 #define DRM_IOCTL_SYNCOBJ_TRANSFER	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
 #define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL	DRM_IOWR(0xCD, struct drm_syncobj_timeline_array)
 
+#define DRM_IOCTL_MODE_GETFB2		DRM_IOWR(0xCE, struct drm_mode_fb_cmd2)
+
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x9f.

Index: xsrc/external/mit/libdrm/dist/intel/intel_bufmgr_gem.c
diff -u xsrc/external/mit/libdrm/dist/intel/intel_bufmgr_gem.c:1.18 xsrc/external/mit/libdrm/dist/intel/intel_bufmgr_gem.c:1.19
--- xsrc/external/mit/libdrm/dist/intel/intel_bufmgr_gem.c:1.18	Wed Aug  7 13:02:16 2019
+++ xsrc/external/mit/libdrm/dist/intel/intel_bufmgr_gem.c	Sun Nov  1 09:57:38 2020
@@ -1069,6 +1069,28 @@ check_bo_alloc_userptr(drm_intel_bufmgr 
 					  tiling_mode, stride, size, flags);
 }
 
+static int get_tiling_mode(drm_intel_bufmgr_gem *bufmgr_gem,
+			   uint32_t gem_handle,
+			   uint32_t *tiling_mode,
+			   uint32_t *swizzle_mode)
+{
+	struct drm_i915_gem_get_tiling get_tiling = {
+		.handle = gem_handle,
+	};
+	int ret;
+
+	ret = drmIoctl(bufmgr_gem->fd,
+		       DRM_IOCTL_I915_GEM_GET_TILING,
+		       &get_tiling);
+	if (ret != 0 && errno != EOPNOTSUPP)
+		return ret;
+
+	*tiling_mode = get_tiling.tiling_mode;
+	*swizzle_mode = get_tiling.swizzle_mode;
+
+	return 0;
+}
+
 /**
  * Returns a drm_intel_bo wrapping the given buffer object handle.
  *
@@ -1084,7 +1106,6 @@ drm_intel_bo_gem_create_from_name(drm_in
 	drm_intel_bo_gem *bo_gem;
 	int ret;
 	struct drm_gem_open open_arg;
-	struct drm_i915_gem_get_tiling get_tiling;
 
 	/* At the moment most applications only have a few named bo.
 	 * For instance, in a DRI client only the render buffers passed
@@ -1146,16 +1167,11 @@ drm_intel_bo_gem_create_from_name(drm_in
 	HASH_ADD(name_hh, bufmgr_gem->name_table,
 		 global_name, sizeof(bo_gem->global_name), bo_gem);
 
-	memclear(get_tiling);
-	get_tiling.handle = bo_gem->gem_handle;
-	ret = drmIoctl(bufmgr_gem->fd,
-		       DRM_IOCTL_I915_GEM_GET_TILING,
-		       &get_tiling);
+	ret = get_tiling_mode(bufmgr_gem, bo_gem->gem_handle,
+			      &bo_gem->tiling_mode, &bo_gem->swizzle_mode);
 	if (ret != 0)
 		goto err_unref;
 
-	bo_gem->tiling_mode = get_tiling.tiling_mode;
-	bo_gem->swizzle_mode = get_tiling.swizzle_mode;
 	/* XXX stride is unknown */
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0);
 	DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
@@ -2634,7 +2650,6 @@ drm_intel_bo_gem_create_from_prime(drm_i
 	int ret;
 	uint32_t handle;
 	drm_intel_bo_gem *bo_gem;
-	struct drm_i915_gem_get_tiling get_tiling;
 
 	pthread_mutex_lock(&bufmgr_gem->lock);
 	ret = drmPrimeFDToHandle(bufmgr_gem->fd, prime_fd, &handle);
@@ -2688,15 +2703,11 @@ drm_intel_bo_gem_create_from_prime(drm_i
 	bo_gem->has_error = false;
 	bo_gem->reusable = false;
 
-	memclear(get_tiling);
-	get_tiling.handle = bo_gem->gem_handle;
-	if (drmIoctl(bufmgr_gem->fd,
-		     DRM_IOCTL_I915_GEM_GET_TILING,
-		     &get_tiling))
+	ret = get_tiling_mode(bufmgr_gem, handle,
+			      &bo_gem->tiling_mode, &bo_gem->swizzle_mode);
+	if (ret)
 		goto err;
 
-	bo_gem->tiling_mode = get_tiling.tiling_mode;
-	bo_gem->swizzle_mode = get_tiling.swizzle_mode;
 	/* XXX stride is unknown */
 	drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0);
 
@@ -2717,7 +2728,7 @@ drm_intel_bo_gem_export_to_prime(drm_int
 	drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
 
 	if (drmPrimeHandleToFD(bufmgr_gem->fd, bo_gem->gem_handle,
-			       DRM_CLOEXEC, prime_fd) != 0)
+			       DRM_CLOEXEC | DRM_RDWR, prime_fd) != 0)
 		return -errno;
 
 	bo_gem->reusable = false;

Index: xsrc/external/mit/libdrm/dist/tests/modetest/modetest.c
diff -u xsrc/external/mit/libdrm/dist/tests/modetest/modetest.c:1.13 xsrc/external/mit/libdrm/dist/tests/modetest/modetest.c:1.14
--- xsrc/external/mit/libdrm/dist/tests/modetest/modetest.c:1.13	Mon Jul 15 05:42:34 2019
+++ xsrc/external/mit/libdrm/dist/tests/modetest/modetest.c	Sun Nov  1 09:57:40 2020
@@ -51,9 +51,10 @@
 #include <errno.h>
 #include <poll.h>
 #include <sys/time.h>
-#ifdef HAVE_SYS_SELECT_H
+#if HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
+#include <math.h>
 
 #include "xf86drm.h"
 #include "xf86drmMode.h"
@@ -99,14 +100,16 @@ struct plane {
 };
 
 struct resources {
-	drmModeRes *res;
-	drmModePlaneRes *plane_res;
-
 	struct crtc *crtcs;
+	int count_crtcs;
 	struct encoder *encoders;
+	int count_encoders;
 	struct connector *connectors;
+	int count_connectors;
 	struct fb *fbs;
+	int count_fbs;
 	struct plane *planes;
+	uint32_t count_planes;
 };
 
 struct device {
@@ -132,6 +135,12 @@ static inline int64_t U642I64(uint64_t v
 	return (int64_t)*((int64_t *)&val);
 }
 
+static float mode_vrefresh(drmModeModeInfo *mode)
+{
+	return  mode->clock * 1000.00
+			/ (mode->htotal * mode->vtotal);
+}
+
 #define bit_name_fn(res)					\
 const char * res##_str(int type) {				\
 	unsigned int i;						\
@@ -192,7 +201,7 @@ static void dump_encoders(struct device 
 
 	printf("Encoders:\n");
 	printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
-	for (i = 0; i < dev->resources->res->count_encoders; i++) {
+	for (i = 0; i < dev->resources->count_encoders; i++) {
 		encoder = dev->resources->encoders[i].encoder;
 		if (!encoder)
 			continue;
@@ -207,11 +216,12 @@ static void dump_encoders(struct device 
 	printf("\n");
 }
 
-static void dump_mode(drmModeModeInfo *mode)
+static void dump_mode(drmModeModeInfo *mode, int index)
 {
-	printf("  %s %d %d %d %d %d %d %d %d %d %d",
+	printf("  #%i %s %.2f %d %d %d %d %d %d %d %d %d",
+	       index,
 	       mode->name,
-	       mode->vrefresh,
+	       mode_vrefresh(mode),
 	       mode->hdisplay,
 	       mode->hsync_start,
 	       mode->hsync_end,
@@ -426,7 +436,7 @@ static void dump_connectors(struct devic
 
 	printf("Connectors:\n");
 	printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n");
-	for (i = 0; i < dev->resources->res->count_connectors; i++) {
+	for (i = 0; i < dev->resources->count_connectors; i++) {
 		struct connector *_connector = &dev->resources->connectors[i];
 		drmModeConnector *connector = _connector->connector;
 		if (!connector)
@@ -446,10 +456,10 @@ static void dump_connectors(struct devic
 
 		if (connector->count_modes) {
 			printf("  modes:\n");
-			printf("\tname refresh (Hz) hdisp hss hse htot vdisp "
+			printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp "
 			       "vss vse vtot)\n");
 			for (j = 0; j < connector->count_modes; j++)
-				dump_mode(&connector->modes[j]);
+				dump_mode(&connector->modes[j], j);
 		}
 
 		if (_connector->props) {
@@ -470,7 +480,7 @@ static void dump_crtcs(struct device *de
 
 	printf("CRTCs:\n");
 	printf("id\tfb\tpos\tsize\n");
-	for (i = 0; i < dev->resources->res->count_crtcs; i++) {
+	for (i = 0; i < dev->resources->count_crtcs; i++) {
 		struct crtc *_crtc = &dev->resources->crtcs[i];
 		drmModeCrtc *crtc = _crtc->crtc;
 		if (!crtc)
@@ -481,7 +491,7 @@ static void dump_crtcs(struct device *de
 		       crtc->buffer_id,
 		       crtc->x, crtc->y,
 		       crtc->width, crtc->height);
-		dump_mode(&crtc->mode);
+		dump_mode(&crtc->mode, 0);
 
 		if (_crtc->props) {
 			printf("  props:\n");
@@ -503,7 +513,7 @@ static void dump_framebuffers(struct dev
 
 	printf("Frame buffers:\n");
 	printf("id\tsize\tpitch\n");
-	for (i = 0; i < dev->resources->res->count_fbs; i++) {
+	for (i = 0; i < dev->resources->count_fbs; i++) {
 		fb = dev->resources->fbs[i].fb;
 		if (!fb)
 			continue;
@@ -523,10 +533,7 @@ static void dump_planes(struct device *d
 	printf("Planes:\n");
 	printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
 
-	if (!dev->resources->plane_res)
-		return;
-
-	for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
+	for (i = 0; i < dev->resources->count_planes; i++) {
 		struct plane *plane = &dev->resources->planes[i];
 		drmModePlane *ovr = plane->plane;
 		if (!ovr)
@@ -567,11 +574,11 @@ static void free_resources(struct resour
 	if (!res)
 		return;
 
-#define free_resource(_res, __res, type, Type)					\
+#define free_resource(_res, type, Type)					\
 	do {									\
 		if (!(_res)->type##s)						\
 			break;							\
-		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
+		for (i = 0; i < (int)(_res)->count_##type##s; ++i) {	\
 			if (!(_res)->type##s[i].type)				\
 				break;						\
 			drmModeFree##Type((_res)->type##s[i].type);		\
@@ -579,42 +586,38 @@ static void free_resources(struct resour
 		free((_res)->type##s);						\
 	} while (0)
 
-#define free_properties(_res, __res, type)					\
+#define free_properties(_res, type)					\
 	do {									\
-		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
-			drmModeFreeObjectProperties(res->type##s[i].props);	\
+		for (i = 0; i < (int)(_res)->count_##type##s; ++i) {	\
+			unsigned int j;										\
+			for (j = 0; j < res->type##s[i].props->count_props; ++j)\
+				drmModeFreeProperty(res->type##s[i].props_info[j]);\
 			free(res->type##s[i].props_info);			\
+			drmModeFreeObjectProperties(res->type##s[i].props);	\
 		}								\
 	} while (0)
 
-	if (res->res) {
-		free_properties(res, res, crtc);
-
-		free_resource(res, res, crtc, Crtc);
-		free_resource(res, res, encoder, Encoder);
+	free_properties(res, plane);
+	free_resource(res, plane, Plane);
 
-		for (i = 0; i < res->res->count_connectors; i++)
-			free(res->connectors[i].name);
+	free_properties(res, connector);
+	free_properties(res, crtc);
 
-		free_resource(res, res, connector, Connector);
-		free_resource(res, res, fb, FB);
+	for (i = 0; i < res->count_connectors; i++)
+		free(res->connectors[i].name);
 
-		drmModeFreeResources(res->res);
-	}
-
-	if (res->plane_res) {
-		free_properties(res, plane_res, plane);
-
-		free_resource(res, plane_res, plane, Plane);
-
-		drmModeFreePlaneResources(res->plane_res);
-	}
+	free_resource(res, fb, FB);
+	free_resource(res, connector, Connector);
+	free_resource(res, encoder, Encoder);
+	free_resource(res, crtc, Crtc);
 
 	free(res);
 }
 
 static struct resources *get_resources(struct device *dev)
 {
+	drmModeRes *_res;
+	drmModePlaneRes *plane_res;
 	struct resources *res;
 	int i;
 
@@ -624,40 +627,51 @@ static struct resources *get_resources(s
 
 	drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
 
-	res->res = drmModeGetResources(dev->fd);
-	if (!res->res) {
+	_res = drmModeGetResources(dev->fd);
+	if (!_res) {
 		fprintf(stderr, "drmModeGetResources failed: %s\n",
 			strerror(errno));
-		goto error;
+		free(res);
+		return NULL;
 	}
 
-	res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs));
-	res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders));
-	res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors));
-	res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs));
+	res->count_crtcs = _res->count_crtcs;
+	res->count_encoders = _res->count_encoders;
+	res->count_connectors = _res->count_connectors;
+	res->count_fbs = _res->count_fbs;
+
+	res->crtcs = calloc(res->count_crtcs, sizeof(*res->crtcs));
+	res->encoders = calloc(res->count_encoders, sizeof(*res->encoders));
+	res->connectors = calloc(res->count_connectors, sizeof(*res->connectors));
+	res->fbs = calloc(res->count_fbs, sizeof(*res->fbs));
 
-	if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs)
+	if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) {
+	    drmModeFreeResources(_res);
 		goto error;
+    }
 
 #define get_resource(_res, __res, type, Type)					\
 	do {									\
-		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
-			(_res)->type##s[i].type =				\
-				drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \
-			if (!(_res)->type##s[i].type)				\
+		for (i = 0; i < (int)(_res)->count_##type##s; ++i) {	\
+			uint32_t type##id = (__res)->type##s[i];			\
+			(_res)->type##s[i].type =							\
+				drmModeGet##Type(dev->fd, type##id);			\
+			if (!(_res)->type##s[i].type)						\
 				fprintf(stderr, "could not get %s %i: %s\n",	\
-					#type, (_res)->__res->type##s[i],	\
+					#type, type##id,							\
 					strerror(errno));			\
 		}								\
 	} while (0)
 
-	get_resource(res, res, crtc, Crtc);
-	get_resource(res, res, encoder, Encoder);
-	get_resource(res, res, connector, Connector);
-	get_resource(res, res, fb, FB);
+	get_resource(res, _res, crtc, Crtc);
+	get_resource(res, _res, encoder, Encoder);
+	get_resource(res, _res, connector, Connector);
+	get_resource(res, _res, fb, FB);
+
+	drmModeFreeResources(_res);
 
 	/* Set the name of all connectors based on the type name and the per-type ID. */
-	for (i = 0; i < res->res->count_connectors; i++) {
+	for (i = 0; i < res->count_connectors; i++) {
 		struct connector *connector = &res->connectors[i];
 		drmModeConnector *conn = connector->connector;
 		int num;
@@ -669,9 +683,9 @@ static struct resources *get_resources(s
 			goto error;
 	}
 
-#define get_properties(_res, __res, type, Type)					\
+#define get_properties(_res, type, Type)					\
 	do {									\
-		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
+		for (i = 0; i < (int)(_res)->count_##type##s; ++i) {	\
 			struct type *obj = &res->type##s[i];			\
 			unsigned int j;						\
 			obj->props =						\
@@ -694,25 +708,30 @@ static struct resources *get_resources(s
 		}								\
 	} while (0)
 
-	get_properties(res, res, crtc, CRTC);
-	get_properties(res, res, connector, CONNECTOR);
+	get_properties(res, crtc, CRTC);
+	get_properties(res, connector, CONNECTOR);
 
-	for (i = 0; i < res->res->count_crtcs; ++i)
+	for (i = 0; i < res->count_crtcs; ++i)
 		res->crtcs[i].mode = &res->crtcs[i].crtc->mode;
 
-	res->plane_res = drmModeGetPlaneResources(dev->fd);
-	if (!res->plane_res) {
+	plane_res = drmModeGetPlaneResources(dev->fd);
+	if (!plane_res) {
 		fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
 			strerror(errno));
 		return res;
 	}
 
-	res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes));
-	if (!res->planes)
+	res->count_planes = plane_res->count_planes;
+
+	res->planes = calloc(res->count_planes, sizeof(*res->planes));
+	if (!res->planes) {
+		drmModeFreePlaneResources(plane_res);
 		goto error;
+	}
 
 	get_resource(res, plane_res, plane, Plane);
-	get_properties(res, plane_res, plane, PLANE);
+	drmModeFreePlaneResources(plane_res);
+	get_properties(res, plane, PLANE);
 
 	return res;
 
@@ -721,17 +740,31 @@ error:
 	return NULL;
 }
 
-static int get_crtc_index(struct device *dev, uint32_t id)
+static struct crtc *get_crtc_by_id(struct device *dev, uint32_t id)
 {
 	int i;
 
-	for (i = 0; i < dev->resources->res->count_crtcs; ++i) {
+	for (i = 0; i < dev->resources->count_crtcs; ++i) {
 		drmModeCrtc *crtc = dev->resources->crtcs[i].crtc;
 		if (crtc && crtc->crtc_id == id)
-			return i;
+			return &dev->resources->crtcs[i];
 	}
 
-	return -1;
+	return NULL;
+}
+
+static uint32_t get_crtc_mask(struct device *dev, struct crtc *crtc)
+{
+	unsigned int i;
+
+	for (i = 0; i < (unsigned int)dev->resources->count_crtcs; i++) {
+		if (crtc->crtc->crtc_id == dev->resources->crtcs[i].crtc->crtc_id)
+			return 1 << i;
+	}
+    /* Unreachable: crtc->crtc is one of resources->crtcs[] */
+    /* Don't return zero or static analysers will complain */
+	abort();
+	return 0;
 }
 
 static drmModeConnector *get_connector_by_name(struct device *dev, const char *name)
@@ -739,7 +772,7 @@ static drmModeConnector *get_connector_b
 	struct connector *connector;
 	int i;
 
-	for (i = 0; i < dev->resources->res->count_connectors; i++) {
+	for (i = 0; i < dev->resources->count_connectors; i++) {
 		connector = &dev->resources->connectors[i];
 
 		if (strcmp(connector->name, name) == 0)
@@ -754,7 +787,7 @@ static drmModeConnector *get_connector_b
 	drmModeConnector *connector;
 	int i;
 
-	for (i = 0; i < dev->resources->res->count_connectors; i++) {
+	for (i = 0; i < dev->resources->count_connectors; i++) {
 		connector = dev->resources->connectors[i].connector;
 		if (connector && connector->connector_id == id)
 			return connector;
@@ -768,7 +801,7 @@ static drmModeEncoder *get_encoder_by_id
 	drmModeEncoder *encoder;
 	int i;
 
-	for (i = 0; i < dev->resources->res->count_encoders; i++) {
+	for (i = 0; i < dev->resources->count_encoders; i++) {
 		encoder = dev->resources->encoders[i].encoder;
 		if (encoder && encoder->encoder_id == id)
 			return encoder;
@@ -795,7 +828,7 @@ struct pipe_arg {
 	uint32_t crtc_id;
 	char mode_str[64];
 	char format_str[5];
-	unsigned int vrefresh;
+	float vrefresh;
 	unsigned int fourcc;
 	drmModeModeInfo *mode;
 	struct crtc *crtc;
@@ -822,7 +855,7 @@ struct plane_arg {
 
 static drmModeModeInfo *
 connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str,
-        const unsigned int vrefresh)
+	const float vrefresh)
 {
 	drmModeConnector *connector;
 	drmModeModeInfo *mode;
@@ -832,16 +865,27 @@ connector_find_mode(struct device *dev, 
 	if (!connector || !connector->count_modes)
 		return NULL;
 
+	/* Pick by Index */
+	if (mode_str[0] == '#') {
+		int index = atoi(mode_str + 1);
+
+		if (index >= connector->count_modes || index < 0)
+			return NULL;
+		return &connector->modes[index];
+	}
+
+	/* Pick by Name */
 	for (i = 0; i < connector->count_modes; i++) {
 		mode = &connector->modes[i];
 		if (!strcmp(mode->name, mode_str)) {
-			/* If the vertical refresh frequency is not specified then return the
-			 * first mode that match with the name. Else, return the mode that match
-			 * the name and the specified vertical refresh frequency.
+			/* If the vertical refresh frequency is not specified
+			 * then return the first mode that match with the name.
+			 * Else, return the mode that match the name and
+			 * the specified vertical refresh frequency.
 			 */
 			if (vrefresh == 0)
 				return mode;
-			else if (mode->vrefresh == vrefresh)
+			else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005)
 				return mode;
 		}
 	}
@@ -861,7 +905,7 @@ static struct crtc *pipe_find_crtc(struc
 		uint32_t crtcs_for_connector = 0;
 		drmModeConnector *connector;
 		drmModeEncoder *encoder;
-		int idx;
+		struct crtc *crtc;
 
 		connector = get_connector_by_id(dev, pipe->con_ids[i]);
 		if (!connector)
@@ -873,10 +917,10 @@ static struct crtc *pipe_find_crtc(struc
 				continue;
 
 			crtcs_for_connector |= encoder->possible_crtcs;
-
-			idx = get_crtc_index(dev, encoder->crtc_id);
-			if (idx >= 0)
-				active_crtcs |= 1 << idx;
+			crtc = get_crtc_by_id(dev, encoder->crtc_id);
+			if (!crtc)
+				continue;
+			active_crtcs |= get_crtc_mask(dev, crtc);
 		}
 
 		possible_crtcs &= crtcs_for_connector;
@@ -907,7 +951,13 @@ static int pipe_find_crtc_and_mode(struc
 		mode = connector_find_mode(dev, pipe->con_ids[i],
 					   pipe->mode_str, pipe->vrefresh);
 		if (mode == NULL) {
-			fprintf(stderr,
+			if (pipe->vrefresh)
+				fprintf(stderr,
+				"failed to find mode "
+				"\"%s-%.2fHz\" for connector %s\n",
+				pipe->mode_str, pipe->vrefresh, pipe->cons[i]);
+			else
+				fprintf(stderr,
 				"failed to find mode \"%s\" for connector %s\n",
 				pipe->mode_str, pipe->cons[i]);
 			return -EINVAL;
@@ -918,16 +968,10 @@ static int pipe_find_crtc_and_mode(struc
 	 * locate a CRTC that can be attached to all the connectors.
 	 */
 	if (pipe->crtc_id != (uint32_t)-1) {
-		for (i = 0; i < dev->resources->res->count_crtcs; i++) {
-			struct crtc *crtc = &dev->resources->crtcs[i];
-
-			if (pipe->crtc_id == crtc->crtc->crtc_id) {
-				pipe->crtc = crtc;
-				break;
-			}
-		}
+		pipe->crtc = get_crtc_by_id(dev, pipe->crtc_id);
 	} else {
 		pipe->crtc = pipe_find_crtc(dev, pipe);
+		pipe->crtc_id = pipe->crtc->crtc->crtc_id;
 	}
 
 	if (!pipe->crtc) {
@@ -965,9 +1009,9 @@ static bool set_property(struct device *
 	p->obj_type = 0;
 	p->prop_id = 0;
 
-#define find_object(_res, __res, type, Type)					\
+#define find_object(_res, type, Type)					\
 	do {									\
-		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
+		for (i = 0; i < (int)(_res)->count_##type##s; ++i) {	\
 			struct type *obj = &(_res)->type##s[i];			\
 			if (obj->type->type##_id != p->obj_id)			\
 				continue;					\
@@ -978,11 +1022,11 @@ static bool set_property(struct device *
 		}								\
 	} while(0)								\
 
-	find_object(dev->resources, res, crtc, CRTC);
+	find_object(dev->resources, crtc, CRTC);
 	if (p->obj_type == 0)
-		find_object(dev->resources, res, connector, CONNECTOR);
+		find_object(dev->resources, connector, CONNECTOR);
 	if (p->obj_type == 0)
-		find_object(dev->resources, plane_res, plane, PLANE);
+		find_object(dev->resources, plane, PLANE);
 	if (p->obj_type == 0) {
 		fprintf(stderr, "Object %i not found, can't set property\n",
 			p->obj_id);
@@ -1041,7 +1085,7 @@ page_flip_handler(int fd, unsigned int f
 	else
 		new_fb_id = pipe->fb_id[0];
 
-	drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id,
+	drmModePageFlip(fd, pipe->crtc_id, new_fb_id,
 			DRM_MODE_PAGE_FLIP_EVENT, pipe);
 	pipe->current_fb_id = new_fb_id;
 	pipe->swap_count++;
@@ -1128,26 +1172,41 @@ static void set_gamma(struct device *dev
 	}
 }
 
+static int
+bo_fb_create(int fd, unsigned int fourcc, const uint32_t w, const uint32_t h,
+             enum util_fill_pattern pat, struct bo **out_bo, unsigned int *out_fb_id)
+{
+	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
+	struct bo *bo;
+	unsigned int fb_id;
+
+	bo = bo_create(fd, fourcc, w, h, handles, pitches, offsets, pat);
+
+	if (bo == NULL)
+		return -1;
+
+	if (drmModeAddFB2(fd, w, h, fourcc, handles, pitches, offsets, &fb_id, 0)) {
+		fprintf(stderr, "failed to add fb (%ux%u): %s\n", w, h, strerror(errno));
+		bo_destroy(bo);
+		return -1;
+	}
+	*out_bo = bo;
+	*out_fb_id = fb_id;
+	return 0;
+}
+
 static int atomic_set_plane(struct device *dev, struct plane_arg *p,
 							int pattern, bool update)
 {
-	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
 	struct bo *plane_bo;
 	int crtc_x, crtc_y, crtc_w, crtc_h;
 	struct crtc *crtc = NULL;
-	unsigned int i;
 	unsigned int old_fb_id;
 
 	/* Find an unused plane which can be connected to our CRTC. Find the
 	 * CRTC index first, then iterate over available planes.
 	 */
-	for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
-		if (p->crtc_id == dev->resources->res->crtcs[i]) {
-			crtc = &dev->resources->crtcs[i];
-			break;
-		}
-	}
-
+	crtc = get_crtc_by_id(dev, p->crtc_id);
 	if (!crtc) {
 		fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
 		return -1;
@@ -1161,17 +1220,9 @@ static int atomic_set_plane(struct devic
 	p->old_bo = p->bo;
 
 	if (!plane_bo) {
-		plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h,
-				     handles, pitches, offsets, pattern);
-
-		if (plane_bo == NULL)
+		if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h,
+                         pattern, &plane_bo, &p->fb_id))
 			return -1;
-
-		if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
-			handles, pitches, offsets, &p->fb_id, 0)) {
-			fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
-			return -1;
-		}
 	}
 
 	p->bo = plane_bo;
@@ -1207,34 +1258,23 @@ static int atomic_set_plane(struct devic
 static int set_plane(struct device *dev, struct plane_arg *p)
 {
 	drmModePlane *ovr;
-	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
 	uint32_t plane_id;
-	struct bo *plane_bo;
-	uint32_t plane_flags = 0;
 	int crtc_x, crtc_y, crtc_w, crtc_h;
 	struct crtc *crtc = NULL;
-	unsigned int pipe;
-	unsigned int i;
+	unsigned int i, crtc_mask;
 
 	/* Find an unused plane which can be connected to our CRTC. Find the
 	 * CRTC index first, then iterate over available planes.
 	 */
-	for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
-		if (p->crtc_id == dev->resources->res->crtcs[i]) {
-			crtc = &dev->resources->crtcs[i];
-			pipe = i;
-			break;
-		}
-	}
-
+	crtc = get_crtc_by_id(dev, p->crtc_id);
 	if (!crtc) {
 		fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
 		return -1;
 	}
-
+	crtc_mask = get_crtc_mask(dev, crtc);
 	plane_id = p->plane_id;
 
-	for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
+	for (i = 0; i < dev->resources->count_planes; i++) {
 		ovr = dev->resources->planes[i].plane;
 		if (!ovr)
 			continue;
@@ -1245,35 +1285,26 @@ static int set_plane(struct device *dev,
 		if (!format_support(ovr, p->fourcc))
 			continue;
 
-		if ((ovr->possible_crtcs & (1 << pipe)) &&
+		if ((ovr->possible_crtcs & crtc_mask) &&
 		    (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) {
 			plane_id = ovr->plane_id;
 			break;
 		}
 	}
 
-	if (i == dev->resources->plane_res->count_planes) {
+	if (i == dev->resources->count_planes) {
 		fprintf(stderr, "no unused plane available for CRTC %u\n",
-			crtc->crtc->crtc_id);
+			p->crtc_id);
 		return -1;
 	}
 
 	fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
 		p->w, p->h, p->format_str, plane_id);
 
-	plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles,
-			     pitches, offsets, secondary_fill);
-	if (plane_bo == NULL)
-		return -1;
-
-	p->bo = plane_bo;
-
 	/* just use single plane format for now.. */
-	if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
-			handles, pitches, offsets, &p->fb_id, plane_flags)) {
-		fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
+	if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h,
+	                 secondary_fill, &p->bo, &p->fb_id))
 		return -1;
-	}
 
 	crtc_w = p->w * p->scale;
 	crtc_h = p->h * p->scale;
@@ -1287,15 +1318,15 @@ static int set_plane(struct device *dev,
 	}
 
 	/* note src coords (last 4 args) are in Q16 format */
-	if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id,
-			    plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
+	if (drmModeSetPlane(dev->fd, plane_id, p->crtc_id, p->fb_id,
+			    0, crtc_x, crtc_y, crtc_w, crtc_h,
 			    0, 0, p->w << 16, p->h << 16)) {
 		fprintf(stderr, "failed to enable plane: %s\n",
 			strerror(errno));
 		return -1;
 	}
 
-	ovr->crtc_id = crtc->crtc->crtc_id;
+	ovr->crtc_id = p->crtc_id;
 
 	return 0;
 }
@@ -1317,6 +1348,41 @@ static void atomic_set_planes(struct dev
 	}
 }
 
+static void
+atomic_test_page_flip(struct device *dev, struct pipe_arg *pipe_args,
+              struct plane_arg *plane_args, unsigned int plane_count)
+{
+    int ret;
+
+	gettimeofday(&pipe_args->start, NULL);
+	pipe_args->swap_count = 0;
+
+	while (true) {
+		drmModeAtomicFree(dev->req);
+		dev->req = drmModeAtomicAlloc();
+		atomic_set_planes(dev, plane_args, plane_count, true);
+
+		ret = drmModeAtomicCommit(dev->fd, dev->req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+		if (ret) {
+			fprintf(stderr, "Atomic Commit failed [2]\n");
+			return;
+		}
+
+		pipe_args->swap_count++;
+		if (pipe_args->swap_count == 60) {
+			struct timeval end;
+			double t;
+
+			gettimeofday(&end, NULL);
+			t = end.tv_sec + end.tv_usec * 1e-6 -
+			    (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6);
+			fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t);
+			pipe_args->swap_count = 0;
+			pipe_args->start = end;
+		}
+	}
+}
+
 static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
 {
 	unsigned int i;
@@ -1372,131 +1438,269 @@ static void clear_planes(struct device *
 	}
 }
 
-static void atomic_set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
+static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
 {
+	drmModeConnector *connector;
 	unsigned int i;
-	unsigned int j;
-	int ret;
+	uint32_t id;
+	char *endp;
 
-	for (i = 0; i < count; i++) {
-		struct pipe_arg *pipe = &pipes[i];
+	for (i = 0; i < pipe->num_cons; i++) {
+		id = strtoul(pipe->cons[i], &endp, 10);
+		if (endp == pipe->cons[i]) {
+			connector = get_connector_by_name(dev, pipe->cons[i]);
+			if (!connector) {
+				fprintf(stderr, "no connector named '%s'\n",
+					pipe->cons[i]);
+				return -ENODEV;
+			}
 
-		ret = pipe_find_crtc_and_mode(dev, pipe);
-		if (ret < 0)
+			id = connector->connector_id;
+		}
+
+		pipe->con_ids[i] = id;
+	}
+
+	return 0;
+}
+
+static int pipe_attempt_connector(struct device *dev, drmModeConnector *con,
+		struct pipe_arg *pipe)
+{
+	char *con_str;
+	int i;
+
+	con_str = calloc(8, sizeof(char));
+	if (!con_str)
+		return -1;
+
+	sprintf(con_str, "%d", con->connector_id);
+	strcpy(pipe->format_str, "XR24");
+	pipe->fourcc = util_format_fourcc(pipe->format_str);
+	pipe->num_cons = 1;
+	pipe->con_ids = calloc(1, sizeof(*pipe->con_ids));
+	pipe->cons = calloc(1, sizeof(*pipe->cons));
+
+	if (!pipe->con_ids || !pipe->cons)
+		goto free_con_str;
+
+	pipe->con_ids[0] = con->connector_id;
+	pipe->cons[0] = (const char*)con_str;
+
+	pipe->crtc = pipe_find_crtc(dev, pipe);
+	if (!pipe->crtc)
+		goto free_all;
+
+	pipe->crtc_id = pipe->crtc->crtc->crtc_id;
+
+	/* Return the first mode if no preferred. */
+	pipe->mode = &con->modes[0];
+
+	for (i = 0; i < con->count_modes; i++) {
+		drmModeModeInfo *current_mode = &con->modes[i];
+
+		if (current_mode->type & DRM_MODE_TYPE_PREFERRED) {
+			pipe->mode = current_mode;
+			break;
+		}
+	}
+
+	sprintf(pipe->mode_str, "%dx%d", pipe->mode->hdisplay, pipe->mode->vdisplay);
+
+	return 0;
+
+free_all:
+	free(pipe->cons);
+	free(pipe->con_ids);
+free_con_str:
+	free(con_str);
+	return -1;
+}
+
+static int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes)
+{
+	struct pipe_arg *pipes;
+	struct resources *res = dev->resources;
+	drmModeConnector *con = NULL;
+	int i, connected = 0, attempted = 0;
+
+	for (i = 0; i < res->count_connectors; i++) {
+		con = res->connectors[i].connector;
+		if (!con || con->connection != DRM_MODE_CONNECTED)
 			continue;
+		connected++;
+	}
+	if (!connected) {
+		printf("no connected connector!\n");
+		return 0;
 	}
 
-	for (i = 0; i < count; i++) {
-		struct pipe_arg *pipe = &pipes[i];
-		uint32_t blob_id;
+	pipes = calloc(connected, sizeof(struct pipe_arg));
+	if (!pipes)
+		return 0;
 
-		if (pipe->mode == NULL)
+	for (i = 0; i < res->count_connectors && attempted < connected; i++) {
+		con = res->connectors[i].connector;
+		if (!con || con->connection != DRM_MODE_CONNECTED)
 			continue;
 
-		printf("setting mode %s-%dHz on connectors ",
-		       pipe->mode_str, pipe->mode->vrefresh);
-		for (j = 0; j < pipe->num_cons; ++j) {
-			printf("%s, ", pipe->cons[j]);
-			add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc->crtc->crtc_id);
+		if (pipe_attempt_connector(dev, con, &pipes[attempted]) < 0) {
+			printf("failed fetching preferred mode for connector\n");
+			continue;
 		}
-		printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
-
-		drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
-		add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", blob_id);
-		add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 1);
+		attempted++;
 	}
+
+	*out_pipes = pipes;
+	return attempted;
 }
 
-static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
+static struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc *crtc)
 {
 	unsigned int i;
-	unsigned int j;
-
-	for (i = 0; i < count; i++) {
-		struct pipe_arg *pipe = &pipes[i];
 
-		if (pipe->mode == NULL)
+	for (i = 0; i < dev->resources->count_planes; i++) {
+		struct plane *plane = &dev->resources->planes[i];
+		drmModePlane *ovr = plane->plane;
+		if (!ovr)
 			continue;
 
-		for (j = 0; j < pipe->num_cons; ++j)
-			add_property(dev, pipe->con_ids[j], "CRTC_ID",0);
+		// XXX: add is_primary_plane and (?) format checks
 
-		add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", 0);
-		add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 0);
+		if (ovr->possible_crtcs & get_crtc_mask(dev, crtc))
+            return plane;
 	}
+	return NULL;
 }
 
 static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
 {
-	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
-	unsigned int fb_id;
-	struct bo *bo;
-	unsigned int i;
-	unsigned int j;
-	int ret, x;
-
-	dev->mode.width = 0;
-	dev->mode.height = 0;
-	dev->mode.fb_id = 0;
+	unsigned int i, j;
+	int ret, x = 0;
+	int preferred = count == 0;
 
 	for (i = 0; i < count; i++) {
 		struct pipe_arg *pipe = &pipes[i];
 
+		ret = pipe_resolve_connectors(dev, pipe);
+		if (ret < 0)
+			return;
+
 		ret = pipe_find_crtc_and_mode(dev, pipe);
 		if (ret < 0)
 			continue;
+	}
+	if (preferred) {
+		struct pipe_arg *pipe_args;
 
-		dev->mode.width += pipe->mode->hdisplay;
-		if (dev->mode.height < pipe->mode->vdisplay)
-			dev->mode.height = pipe->mode->vdisplay;
+		count = pipe_find_preferred(dev, &pipe_args);
+		if (!count) {
+			fprintf(stderr, "can't find any preferred connector/mode.\n");
+			return;
+		}
+		pipes = pipe_args;
 	}
 
-	bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
-		       dev->mode.height, handles, pitches, offsets,
-		       primary_fill);
-	if (bo == NULL)
-		return;
+	if (!dev->use_atomic) {
+		for (i = 0; i < count; i++) {
+			struct pipe_arg *pipe = &pipes[i];
 
-	dev->mode.bo = bo;
+			if (pipe->mode == NULL)
+				continue;
 
-	ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
-			    pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0);
-	if (ret) {
-		fprintf(stderr, "failed to add fb (%ux%u): %s\n",
-			dev->mode.width, dev->mode.height, strerror(errno));
-		return;
-	}
+			if (!preferred) {
+				dev->mode.width += pipe->mode->hdisplay;
+				if (dev->mode.height < pipe->mode->vdisplay)
+					dev->mode.height = pipe->mode->vdisplay;
+			} else {
+				/* XXX: Use a clone mode, more like atomic. We could do per
+				 * connector bo/fb, so we don't have the stretched image.
+				 */
+				if (dev->mode.width < pipe->mode->hdisplay)
+					dev->mode.width = pipe->mode->hdisplay;
+				if (dev->mode.height < pipe->mode->vdisplay)
+					dev->mode.height = pipe->mode->vdisplay;
+			}
+		}
 
-	dev->mode.fb_id = fb_id;
+		if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height,
+			             primary_fill, &dev->mode.bo, &dev->mode.fb_id))
+			return;
+	}
 
-	x = 0;
 	for (i = 0; i < count; i++) {
 		struct pipe_arg *pipe = &pipes[i];
+		uint32_t blob_id;
 
 		if (pipe->mode == NULL)
 			continue;
 
-		printf("setting mode %s-%dHz@%s on connectors ",
-		       pipe->mode_str, pipe->mode->vrefresh, pipe->format_str);
-		for (j = 0; j < pipe->num_cons; ++j)
+		printf("setting mode %s-%.2fHz on connectors ",
+		       pipe->mode->name, mode_vrefresh(pipe->mode));
+		for (j = 0; j < pipe->num_cons; ++j) {
 			printf("%s, ", pipe->cons[j]);
-		printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
+			if (dev->use_atomic)
+				add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc_id);
+		}
+		printf("crtc %d\n", pipe->crtc_id);
 
-		ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id,
-				     x, 0, pipe->con_ids, pipe->num_cons,
-				     pipe->mode);
+		if (!dev->use_atomic) {
+			ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, dev->mode.fb_id,
+								 x, 0, pipe->con_ids, pipe->num_cons,
+								 pipe->mode);
 
-		/* XXX: Actually check if this is needed */
-		drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
+			/* XXX: Actually check if this is needed */
+			drmModeDirtyFB(dev->fd, dev->mode.fb_id, NULL, 0);
 
-		x += pipe->mode->hdisplay;
+			if (!preferred)
+				x += pipe->mode->hdisplay;
 
-		if (ret) {
-			fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
-			return;
+			if (ret) {
+				fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
+				return;
+			}
+
+			set_gamma(dev, pipe->crtc_id, pipe->fourcc);
+		} else {
+			drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
+			add_property(dev, pipe->crtc_id, "MODE_ID", blob_id);
+			add_property(dev, pipe->crtc_id, "ACTIVE", 1);
+
+			/* By default atomic modeset does not set a primary plane, shrug */
+			if (preferred) {
+				struct plane *plane = get_primary_plane_by_crtc(dev, pipe->crtc);
+				struct plane_arg plane_args = {
+					.plane_id = plane->plane->plane_id,
+					.crtc_id = pipe->crtc_id,
+					.w = pipe->mode->hdisplay,
+					.h = pipe->mode->vdisplay,
+					.scale = 1.0,
+					.format_str = "XR24",
+					.fourcc = util_format_fourcc(pipe->format_str),
+				};
+
+				atomic_set_planes(dev, &plane_args, 1, false);
+			}
 		}
+	}
+}
+
+static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
+{
+	unsigned int i;
+	unsigned int j;
+
+	for (i = 0; i < count; i++) {
+		struct pipe_arg *pipe = &pipes[i];
 
-		set_gamma(dev, pipe->crtc->crtc->crtc_id, pipe->fourcc);
+		if (pipe->mode == NULL)
+			continue;
+
+		for (j = 0; j < pipe->num_cons; ++j)
+			add_property(dev, pipe->con_ids[j], "CRTC_ID",0);
+
+		add_property(dev, pipe->crtc_id, "MODE_ID", 0);
+		add_property(dev, pipe->crtc_id, "ACTIVE", 0);
 	}
 }
 
@@ -1542,7 +1746,7 @@ static void set_cursors(struct device *d
 	for (i = 0; i < count; i++) {
 		struct pipe_arg *pipe = &pipes[i];
 		ret = cursor_init(dev->fd, handles[0],
-				pipe->crtc->crtc->crtc_id,
+				pipe->crtc_id,
 				pipe->mode->hdisplay, pipe->mode->vdisplay,
 				cw, ch);
 		if (ret) {
@@ -1565,34 +1769,23 @@ static void clear_cursors(struct device 
 
 static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count)
 {
-	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
 	unsigned int other_fb_id;
 	struct bo *other_bo;
 	drmEventContext evctx;
 	unsigned int i;
 	int ret;
 
-	other_bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
-			     dev->mode.height, handles, pitches, offsets,
-			     UTIL_PATTERN_PLAIN);
-	if (other_bo == NULL)
+	if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height,
+	                 UTIL_PATTERN_PLAIN, &other_bo, &other_fb_id))
 		return;
 
-	ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
-			    pipes[0].fourcc, handles, pitches, offsets,
-			    &other_fb_id, 0);
-	if (ret) {
-		fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
-		goto err;
-	}
-
 	for (i = 0; i < count; i++) {
 		struct pipe_arg *pipe = &pipes[i];
 
 		if (pipe->mode == NULL)
 			continue;
 
-		ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id,
+		ret = drmModePageFlip(dev->fd, pipe->crtc_id,
 				      other_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
 				      pipe);
 		if (ret) {
@@ -1650,7 +1843,6 @@ static void test_page_flip(struct device
 
 err_rmfb:
 	drmModeRmFB(dev->fd, other_fb_id);
-err:
 	bo_destroy(other_bo);
 }
 
@@ -1695,6 +1887,8 @@ static int parse_connector(struct pipe_a
 		return -1;
 
 	/* Parse the remaining parameters. */
+	if (!endp)
+		return -1;
 	if (*endp == '@') {
 		arg = endp + 1;
 		pipe->crtc_id = strtoul(arg, &endp, 10);
@@ -1713,7 +1907,7 @@ static int parse_connector(struct pipe_a
 	pipe->mode_str[len] = '\0';
 
 	if (*p == '-') {
-		pipe->vrefresh = strtoul(p + 1, &endp, 10);
+		pipe->vrefresh = strtof(p + 1, &endp);
 		p = endp;
 	}
 
@@ -1811,7 +2005,7 @@ static void parse_fill_patterns(char *ar
 
 static void usage(char *name)
 {
-	fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
+	fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name);
 
 	fprintf(stderr, "\n Query options:\n\n");
 	fprintf(stderr, "\t-c\tlist connectors\n");
@@ -1821,9 +2015,10 @@ static void usage(char *name)
 
 	fprintf(stderr, "\n Test options:\n\n");
 	fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
-	fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n");
+	fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>]\tset a mode\n");
 	fprintf(stderr, "\t-C\ttest hw cursor\n");
 	fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
+	fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n");
 	fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
 	fprintf(stderr, "\t-a \tuse atomic API\n");
 	fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n");
@@ -1837,60 +2032,7 @@ static void usage(char *name)
 	exit(0);
 }
 
-static int page_flipping_supported(void)
-{
-	/*FIXME: generic ioctl needed? */
-	return 1;
-#if 0
-	int ret, value;
-	struct drm_i915_getparam gp;
-
-	gp.param = I915_PARAM_HAS_PAGEFLIPPING;
-	gp.value = &value;
-
-	ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
-	if (ret) {
-		fprintf(stderr, "drm_i915_getparam: %m\n");
-		return 0;
-	}
-
-	return *gp.value;
-#endif
-}
-
-static int cursor_supported(void)
-{
-	/*FIXME: generic ioctl needed? */
-	return 1;
-}
-
-static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
-{
-	drmModeConnector *connector;
-	unsigned int i;
-	uint32_t id;
-	char *endp;
-
-	for (i = 0; i < pipe->num_cons; i++) {
-		id = strtoul(pipe->cons[i], &endp, 10);
-		if (endp == pipe->cons[i]) {
-			connector = get_connector_by_name(dev, pipe->cons[i]);
-			if (!connector) {
-				fprintf(stderr, "no connector named '%s'\n",
-					pipe->cons[i]);
-				return -ENODEV;
-			}
-
-			id = connector->connector_id;
-		}
-
-		pipe->con_ids[i] = id;
-	}
-
-	return 0;
-}
-
-static char optstr[] = "acdD:efF:M:P:ps:Cvw:";
+static char optstr[] = "acdD:efF:M:P:ps:Cvrw:";
 
 int main(int argc, char **argv)
 {
@@ -1901,6 +2043,7 @@ int main(int argc, char **argv)
 	int drop_master = 0;
 	int test_vsync = 0;
 	int test_cursor = 0;
+	int set_preferred = 0;
 	int use_atomic = 0;
 	char *device = NULL;
 	char *module = NULL;
@@ -1922,12 +2065,15 @@ int main(int argc, char **argv)
 		switch (c) {
 		case 'a':
 			use_atomic = 1;
+			/* Preserve the default behaviour of dumping all information. */
+			args--;
 			break;
 		case 'c':
 			connectors = 1;
 			break;
 		case 'D':
 			device = optarg;
+			/* Preserve the default behaviour of dumping all information. */
 			args--;
 			break;
 		case 'd':
@@ -1985,6 +2131,9 @@ int main(int argc, char **argv)
 		case 'v':
 			test_vsync = 1;
 			break;
+		case 'r':
+			set_preferred = 1;
+			break;
 		case 'w':
 			prop_args = realloc(prop_args,
 					   (prop_count + 1) * sizeof *prop_args);
@@ -2005,51 +2154,45 @@ int main(int argc, char **argv)
 		}
 	}
 
-	if (!args || (args == 1 && use_atomic))
+	/* Dump all the details when no* arguments are provided. */
+	if (!args)
 		encoders = connectors = crtcs = planes = framebuffers = 1;
 
-	dev.fd = util_open(device, module);
-	if (dev.fd < 0)
-		return -1;
-
-	ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
-	if (ret && use_atomic) {
-		fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
-		drmClose(dev.fd);
+	if (test_vsync && !count) {
+		fprintf(stderr, "page flipping requires at least one -s option.\n");
 		return -1;
 	}
-
-	dev.use_atomic = use_atomic;
-
-	if (test_vsync && !page_flipping_supported()) {
-		fprintf(stderr, "page flipping not supported by drm.\n");
+	if (set_preferred && count) {
+		fprintf(stderr, "cannot use -r (preferred) when -s (mode) is set\n");
 		return -1;
 	}
 
-	if (test_vsync && !count) {
-		fprintf(stderr, "page flipping requires at least one -s option.\n");
+	if (set_preferred && plane_count) {
+		fprintf(stderr, "cannot use -r (preferred) when -P (plane) is set\n");
 		return -1;
 	}
 
-	if (test_cursor && !cursor_supported()) {
-		fprintf(stderr, "hw cursor not supported by drm.\n");
+	dev.fd = util_open(device, module);
+	if (dev.fd < 0)
 		return -1;
+
+	if (use_atomic) {
+		ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
+		if (ret) {
+			fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
+			drmClose(dev.fd);
+			return -1;
+		}
 	}
 
+	dev.use_atomic = use_atomic;
+
 	dev.resources = get_resources(&dev);
 	if (!dev.resources) {
 		drmClose(dev.fd);
 		return 1;
 	}
 
-	for (i = 0; i < count; i++) {
-		if (pipe_resolve_connectors(&dev, &pipe_args[i]) < 0) {
-			free_resources(dev.resources);
-			drmClose(dev.fd);
-			return 1;
-		}
-	}
-
 #define dump_resource(dev, res) if (res) dump_##res(dev)
 
 	dump_resource(&dev, encoders);
@@ -2064,7 +2207,7 @@ int main(int argc, char **argv)
 	if (dev.use_atomic) {
 		dev.req = drmModeAtomicAlloc();
 
-		if (count && plane_count) {
+		if (set_preferred || (count && plane_count)) {
 			uint64_t cap = 0;
 
 			ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
@@ -2073,8 +2216,11 @@ int main(int argc, char **argv)
 				return 1;
 			}
 
-			atomic_set_mode(&dev, pipe_args, count);
-			atomic_set_planes(&dev, plane_args, plane_count, false);
+			if (set_preferred || count)
+				set_mode(&dev, pipe_args, count);
+
+			if (plane_count)
+				atomic_set_planes(&dev, plane_args, plane_count, false);
 
 			ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
 			if (ret) {
@@ -2082,33 +2228,8 @@ int main(int argc, char **argv)
 				return 1;
 			}
 
-			gettimeofday(&pipe_args->start, NULL);
-			pipe_args->swap_count = 0;
-
-			while (test_vsync) {
-				drmModeAtomicFree(dev.req);
-				dev.req = drmModeAtomicAlloc();
-				atomic_set_planes(&dev, plane_args, plane_count, true);
-
-				ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
-				if (ret) {
-					fprintf(stderr, "Atomic Commit failed [2]\n");
-					return 1;
-				}
-
-				pipe_args->swap_count++;
-				if (pipe_args->swap_count == 60) {
-					struct timeval end;
-					double t;
-
-					gettimeofday(&end, NULL);
-					t = end.tv_sec + end.tv_usec * 1e-6 -
-				    (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6);
-					fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t);
-					pipe_args->swap_count = 0;
-					pipe_args->start = end;
-				}
-			}
+			if (test_vsync)
+				atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count);
 
 			if (drop_master)
 				drmDropMaster(dev.fd);
@@ -2118,20 +2239,24 @@ int main(int argc, char **argv)
 			drmModeAtomicFree(dev.req);
 			dev.req = drmModeAtomicAlloc();
 
-			atomic_clear_mode(&dev, pipe_args, count);
-			atomic_clear_planes(&dev, plane_args, plane_count);
+			/* XXX: properly teardown the preferred mode/plane state */
+			if (plane_count)
+				atomic_clear_planes(&dev, plane_args, plane_count);
+
+			if (count)
+				atomic_clear_mode(&dev, pipe_args, count);
+
 			ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
-			if (ret) {
+			if (ret)
 				fprintf(stderr, "Atomic Commit failed\n");
-				return 1;
-			}
 
-			atomic_clear_FB(&dev, plane_args, plane_count);
+			if (plane_count)
+				atomic_clear_FB(&dev, plane_args, plane_count);
 		}
 
 		drmModeAtomicFree(dev.req);
 	} else {
-		if (count || plane_count) {
+		if (set_preferred || count || plane_count) {
 			uint64_t cap = 0;
 
 			ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
@@ -2140,7 +2265,7 @@ int main(int argc, char **argv)
 				return 1;
 			}
 
-			if (count)
+			if (set_preferred || count)
 				set_mode(&dev, pipe_args, count);
 
 			if (plane_count)
@@ -2163,12 +2288,13 @@ int main(int argc, char **argv)
 			if (plane_count)
 				clear_planes(&dev, plane_args, plane_count);
 
-			if (count)
+			if (set_preferred || count)
 				clear_mode(&dev);
 		}
 	}
 
 	free_resources(dev.resources);
+	drmClose(dev.fd);
 
 	return 0;
 }

Added files:

Index: xsrc/external/mit/libdrm/dist/Android.mk
diff -u /dev/null xsrc/external/mit/libdrm/dist/Android.mk:1.3
--- /dev/null	Sun Nov  1 09:57:41 2020
+++ xsrc/external/mit/libdrm/dist/Android.mk	Sun Nov  1 09:57:37 2020
@@ -0,0 +1,74 @@
+#
+# Copyright © 2011-2012 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.
+#
+
+LIBDRM_ANDROID_MAJOR_VERSION := $(word 1, $(subst ., , $(PLATFORM_VERSION)))
+ifneq ($(filter 2 4, $(LIBDRM_ANDROID_MAJOR_VERSION)),)
+$(error "Android 4.4 and earlier not supported")
+endif
+
+LIBDRM_COMMON_MK := $(call my-dir)/Android.common.mk
+
+LOCAL_PATH := $(call my-dir)
+LIBDRM_TOP := $(LOCAL_PATH)
+
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_{,H,INCLUDE_H,INCLUDE_ANDROID_H,INCLUDE_VMWGFX_H}_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+#static library for the device (recovery)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdrm
+
+LOCAL_SRC_FILES := $(LIBDRM_FILES)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/include/drm \
+	$(LOCAL_PATH)/android
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/include/drm
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+# Shared library for the device
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdrm
+
+LOCAL_SRC_FILES := $(LIBDRM_FILES)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/include/drm \
+	$(LOCAL_PATH)/android
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
+
+LOCAL_C_INCLUDES := \
+        $(LOCAL_PATH)/include/drm
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))

Index: xsrc/external/mit/libdrm/dist/freedreno/Android.mk
diff -u /dev/null xsrc/external/mit/libdrm/dist/freedreno/Android.mk:1.3
--- /dev/null	Sun Nov  1 09:57:41 2020
+++ xsrc/external/mit/libdrm/dist/freedreno/Android.mk	Sun Nov  1 09:57:38 2020
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_FREEDRENO_FILES, LIBDRM_FREEDRENO_H_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_MODULE := libdrm_freedreno
+
+LOCAL_SHARED_LIBRARIES := libdrm
+
+LOCAL_SRC_FILES := $(LIBDRM_FREEDRENO_FILES)
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)

Index: xsrc/external/mit/libdrm/dist/intel/Android.mk
diff -u /dev/null xsrc/external/mit/libdrm/dist/intel/Android.mk:1.3
--- /dev/null	Sun Nov  1 09:57:41 2020
+++ xsrc/external/mit/libdrm/dist/intel/Android.mk	Sun Nov  1 09:57:38 2020
@@ -0,0 +1,38 @@
+#
+# Copyright © 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_INTEL_FILES, LIBDRM_INTEL_H_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_MODULE := libdrm_intel
+
+LOCAL_SRC_FILES := $(LIBDRM_INTEL_FILES)
+
+LOCAL_SHARED_LIBRARIES := \
+	libdrm
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)

Index: xsrc/external/mit/libdrm/dist/libkms/Android.mk
diff -u /dev/null xsrc/external/mit/libdrm/dist/libkms/Android.mk:1.3
--- /dev/null	Sun Nov  1 09:57:41 2020
+++ xsrc/external/mit/libdrm/dist/libkms/Android.mk	Sun Nov  1 09:57:38 2020
@@ -0,0 +1,51 @@
+DRM_GPU_DRIVERS := $(strip $(filter-out swrast, $(BOARD_GPU_DRIVERS)))
+
+intel_drivers := i915 i965 i915g iris
+radeon_drivers := r300g r600g radeonsi
+nouveau_drivers := nouveau
+virgl_drivers := virgl
+vmwgfx_drivers := vmwgfx
+
+valid_drivers := \
+	$(intel_drivers) \
+	$(radeon_drivers) \
+	$(nouveau_drivers) \
+	$(virgl_drivers) \
+	$(vmwgfx_drivers)
+
+# warn about invalid drivers
+invalid_drivers := $(filter-out $(valid_drivers), $(DRM_GPU_DRIVERS))
+ifneq ($(invalid_drivers),)
+$(warning invalid GPU drivers: $(invalid_drivers))
+# tidy up
+DRM_GPU_DRIVERS := $(filter-out $(invalid_drivers), $(DRM_GPU_DRIVERS))
+endif
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_SRC_FILES := $(LIBKMS_FILES)
+
+ifneq ($(filter $(vmwgfx_drivers), $(DRM_GPU_DRIVERS)),)
+LOCAL_SRC_FILES += $(LIBKMS_VMWGFX_FILES)
+endif
+
+ifneq ($(filter $(intel_drivers), $(DRM_GPU_DRIVERS)),)
+LOCAL_SRC_FILES += $(LIBKMS_INTEL_FILES)
+endif
+
+ifneq ($(filter $(nouveau_drivers), $(DRM_GPU_DRIVERS)),)
+LOCAL_SRC_FILES += $(LIBKMS_NOUVEAU_FILES)
+endif
+
+ifneq ($(filter $(radeon_drivers), $(DRM_GPU_DRIVERS)),)
+LOCAL_SRC_FILES += $(LIBKMS_RADEON_FILES)
+endif
+
+LOCAL_MODULE := libkms
+LOCAL_SHARED_LIBRARIES := libdrm
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)

Index: xsrc/external/mit/libdrm/dist/nouveau/Android.mk
diff -u /dev/null xsrc/external/mit/libdrm/dist/nouveau/Android.mk:1.3
--- /dev/null	Sun Nov  1 09:57:41 2020
+++ xsrc/external/mit/libdrm/dist/nouveau/Android.mk	Sun Nov  1 09:57:39 2020
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_NOUVEAU_FILES, LIBDRM_NOUVEAU_H_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_MODULE := libdrm_nouveau
+
+LOCAL_SHARED_LIBRARIES := libdrm
+
+LOCAL_SRC_FILES := $(LIBDRM_NOUVEAU_FILES)
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)

Index: xsrc/external/mit/libdrm/dist/radeon/Android.mk
diff -u /dev/null xsrc/external/mit/libdrm/dist/radeon/Android.mk:1.3
--- /dev/null	Sun Nov  1 09:57:41 2020
+++ xsrc/external/mit/libdrm/dist/radeon/Android.mk	Sun Nov  1 09:57:39 2020
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_RADEON_FILES, LIBDRM_RADEON_H_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_MODULE := libdrm_radeon
+
+LOCAL_SHARED_LIBRARIES := libdrm
+
+LOCAL_SRC_FILES := $(LIBDRM_RADEON_FILES)
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_SHARED_LIBRARY)

Index: xsrc/external/mit/libdrm/dist/tests/modetest/Android.mk
diff -u /dev/null xsrc/external/mit/libdrm/dist/tests/modetest/Android.mk:1.3
--- /dev/null	Sun Nov  1 09:57:41 2020
+++ xsrc/external/mit/libdrm/dist/tests/modetest/Android.mk	Sun Nov  1 09:57:40 2020
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_SRC_FILES := $(MODETEST_FILES)
+
+LOCAL_MODULE := modetest
+
+LOCAL_SHARED_LIBRARIES := libdrm
+LOCAL_STATIC_LIBRARIES := libdrm_util
+
+include $(LIBDRM_COMMON_MK)
+include $(BUILD_EXECUTABLE)

Reply via email to