struct drm_gem_object *obj;
        struct drm_radeon_gem_object *obj_priv;
        uint64_t fb_location;
-       uint32_t fb_format, fb_pitch_pixels;
+       uint32_t fb_format, fb_pitch_pixels, tiling_flags;
 
        if (!crtc->fb)
                return -EINVAL;
                return -EINVAL;
        }
 
-       /* TODO tiling */
+       radeon_object_get_tiling_flags(obj->driver_private,
+                                      &tiling_flags, NULL);
+       if (tiling_flags & RADEON_TILING_MACRO)
+               fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
+
+       if (tiling_flags & RADEON_TILING_MICRO)
+               fb_format |= AVIVO_D1GRPH_TILED;
+
        if (radeon_crtc->crtc_id == 0)
                WREG32(AVIVO_D1VGA_CONTROL, 0);
        else
 
        unsigned idx;
        bool onereg;
        int r;
+       u32 tile_flags = 0;
 
        ib = p->ib->ptr;
        ib_chunk = &p->chunks[p->chunk_ib_idx];
                        }
                        tmp = ib_chunk->kdata[idx] & 0x003fffff;
                        tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
-                       ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp;
+
+                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                               tile_flags |= RADEON_DST_TILE_MACRO;
+                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+                               if (reg == RADEON_SRC_PITCH_OFFSET) {
+                                       DRM_ERROR("Cannot src blit from microtiled surface\n");
+                                       r100_cs_dump_packet(p, pkt);
+                                       return -EINVAL;
+                               }
+                               tile_flags |= RADEON_DST_TILE_MICRO;
+                       }
+
+                       tmp |= tile_flags;
+                       ib[idx] = (ib_chunk->kdata[idx] & 0x3fc00000) | tmp;
                        break;
                case RADEON_RB3D_DEPTHOFFSET:
                case RADEON_RB3D_COLOROFFSET:
                        }
                        ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);
                        break;
+               case R300_RB3D_COLORPITCH0:
+               case RADEON_RB3D_COLORPITCH:
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                         idx, reg);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+
+                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                               tile_flags |= RADEON_COLOR_TILE_ENABLE;
+                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                               tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
+
+                       tmp = ib_chunk->kdata[idx] & ~(0x7 << 16);
+                       tmp |= tile_flags;
+                       ib[idx] = tmp;
+                       break;
                default:
                        /* FIXME: we don't want to allow anyothers packet */
                        break;
        return 0;
 #endif
 }
+
+int r100_set_surface_reg(struct radeon_device *rdev, int reg,
+                        uint32_t tiling_flags, uint32_t pitch,
+                        uint32_t offset, uint32_t obj_size)
+{
+       int surf_index = reg * 16;
+       int flags = 0;
+
+       /* r100/r200 divide by 16 */
+       if (rdev->family < CHIP_R300)
+               flags = pitch / 16;
+       else
+               flags = pitch / 8;
+
+       if (rdev->family <= CHIP_RS200) {
+               if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO))
+                                == (RADEON_TILING_MACRO|RADEON_TILING_MICRO))
+                       flags |= RADEON_SURF_TILE_COLOR_BOTH;
+               if (tiling_flags & RADEON_TILING_MACRO)
+                       flags |= RADEON_SURF_TILE_COLOR_MACRO;
+       } else if (rdev->family <= CHIP_RV280) {
+               if (tiling_flags & (RADEON_TILING_MACRO))
+                       flags |= R200_SURF_TILE_COLOR_MACRO;
+               if (tiling_flags & RADEON_TILING_MICRO)
+                       flags |= R200_SURF_TILE_COLOR_MICRO;
+       } else {
+               if (tiling_flags & RADEON_TILING_MACRO)
+                       flags |= R300_SURF_TILE_MACRO;
+               if (tiling_flags & RADEON_TILING_MICRO)
+                       flags |= R300_SURF_TILE_MICRO;
+       }
+
+       DRM_DEBUG("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1);
+       WREG32(RADEON_SURFACE0_INFO + surf_index, flags);
+       WREG32(RADEON_SURFACE0_LOWER_BOUND + surf_index, offset);
+       WREG32(RADEON_SURFACE0_UPPER_BOUND + surf_index, offset + obj_size - 1);
+       return 0;
+}
+
+void r100_clear_surface_reg(struct radeon_device *rdev, int reg)
+{
+       int surf_index = reg * 16;
+       WREG32(RADEON_SURFACE0_INFO + surf_index, 0);
+}
 
 #include "drm.h"
 #include "radeon_reg.h"
 #include "radeon.h"
