drm/radeon/kms: add initial colortiling support.
authorDave Airlie <airlied@redhat.com>
Tue, 23 Jun 2009 23:48:08 +0000 (09:48 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 29 Jul 2009 05:42:18 +0000 (15:42 +1000)
This adds new set/get tiling interfaces where the pitch
and macro/micro tiling enables can be set. Along with
a flag to decide if this object should have a surface when mapped.

The only thing we need to allocate with a mapped surface should be
the frontbuffer. Note rotate scanout shouldn't require one, and
back/depth shouldn't either, though mesa needs some fixes.

It fixes the TTM interfaces along Thomas's suggestions, and I've tested
the surface stealing code with two X servers and not seen any lockdep issues.

I've stopped tiling the fbcon frontbuffer, as I don't see there being
any advantage other than testing, I've left the testing commands in there,
just flip the fb_tiled to true in radeon_fb.c

Open: Can we integrate endian swapping in with this?

Future features:
texture tiling - need to relocate texture registers TXOFFSET* with tiling info.

This also merges Michel's cleanup surfaces regs at init time patch
even though it makes sense on its own, this patch really relies on it.

Some PowerMac firmwares set up a tiling surface at the beginning of VRAM
which messes us up otherwise.
that patch is:
Signed-off-by: Michel Dänzer <daenzer@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
17 files changed:
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r300_reg.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
include/drm/radeon_drm.h
include/drm/ttm/ttm_bo_driver.h

index e64a199b5ee1c7b62ae81ad8a8e7d23bf2deb9c8..eac26cdb5dae051495356fbee87fa59b3c643a6c 100644 (file)
@@ -327,7 +327,7 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        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;
@@ -364,7 +364,14 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                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
index 0d05909f03f655bdb8cf8412bac5d9d963c3885f..69bd7cb5997272c357e704c14b60538eac6403b1 100644 (file)
@@ -909,6 +909,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
        unsigned idx;
        bool onereg;
        int r;
+       u32 tile_flags = 0;
 
        ib = p->ib->ptr;
        ib_chunk = &p->chunks[p->chunk_ib_idx];
@@ -942,7 +943,20 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        }
                        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:
@@ -987,6 +1001,25 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        }
                        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;
@@ -1707,3 +1740,47 @@ int r100_debugfs_mc_info_init(struct radeon_device *rdev)
        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);
+}
index 0e0e094da50308b2c31f2501ff3a1e7dd9e0a28e..28e5777658be771c69041658fd83d64737c7d8ee 100644 (file)
@@ -30,6 +30,7 @@
 #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);
@@ -1023,7 +1024,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        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;
 
@@ -1052,7 +1053,19 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                }
                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:
@@ -1141,6 +1154,23 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                /* 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)) {
@@ -1196,6 +1226,23 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                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:
index 70f48609515e2c1c69b19e83a7cc5ce6595399f9..4b7afef35a655511a2431682bd77e24fe37838b4 100644 (file)
@@ -27,7 +27,9 @@
 #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
index 7f007185e7f728b1061a337caa8873e5852cff02..af12a2fe3221978f98cbe167d9b4e0bb1f52bbe5 100644 (file)
@@ -201,6 +201,14 @@ int radeon_fence_wait_last(struct radeon_device *rdev);
 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.
@@ -213,6 +221,7 @@ struct radeon_object_list {
        uint64_t                gpu_offset;
        unsigned                rdomain;
        unsigned                wdomain;
+       uint32_t                tiling_flags;
 };
 
 int radeon_object_init(struct radeon_device *rdev);
@@ -242,8 +251,15 @@ void radeon_object_list_clean(struct list_head *head);
 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.
  */
@@ -535,6 +551,11 @@ struct radeon_asic {
        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 {
@@ -568,6 +589,10 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
 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);
 
 
 /*
@@ -627,6 +652,7 @@ struct radeon_device {
        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,
@@ -801,5 +827,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
 #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
index e2e567395df887fe19f85a3cea9b5ebf5cd81423..dd903d3294062989d604c7c1ebe864fab75a38c9 100644 (file)
@@ -71,6 +71,10 @@ int r100_copy_blit(struct radeon_device *rdev,
                   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,
@@ -100,6 +104,8 @@ static struct radeon_asic r100_asic = {
        .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,
 };
 
 
@@ -128,6 +134,7 @@ int r300_copy_dma(struct radeon_device *rdev,
                  uint64_t dst_offset,
                  unsigned num_pages,
                  struct radeon_fence *fence);
+
 static struct radeon_asic r300_asic = {
        .init = &r300_init,
        .errata = &r300_errata,
@@ -156,6 +163,8 @@ static struct radeon_asic r300_asic = {
        .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,
 };
 
 /*
@@ -193,6 +202,8 @@ static struct radeon_asic r420_asic = {
        .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,
 };
 
 
@@ -237,6 +248,8 @@ static struct radeon_asic rs400_asic = {
        .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,
 };
 
 
@@ -322,6 +335,8 @@ static struct radeon_asic rs690_asic = {
        .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,
 };
 
 
@@ -367,6 +382,8 @@ static struct radeon_asic rv515_asic = {
        .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,
 };
 
 
@@ -405,6 +422,8 @@ static struct radeon_asic r520_asic = {
        .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,
 };
 
 /*
index cdef6eb01baf096adadea61915c6dfa60888d881..f23083bbba3f6ac403d15a6889699c240937d02f 100644 (file)
@@ -48,6 +48,8 @@ static void radeon_surface_init(struct radeon_device *rdev)
                               i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO),
                               0);
                }
+               /* enable surfaces */
+               WREG32(RADEON_SURFACE_CNTL, 0);
        }
 }
 
