diff --git a/.gitignore b/.gitignore
index 243457e..a20a3eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ libdrm.pc
 libdrm_intel.pc
 libdrm_nouveau.pc
 libdrm_radeon.pc
+libdrm_freedreno.pc
 libkms.pc
 libtool
 ltmain.sh
diff --git a/Makefile.am b/Makefile.am
index 8ecd9d9..ebf2ae2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,7 +49,11 @@ if HAVE_EXYNOS
 EXYNOS_SUBDIR = exynos
 endif
 
-SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) tests include man
+if HAVE_FREEDRENO
+FREEDRENO_SUBDIR = freedreno
+endif
+
+SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) $(FREEDRENO_SUBDIR) tests include man
 
 libdrm_la_LTLIBRARIES = libdrm.la
 libdrm_ladir = $(libdir)
diff --git a/configure.ac b/configure.ac
index 290362c..8ce6011 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,6 +114,11 @@ AC_ARG_ENABLE(exynos-experimental-api,
 	      [Enable support for EXYNOS's experimental API (default: disabled)]),
 	      [EXYNOS=$enableval], [EXYNOS=no])
 
+AC_ARG_ENABLE(freedreno-experimental-api,
+	      AS_HELP_STRING([--enable-freedreno-experimental-api],
+	      [Enable support for freedreno's experimental API (default: disabled)]),
+	      [FREEDRENO=$enableval], [FREEDRENO=no])
+
 dnl ===========================================================================
 dnl check compiler flags
 AC_DEFUN([LIBDRM_CC_TRY_FLAG], [
@@ -222,6 +227,11 @@ if test "x$EXYNOS" = xyes; then
 	AC_DEFINE(HAVE_EXYNOS, 1, [Have EXYNOS support])
 fi
 
+AM_CONDITIONAL(HAVE_FREEDRENO, [test "x$FREEDRENO" = xyes])
+if test "x$FREEDRENO" = xyes; then
+	AC_DEFINE(HAVE_FREEDRENO, 1, [Have freedreno support])
+fi
+
 PKG_CHECK_MODULES(CAIRO, cairo, [HAVE_CAIRO=yes], [HAVE_CAIRO=no])
 if test "x$HAVE_CAIRO" = xyes; then
 	AC_DEFINE(HAVE_CAIRO, 1, [Have cairo support])
@@ -346,6 +356,8 @@ AC_CONFIG_FILES([
 	omap/libdrm_omap.pc
 	exynos/Makefile
 	exynos/libdrm_exynos.pc
+	freedreno/Makefile
+	freedreno/libdrm_freedreno.pc
 	tests/Makefile
 	tests/modeprint/Makefile
 	tests/modetest/Makefile
@@ -368,4 +380,5 @@ echo "  Radeon API     $RADEON"
 echo "  Nouveau API    $NOUVEAU"
 echo "  OMAP API       $OMAP"
 echo "  EXYNOS API     $EXYNOS"
+echo "  Freedreno API  $FREEDRENO"
 echo ""
diff --git a/freedreno/Makefile.am b/freedreno/Makefile.am
new file mode 100644
index 0000000..f46a780
--- /dev/null
+++ b/freedreno/Makefile.am
@@ -0,0 +1,19 @@
+AM_CFLAGS = \
+	$(WARN_CFLAGS) \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/freedreno \
+	$(PTHREADSTUBS_CFLAGS) \
+	-I$(top_srcdir)/include/drm
+
+libdrm_freedreno_la_LTLIBRARIES = libdrm_freedreno.la
+libdrm_freedreno_ladir = $(libdir)
+libdrm_freedreno_la_LDFLAGS = -version-number 1:0:0 -no-undefined
+libdrm_freedreno_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
+
+libdrm_freedreno_la_SOURCES = freedreno_device.c freedreno_pipe.c freedreno_ringbuffer.c freedreno_bo.c
+
+libdrm_freedrenocommonincludedir = ${includedir}/freedreno
+libdrm_freedrenocommoninclude_HEADERS = freedreno_drmif.h freedreno_ringbuffer.h
+
+pkgconfigdir = @pkgconfigdir@
+pkgconfig_DATA = libdrm_freedreno.pc
diff --git a/freedreno/README b/freedreno/README
new file mode 100644
index 0000000..ae22e01
--- /dev/null
+++ b/freedreno/README
@@ -0,0 +1,16 @@
+Note that current msm kernel driver is a bit strange.  It provides a
+DRM interface for GEM, which is basically sufficient to have DRI2
+working.  But it does not provide KMS.  And interface to 2d and 3d
+cores is via different other devices (/dev/kgsl-*).  This is not
+quite how I'd write a DRM driver, but at this stage it is useful for
+xf86-video-freedreno and fdre (and eventual gallium driver) to be
+able to work on existing kernel driver from QCOM, to allow to
+capture cmdstream dumps from the binary blob drivers without having
+to reboot.  So libdrm_freedreno attempts to hide most of the crazy.
+The intention is that when there is a proper kernel driver, it will
+be mostly just changes in libdrm_freedreno to adapt the gallium
+driver and xf86-video-freedreno (ignoring the fbdev->KMS changes).
+
+So don't look at freedreno as an example of how to write a libdrm
+module or a DRM driver.. it is just an attempt to paper over a non-
+standard kernel driver architecture.
diff --git a/freedreno/freedreno_bo.c b/freedreno/freedreno_bo.c
new file mode 100644
index 0000000..84526d5
--- /dev/null
+++ b/freedreno/freedreno_bo.c
@@ -0,0 +1,229 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#include "freedreno_drmif.h"
+#include "freedreno_priv.h"
+
+static struct fd_bo * bo_from_handle(struct fd_device *dev,
+		uint32_t size, uint32_t handle)
+{
+	struct fd_bo *bo = calloc(1, sizeof(*bo));
+	if (!bo)
+		return NULL;
+	bo->dev = dev;
+	bo->size = size;
+	bo->handle = handle;
+	return bo;
+}
+
+static int set_memtype(struct fd_bo *bo, uint32_t flags)
+{
+	struct drm_kgsl_gem_memtype req = {
+			.handle = bo->handle,
+			.type = flags & DRM_FREEDRENO_GEM_TYPE_MEM_MASK,
+	};
+
+	return drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_SETMEMTYPE,
+			&req, sizeof(req));
+}
+
+static int bo_alloc(struct fd_bo *bo)
+{
+	if (!bo->offset) {
+		struct drm_kgsl_gem_alloc req = {
+				.handle = bo->handle,
+		};
+		int ret;
+
+		/* if the buffer is already backed by pages then this
+		 * doesn't actually do anything (other than giving us
+		 * the offset)
+		 */
+		ret = drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_ALLOC,
+				&req, sizeof(req));
+		if (ret) {
+			ERROR_MSG("alloc failed: %s", strerror(errno));
+			return ret;
+		}
+
+		bo->offset = req.offset;
+	}
+	return 0;
+}
+
+struct fd_bo * fd_bo_new(struct fd_device *dev,
+		uint32_t size, uint32_t flags)
+{
+	struct drm_kgsl_gem_create req = {
+			.size = size,
+	};
+	struct fd_bo *bo = NULL;
+
+	if (drmCommandWriteRead(dev->fd, DRM_KGSL_GEM_CREATE,
+			&req, sizeof(req))) {
+		return NULL;
+	}
+
+	bo = bo_from_handle(dev, size, req.handle);
+	if (!bo) {
+		goto fail;
+	}
+
+	if (set_memtype(bo, flags)) {
+		goto fail;
+	}
+
+	return bo;
+fail:
+	if (bo)
+		fd_bo_del(bo);
+	return NULL;
+}
+
+/* don't use this... it is just needed to get a bo from the
+ * framebuffer (pre-dmabuf)
+ */
+struct fd_bo * fd_bo_from_fbdev(struct fd_device *dev,
+		int fbfd, uint32_t size)
+{
+	struct drm_kgsl_gem_create_fd req = {
+			.fd = fbfd,
+	};
+
+	if (drmCommandWriteRead(dev->fd, DRM_KGSL_GEM_CREATE_FD,
+			&req, sizeof(req))) {
+		return NULL;
+	}
+
+	return bo_from_handle(dev, size, req.handle);
+}
+
+struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name)
+{
+	struct drm_gem_open req = {
+			.name = name,
+	};
+
+	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
+		return NULL;
+	}
+
+	return bo_from_handle(dev, req.size, req.handle);
+}
+
+void fd_bo_del(struct fd_bo *bo)
+{
+	if (bo->map) {
+		munmap(bo->map, bo->size);
+	}
+
+	if (bo->handle) {
+		struct drm_gem_close req = {
+				.handle = bo->handle,
+		};
+		drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
+	}
+
+	free(bo);
+}
+
+int fd_bo_get_name(struct fd_bo *bo, uint32_t *name)
+{
+	if (!bo->name) {
+		struct drm_gem_flink req = {
+				.handle = bo->handle,
+		};
+		int ret;
+
+		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
+		if (ret) {
+			return ret;
+		}
+
+		bo->name = req.name;
+	}
+
+	*name = bo->name;
+
+	return 0;
+}
+
+uint32_t fd_bo_handle(struct fd_bo *bo)
+{
+	return bo->handle;
+}
+
+uint32_t fd_bo_size(struct fd_bo *bo)
+{
+	return bo->size;
+}
+
+void * fd_bo_map(struct fd_bo *bo)
+{
+	if (!bo->map) {
+		int ret;
+
+		ret = bo_alloc(bo);
+		if (ret) {
+			return NULL;
+		}
+
+		bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+				bo->dev->fd, bo->offset);
+		if (bo->map == MAP_FAILED) {
+			ERROR_MSG("mmap failed: %s", strerror(errno));
+			bo->map = NULL;
+		}
+	}
+	return bo->map;
+}
+
+uint32_t fd_bo_gpuaddr(struct fd_bo *bo, uint32_t offset)
+{
+	if (!bo->gpuaddr) {
+		struct drm_kgsl_gem_bufinfo req = {
+				.handle = bo->handle,
+		};
+		int ret;
+
+		ret = bo_alloc(bo);
+		if (ret) {
+			return ret;
+		}
+
+		ret = drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO,
+				&req, sizeof(req));
+		if (ret) {
+			ERROR_MSG("alloc failed: %s", strerror(errno));
+			return ret;
+		}
+
+		bo->gpuaddr = req.gpuaddr[0];
+	}
+	return bo->gpuaddr + offset;
+}
diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c
new file mode 100644
index 0000000..0a9ef9f
--- /dev/null
+++ b/freedreno/freedreno_device.c
@@ -0,0 +1,45 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#include "freedreno_drmif.h"
+#include "freedreno_priv.h"
+
+struct fd_device * fd_device_new(int fd)
+{
+	struct fd_device *dev = calloc(1, sizeof(*dev));
+	if (!dev)
+		return NULL;
+	dev->fd = fd;
+	return dev;
+}
+
+void fd_device_del(struct fd_device *dev)
+{
+	free(dev);
+}
+
diff --git a/freedreno/freedreno_drmif.h b/freedreno/freedreno_drmif.h
new file mode 100644
index 0000000..10273a3
--- /dev/null
+++ b/freedreno/freedreno_drmif.h
@@ -0,0 +1,97 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#ifndef FREEDRENO_DRMIF_H_
+#define FREEDRENO_DRMIF_H_
+
+#include <xf86drm.h>
+#include <stdint.h>
+
+struct fd_bo;
+struct fd_pipe;
+struct fd_device;
+
+enum fd_pipe_id {
+	FD_PIPE_3D = 1,
+	FD_PIPE_2D = 2,
+	/* some devices have two 2d blocks.. not really sure how to
+	 * use that yet, so just ignoring the 2nd 2d pipe for now
+	 */
+	FD_PIPE_MAX
+};
+
+enum fd_param {
+	FD_DEVICE_ID,
+	FD_GMEM_SIZE,
+};
+
+/* bo flags: */
+#define DRM_FREEDRENO_GEM_TYPE_SMI        0x00000001
+#define DRM_FREEDRENO_GEM_TYPE_KMEM       0x00000002
+#define DRM_FREEDRENO_GEM_TYPE_MEM_MASK   0x0000000f
+#define DRM_FREEDRENO_GEM_CACHE_NONE      0x00000000
+#define DRM_FREEDRENO_GEM_CACHE_WCOMBINE  0x00100000
+#define DRM_FREEDRENO_GEM_CACHE_WTHROUGH  0x00200000
+#define DRM_FREEDRENO_GEM_CACHE_WBACK     0x00400000
+#define DRM_FREEDRENO_GEM_CACHE_WBACKWA   0x00800000
+#define DRM_FREEDRENO_GEM_CACHE_MASK      0x00f00000
+#define DRM_FREEDRENO_GEM_GPUREADONLY     0x01000000
+
+
+/* device functions:
+ */
+
+struct fd_device * fd_device_new(int fd);
+void fd_device_del(struct fd_device *dev);
+
+
+/* pipe functions:
+ */
+
+struct fd_pipe * fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id);
+void fd_pipe_del(struct fd_pipe *pipe);
+int fd_pipe_get_param(struct fd_pipe *pipe, enum fd_param param,
+		uint64_t *value);
+int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp);
+
+
+/* buffer-object functions:
+ */
+
+struct fd_bo * fd_bo_new(struct fd_device *dev,
+		uint32_t size, uint32_t flags);
+struct fd_bo * fd_bo_from_fbdev(struct fd_device *dev,
+		int fbfd, uint32_t size);
+struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name);
+void fd_bo_del(struct fd_bo *bo);
+int fd_bo_get_name(struct fd_bo *bo, uint32_t *name);
+uint32_t fd_bo_handle(struct fd_bo *bo);
+uint32_t fd_bo_size(struct fd_bo *bo);
+void * fd_bo_map(struct fd_bo *bo);
+
+#endif /* FREEDRENO_DRMIF_H_ */
diff --git a/freedreno/freedreno_pipe.c b/freedreno/freedreno_pipe.c
new file mode 100644
index 0000000..ed0928d
--- /dev/null
+++ b/freedreno/freedreno_pipe.c
@@ -0,0 +1,163 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#include "freedreno_drmif.h"
+#include "freedreno_priv.h"
+
+
+static int getprop(int fd, enum kgsl_property_type type,
+		void *value, int sizebytes)
+{
+	struct kgsl_device_getproperty req = {
+			.type = type,
+			.value = value,
+			.sizebytes = sizebytes,
+	};
+	return ioctl(fd, IOCTL_KGSL_DEVICE_GETPROPERTY, &req);
+}
+
+#define GETPROP(fd, prop, x) do { \
+	if (getprop((fd), KGSL_PROP_##prop, &(x), sizeof(x))) {     \
+		ERROR_MSG("failed to get property: " #prop);            \
+		goto fail;                                              \
+	} } while (0)
+
+
+struct fd_pipe * fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id)
+{
+	static const char *paths[] = {
+			[FD_PIPE_3D] = "/dev/kgsl-3d0",
+			[FD_PIPE_2D] = "/dev/kgsl-2d0",
+	};
+	struct kgsl_drawctxt_create req = {
+			.flags = 0x2000, /* ??? */
+	};
+	struct fd_pipe *pipe = NULL;
+	int ret, fd;
+
+	if (id > FD_PIPE_MAX) {
+		ERROR_MSG("invalid pipe id: %d", id);
+		goto fail;
+	}
+
+	fd = open(paths[id], O_RDWR);
+	if (fd < 0) {
+		ERROR_MSG("could not open %s device: %d (%s)",
+				paths[id], fd, strerror(errno));
+		goto fail;
+	}
+
+	ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &req);
+	if (ret) {
+		ERROR_MSG("failed to allocate context: %d (%s)",
+				ret, strerror(errno));
+		goto fail;
+	}
+
+	pipe = calloc(1, sizeof(*pipe));
+	if (!pipe) {
+		ERROR_MSG("allocation failed");
+		goto fail;
+	}
+
+	pipe->dev = dev;
+	pipe->fd = fd;
+	pipe->drawctxt_id = req.drawctxt_id;
+
+	GETPROP(fd, VERSION,     pipe->version);
+	GETPROP(fd, DEVICE_INFO, pipe->devinfo);
+
+	INFO_MSG("Pipe Info:");
+	INFO_MSG(" Device:          %s", paths[id]);
+	INFO_MSG(" Chip-id:         %d.%d.%d.%d",
+			(pipe->devinfo.chip_id >> 24) & 0xff,
+			(pipe->devinfo.chip_id >> 16) & 0xff,
+			(pipe->devinfo.chip_id >>  8) & 0xff,
+			(pipe->devinfo.chip_id >>  0) & 0xff);
+	INFO_MSG(" Device-id:       %d", pipe->devinfo.device_id);
+	INFO_MSG(" GPU-id:          %d", pipe->devinfo.gpu_id);
+	INFO_MSG(" MMU enabled:     %d", pipe->devinfo.mmu_enabled);
+	INFO_MSG(" GMEM Base addr:  0x%08x", pipe->devinfo.gmem_gpubaseaddr);
+	INFO_MSG(" GMEM size:       0x%08x", pipe->devinfo.gmem_sizebytes);
+	INFO_MSG(" Driver version:  %d.%d",
+			pipe->version.drv_major, pipe->version.drv_minor);
+	INFO_MSG(" Device version:  %d.%d",
+			pipe->version.dev_major, pipe->version.dev_minor);
+
+	return pipe;
+fail:
+	if (pipe)
+		fd_pipe_del(pipe);
+	return NULL;
+}
+
+void fd_pipe_del(struct fd_pipe *pipe)
+{
+	struct kgsl_drawctxt_destroy req = {
+			.drawctxt_id = pipe->drawctxt_id,
+	};
+
+	if (pipe->drawctxt_id)
+		ioctl(pipe->fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &req);
+
+	if (pipe->fd)
+		close(pipe->fd);
+
+	free(pipe);
+}
+
+int fd_pipe_get_param(struct fd_pipe *pipe, enum fd_param param,
+		uint64_t *value)
+{
+	switch (param) {
+	case FD_DEVICE_ID:
+		*value = pipe->devinfo.device_id;
+		return 0;
+	case FD_GMEM_SIZE:
+		*value = pipe->devinfo.gmem_sizebytes;
+		return 0;
+	default:
+		ERROR_MSG("invalid param id: %d", param);
+		return -1;
+	}
+}
+
+int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp)
+{
+	struct kgsl_device_waittimestamp req = {
+			.timestamp = timestamp,
+			.timeout   = 5000,
+	};
+	int ret;
+
+	ret = ioctl(pipe->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP, &req);
+	if (ret)
+		ERROR_MSG("waittimestamp failed! %d (%s)", ret, strerror(errno));
+
+	return ret;
+}
diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h
new file mode 100644
index 0000000..68bd5a6
--- /dev/null
+++ b/freedreno/freedreno_priv.h
@@ -0,0 +1,90 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#ifndef FREEDRENO_PRIV_H_
+#define FREEDRENO_PRIV_H_
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "freedreno_drmif.h"
+#include "msm_kgsl.h"
+#include "kgsl_drm.h"
+
+struct fd_device {
+	int fd;
+};
+
+struct fd_pipe {
+	struct fd_device *dev;
+	int fd;
+	uint32_t drawctxt_id;
+
+	/* device properties: */
+	struct kgsl_version version;
+	struct kgsl_devinfo devinfo;
+};
+
+struct fd_bo {
+	struct fd_device *dev;
+	uint32_t size;
+	uint32_t handle;
+	uint32_t name;
+	uint32_t gpuaddr;
+	void *map;
+	uint64_t offset;
+};
+
+/* not exposed publicly, because won't be needed when we have
+ * a proper kernel driver
+ */
+uint32_t fd_bo_gpuaddr(struct fd_bo *bo, uint32_t offset);
+
+
+#define enable_debug 1  /* TODO make dynamic */
+
+#define INFO_MSG(fmt, ...) \
+		do { drmMsg("[I] "fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+#define DEBUG_MSG(fmt, ...) \
+		do if (enable_debug) { printf("[D] "fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+#define WARN_MSG(fmt, ...) \
+		do { drmMsg("[W] "fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+#define ERROR_MSG(fmt, ...) \
+		do { drmMsg("[E] " fmt " (%s:%d)\n", \
+				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
+
+#endif /* FREEDRENO_PRIV_H_ */
diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c
new file mode 100644
index 0000000..93ca843
--- /dev/null
+++ b/freedreno/freedreno_ringbuffer.c
@@ -0,0 +1,123 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#include "freedreno_drmif.h"
+#include "freedreno_priv.h"
+#include "freedreno_ringbuffer.h"
+
+struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe,
+		uint32_t size)
+{
+	struct fd_ringbuffer *ring = NULL;
+
+	ring = calloc(1, sizeof(*ring));
+	if (!ring) {
+		ERROR_MSG("allocation failed");
+		goto fail;
+	}
+
+	ring->bo = fd_bo_new(pipe->dev, size, DRM_FREEDRENO_GEM_GPUREADONLY |
+			DRM_FREEDRENO_GEM_TYPE_KMEM);
+	if (!ring->bo) {
+		ERROR_MSG("ringbuffer allocation failed");
+		goto fail;
+	}
+
+	ring->pipe = pipe;
+	ring->start = fd_bo_map(ring->bo);
+	ring->end = &(ring->start[size/4]);
+
+	fd_ringbuffer_reset(ring);
+
+	return ring;
+fail:
+	if (ring)
+		fd_ringbuffer_del(ring);
+	return NULL;
+}
+
+void fd_ringbuffer_del(struct fd_ringbuffer *ring)
+{
+	if (ring->bo)
+		fd_bo_del(ring->bo);
+	free(ring);
+}
+
+void fd_ringbuffer_reset(struct fd_ringbuffer *ring)
+{
+	ring->cur = ring->last_start = ring->start;
+}
+
+int fd_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t flags,
+		uint32_t *timestamp)
+{
+	struct kgsl_ibdesc ibdesc = {
+			.gpuaddr     = fd_bo_gpuaddr(ring->bo, ring->last_start - ring->start),
+			.hostptr     = ring->last_start,
+			.sizedwords  = ring->cur - ring->last_start,
+	};
+	struct kgsl_ringbuffer_issueibcmds req = {
+			.drawctxt_id = ring->pipe->drawctxt_id,
+			.ibdesc_addr = (unsigned long)&ibdesc,
+			.numibs      = 1,
+			.flags       = flags,
+	};
+	int ret;
+
+	ret = ioctl(ring->pipe->fd, IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS, &req);
+	if (ret)
+		ERROR_MSG("issueibcmds failed!  %d (%s)", ret, strerror(errno));
+
+	*timestamp = req.timestamp;
+	ring->last_start = ring->cur;
+
+	return ret;
+}
+
+int fd_ringbuffer_begin(struct fd_ringbuffer *ring, int ndwords)
+{
+	int ret;
+	if ((ring->cur + ndwords) >= ring->end) {
+		uint32_t timestamp;
+		/* this probably won't really work if we have multiple tiles..
+		 * but it is ok for 2d..  we might need different behavior
+		 * depending on 2d or 3d pipe.
+		 */
+		WARN_MSG("unexpected flush");
+		ret = fd_ringbuffer_flush(ring, 0, &timestamp);
+		fd_ringbuffer_reset(ring);
+		return ret;
+	}
+	return 0;
+}
+
+void fd_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
+		struct fd_bo *bo, uint32_t offset)
+{
+	fd_ringbuffer_emit(ring, fd_bo_gpuaddr(bo, offset));
+}
diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h
new file mode 100644
index 0000000..c502202
--- /dev/null
+++ b/freedreno/freedreno_ringbuffer.h
@@ -0,0 +1,75 @@
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#ifndef FREEDRENO_RINGBUFFER_H_
+#define FREEDRENO_RINGBUFFER_H_
+
+#include <freedreno_drmif.h>
+
+/* the ringbuffer object is not opaque so that OUT_RING() type stuff
+ * can be inlined.  Note that users should not make assumptions about
+ * the size of this struct.. more stuff will be added when we eventually
+ * have a kernel driver that can deal w/ reloc's..
+ */
+
+struct fd_ringbuffer {
+	int size;
+	uint32_t *cur, *end, *start, *last_start;
+	struct fd_pipe *pipe;
+	struct fd_bo *bo;
+};
+
+/* ringbuffer flush flags:
+ *   SAVE_GMEM - GMEM contents not preserved to system memory
+ *       in cmds flushed so if there is a context switch after
+ *       this flush and before the next one the kernel must
+ *       save GMEM contents
+ *   SUBMIT_IB_LIST - tbd..
+ */
+#define DRM_FREEDRENO_CONTEXT_SAVE_GMEM       1
+#define DRM_FREEDRENO_CONTEXT_SUBMIT_IB_LIST  4
+
+
+struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe,
+		uint32_t size);
+void fd_ringbuffer_del(struct fd_ringbuffer *ring);
+void fd_ringbuffer_reset(struct fd_ringbuffer *ring);
+int fd_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t flags,
+		uint32_t *timestamp);
+int fd_ringbuffer_begin(struct fd_ringbuffer *ring, int ndwords);
+
+static inline void fd_ringbuffer_emit(struct fd_ringbuffer *ring,
+		uint32_t data)
+{
+	(*ring->cur++) = data;
+}
+
+void fd_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
+		struct fd_bo *bo, uint32_t offset);
+
+#endif /* FREEDRENO_RINGBUFFER_H_ */
diff --git a/freedreno/kgsl_drm.h b/freedreno/kgsl_drm.h
new file mode 100644
index 0000000..f1c7f4e
--- /dev/null
+++ b/freedreno/kgsl_drm.h
@@ -0,0 +1,192 @@
+#ifndef _KGSL_DRM_H_
+#define _KGSL_DRM_H_
+
+#include "drm.h"
+
+#define DRM_KGSL_GEM_CREATE 0x00
+#define DRM_KGSL_GEM_PREP   0x01
+#define DRM_KGSL_GEM_SETMEMTYPE 0x02
+#define DRM_KGSL_GEM_GETMEMTYPE 0x03
+#define DRM_KGSL_GEM_MMAP 0x04
+#define DRM_KGSL_GEM_ALLOC 0x05
+#define DRM_KGSL_GEM_BIND_GPU 0x06
+#define DRM_KGSL_GEM_UNBIND_GPU 0x07
+
+#define DRM_KGSL_GEM_GET_BUFINFO 0x08
+#define DRM_KGSL_GEM_SET_BUFCOUNT 0x09
+#define DRM_KGSL_GEM_SET_ACTIVE 0x0A
+#define DRM_KGSL_GEM_LOCK_HANDLE 0x0B
+#define DRM_KGSL_GEM_UNLOCK_HANDLE 0x0C
+#define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D
+#define DRM_KGSL_GEM_CREATE_FD 0x0E
+
+#define DRM_IOCTL_KGSL_GEM_CREATE \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create)
+
+#define DRM_IOCTL_KGSL_GEM_PREP \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_PREP, struct drm_kgsl_gem_prep)
+
+#define DRM_IOCTL_KGSL_GEM_SETMEMTYPE \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SETMEMTYPE, \
+struct drm_kgsl_gem_memtype)
+
+#define DRM_IOCTL_KGSL_GEM_GETMEMTYPE \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GETMEMTYPE, \
+struct drm_kgsl_gem_memtype)
+
+#define DRM_IOCTL_KGSL_GEM_MMAP \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_MMAP, struct drm_kgsl_gem_mmap)
+
+#define DRM_IOCTL_KGSL_GEM_ALLOC \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_ALLOC, struct drm_kgsl_gem_alloc)
+
+#define DRM_IOCTL_KGSL_GEM_BIND_GPU \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_BIND_GPU, struct drm_kgsl_gem_bind_gpu)
+
+#define DRM_IOCTL_KGSL_GEM_UNBIND_GPU \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNBIND_GPU, \
+struct drm_kgsl_gem_bind_gpu)
+
+#define DRM_IOCTL_KGSL_GEM_GET_BUFINFO \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_BUFINFO, \
+	 struct drm_kgsl_gem_bufinfo)
+
+#define DRM_IOCTL_KGSL_GEM_SET_BUFCOUNT \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_BUFCOUNT, \
+	 struct drm_kgsl_gem_bufcount)
+
+#define DRM_IOCTL_KGSL_GEM_SET_ACTIVE \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_ACTIVE, \
+	 struct drm_kgsl_gem_active)
+
+#define DRM_IOCTL_KGSL_GEM_LOCK_HANDLE \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_LOCK_HANDLE, \
+struct drm_kgsl_gem_lock_handles)
+
+#define DRM_IOCTL_KGSL_GEM_UNLOCK_HANDLE \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_HANDLE, \
+struct drm_kgsl_gem_unlock_handles)
+
+#define DRM_IOCTL_KGSL_GEM_UNLOCK_ON_TS \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_ON_TS, \
+struct drm_kgsl_gem_unlock_on_ts)
+
+#define DRM_IOCTL_KGSL_GEM_CREATE_FD \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FD, \
+struct drm_kgsl_gem_create_fd)
+
+/* Maximum number of sub buffers per GEM object */
+#define DRM_KGSL_GEM_MAX_BUFFERS 2
+
+/* Memory types - these define the source and caching policies
+   of the GEM memory chunk */
+
+/* Legacy definitions left for compatability */
+
+#define DRM_KGSL_GEM_TYPE_EBI          0
+#define DRM_KGSL_GEM_TYPE_SMI          1
+#define DRM_KGSL_GEM_TYPE_KMEM         2
+#define DRM_KGSL_GEM_TYPE_KMEM_NOCACHE 3
+#define DRM_KGSL_GEM_TYPE_MEM_MASK     0xF
+
+/* Contiguous memory (PMEM) */
+#define DRM_KGSL_GEM_TYPE_PMEM       0x000100
+
+/* PMEM memory types */
+#define DRM_KGSL_GEM_PMEM_EBI        0x001000
+#define DRM_KGSL_GEM_PMEM_SMI        0x002000
+
+/* Standard paged memory */
+#define DRM_KGSL_GEM_TYPE_MEM        0x010000
+
+/* Caching controls */
+#define DRM_KGSL_GEM_CACHE_NONE      0x000000
+#define DRM_KGSL_GEM_CACHE_WCOMBINE  0x100000
+#define DRM_KGSL_GEM_CACHE_WTHROUGH  0x200000
+#define DRM_KGSL_GEM_CACHE_WBACK     0x400000
+#define DRM_KGSL_GEM_CACHE_WBACKWA   0x800000
+#define DRM_KGSL_GEM_CACHE_MASK      0xF00000
+
+/* FD based objects */
+#define DRM_KGSL_GEM_TYPE_FD_FBMEM   0x1000000
+#define DRM_KGSL_GEM_TYPE_FD_MASK    0xF000000
+
+/* Timestamp types */
+#define DRM_KGSL_GEM_TS_3D         0x00000430
+#define DRM_KGSL_GEM_TS_2D         0x00000180
+
+
+struct drm_kgsl_gem_create {
+	uint32_t size;
+	uint32_t handle;
+};
+
+struct drm_kgsl_gem_prep {
+	uint32_t handle;
+	uint32_t phys;
+	uint64_t offset;
+};
+
+struct drm_kgsl_gem_memtype {
+	uint32_t handle;
+	uint32_t type;
+};
+
+struct drm_kgsl_gem_mmap {
+	uint32_t handle;
+	uint32_t size;
+	uint32_t hostptr;
+	uint64_t offset;
+};
+
+struct drm_kgsl_gem_alloc {
+	uint32_t handle;
+	uint64_t offset;
+};
+
+struct drm_kgsl_gem_bind_gpu {
+	uint32_t handle;
+	uint32_t gpuptr;
+};
+
+struct drm_kgsl_gem_bufinfo {
+	uint32_t handle;
+	uint32_t count;
+	uint32_t active;
+	uint32_t offset[DRM_KGSL_GEM_MAX_BUFFERS];
+	uint32_t gpuaddr[DRM_KGSL_GEM_MAX_BUFFERS];
+};
+
+struct drm_kgsl_gem_bufcount {
+	uint32_t handle;
+	uint32_t bufcount;
+};
+
+struct drm_kgsl_gem_active {
+	uint32_t handle;
+	uint32_t active;
+};
+
+struct drm_kgsl_gem_lock_handles {
+	uint32_t num_handles;
+	uint32_t *handle_list;
+	uint32_t pid;
+	uint32_t lock_id;	  /* Returned lock id used for unlocking */
+};
+
+struct drm_kgsl_gem_unlock_handles {
+	uint32_t lock_id;
+};
+
+struct drm_kgsl_gem_unlock_on_ts {
+	uint32_t lock_id;
+	uint32_t timestamp;	 /* This field is a hw generated ts */
+	uint32_t type;		 /* Which pipe to check for ts generation */
+};
+
+struct drm_kgsl_gem_create_fd {
+	uint32_t fd;
+	uint32_t handle;
+};
+
+#endif
diff --git a/freedreno/libdrm_freedreno.pc.in b/freedreno/libdrm_freedreno.pc.in
new file mode 100644
index 0000000..95ec1c3
--- /dev/null
+++ b/freedreno/libdrm_freedreno.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdrm_freedreno
+Description: Userspace interface to freedreno kernel DRM services
+Version: 0.6
+Libs: -L${libdir} -ldrm_freedreno
+Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/freedreno
+Requires.private: libdrm
diff --git a/freedreno/msm_kgsl.h b/freedreno/msm_kgsl.h
new file mode 100644
index 0000000..e67190f
--- /dev/null
+++ b/freedreno/msm_kgsl.h
@@ -0,0 +1,519 @@
+#ifndef _MSM_KGSL_H
+#define _MSM_KGSL_H
+
+#define KGSL_VERSION_MAJOR        3
+#define KGSL_VERSION_MINOR        11
+
+/*context flags */
+#define KGSL_CONTEXT_SAVE_GMEM		0x00000001
+#define KGSL_CONTEXT_NO_GMEM_ALLOC	0x00000002
+#define KGSL_CONTEXT_SUBMIT_IB_LIST	0x00000004
+#define KGSL_CONTEXT_CTX_SWITCH		0x00000008
+#define KGSL_CONTEXT_PREAMBLE		0x00000010
+#define KGSL_CONTEXT_TRASH_STATE	0x00000020
+#define KGSL_CONTEXT_PER_CONTEXT_TS	0x00000040
+
+#define KGSL_CONTEXT_INVALID 0xffffffff
+
+/* Memory allocayion flags */
+#define KGSL_MEMFLAGS_GPUREADONLY	0x01000000
+
+/* generic flag values */
+#define KGSL_FLAGS_NORMALMODE  0x00000000
+#define KGSL_FLAGS_SAFEMODE    0x00000001
+#define KGSL_FLAGS_INITIALIZED0 0x00000002
+#define KGSL_FLAGS_INITIALIZED 0x00000004
+#define KGSL_FLAGS_STARTED     0x00000008
+#define KGSL_FLAGS_ACTIVE      0x00000010
+#define KGSL_FLAGS_RESERVED0   0x00000020
+#define KGSL_FLAGS_RESERVED1   0x00000040
+#define KGSL_FLAGS_RESERVED2   0x00000080
+#define KGSL_FLAGS_SOFT_RESET  0x00000100
+#define KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS 0x00000200
+
+/* Clock flags to show which clocks should be controled by a given platform */
+#define KGSL_CLK_SRC	0x00000001
+#define KGSL_CLK_CORE	0x00000002
+#define KGSL_CLK_IFACE	0x00000004
+#define KGSL_CLK_MEM	0x00000008
+#define KGSL_CLK_MEM_IFACE 0x00000010
+#define KGSL_CLK_AXI	0x00000020
+
+/*
+ * Reset status values for context
+ */
+enum kgsl_ctx_reset_stat {
+	KGSL_CTX_STAT_NO_ERROR				= 0x00000000,
+	KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT		= 0x00000001,
+	KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT	= 0x00000002,
+	KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT		= 0x00000003
+};
+
+#define KGSL_MAX_PWRLEVELS 5
+
+#define KGSL_CONVERT_TO_MBPS(val) \
+	(val*1000*1000U)
+
+/* device id */
+enum kgsl_deviceid {
+	KGSL_DEVICE_3D0		= 0x00000000,
+	KGSL_DEVICE_2D0		= 0x00000001,
+	KGSL_DEVICE_2D1		= 0x00000002,
+	KGSL_DEVICE_MAX		= 0x00000003
+};
+
+enum kgsl_user_mem_type {
+	KGSL_USER_MEM_TYPE_PMEM		= 0x00000000,
+	KGSL_USER_MEM_TYPE_ASHMEM	= 0x00000001,
+	KGSL_USER_MEM_TYPE_ADDR		= 0x00000002,
+	KGSL_USER_MEM_TYPE_ION		= 0x00000003,
+	KGSL_USER_MEM_TYPE_MAX		= 0x00000004,
+};
+
+struct kgsl_devinfo {
+
+	unsigned int device_id;
+	/* chip revision id
+	* coreid:8 majorrev:8 minorrev:8 patch:8
+	*/
+	unsigned int chip_id;
+	unsigned int mmu_enabled;
+	unsigned int gmem_gpubaseaddr;
+	/*
+	* This field contains the adreno revision
+	* number 200, 205, 220, etc...
+	*/
+	unsigned int gpu_id;
+	unsigned int gmem_sizebytes;
+};
+
+/* this structure defines the region of memory that can be mmap()ed from this
+   driver. The timestamp fields are volatile because they are written by the
+   GPU
+*/
+struct kgsl_devmemstore {
+	volatile unsigned int soptimestamp;
+	unsigned int sbz;
+	volatile unsigned int eoptimestamp;
+	unsigned int sbz2;
+	volatile unsigned int ts_cmp_enable;
+	unsigned int sbz3;
+	volatile unsigned int ref_wait_ts;
+	unsigned int sbz4;
+	unsigned int current_context;
+	unsigned int sbz5;
+};
+
+#define KGSL_MEMSTORE_OFFSET(ctxt_id, field) \
+	((ctxt_id)*sizeof(struct kgsl_devmemstore) + \
+	 offsetof(struct kgsl_devmemstore, field))
+
+/* timestamp id*/
+enum kgsl_timestamp_type {
+	KGSL_TIMESTAMP_CONSUMED = 0x00000001, /* start-of-pipeline timestamp */
+	KGSL_TIMESTAMP_RETIRED  = 0x00000002, /* end-of-pipeline timestamp*/
+	KGSL_TIMESTAMP_QUEUED   = 0x00000003,
+};
+
+/* property types - used with kgsl_device_getproperty */
+enum kgsl_property_type {
+	KGSL_PROP_DEVICE_INFO     = 0x00000001,
+	KGSL_PROP_DEVICE_SHADOW   = 0x00000002,
+	KGSL_PROP_DEVICE_POWER    = 0x00000003,
+	KGSL_PROP_SHMEM           = 0x00000004,
+	KGSL_PROP_SHMEM_APERTURES = 0x00000005,
+	KGSL_PROP_MMU_ENABLE 	  = 0x00000006,
+	KGSL_PROP_INTERRUPT_WAITS = 0x00000007,
+	KGSL_PROP_VERSION         = 0x00000008,
+	KGSL_PROP_GPU_RESET_STAT  = 0x00000009,
+	KGSL_PROP_PWRCTRL         = 0x0000000E,
+};
+
+struct kgsl_shadowprop {
+	unsigned int gpuaddr;
+	unsigned int size;
+	unsigned int flags; /* contains KGSL_FLAGS_ values */
+};
+
+struct kgsl_pwrlevel {
+	unsigned int gpu_freq;
+	unsigned int bus_freq;
+	unsigned int io_fraction;
+};
+
+struct kgsl_version {
+	unsigned int drv_major;
+	unsigned int drv_minor;
+	unsigned int dev_major;
+	unsigned int dev_minor;
+};
+
+#ifdef __KERNEL__
+
+#define KGSL_3D0_REG_MEMORY	"kgsl_3d0_reg_memory"
+#define KGSL_3D0_IRQ		"kgsl_3d0_irq"
+#define KGSL_2D0_REG_MEMORY	"kgsl_2d0_reg_memory"
+#define KGSL_2D0_IRQ		"kgsl_2d0_irq"
+#define KGSL_2D1_REG_MEMORY	"kgsl_2d1_reg_memory"
+#define KGSL_2D1_IRQ		"kgsl_2d1_irq"
+
+enum kgsl_iommu_context_id {
+	KGSL_IOMMU_CONTEXT_USER = 0,
+	KGSL_IOMMU_CONTEXT_PRIV = 1,
+};
+
+struct kgsl_iommu_ctx {
+	const char *iommu_ctx_name;
+	enum kgsl_iommu_context_id ctx_id;
+};
+
+struct kgsl_device_iommu_data {
+	const struct kgsl_iommu_ctx *iommu_ctxs;
+	int iommu_ctx_count;
+	unsigned int physstart;
+	unsigned int physend;
+};
+
+struct kgsl_device_platform_data {
+	struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
+	int init_level;
+	int num_levels;
+	int (*set_grp_async)(void);
+	unsigned int idle_timeout;
+	bool strtstp_sleepwake;
+	unsigned int nap_allowed;
+	unsigned int clk_map;
+	unsigned int idle_needed;
+	struct msm_bus_scale_pdata *bus_scale_table;
+	struct kgsl_device_iommu_data *iommu_data;
+	int iommu_count;
+	struct msm_dcvs_core_info *core_info;
+};
+
+#endif
+
+/* structure holds list of ibs */
+struct kgsl_ibdesc {
+	unsigned int gpuaddr;
+	void *hostptr;
+	unsigned int sizedwords;
+	unsigned int ctrl;
+};
+
+/* ioctls */
+#define KGSL_IOC_TYPE 0x09
+
+/* get misc info about the GPU
+   type should be a value from enum kgsl_property_type
+   value points to a structure that varies based on type
+   sizebytes is sizeof() that structure
+   for KGSL_PROP_DEVICE_INFO, use struct kgsl_devinfo
+   this structure contaings hardware versioning info.
+   for KGSL_PROP_DEVICE_SHADOW, use struct kgsl_shadowprop
+   this is used to find mmap() offset and sizes for mapping
+   struct kgsl_memstore into userspace.
+*/
+struct kgsl_device_getproperty {
+	unsigned int type;
+	void  *value;
+	unsigned int sizebytes;
+};
+
+#define IOCTL_KGSL_DEVICE_GETPROPERTY \
+	_IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty)
+
+/* IOCTL_KGSL_DEVICE_READ (0x3) - removed 03/2012
+ */
+
+/* block until the GPU has executed past a given timestamp
+ * timeout is in milliseconds.
+ */
+struct kgsl_device_waittimestamp {
+	unsigned int timestamp;
+	unsigned int timeout;
+};
+
+#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP \
+	_IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp)
+
+struct kgsl_device_waittimestamp_ctxtid {
+	unsigned int context_id;
+	unsigned int timestamp;
+	unsigned int timeout;
+};
+
+#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \
+	_IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid)
+
+/* issue indirect commands to the GPU.
+ * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE
+ * ibaddr and sizedwords must specify a subset of a buffer created
+ * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM
+ * flags may be a mask of KGSL_CONTEXT_ values
+ * timestamp is a returned counter value which can be passed to
+ * other ioctls to determine when the commands have been executed by
+ * the GPU.
+ */
+struct kgsl_ringbuffer_issueibcmds {
+	unsigned int drawctxt_id;
+	unsigned int ibdesc_addr;
+	unsigned int numibs;
+	unsigned int timestamp; /*output param */
+	unsigned int flags;
+};
+
+#define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS \
+	_IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds)
+
+/* read the most recently executed timestamp value
+ * type should be a value from enum kgsl_timestamp_type
+ */
+struct kgsl_cmdstream_readtimestamp {
+	unsigned int type;
+	unsigned int timestamp; /*output param */
+};
+
+#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD \
+	_IOR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp)
+
+#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP \
+	_IOWR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp)
+
+/* free memory when the GPU reaches a given timestamp.
+ * gpuaddr specify a memory region created by a
+ * IOCTL_KGSL_SHAREDMEM_FROM_PMEM call
+ * type should be a value from enum kgsl_timestamp_type
+ */
+struct kgsl_cmdstream_freememontimestamp {
+	unsigned int gpuaddr;
+	unsigned int type;
+	unsigned int timestamp;
+};
+
+#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP \
+	_IOW(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp)
+
+/* Previous versions of this header had incorrectly defined
+   IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP as a read-only ioctl instead
+   of a write only ioctl.  To ensure binary compatability, the following
+   #define will be used to intercept the incorrect ioctl
+*/
+
+#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_OLD \
+	_IOR(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp)
+
+/* create a draw context, which is used to preserve GPU state.
+ * The flags field may contain a mask KGSL_CONTEXT_*  values
+ */
+struct kgsl_drawctxt_create {
+	unsigned int flags;
+	unsigned int drawctxt_id; /*output param */
+};
+
+#define IOCTL_KGSL_DRAWCTXT_CREATE \
+	_IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create)
+
+/* destroy a draw context */
+struct kgsl_drawctxt_destroy {
+	unsigned int drawctxt_id;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_DESTROY \
+	_IOW(KGSL_IOC_TYPE, 0x14, struct kgsl_drawctxt_destroy)
+
+/* add a block of pmem, fb, ashmem or user allocated address
+ * into the GPU address space */
+struct kgsl_map_user_mem {
+	int fd;
+	unsigned int gpuaddr;   /*output param */
+	unsigned int len;
+	unsigned int offset;
+	unsigned int hostptr;   /*input param */
+	enum kgsl_user_mem_type memtype;
+	unsigned int reserved;	/* May be required to add
+				params for another mem type */
+};
+
+#define IOCTL_KGSL_MAP_USER_MEM \
+	_IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem)
+
+struct kgsl_cmdstream_readtimestamp_ctxtid {
+	unsigned int context_id;
+	unsigned int type;
+	unsigned int timestamp; /*output param */
+};
+
+#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID \
+	_IOWR(KGSL_IOC_TYPE, 0x16, struct kgsl_cmdstream_readtimestamp_ctxtid)
+
+struct kgsl_cmdstream_freememontimestamp_ctxtid {
+	unsigned int context_id;
+	unsigned int gpuaddr;
+	unsigned int type;
+	unsigned int timestamp;
+};
+
+#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID \
+	_IOW(KGSL_IOC_TYPE, 0x17, \
+	struct kgsl_cmdstream_freememontimestamp_ctxtid)
+
+/* add a block of pmem or fb into the GPU address space */
+struct kgsl_sharedmem_from_pmem {
+	int pmem_fd;
+	unsigned int gpuaddr;	/*output param */
+	unsigned int len;
+	unsigned int offset;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FROM_PMEM \
+	_IOWR(KGSL_IOC_TYPE, 0x20, struct kgsl_sharedmem_from_pmem)
+
+/* remove memory from the GPU's address space */
+struct kgsl_sharedmem_free {
+	unsigned int gpuaddr;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FREE \
+	_IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free)
+
+struct kgsl_cff_user_event {
+	unsigned char cff_opcode;
+	unsigned int op1;
+	unsigned int op2;
+	unsigned int op3;
+	unsigned int op4;
+	unsigned int op5;
+	unsigned int __pad[2];
+};
+
+#define IOCTL_KGSL_CFF_USER_EVENT \
+	_IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_cff_user_event)
+
+struct kgsl_gmem_desc {
+	unsigned int x;
+	unsigned int y;
+	unsigned int width;
+	unsigned int height;
+	unsigned int pitch;
+};
+
+struct kgsl_buffer_desc {
+	void 			*hostptr;
+	unsigned int	gpuaddr;
+	int				size;
+	unsigned int	format;
+	unsigned int  	pitch;
+	unsigned int  	enabled;
+};
+
+struct kgsl_bind_gmem_shadow {
+	unsigned int drawctxt_id;
+	struct kgsl_gmem_desc gmem_desc;
+	unsigned int shadow_x;
+	unsigned int shadow_y;
+	struct kgsl_buffer_desc shadow_buffer;
+	unsigned int buffer_id;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_BIND_GMEM_SHADOW \
+    _IOW(KGSL_IOC_TYPE, 0x22, struct kgsl_bind_gmem_shadow)
+
+/* add a block of memory into the GPU address space */
+struct kgsl_sharedmem_from_vmalloc {
+	unsigned int gpuaddr;	/*output param */
+	unsigned int hostptr;
+	unsigned int flags;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \
+	_IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc)
+
+#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \
+	_IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free)
+
+struct kgsl_drawctxt_set_bin_base_offset {
+	unsigned int drawctxt_id;
+	unsigned int offset;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET \
+	_IOW(KGSL_IOC_TYPE, 0x25, struct kgsl_drawctxt_set_bin_base_offset)
+
+enum kgsl_cmdwindow_type {
+	KGSL_CMDWINDOW_MIN     = 0x00000000,
+	KGSL_CMDWINDOW_2D      = 0x00000000,
+	KGSL_CMDWINDOW_3D      = 0x00000001, /* legacy */
+	KGSL_CMDWINDOW_MMU     = 0x00000002,
+	KGSL_CMDWINDOW_ARBITER = 0x000000FF,
+	KGSL_CMDWINDOW_MAX     = 0x000000FF,
+};
+
+/* write to the command window */
+struct kgsl_cmdwindow_write {
+	enum kgsl_cmdwindow_type target;
+	unsigned int addr;
+	unsigned int data;
+};
+
+#define IOCTL_KGSL_CMDWINDOW_WRITE \
+	_IOW(KGSL_IOC_TYPE, 0x2e, struct kgsl_cmdwindow_write)
+
+struct kgsl_gpumem_alloc {
+	unsigned long gpuaddr;
+	size_t size;
+	unsigned int flags;
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC \
+	_IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc)
+
+struct kgsl_cff_syncmem {
+	unsigned int gpuaddr;
+	unsigned int len;
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_CFF_SYNCMEM \
+	_IOW(KGSL_IOC_TYPE, 0x30, struct kgsl_cff_syncmem)
+
+/*
+ * A timestamp event allows the user space to register an action following an
+ * expired timestamp.
+ */
+
+struct kgsl_timestamp_event {
+	int type;                /* Type of event (see list below) */
+	unsigned int timestamp;  /* Timestamp to trigger event on */
+	unsigned int context_id; /* Context for the timestamp */
+	void *priv;              /* Pointer to the event specific blob */
+	size_t len;              /* Size of the event specific blob */
+};
+
+#define IOCTL_KGSL_TIMESTAMP_EVENT \
+	_IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event)
+
+/* A genlock timestamp event releases an existing lock on timestamp expire */
+
+#define KGSL_TIMESTAMP_EVENT_GENLOCK 1
+
+struct kgsl_timestamp_event_genlock {
+	int handle; /* Handle of the genlock lock to release */
+};
+
+/*
+ * Set a property within the kernel.  Uses the same structure as
+ * IOCTL_KGSL_GETPROPERTY
+ */
+
+#define IOCTL_KGSL_SETPROPERTY \
+	_IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty)
+
+#ifdef __KERNEL__
+#ifdef CONFIG_MSM_KGSL_DRM
+int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
+			unsigned long *len);
+#else
+#define kgsl_gem_obj_addr(...) 0
+#endif
+#endif
+#endif /* _MSM_KGSL_H */