+#include "radeon_drm.h"
 
 /* r300,r350,rv350,rv370,rv380 depends on : */
 void r100_hdp_reset(struct radeon_device *rdev);
        struct radeon_cs_reloc *reloc;
        struct r300_cs_track *track;
        volatile uint32_t *ib;
-       uint32_t tmp;
+       uint32_t tmp, tile_flags = 0;
        unsigned i;
        int r;
 
                }
                tmp = ib_chunk->kdata[idx] & 0x003fffff;
                tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
-               ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp;
+
+               if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       tile_flags |= RADEON_DST_TILE_MACRO;
+               if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+                       if (reg == RADEON_SRC_PITCH_OFFSET) {
+                               DRM_ERROR("Cannot src blit from microtiled surface\n");
+                               r100_cs_dump_packet(p, pkt);
+                               return -EINVAL;
+                       }
+                       tile_flags |= RADEON_DST_TILE_MICRO;
+               }
+               tmp |= tile_flags;
+               ib[idx] = (ib_chunk->kdata[idx] & 0x3fc00000) | tmp;
                break;
        case R300_RB3D_COLOROFFSET0:
        case R300_RB3D_COLOROFFSET1:
                /* RB3D_COLORPITCH1 */
                /* RB3D_COLORPITCH2 */
                /* RB3D_COLORPITCH3 */
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                 idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+
+               if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       tile_flags |= R300_COLOR_TILE_ENABLE;
+               if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       tile_flags |= R300_COLOR_MICROTILE_ENABLE;
+
+               tmp = ib_chunk->kdata[idx] & ~(0x7 << 16);
+               tmp |= tile_flags;
+               ib[idx] = tmp;
+
                i = (reg - 0x4E38) >> 2;
                track->cb[i].pitch = ib_chunk->kdata[idx] & 0x3FFE;
                switch (((ib_chunk->kdata[idx] >> 21) & 0xF)) {
                break;
        case 0x4F24:
                /* ZB_DEPTHPITCH */
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                 idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+
+               if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       tile_flags |= R300_DEPTHMACROTILE_ENABLE;
+               if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       tile_flags |= R300_DEPTHMICROTILE_TILED;;
+
+               tmp = ib_chunk->kdata[idx] & ~(0x7 << 16);
+               tmp |= tile_flags;
+               ib[idx] = tmp;
+
                track->zb.pitch = ib_chunk->kdata[idx] & 0x3FFC;
                break;
        case 0x4104:
 
 #ifndef _R300_REG_H_
 #define _R300_REG_H_
 
-
+#define R300_SURF_TILE_MACRO (1<<16)
+#define R300_SURF_TILE_MICRO (2<<16)
+#define R300_SURF_TILE_BOTH (3<<16)
 
 
 #define R300_MC_INIT_MISC_LAT_TIMER    0x180
 
 struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);
 void radeon_fence_unref(struct radeon_fence **fence);
 
+/*
+ * Tiling registers
+ */
+struct radeon_surface_reg {
+       struct radeon_object *robj;
+};
+
+#define RADEON_GEM_MAX_SURFACES 8
 
 /*
  * Radeon buffer.
        uint64_t                gpu_offset;
        unsigned                rdomain;
        unsigned                wdomain;
+       uint32_t                tiling_flags;
 };
 
 int radeon_object_init(struct radeon_device *rdev);
 int radeon_object_fbdev_mmap(struct radeon_object *robj,
                             struct vm_area_struct *vma);
 unsigned long radeon_object_size(struct radeon_object *robj);
-
-
+void radeon_object_clear_surface_reg(struct radeon_object *robj);
+int radeon_object_check_tiling(struct radeon_object *robj, bool has_moved,
+                              bool force_drop);
+void radeon_object_set_tiling_flags(struct radeon_object *robj,
+                                   uint32_t tiling_flags, uint32_t pitch);
+void radeon_object_get_tiling_flags(struct radeon_object *robj, uint32_t *tiling_flags, uint32_t *pitch);
+void radeon_bo_move_notify(struct ttm_buffer_object *bo,
+                          struct ttm_mem_reg *mem);
+void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
 /*
  * GEM objects.
  */
        void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
        void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
        void (*set_clock_gating)(struct radeon_device *rdev, int enable);