index 260870a29d83d10d484448a50c839989d6f821c0..36d2f5588f20c748103985ef2537d989c847fab3 100644 (file)
@@ -471,10 +471,10 @@ static struct notifier_block paniced = {
        .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) {
@@ -512,12 +512,13 @@ int radeonfb_create(struct radeon_device *rdev,
        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;
@@ -535,6 +536,8 @@ int radeonfb_create(struct radeon_device *rdev,
        }
        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) {
@@ -563,6 +566,9 @@ int radeonfb_create(struct radeon_device *rdev,
        }
        rfbdev = info->par;
 
+       if (fb_tiled)
+               radeon_object_check_tiling(robj, 0, 0);
+
        ret = radeon_object_kmap(robj, &fbptr);
        if (ret) {
                goto out_unref;
index eb516034235deec6332c00f0f543e0e538fe791b..12542087b298a88de79826fdc58ed9aa082f8c57 100644 (file)
@@ -285,3 +285,44 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
        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;
+}
index 4612a7c146d18d380ba3a1b544e343c25a53a62e..937a2f1cdb46997e1e7397cb74d932005dc6df14 100644 (file)
@@ -291,5 +291,7 @@ struct drm_ioctl_desc radeon_ioctls_kms[] = {
        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);
index 14c1a5107fc92ab5f4f28acba56e78d579108be8..0613790e2a5b961af795138727c01b6d5d50da33 100644 (file)
@@ -235,6 +235,7 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        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");
 
@@ -258,8 +259,12 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                       (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 |
@@ -275,15 +280,13 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                        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);
                }
index bac0d06c52ace7a48841d351d6978e3452d634a3..d5b1fd562d88c6a5eec3090ee738e78036cedbc1 100644 (file)
@@ -44,6 +44,9 @@ struct radeon_object {
        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);
@@ -70,6 +73,7 @@ static void radeon_ttm_object_object_destroy(struct ttm_buffer_object *tobj)
 
        robj = container_of(tobj, struct radeon_object, tobj);
        list_del_init(&robj->list);
+       radeon_object_clear_surface_reg(robj);
        kfree(robj);
 }
 
@@ -141,6 +145,7 @@ int radeon_object_create(struct radeon_device *rdev,
        }
        robj->rdev = rdev;
        robj->gobj = gobj;
+       robj->surface_reg = -1;
        INIT_LIST_HEAD(&robj->list);
 
        flags = radeon_object_flags_from_domain(domain);
@@ -435,6 +440,7 @@ int radeon_object_list_validate(struct list_head *head, void *fence)
                        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);
@@ -479,3 +485,127 @@ unsigned long radeon_object_size(struct radeon_object *robj)
 {
        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);
+}
index 4ca9aa9203d0fb74b533851e0228d4c5f7c67114..37e1cbcce3a90a049a0781f35d186e3b45ea0d98 100644 (file)
@@ -429,6 +429,8 @@ static struct ttm_bo_driver radeon_bo_driver = {
        .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)
index e55e7972c8979753d4b6062d813ea5924cba6588..6538d42369891fcccb1fed21b436ecd7f1c6773c 100644 (file)
@@ -43,7 +43,6 @@
 #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)
@@ -307,6 +306,9 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
 
        }
 
+       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);
@@ -1451,6 +1453,7 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
 
        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)
 {
index 40b75032ea47459a43b5de71d8801c84e201180b..41c907f6c560819b7a1ba651c64334cb4014e025 100644 (file)
@@ -101,6 +101,9 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                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.
index 41862e9a4c2097bd2cae6e6a90d33b50fe8f751f..af4b4826997e0b9f25812350bc166e073ccdeec6 100644 (file)
@@ -506,6 +506,8 @@ typedef struct {
 #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)
@@ -544,7 +546,8 @@ typedef struct {
 #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 {
@@ -796,6 +799,24 @@ struct drm_radeon_gem_create {
        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;
index ea83dd23a4d71b4ec4ca12d8eca0a675057fce2d..a68829db381aea2543bace257b14b4eefee3c1a8 100644 (file)
@@ -354,6 +354,14 @@ struct ttm_bo_driver {
        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
@@ -653,6 +661,13 @@ extern int ttm_bo_device_init(struct ttm_bo_device *bdev,
                              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:
  *