From 5b9df93147cfdabe007033a90df1d409e9722610 Mon Sep 17 00:00:00 2001
From: Jerome Glisse <jglisse@redhat.com>
Date: Fri, 9 Dec 2011 21:07:15 -0500
Subject: [PATCH] radeon: add surface allocator helper v5

The surface allocator is able to build complete miptree when allocating
surface for r600/r700/evergreen/northern islands GPU family. It also
compute bo size and alignment for render buffer, depth buffer and
scanout buffer.

v2 fix r6xx/r7xx 2D tiling width align computation
v3 add tile split support and fix 1d texture alignment
v4 rework to more properly support compressed format, split surface pixel
   size and surface element size in separate fields
v5 support texture array (still issue on r6xx)

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
---
 include/drm/radeon_drm.h |   22 +-
 radeon/Makefile.am       |    2 +
 radeon/r600_pci_ids.h    |  271 ++++++++++++++++
 radeon/radeon_surface.c  |  787 ++++++++++++++++++++++++++++++++++++++++++++++
 radeon/radeon_surface.h  |  110 +++++++
 5 files changed, 1185 insertions(+), 7 deletions(-)
 create mode 100644 radeon/r600_pci_ids.h
 create mode 100644 radeon/radeon_surface.c
 create mode 100644 radeon/radeon_surface.h

diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index 67b5622..c4dbe0d 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -804,13 +804,21 @@ struct drm_radeon_gem_create {
 	uint32_t	flags;
 };
 