+
+       int (*set_surface_reg)(struct radeon_device *rdev, int reg,
+                              uint32_t tiling_flags, uint32_t pitch,
+                              uint32_t offset, uint32_t obj_size);
+       int (*clear_surface_reg)(struct radeon_device *rdev, int reg);
 };
 
 union radeon_asic_config {
 int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *filp);
 int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
+int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *filp);
+int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *filp);
 
 
 /*
        bool                            shutdown;
        bool                            suspend;
        bool                            need_dma32;
+       struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];
 };
 
 int radeon_device_init(struct radeon_device *rdev,
 #define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
 #define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))
 #define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e))
+#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s)))
+#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->clear_surface_reg((rdev), (r)))
 
 #endif
 
                   uint64_t dst_offset,
                   unsigned num_pages,
                   struct radeon_fence *fence);
+int r100_set_surface_reg(struct radeon_device *rdev, int reg,
+                        uint32_t tiling_flags, uint32_t pitch,
+                        uint32_t offset, uint32_t obj_size);
+int r100_clear_surface_reg(struct radeon_device *rdev, int reg);
 
 static struct radeon_asic r100_asic = {
        .init = &r100_init,
        .set_memory_clock = NULL,
        .set_pcie_lanes = NULL,
        .set_clock_gating = &radeon_legacy_set_clock_gating,
+       .set_surface_reg = r100_set_surface_reg,
+       .clear_surface_reg = r100_clear_surface_reg,
 };
 
 
                  uint64_t dst_offset,
                  unsigned num_pages,
                  struct radeon_fence *fence);
+
 static struct radeon_asic r300_asic = {
        .init = &r300_init,
        .errata = &r300_errata,
        .set_memory_clock = NULL,
        .set_pcie_lanes = &rv370_set_pcie_lanes,
        .set_clock_gating = &radeon_legacy_set_clock_gating,
+       .set_surface_reg = r100_set_surface_reg,
+       .clear_surface_reg = r100_clear_surface_reg,
 };
 
 /*
        .set_memory_clock = &radeon_atom_set_memory_clock,
        .set_pcie_lanes = &rv370_set_pcie_lanes,
        .set_clock_gating = &radeon_atom_set_clock_gating,
+       .set_surface_reg = r100_set_surface_reg,
+       .clear_surface_reg = r100_clear_surface_reg,
 };
 
 
        .set_memory_clock = NULL,
        .set_pcie_lanes = NULL,
        .set_clock_gating = &radeon_legacy_set_clock_gating,
+       .set_surface_reg = r100_set_surface_reg,
+       .clear_surface_reg = r100_clear_surface_reg,
 };
 
 
        .set_memory_clock = &radeon_atom_set_memory_clock,
        .set_pcie_lanes = NULL,
        .set_clock_gating = &radeon_atom_set_clock_gating,
+       .set_surface_reg = r100_set_surface_reg,
+       .clear_surface_reg = r100_clear_surface_reg,
 };
 
 
        .set_memory_clock = &radeon_atom_set_memory_clock,
        .set_pcie_lanes = &rv370_set_pcie_lanes,
        .set_clock_gating = &radeon_atom_set_clock_gating,
+       .set_surface_reg = r100_set_surface_reg,
+       .clear_surface_reg = r100_clear_surface_reg,
 };
 
 
        .set_memory_clock = &radeon_atom_set_memory_clock,
        .set_pcie_lanes = &rv370_set_pcie_lanes,
        .set_clock_gating = &radeon_atom_set_clock_gating,
+       .set_surface_reg = r100_set_surface_reg,
+       .clear_surface_reg = r100_clear_surface_reg,
 };
 
 /*
 
                               i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO),
                               0);
                }
+               /* enable surfaces */
+               WREG32(RADEON_SURFACE_CNTL, 0);
        }
 }
 
 
        .notifier_call = radeonfb_panic,
 };
 