-#define RADEON_TILING_MACRO       0x1
-#define RADEON_TILING_MICRO       0x2
-#define RADEON_TILING_SWAP_16BIT  0x4
-#define RADEON_TILING_SWAP_32BIT  0x8
-#define RADEON_TILING_SURFACE     0x10 /* this object requires a surface
-					* when mapped - i.e. front buffer */
-#define RADEON_TILING_MICRO_SQUARE 0x20
+#define RADEON_TILING_MACRO				0x1
+#define RADEON_TILING_MICRO				0x2
+#define RADEON_TILING_SWAP_16BIT			0x4
+#define RADEON_TILING_SWAP_32BIT			0x8
+/* this object requires a surface when mapped - i.e. front buffer */
+#define RADEON_TILING_SURFACE				0x10
+#define RADEON_TILING_MICRO_SQUARE			0x20
+#define RADEON_TILING_EG_BANKW_SHIFT			8
+#define RADEON_TILING_EG_BANKW_MASK			0xf
+#define RADEON_TILING_EG_BANKH_SHIFT			12
+#define RADEON_TILING_EG_BANKH_MASK			0xf
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT	16
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK		0xf
+#define RADEON_TILING_EG_TILE_SPLIT_SHIFT		24
+#define RADEON_TILING_EG_TILE_SPLIT_MASK		0xf
 
 struct drm_radeon_gem_set_tiling {
 	uint32_t	handle;
diff --git a/radeon/Makefile.am b/radeon/Makefile.am
index dc94b5f..e64aff4 100644
--- a/radeon/Makefile.am
+++ b/radeon/Makefile.am
@@ -40,6 +40,7 @@ libdrm_radeon_la_SOURCES = \
 	radeon_cs_space.c \
 	radeon_bo.c \
 	radeon_cs.c \
+	radeon_surface.c \
 	bof.c \
 	bof.h
 
@@ -47,6 +48,7 @@ libdrm_radeonincludedir = ${includedir}/libdrm
 libdrm_radeoninclude_HEADERS = \
 	radeon_bo.h \
 	radeon_cs.h \
+	radeon_surface.h \
 	radeon_bo_gem.h \
 	radeon_cs_gem.h \
 	radeon_bo_int.h \
diff --git a/radeon/r600_pci_ids.h b/radeon/r600_pci_ids.h
new file mode 100644
index 0000000..0ffb741
--- /dev/null
+++ b/radeon/r600_pci_ids.h
@@ -0,0 +1,271 @@
+CHIPSET(0x9400, R600_9400, R600)
+CHIPSET(0x9401, R600_9401, R600)
+CHIPSET(0x9402, R600_9402, R600)
+CHIPSET(0x9403, R600_9403, R600)
+CHIPSET(0x9405, R600_9405, R600)
+CHIPSET(0x940A, R600_940A, R600)
+CHIPSET(0x940B, R600_940B, R600)
+CHIPSET(0x940F, R600_940F, R600)
+
+CHIPSET(0x94C0, RV610_94C0, RV610)
+CHIPSET(0x94C1, RV610_94C1, RV610)
+CHIPSET(0x94C3, RV610_94C3, RV610)
+CHIPSET(0x94C4, RV610_94C4, RV610)
+CHIPSET(0x94C5, RV610_94C5, RV610)
+CHIPSET(0x94C6, RV610_94C6, RV610)
+CHIPSET(0x94C7, RV610_94C7, RV610)
+CHIPSET(0x94C8, RV610_94C8, RV610)
+CHIPSET(0x94C9, RV610_94C9, RV610)
+CHIPSET(0x94CB, RV610_94CB, RV610)
+CHIPSET(0x94CC, RV610_94CC, RV610)
+CHIPSET(0x94CD, RV610_94CD, RV610)
+
+CHIPSET(0x9580, RV630_9580, RV630)
+CHIPSET(0x9581, RV630_9581, RV630)
+CHIPSET(0x9583, RV630_9583, RV630)
+CHIPSET(0x9586, RV630_9586, RV630)
+CHIPSET(0x9587, RV630_9587, RV630)
+CHIPSET(0x9588, RV630_9588, RV630)
+CHIPSET(0x9589, RV630_9589, RV630)
+CHIPSET(0x958A, RV630_958A, RV630)
+CHIPSET(0x958B, RV630_958B, RV630)
+CHIPSET(0x958C, RV630_958C, RV630)
+CHIPSET(0x958D, RV630_958D, RV630)
+CHIPSET(0x958E, RV630_958E, RV630)
+CHIPSET(0x958F, RV630_958F, RV630)
+
+CHIPSET(0x9500, RV670_9500, RV670)
+CHIPSET(0x9501, RV670_9501, RV670)
+CHIPSET(0x9504, RV670_9504, RV670)
+CHIPSET(0x9505, RV670_9505, RV670)
+CHIPSET(0x9506, RV670_9506, RV670)
+CHIPSET(0x9507, RV670_9507, RV670)
+CHIPSET(0x9508, RV670_9508, RV670)
+CHIPSET(0x9509, RV670_9509, RV670)
+CHIPSET(0x950F, RV670_950F, RV670)
+CHIPSET(0x9511, RV670_9511, RV670)
+CHIPSET(0x9515, RV670_9515, RV670)
+CHIPSET(0x9517, RV670_9517, RV670)
+CHIPSET(0x9519, RV670_9519, RV670)
+
+CHIPSET(0x95C0, RV620_95C0, RV620)
+CHIPSET(0x95C2, RV620_95C2, RV620)
+CHIPSET(0x95C4, RV620_95C4, RV620)
+CHIPSET(0x95C5, RV620_95C5, RV620)
+CHIPSET(0x95C6, RV620_95C6, RV620)
+CHIPSET(0x95C7, RV620_95C7, RV620)
+CHIPSET(0x95C9, RV620_95C9, RV620)
+CHIPSET(0x95CC, RV620_95CC, RV620)
+CHIPSET(0x95CD, RV620_95CD, RV620)
+CHIPSET(0x95CE, RV620_95CE, RV620)
+CHIPSET(0x95CF, RV620_95CF, RV620)
+
+CHIPSET(0x9590, RV635_9590, RV635)
+CHIPSET(0x9591, RV635_9591, RV635)
+CHIPSET(0x9593, RV635_9593, RV635)
+CHIPSET(0x9595, RV635_9595, RV635)
+CHIPSET(0x9596, RV635_9596, RV635)
+CHIPSET(0x9597, RV635_9597, RV635)
+CHIPSET(0x9598, RV635_9598, RV635)
+CHIPSET(0x9599, RV635_9599, RV635)
+CHIPSET(0x959B, RV635_959B, RV635)
+
+CHIPSET(0x9610, RS780_9610, RS780)
+CHIPSET(0x9611, RS780_9611, RS780)
+CHIPSET(0x9612, RS780_9612, RS780)
+CHIPSET(0x9613, RS780_9613, RS780)
+CHIPSET(0x9614, RS780_9614, RS780)
+CHIPSET(0x9615, RS780_9615, RS780)
+CHIPSET(0x9616, RS780_9616, RS780)
+
+CHIPSET(0x9710, RS880_9710, RS880)
+CHIPSET(0x9711, RS880_9711, RS880)
+CHIPSET(0x9712, RS880_9712, RS880)
+CHIPSET(0x9713, RS880_9713, RS880)
+CHIPSET(0x9714, RS880_9714, RS880)
+CHIPSET(0x9715, RS880_9715, RS880)
+
+CHIPSET(0x9440, RV770_9440, RV770)
+CHIPSET(0x9441, RV770_9441, RV770)
+CHIPSET(0x9442, RV770_9442, RV770)
+CHIPSET(0x9443, RV770_9443, RV770)
+CHIPSET(0x9444, RV770_9444, RV770)
+CHIPSET(0x9446, RV770_9446, RV770)
+CHIPSET(0x944A, RV770_944A, RV770)
+CHIPSET(0x944B, RV770_944B, RV770)
+CHIPSET(0x944C, RV770_944C, RV770)
+CHIPSET(0x944E, RV770_944E, RV770)
+CHIPSET(0x9450, RV770_9450, RV770)
+CHIPSET(0x9452, RV770_9452, RV770)
+CHIPSET(0x9456, RV770_9456, RV770)
+CHIPSET(0x945A, RV770_945A, RV770)
+CHIPSET(0x945B, RV770_945B, RV770)
+CHIPSET(0x945E, RV770_945E, RV770)
+CHIPSET(0x9460, RV790_9460, RV770)
+CHIPSET(0x9462, RV790_9462, RV770)
+CHIPSET(0x946A, RV770_946A, RV770)
+CHIPSET(0x946B, RV770_946B, RV770)
+CHIPSET(0x947A, RV770_947A, RV770)
+CHIPSET(0x947B, RV770_947B, RV770)
+
+CHIPSET(0x9480, RV730_9480, RV730)
+CHIPSET(0x9487, RV730_9487, RV730)
+CHIPSET(0x9488, RV730_9488, RV730)
+CHIPSET(0x9489, RV730_9489, RV730)
+CHIPSET(0x948A, RV730_948A, RV730)
+CHIPSET(0x948F, RV730_948F, RV730)
+CHIPSET(0x9490, RV730_9490, RV730)
+CHIPSET(0x9491, RV730_9491, RV730)
+CHIPSET(0x9495, RV730_9495, RV730)
+CHIPSET(0x9498, RV730_9498, RV730)
+CHIPSET(0x949C, RV730_949C, RV730)
+CHIPSET(0x949E, RV730_949E, RV730)
+CHIPSET(0x949F, RV730_949F, RV730)
+
+CHIPSET(0x9540, RV710_9540, RV710)
+CHIPSET(0x9541, RV710_9541, RV710)
+CHIPSET(0x9542, RV710_9542, RV710)
+CHIPSET(0x954E, RV710_954E, RV710)
+CHIPSET(0x954F, RV710_954F, RV710)
+CHIPSET(0x9552, RV710_9552, RV710)
+CHIPSET(0x9553, RV710_9553, RV710)
+CHIPSET(0x9555, RV710_9555, RV710)
+CHIPSET(0x9557, RV710_9557, RV710)
+CHIPSET(0x955F, RV710_955F, RV710)
+
+CHIPSET(0x94A0, RV740_94A0, RV740)
+CHIPSET(0x94A1, RV740_94A1, RV740)
+CHIPSET(0x94A3, RV740_94A3, RV740)
+CHIPSET(0x94B1, RV740_94B1, RV740)
+CHIPSET(0x94B3, RV740_94B3, RV740)
+CHIPSET(0x94B4, RV740_94B4, RV740)
+CHIPSET(0x94B5, RV740_94B5, RV740)
+CHIPSET(0x94B9, RV740_94B9, RV740)
+
+CHIPSET(0x68E0, CEDAR_68E0, CEDAR)
+CHIPSET(0x68E1, CEDAR_68E1, CEDAR)
+CHIPSET(0x68E4, CEDAR_68E4, CEDAR)
+CHIPSET(0x68E5, CEDAR_68E5, CEDAR)
+CHIPSET(0x68E8, CEDAR_68E8, CEDAR)
+CHIPSET(0x68E9, CEDAR_68E9, CEDAR)
+CHIPSET(0x68F1, CEDAR_68F1, CEDAR)
+CHIPSET(0x68F2, CEDAR_68F2, CEDAR)
+CHIPSET(0x68F8, CEDAR_68F8, CEDAR)
+CHIPSET(0x68F9, CEDAR_68F9, CEDAR)
+CHIPSET(0x68FE, CEDAR_68FE, CEDAR)
+
+CHIPSET(0x68C0, REDWOOD_68C0, REDWOOD)
+CHIPSET(0x68C1, REDWOOD_68C1, REDWOOD)
+CHIPSET(0x68C8, REDWOOD_68C8, REDWOOD)
+CHIPSET(0x68C9, REDWOOD_68C9, REDWOOD)
+CHIPSET(0x68D8, REDWOOD_68D8, REDWOOD)
+CHIPSET(0x68D9, REDWOOD_68D9, REDWOOD)
+CHIPSET(0x68DA, REDWOOD_68DA, REDWOOD)
+CHIPSET(0x68DE, REDWOOD_68DE, REDWOOD)
+
+CHIPSET(0x68A0, JUNIPER_68A0, JUNIPER)
+CHIPSET(0x68A1, JUNIPER_68A1, JUNIPER)
+CHIPSET(0x68A8, JUNIPER_68A8, JUNIPER)
+CHIPSET(0x68A9, JUNIPER_68A9, JUNIPER)
+CHIPSET(0x68B0, JUNIPER_68B0, JUNIPER)
+CHIPSET(0x68B8, JUNIPER_68B8, JUNIPER)
+CHIPSET(0x68B9, JUNIPER_68B9, JUNIPER)
+CHIPSET(0x68BA, JUNIPER_68BA, JUNIPER)
+CHIPSET(0x68BE, JUNIPER_68BE, JUNIPER)
+CHIPSET(0x68BF, JUNIPER_68BF, JUNIPER)
+
+CHIPSET(0x6880, CYPRESS_6880, CYPRESS)
+CHIPSET(0x6888, CYPRESS_6888, CYPRESS)
+CHIPSET(0x6889, CYPRESS_6889, CYPRESS)
+CHIPSET(0x688A, CYPRESS_688A, CYPRESS)
+CHIPSET(0x6898, CYPRESS_6898, CYPRESS)
+CHIPSET(0x6899, CYPRESS_6899, CYPRESS)
+CHIPSET(0x689B, CYPRESS_689B, CYPRESS)
+CHIPSET(0x689E, CYPRESS_689E, CYPRESS)
+
+CHIPSET(0x689C, HEMLOCK_689C, HEMLOCK)
+CHIPSET(0x689D, HEMLOCK_689D, HEMLOCK)
+
+CHIPSET(0x9802, PALM_9802, PALM)
+CHIPSET(0x9803, PALM_9803, PALM)
+CHIPSET(0x9804, PALM_9804, PALM)
+CHIPSET(0x9805, PALM_9805, PALM)
+CHIPSET(0x9806, PALM_9806, PALM)
+CHIPSET(0x9807, PALM_9807, PALM)
+
+CHIPSET(0x9640, SUMO_9640,  SUMO)
+CHIPSET(0x9641, SUMO_9641,  SUMO)
+CHIPSET(0x9642, SUMO2_9642, SUMO2)
+CHIPSET(0x9643, SUMO2_9643, SUMO2)
+CHIPSET(0x9644, SUMO2_9644, SUMO2)
+CHIPSET(0x9645, SUMO2_9645, SUMO2)
+CHIPSET(0x9647, SUMO_9647,  SUMO)
+CHIPSET(0x9648, SUMO_9648,  SUMO)
+CHIPSET(0x964a, SUMO_964A,  SUMO)
+CHIPSET(0x964e, SUMO_964E,  SUMO)
+CHIPSET(0x964f, SUMO_964F,  SUMO)
+
+CHIPSET(0x6700, CAYMAN_6700, CAYMAN)
+CHIPSET(0x6701, CAYMAN_6701, CAYMAN)
+CHIPSET(0x6702, CAYMAN_6702, CAYMAN)
+CHIPSET(0x6703, CAYMAN_6703, CAYMAN)
+CHIPSET(0x6704, CAYMAN_6704, CAYMAN)
+CHIPSET(0x6705, CAYMAN_6705, CAYMAN)
+CHIPSET(0x6706, CAYMAN_6706, CAYMAN)
+CHIPSET(0x6707, CAYMAN_6707, CAYMAN)
+CHIPSET(0x6708, CAYMAN_6708, CAYMAN)
+CHIPSET(0x6709, CAYMAN_6709, CAYMAN)
+CHIPSET(0x6718, CAYMAN_6718, CAYMAN)
+CHIPSET(0x6719, CAYMAN_6719, CAYMAN)
+CHIPSET(0x671C, CAYMAN_671C, CAYMAN)
+CHIPSET(0x671D, CAYMAN_671D, CAYMAN)
+CHIPSET(0x671F, CAYMAN_671F, CAYMAN)
+
+CHIPSET(0x6720, BARTS_6720, BARTS)
+CHIPSET(0x6721, BARTS_6721, BARTS)
+CHIPSET(0x6722, BARTS_6722, BARTS)
+CHIPSET(0x6723, BARTS_6723, BARTS)
+CHIPSET(0x6724, BARTS_6724, BARTS)
+CHIPSET(0x6725, BARTS_6725, BARTS)
+CHIPSET(0x6726, BARTS_6726, BARTS)
+CHIPSET(0x6727, BARTS_6727, BARTS)
+CHIPSET(0x6728, BARTS_6728, BARTS)
+CHIPSET(0x6729, BARTS_6729, BARTS)
+CHIPSET(0x6738, BARTS_6738, BARTS)
+CHIPSET(0x6739, BARTS_6739, BARTS)
+CHIPSET(0x673E, BARTS_673E, BARTS)
+CHIPSET(0x6740, TURKS_6740, TURKS)
+CHIPSET(0x6741, TURKS_6741, TURKS)
+CHIPSET(0x6742, TURKS_6742, TURKS)
+CHIPSET(0x6743, TURKS_6743, TURKS)
+CHIPSET(0x6744, TURKS_6744, TURKS)
+CHIPSET(0x6745, TURKS_6745, TURKS)
+CHIPSET(0x6746, TURKS_6746, TURKS)
+CHIPSET(0x6747, TURKS_6747, TURKS)
+CHIPSET(0x6748, TURKS_6748, TURKS)
+CHIPSET(0x6749, TURKS_6749, TURKS)
+CHIPSET(0x6750, TURKS_6750, TURKS)
+CHIPSET(0x6758, TURKS_6758, TURKS)
+CHIPSET(0x6759, TURKS_6759, TURKS)
+CHIPSET(0x675F, TURKS_675F, TURKS)
+CHIPSET(0x6840, TURKS_6840, TURKS)
+CHIPSET(0x6841, TURKS_6841, TURKS)
+CHIPSET(0x6842, TURKS_6842, TURKS)
+CHIPSET(0x6843, TURKS_6843, TURKS)
+CHIPSET(0x6849, TURKS_6849, TURKS)
+CHIPSET(0x6850, TURKS_6850, TURKS)
+CHIPSET(0x6858, TURKS_6858, TURKS)
+CHIPSET(0x6859, TURKS_6859, TURKS)
+
+CHIPSET(0x6760, CAICOS_6760, CAICOS)
+CHIPSET(0x6761, CAICOS_6761, CAICOS)
+CHIPSET(0x6762, CAICOS_6762, CAICOS)
+CHIPSET(0x6763, CAICOS_6763, CAICOS)
+CHIPSET(0x6764, CAICOS_6764, CAICOS)
+CHIPSET(0x6765, CAICOS_6765, CAICOS)
+CHIPSET(0x6766, CAICOS_6766, CAICOS)
+CHIPSET(0x6767, CAICOS_6767, CAICOS)
+CHIPSET(0x6768, CAICOS_6768, CAICOS)
+CHIPSET(0x6770, CAICOS_6770, CAICOS)
+CHIPSET(0x6778, CAICOS_6778, CAICOS)
+CHIPSET(0x6779, CAICOS_6779, CAICOS)
diff --git a/radeon/radeon_surface.c b/radeon/radeon_surface.c
new file mode 100644
index 0000000..8827da9
--- /dev/null
+++ b/radeon/radeon_surface.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright © 2011 Red Hat All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
+ * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ */
+/*
+ * Authors:
+ *      Jérôme Glisse <jglisse@redhat.com>
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "xf86drm.h"
+#include "radeon_drm.h"
+#include "radeon_surface.h"
+
+#define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
+#define MAX2(A, B)              ((A) > (B) ? (A) : (B))
+#define MIN2(A, B)              ((A) < (B) ? (A) : (B))
+
+/* keep this private */
+enum radeon_family {
+    CHIP_UNKNOWN,
+    CHIP_R600,
+    CHIP_RV610,
+    CHIP_RV630,
+    CHIP_RV670,
+    CHIP_RV620,
+    CHIP_RV635,
+    CHIP_RS780,
+    CHIP_RS880,
+    CHIP_RV770,
+    CHIP_RV730,
+    CHIP_RV710,
+    CHIP_RV740,
+    CHIP_CEDAR,
+    CHIP_REDWOOD,
+    CHIP_JUNIPER,
+    CHIP_CYPRESS,
+    CHIP_HEMLOCK,
+    CHIP_PALM,
+    CHIP_SUMO,
+    CHIP_SUMO2,
+    CHIP_BARTS,
+    CHIP_TURKS,
+    CHIP_CAICOS,
+    CHIP_CAYMAN,
+    CHIP_LAST,
+};
+
+typedef int (*hw_init_surface_t)(struct radeon_surface_manager *surf_man,
+                                 struct radeon_surface *surf);
+
+struct radeon_hw_info {
+    /* apply to r6, eg */
+    uint32_t                    group_bytes;
+    uint32_t                    num_banks;
+    uint32_t                    num_pipes;
+    /* apply to eg */
+    uint32_t                    row_size;
+    unsigned                    allow_2d;
+};
+
+struct radeon_surface_manager {
+    int                         fd;
+    uint32_t                    device_id;
+    struct radeon_hw_info       hw_info;
+    unsigned                    family;
+    hw_init_surface_t           surface_init;
+};
+
+/* helper */
+static int radeon_get_value(int fd, unsigned req, uint32_t *value)
+{
+    struct drm_radeon_info info = {};
+    int r;
+
+    *value = 0;
+    info.request = req;
+    info.value = (uintptr_t)value;
+    r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info,
+                            sizeof(struct drm_radeon_info));
+    return r;
+}
+
+static int radeon_get_family(struct radeon_surface_manager *surf_man)
+{
+    switch (surf_man->device_id) {
+#define CHIPSET(pci_id, name, fam) case pci_id: surf_man->family = CHIP_##fam; break;
+#include "r600_pci_ids.h"
+#undef CHIPSET
+    default:
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static unsigned next_power_of_two(unsigned x)
+{
+   if (x <= 1)
+       return 1;
+
+   return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1)));
+}
+
+static unsigned mip_minify(unsigned size, unsigned level)
+{
+    unsigned val;
+
+    val = MAX2(1, size >> level);
+    if (level > 0)
+        val = next_power_of_two(val);
+    return val;
+}
+
+static void surf_minify(struct radeon_surface_manager *surf_man,
+                        struct radeon_surface *surf,
+                        unsigned level,
+                        uint32_t xalign, uint32_t yalign, uint32_t zalign,
+                        unsigned offset,
+                        unsigned type)
+{
+    surf->level[level].nblk_x = mip_minify(surf->nblk_x, level);
+    surf->level[level].nblk_y = mip_minify(surf->nblk_y, level);
+    surf->level[level].nblk_z = mip_minify(surf->nblk_z, level);
+    surf->level[level].npix_x = mip_minify(surf->npix_x, level);
+    surf->level[level].npix_y = mip_minify(surf->npix_y, level);
+    surf->level[level].npix_z = mip_minify(surf->npix_z, level);
+    if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
+        if (surf->level[level].nblk_x < xalign || surf->level[level].nblk_y < yalign) {
+            surf->level[level].mode = RADEON_SURF_MODE_1D;
+            return;
+        }
+    }
+    surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, xalign);
+    surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, yalign);
+    surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, zalign);
+
+    surf->level[level].offset = offset;
+    surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe;
+    surf->level[level].slice_size = surf->level[level].pitch_bytes * surf->level[level].nblk_y;
+
+    if (type == RADEON_SURF_TYPE_CUBEMAP) {
+        if (surf_man->family >= CHIP_RV770) {
+            surf->bo_size = offset + surf->level[level].slice_size * 8 * surf->array_size;
+        } else {
+            surf->bo_size = offset + surf->level[level].slice_size * 6 * surf->array_size;
+        }
+    } else {
+        surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
+    }
+}
+
+/* ===========================================================================
+ * r600/r700 family
+ */
+static int r6_init_hw_info(struct radeon_surface_manager *surf_man)
+{
+    uint32_t tiling_config;
+    int r;
+
+    r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
+                         &tiling_config);
+    if (r) {
+        return r;
+    }
+
+    switch ((tiling_config & 0xe) >> 1) {
+    case 0:
+        surf_man->hw_info.num_pipes = 1;
+        break;
+    case 1:
+        surf_man->hw_info.num_pipes = 2;
+        break;
+    case 2:
+        surf_man->hw_info.num_pipes = 4;
+        break;
+    case 3:
+        surf_man->hw_info.num_pipes = 8;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    switch ((tiling_config & 0x30) >> 4) {
+    case 0:
+        surf_man->hw_info.num_banks = 4;
+        break;
+    case 1:
+        surf_man->hw_info.num_banks = 8;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    switch ((tiling_config & 0xc0) >> 6) {
+    case 0:
+        surf_man->hw_info.group_bytes = 256;
+        break;
+    case 1:
+        surf_man->hw_info.group_bytes = 512;
+        break;
+    default:
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int r6_surface_init_linear(struct radeon_surface_manager *surf_man,
+                                  struct radeon_surface *surf,
+                                  uint64_t offset, unsigned start_level)
+{
+    uint32_t xalign, yalign, zalign;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* compute alignment */
+    if (!start_level) {
+        surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
+    }
+    /* the 32 alignment is for scanout, cb or db but to allow texture to be
+     * easily bound as such we force this alignment to all surface
+     */
+    xalign = MAX2(32, surf_man->hw_info.group_bytes / surf->bpe);
+    yalign = 1;
+    zalign = 1;
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf_minify(surf_man, surf, i, xalign, yalign, zalign, offset, type);
+        surf->level[i].mode = RADEON_SURF_MODE_LINEAR;
+        /* level0 and first mipmap need to have alignment */
+        offset = surf->bo_size;
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    return 0;
+}
+
+static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
+                                          struct radeon_surface *surf,
+                                          uint64_t offset, unsigned start_level)
+{
+    uint32_t xalign, yalign, zalign;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* compute alignment */
+    if (!start_level) {
+        surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
+    }
+    xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe);
+    yalign = 1;
+    zalign = 1;
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf_minify(surf_man, surf, i, xalign, yalign, zalign, offset, type);
+        surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
+        /* level0 and first mipmap need to have alignment */
+        offset = surf->bo_size;
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    return 0;
+}
+
+static int r6_surface_init_1d(struct radeon_surface_manager *surf_man,
+                              struct radeon_surface *surf,
+                              uint64_t offset, unsigned start_level)
+{
+    uint32_t xalign, yalign, zalign, tilew;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+
+    /* compute alignment */
+    tilew = 8;
+    xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
+    xalign = MAX2(tilew, xalign);
+    yalign = tilew;
+    zalign = 1;
+    if (!start_level) {
+        surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
+    }
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf_minify(surf_man, surf, i, xalign, yalign, zalign, offset, type);
+        surf->level[i].mode = RADEON_SURF_MODE_1D;
+        /* level0 and first mipmap need to have alignment */
+        offset = surf->bo_size;
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    return 0;
+}
+
+static int r6_surface_init_2d(struct radeon_surface_manager *surf_man,
+                              struct radeon_surface *surf,
+                              uint64_t offset, unsigned start_level)
+{
+    uint32_t xalign, yalign, zalign, tilew;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+
+    /* compute alignment */
+    tilew = 8;
+    zalign = 1;
+    xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) /
+             (tilew * surf->bpe * surf->nsamples);
+    xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign);
+    yalign = tilew * surf_man->hw_info.num_pipes;
+    if (!start_level) {
+        surf->bo_alignment =
+            MAX2(surf_man->hw_info.num_pipes *
+                 surf_man->hw_info.num_banks *
+                 surf->bpe * 64,
+                 xalign * yalign * surf->nsamples * surf->bpe);
+    }
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf->level[i].mode = RADEON_SURF_MODE_2D;
+        surf_minify(surf_man, surf, i, xalign, yalign, zalign, offset, type);
+        if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
+            return r6_surface_init_1d(surf_man, surf, offset, i);
+        }
+        /* level0 and first mipmap need to have alignment */
+        offset = surf->bo_size;
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    return 0;
+}
+
+static int r6_surface_init(struct radeon_surface_manager *surf_man,
+                           struct radeon_surface *surf)
+{
+    unsigned mode;
+    int r;
+
+    /* tiling mode */
+    mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
+
+    /* check surface dimension */
+    if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) {
+        return -EINVAL;
+    }
+
+    /* check mipmap last_level */
+    if (surf->last_level > 14) {
+        return -EINVAL;
+    }
+
+    /* check tiling mode */
+    switch (mode) {
+    case RADEON_SURF_MODE_LINEAR:
+        r = r6_surface_init_linear(surf_man, surf, 0, 0);
+        break;
+    case RADEON_SURF_MODE_LINEAR_ALIGNED:
+        r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
+        break;
+    case RADEON_SURF_MODE_1D:
+        r = r6_surface_init_1d(surf_man, surf, 0, 0);
+        break;
+    case RADEON_SURF_MODE_2D:
+        r = r6_surface_init_2d(surf_man, surf, 0, 0);
+        break;
+    default:
+        return -EINVAL;
+    }
+    return r;
+}
+
+
+/* ===========================================================================
+ * evergreen family
+ */
+static int eg_init_hw_info(struct radeon_surface_manager *surf_man)
+{
+    uint32_t tiling_config;
+    drmVersionPtr version;
+    int r;
+
+    r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
+                         &tiling_config);
+    if (r) {
+        return r;
+    }
+
+    surf_man->hw_info.allow_2d = 0;
+    version = drmGetVersion(surf_man->fd);
+    if (version && version->version_minor >= 14) {
+        surf_man->hw_info.allow_2d = 1;
+    }
+
+    switch (tiling_config & 0xf) {
+    case 0:
+        surf_man->hw_info.num_pipes = 1;
+        break;
+    case 1:
+        surf_man->hw_info.num_pipes = 2;
+        break;
+    case 2:
+        surf_man->hw_info.num_pipes = 4;
+        break;
+    case 3:
+        surf_man->hw_info.num_pipes = 8;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    switch ((tiling_config & 0xf0) >> 4) {
+    case 0:
+        surf_man->hw_info.num_banks = 4;
+        break;
+    case 1:
+        surf_man->hw_info.num_banks = 8;
+        break;
+    case 2:
+        surf_man->hw_info.num_banks = 16;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    switch ((tiling_config & 0xf00) >> 8) {
+    case 0:
+        surf_man->hw_info.group_bytes = 256;
+        break;
+    case 1:
+        surf_man->hw_info.group_bytes = 512;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    switch ((tiling_config & 0xf000) >> 12) {
+    case 0:
+        surf_man->hw_info.row_size = 1024;
+        break;
+    case 1:
+        surf_man->hw_info.row_size = 2048;
+        break;
+    case 2:
+        surf_man->hw_info.row_size = 4096;
+        break;
+    default:
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static unsigned eg_adjust_bankh(unsigned group_bytes,
+                                unsigned tileb,
+                                unsigned bankw, unsigned bankh)
+{
+    for (; bankh <= 8; bankh *= 2) {
+        if ((tileb * bankw * bankh) >= group_bytes) {
+            return bankh;
+        }
+    }
+    return 0;
+}
+
+static unsigned eg_adjust_tilea(unsigned group_bytes,
+                                unsigned num_pipes,
+                                unsigned tileb,
+                                unsigned tilea,
+                                unsigned bankw)
+{
+    for (; tilea <= 8; tilea *= 2) {
+        if ((tileb * bankw * tilea * num_pipes) >= group_bytes) {
+            return tilea;
+        }
+    }
+    return 0;
+}
+
+static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
+                              struct radeon_surface *surf,
+                              uint64_t offset, unsigned start_level)
+{
+    uint32_t xalign, yalign, zalign, bankw, bankh;
+    uint32_t tilew, tileh, tileb, tilea;
+    unsigned i, type, macro_tile_bytes;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* check aspect ratio */
+    if (surf->macro_tile_aspect > surf_man->hw_info.num_banks) {
+        /* as num_banks/2 <= 8 which is the max tile aspect ratio */
+        surf->macro_tile_aspect = surf_man->hw_info.num_banks / 2;
+    }
+    switch (surf->macro_tile_aspect) {
+    case 0:
+    case 1:
+        surf->macro_tile_aspect = 1;
+        break;
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check bank width */
+    switch (surf->bank_width) {
+    case 0:
+    case 1:
+        surf->bank_width = 1;
+        break;
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check bank height */
+    switch (surf->bank_height) {
+    case 0:
+    case 1:
+        surf->bank_height = 1;
+        break;
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    /* compute alignment */
+    tilew = 8;
+    tileh = 8;
+    tilea = surf->macro_tile_aspect;
+    bankw = surf->bank_width;
+    bankh = surf->bank_height;
+    tileb = tilew * tileh * surf->bpe * surf->nsamples;
+    tileb = MIN2(surf->tile_split, tileb);
+
+    bankh = eg_adjust_bankh(surf_man->hw_info.group_bytes,
+                            tileb, bankw, bankh);
+    if (!bankh) {
+        surf->level[start_level].mode = RADEON_SURF_MODE_1D;
+        return r6_surface_init_1d(surf_man, surf, offset, start_level);
+    }
+    tilea = eg_adjust_tilea(surf_man->hw_info.group_bytes,
+                            surf_man->hw_info.num_pipes,
+                            tileb, tilea, bankw);
+    /* should we lower the aspect ratio when tilea > num_banks ?? */
+    if (!tilea || tilea > surf_man->hw_info.num_banks) {
+        surf->level[start_level].mode = RADEON_SURF_MODE_1D;
+        return r6_surface_init_1d(surf_man, surf, offset, start_level);
+    }
+
+    surf->macro_tile_aspect = tilea;
+    surf->bank_height = bankh;
+
+    zalign = 1;
+    xalign = surf_man->hw_info.num_pipes * bankw * tilew * tilea;
+    yalign = (surf_man->hw_info.num_banks * bankh * tileh) / tilea;
+    /* macro tile value needed for layer computation */
+    macro_tile_bytes = (xalign / tilew) * (yalign / tileh) * tileb;
+    if (!start_level) {
+        surf->bo_alignment = MAX2(256, macro_tile_bytes);
+    }
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf->level[i].mode = RADEON_SURF_MODE_2D;
+        surf_minify(surf_man, surf, i, xalign, yalign, zalign, offset, type);
+        if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
+            return r6_surface_init_1d(surf_man, surf, offset, i);
+        }
+        /* level0 and first mipmap need to have alignment */
+        offset = surf->bo_size;
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    return 0;
+}
+
+static int eg_surface_init(struct radeon_surface_manager *surf_man,
+                           struct radeon_surface *surf)
+{
+    unsigned mode;
+    int r;
+
+    /* tiling mode */
+    mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
+
+    /* check surface dimension */
+    if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
+        return -EINVAL;
+    }
+
+    /* check mipmap last_level */
+    if (surf->last_level > 15) {
+        return -EINVAL;
+    }
+
+    /* check tile split */
+    switch (surf->tile_split) {
+    case 0:
+        /* use row size so we match kernel ... i hate this */
+        switch (surf_man->hw_info.row_size) {
+        default:
+        case 1024:
+            surf->tile_split = 1024;
+            break;
+        case 2048:
+            surf->tile_split = 2048;
+            break;
+        case 4096:
+            surf->tile_split = 4096;
+            break;
+        }
+        break;
+    case 64:
+    case 128:
+    case 256:
+    case 512:
+    case 1024:
+    case 2048:
+    case 4096:
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    /* force 1d on kernel that can't do 2d */
+    if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
+        mode = RADEON_SURF_MODE_1D;
+    }
+
+    /* check tiling mode */
+    switch (mode) {
+    case RADEON_SURF_MODE_LINEAR:
+        r = r6_surface_init_linear(surf_man, surf, 0, 0);
+        break;
+    case RADEON_SURF_MODE_LINEAR_ALIGNED:
+        r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
+        break;
+    case RADEON_SURF_MODE_1D:
+        r = r6_surface_init_1d(surf_man, surf, 0, 0);
+        break;
+    case RADEON_SURF_MODE_2D:
+        r = eg_surface_init_2d(surf_man, surf, 0, 0);
+        break;
+    default:
+        return -EINVAL;
+    }
+    return r;
+}
+
+
+/* ===========================================================================
+ * public API
+ */
+struct radeon_surface_manager *radeon_surface_manager_new(int fd)
+{
+    struct radeon_surface_manager *surf_man;
+
+    surf_man = calloc(1, sizeof(struct radeon_surface_manager));
+    if (surf_man == NULL) {
+        return NULL;
+    }
+    surf_man->fd = fd;
+    if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
+        goto out_err;
+    }
+    if (radeon_get_family(surf_man)) {
+        goto out_err;
+    }
+
+    if (surf_man->family <= CHIP_RV740) {
+        if (r6_init_hw_info(surf_man)) {
+            goto out_err;
+        }
+        surf_man->surface_init = &r6_surface_init;
+    } else {
+        if (eg_init_hw_info(surf_man)) {
+            goto out_err;
+        }
+        surf_man->surface_init = &eg_surface_init;
+    }
+
+    return surf_man;
+out_err:
+    free(surf_man);
+    return NULL;
+}
+
+void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
+{
+    free(surf_man);
+}
+
+int radeon_surface_init(struct radeon_surface_manager *surf_man,
+                        struct radeon_surface *surf)
+{
+    unsigned type;
+
+    if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
+        return -EINVAL;
+    }
+
+    /* all dimension must be at least 1 ! */
+    if (!surf->npix_x || !surf->npix_y || !surf->npix_z) {
+        return -EINVAL;
+    }
+    if (!surf->nblk_x || !surf->nblk_y || !surf->nblk_z) {
+        return -EINVAL;
+    }
+    if (surf->npix_x < surf->nblk_x || surf->npix_y < surf->nblk_y || surf->npix_z < surf->nblk_z) {
+        return -EINVAL;
+    }
+    if (!surf->array_size) {
+        return -EINVAL;
+    }
+
+    switch (surf->nsamples) {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check type */
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    switch (type) {
+    case RADEON_SURF_TYPE_1D:
+        if (surf->npix_y > 1) {
+            return -EINVAL;
+        }
+    case RADEON_SURF_TYPE_2D:
+    case RADEON_SURF_TYPE_CUBEMAP:
+        if (surf->npix_z > 1) {
+            return -EINVAL;
+        }
+    case RADEON_SURF_TYPE_3D:
+        break;
+    case RADEON_SURF_TYPE_1D_ARRAY:
+        if (surf->npix_y > 1) {
+            return -EINVAL;
+        }
+    case RADEON_SURF_TYPE_2D_ARRAY:
+        break;
+    default:
+        return -EINVAL;
+    }
+    return surf_man->surface_init(surf_man, surf);
+}
diff --git a/radeon/radeon_surface.h b/radeon/radeon_surface.h
new file mode 100644
index 0000000..3fb4121
--- /dev/null
+++ b/radeon/radeon_surface.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2011 Red Hat All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
+ * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ */
+/*
+ * Authors:
+ *      Jérôme Glisse <jglisse@redhat.com>
+ */
+#ifndef RADEON_SURFACE_H
+#define RADEON_SURFACE_H
+
+/* Note :
+ *
+ * For texture array, the n layer are stored one after the other within each
+ * mipmap level. 0 value for field than can be hint is always valid.
+ */
+
+#define RADEON_SURF_MAX_LEVEL                   32
+
+#define RADEON_SURF_TYPE_MASK                   0xFF
+#define RADEON_SURF_TYPE_SHIFT                  0
+#define     RADEON_SURF_TYPE_1D                     0
+#define     RADEON_SURF_TYPE_2D                     1
+#define     RADEON_SURF_TYPE_3D                     2
+#define     RADEON_SURF_TYPE_CUBEMAP                3
+#define     RADEON_SURF_TYPE_1D_ARRAY               4
+#define     RADEON_SURF_TYPE_2D_ARRAY               5
+#define RADEON_SURF_MODE_MASK                   0xFF
+#define RADEON_SURF_MODE_SHIFT                  8
+#define     RADEON_SURF_MODE_LINEAR                 0
+#define     RADEON_SURF_MODE_LINEAR_ALIGNED         1
+#define     RADEON_SURF_MODE_1D                     2
+#define     RADEON_SURF_MODE_2D                     3
+#define RADEON_SURF_SCANOUT                     (1 << 16)
+#define RADEON_SURF_ZBUFFER                     (1 << 17)
+#define RADEON_SURF_SBUFFER                     (1 << 18)
+
+#define RADEON_SURF_GET(v, field)   (((v) >> RADEON_SURF_ ## field ## _SHIFT) & RADEON_SURF_ ## field ## _MASK)
+#define RADEON_SURF_SET(v, field)   (((v) & RADEON_SURF_ ## field ## _MASK) << RADEON_SURF_ ## field ## _SHIFT)
+#define RADEON_SURF_CLR(v, field)   ((v) & ~(RADEON_SURF_ ## field ## _MASK << RADEON_SURF_ ## field ## _SHIFT))
+
+/* first field up to mode need to match r6 struct so that we can reuse
+ * same function for linear & linear aligned
+ */
+struct radeon_surface_level {
+    uint64_t                    offset;
+    uint64_t                    slice_size;
+    uint32_t                    npix_x;
+    uint32_t                    npix_y;
+    uint32_t                    npix_z;
+    uint32_t                    nblk_x;
+    uint32_t                    nblk_y;
+    uint32_t                    nblk_z;
+    uint32_t                    pitch_bytes;
+    uint32_t                    mode;
+};
+
+struct radeon_surface {
+    uint32_t                    npix_x;
+    uint32_t                    npix_y;
+    uint32_t                    npix_z;
+    uint32_t                    nblk_x;
+    uint32_t                    nblk_y;
+    uint32_t                    nblk_z;
+    uint32_t                    array_size;
+    uint32_t                    last_level;
+    uint32_t                    bpe;
+    uint32_t                    nsamples;
+    uint32_t                    flags;
+    /* Following is updated/fill by the allocator. It's allowed to
+     * set some of the value but they are use as hint and can be
+     * overridden (things lile bank_width/height on evergreen for
+     * instance).
+     */
+    uint64_t                    bo_size;
+    uint64_t                    bo_alignment;
+    /* apply to eg */
+    uint32_t                    bank_width;
+    uint32_t                    bank_height;
+    uint32_t                    macro_tile_aspect;
+    uint32_t                    tile_split;
+    struct radeon_surface_level level[RADEON_SURF_MAX_LEVEL];
+};
+
+struct radeon_surface_manager *radeon_surface_manager_new(int fd);
+void radeon_surface_manager_free(struct radeon_surface_manager *surf_man);
+int radeon_surface_init(struct radeon_surface_manager *surf_man,
+                        struct radeon_surface *surf);
+
+#endif
-- 
1.7.7.1