-static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp)
+static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
 {
        int aligned = width;
-       int align_large = (ASIC_IS_AVIVO(rdev));
+       int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
        int pitch_mask = 0;
 
        switch (bpp / 8) {
        u64 fb_gpuaddr;
        void *fbptr = NULL;
        unsigned long tmp;
+       bool fb_tiled = false; /* useful for testing */
 
        mode_cmd.width = surface_width;
        mode_cmd.height = surface_height;
        mode_cmd.bpp = 32;
        /* need to align pitch with crtc limits */
-       mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8);
+       mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
        mode_cmd.depth = 24;
 
        size = mode_cmd.pitch * mode_cmd.height;
        }
        robj = gobj->driver_private;
 
+       if (fb_tiled)
+               radeon_object_set_tiling_flags(robj, RADEON_TILING_MACRO|RADEON_TILING_SURFACE, mode_cmd.pitch);
        mutex_lock(&rdev->ddev->struct_mutex);
        fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
        if (fb == NULL) {
        }
        rfbdev = info->par;
 
+       if (fb_tiled)
+               radeon_object_check_tiling(robj, 0, 0);
+
        ret = radeon_object_kmap(robj, &fbptr);
        if (ret) {
                goto out_unref;
 
        mutex_unlock(&dev->struct_mutex);
        return r;
 }
+
+int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *filp)
+{
+       struct drm_radeon_gem_set_tiling *args = data;
+       struct drm_gem_object *gobj;
+       struct radeon_object *robj;
+       int r = 0;
+
+       DRM_DEBUG("%d \n", args->handle);
+       gobj = drm_gem_object_lookup(dev, filp, args->handle);
+       if (gobj == NULL)
+               return -EINVAL;
+       robj = gobj->driver_private;
+       radeon_object_set_tiling_flags(robj, args->tiling_flags, args->pitch);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(gobj);
+       mutex_unlock(&dev->struct_mutex);
+       return r;
+}
+
+int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *filp)
+{
+       struct drm_radeon_gem_get_tiling *args = data;
+       struct drm_gem_object *gobj;
+       struct radeon_object *robj;
+       int r = 0;
+
+       DRM_DEBUG("\n");
+       gobj = drm_gem_object_lookup(dev, filp, args->handle);
+       if (gobj == NULL)
+               return -EINVAL;
+       robj = gobj->driver_private;
+       radeon_object_get_tiling_flags(robj, &args->tiling_flags,
+                                      &args->pitch);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(gobj);
+       mutex_unlock(&dev->struct_mutex);
+       return r;
+}
 
        DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH),
 };
 int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms);
 
        uint64_t base;
        uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;
        uint32_t crtc_pitch, pitch_pixels;
+       uint32_t tiling_flags;
 
        DRM_DEBUG("\n");
 
                       (crtc->fb->bits_per_pixel * 8));
        crtc_pitch |= crtc_pitch << 16;
 
-       /* TODO tiling */
-       if (0) {
+       radeon_object_get_tiling_flags(obj->driver_private,
+                                      &tiling_flags, NULL);
+       if (tiling_flags & RADEON_TILING_MICRO)
+               DRM_ERROR("trying to scanout microtiled buffer\n");
+
+       if (tiling_flags & RADEON_TILING_MACRO) {
                if (ASIC_IS_R300(rdev))
                        crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
                                             R300_CRTC_MICRO_TILE_BUFFER_DIS |
                        crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
        }
 
-
-       /* TODO more tiling */
-       if (0) {
+       if (tiling_flags & RADEON_TILING_MACRO) {
                if (ASIC_IS_R300(rdev)) {
                        crtc_tile_x0_y0 = x | (y << 16);
                        base &= ~0x7ff;
                } else {
                        int byteshift = crtc->fb->bits_per_pixel >> 4;
-                       int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11;
+                       int tile_addr = (((y >> 3) * pitch_pixels +  x) >> (8 - byteshift)) << 11;
                        base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
                        crtc_offset_cntl |= (y % 16);
                }
 
        uint64_t                        gpu_addr;
        void                            *kptr;
        bool                            is_iomem;
+       uint32_t                        tiling_flags;
+       uint32_t                        pitch;
+       int                             surface_reg;
 };
 
 int radeon_ttm_init(struct radeon_device *rdev);
 
        robj = container_of(tobj, struct radeon_object, tobj);
        list_del_init(&robj->list);
+       radeon_object_clear_surface_reg(robj);
        kfree(robj);
 }
 
        }
        robj->rdev = rdev;
        robj->gobj = gobj;
+       robj->surface_reg = -1;
        INIT_LIST_HEAD(&robj->list);
 
        flags = radeon_object_flags_from_domain(domain);
                        radeon_object_gpu_addr(robj);
                }
                lobj->gpu_offset = robj->gpu_addr;
+               lobj->tiling_flags = robj->tiling_flags;
                if (fence) {
                        old_fence = (struct radeon_fence *)robj->tobj.sync_obj;
                        robj->tobj.sync_obj = radeon_fence_ref(fence);
 {
        return robj->tobj.num_pages << PAGE_SHIFT;
 }
+
+int radeon_object_get_surface_reg(struct radeon_object *robj)
+{
+       struct radeon_device *rdev = robj->rdev;
+       struct radeon_surface_reg *reg;
+       struct radeon_object *old_object;
+       int steal;
+       int i;
+
+       if (!robj->tiling_flags)
+               return 0;
+
+       if (robj->surface_reg >= 0) {
+               reg = &rdev->surface_regs[robj->surface_reg];
+               i = robj->surface_reg;
+               goto out;
+       }
+
+       steal = -1;
+       for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) {
+
+               reg = &rdev->surface_regs[i];
+               if (!reg->robj)
+                       break;
+
+               old_object = reg->robj;
+               if (old_object->pin_count == 0)
+                       steal = i;
+       }
+
+       /* if we are all out */
+       if (i == RADEON_GEM_MAX_SURFACES) {
+               if (steal == -1)
+                       return -ENOMEM;
+               /* find someone with a surface reg and nuke their BO */
+               reg = &rdev->surface_regs[steal];
+               old_object = reg->robj;
+               /* blow away the mapping */
+               DRM_DEBUG("stealing surface reg %d from %p\n", steal, old_object);
+               ttm_bo_unmap_virtual(&old_object->tobj);
+               old_object->surface_reg = -1;
+               i = steal;
+       }
+
+       robj->surface_reg = i;
+       reg->robj = robj;
+
+out:
+       radeon_set_surface_reg(rdev, i, robj->tiling_flags, robj->pitch,
+                              robj->tobj.mem.mm_node->start << PAGE_SHIFT,
+                              robj->tobj.num_pages << PAGE_SHIFT);
+       return 0;
+}
+
+void radeon_object_clear_surface_reg(struct radeon_object *robj)
+{
+       struct radeon_device *rdev = robj->rdev;
+       struct radeon_surface_reg *reg;
+
+       if (robj->surface_reg == -1)
+               return;
+
+       reg = &rdev->surface_regs[robj->surface_reg];
+       radeon_clear_surface_reg(rdev, robj->surface_reg);
+
+       reg->robj = NULL;
+       robj->surface_reg = -1;
+}
+
+void radeon_object_set_tiling_flags(struct radeon_object *robj,
+                                   uint32_t tiling_flags, uint32_t pitch)
+{
+       robj->tiling_flags = tiling_flags;
+       robj->pitch = pitch;
+}
+
+void radeon_object_get_tiling_flags(struct radeon_object *robj,
+                                   uint32_t *tiling_flags,
+                                   uint32_t *pitch)
+{
+       if (tiling_flags)
+               *tiling_flags = robj->tiling_flags;
+       if (pitch)
+               *pitch = robj->pitch;
+}
+
+int radeon_object_check_tiling(struct radeon_object *robj, bool has_moved,
+                              bool force_drop)
+{
+       if (!(robj->tiling_flags & RADEON_TILING_SURFACE))
+               return 0;
+
+       if (force_drop) {
+               radeon_object_clear_surface_reg(robj);
+               return 0;
+       }
+
+       if (robj->tobj.mem.mem_type != TTM_PL_VRAM) {
+               if (!has_moved)
+                       return 0;
+
+               if (robj->surface_reg >= 0)
+                       radeon_object_clear_surface_reg(robj);
+               return 0;
+       }
+
+       if ((robj->surface_reg >= 0) && !has_moved)
+               return 0;
+
+       return radeon_object_get_surface_reg(robj);
+}
+
+void radeon_bo_move_notify(struct ttm_buffer_object *bo,
+                         struct ttm_mem_reg *mem)
+{
+       struct radeon_object *robj = container_of(bo, struct radeon_object, tobj);
+       radeon_object_check_tiling(robj, 0, 1);
+}
+
+void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
+{
+       struct radeon_object *robj = container_of(bo, struct radeon_object, tobj);
+       radeon_object_check_tiling(robj, 0, 0);
+}
 
        .sync_obj_flush = &radeon_sync_obj_flush,
        .sync_obj_unref = &radeon_sync_obj_unref,
        .sync_obj_ref = &radeon_sync_obj_ref,
+       .move_notify = &radeon_bo_move_notify,
+       .fault_reserve_notify = &radeon_bo_fault_reserve_notify,
 };
 
 int radeon_ttm_init(struct radeon_device *rdev)
 
 #define TTM_BO_HASH_ORDER 13
 
 static int ttm_bo_setup_vm(struct ttm_buffer_object *bo);
-static void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);
 static int ttm_bo_swapout(struct ttm_mem_shrink *shrink);
 
 static inline uint32_t ttm_bo_type_flags(unsigned type)
 
        }
 
+       if (bdev->driver->move_notify)
+               bdev->driver->move_notify(bo, mem);
+
        if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
            !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
                ret = ttm_bo_move_ttm(bo, evict, no_wait, mem);
 
        unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1);
 }
+EXPORT_SYMBOL(ttm_bo_unmap_virtual);
 
 static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo)
 {
 
                return VM_FAULT_NOPAGE;
        }
 
+       if (bdev->driver->fault_reserve_notify)
+               bdev->driver->fault_reserve_notify(bo);
+
        /*
         * Wait for buffer data in transit, due to a pipelined
         * move.
 
 #define DRM_RADEON_GEM_WAIT_IDLE       0x24
 #define DRM_RADEON_CS                  0x26
 #define DRM_RADEON_INFO                        0x27
+#define DRM_RADEON_GEM_SET_TILING      0x28
+#define DRM_RADEON_GEM_GET_TILING      0x29
 
 #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
 #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
 #define DRM_IOCTL_RADEON_GEM_WAIT_IDLE DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_IDLE, struct drm_radeon_gem_wait_idle)
 #define DRM_IOCTL_RADEON_CS            DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs)
 #define DRM_IOCTL_RADEON_INFO          DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INFO, struct drm_radeon_info)
-
+#define DRM_IOCTL_RADEON_SET_TILING    DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_TILING, struct drm_radeon_gem_set_tiling)
+#define DRM_IOCTL_RADEON_GET_TILING    DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling)
 
 typedef struct drm_radeon_init {
        enum {
        uint32_t        flags;
 };
 
+#define RADEON_TILING_MACRO 0x1
+#define RADEON_TILING_MICRO 0x2
+#define RADEON_TILING_SWAP  0x4
+#define RADEON_TILING_SURFACE  0x8 /* this object requires a surface
+                                   * when mapped - i.e. front buffer */
+
+struct drm_radeon_gem_set_tiling {
+       uint32_t        handle;
+       uint32_t        tiling_flags;
+       uint32_t        pitch;
+};
+
+struct drm_radeon_gem_get_tiling {
+       uint32_t        handle;
+       uint32_t        tiling_flags;
+       uint32_t        pitch;
+};
+
 struct drm_radeon_gem_mmap {
        uint32_t        handle;
        uint32_t        pad;
 
        int (*sync_obj_flush) (void *sync_obj, void *sync_arg);
        void (*sync_obj_unref) (void **sync_obj);
        void *(*sync_obj_ref) (void *sync_obj);
+
+       /* hook to notify driver about a driver move so it
+        * can do tiling things */
+       void (*move_notify)(struct ttm_buffer_object *bo,
+                           struct ttm_mem_reg *new_mem);
+       /* notify the driver we are taking a fault on this BO
+        * and have reserved it */
+       void (*fault_reserve_notify)(struct ttm_buffer_object *bo);
 };
 
 #define TTM_NUM_MEM_TYPES 8
                              struct ttm_bo_driver *driver,
                              uint64_t file_page_offset, bool need_dma32);
 
+/**
+ * ttm_bo_unmap_virtual
+ *
+ * @bo: tear down the virtual mappings for this BO
+ */
+extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);
+
 /**
  * ttm_bo_reserve:
  *