linux/drivers/gpu/drm/nouveau/nv10_fb.c
<<
>>
Prefs
   1#include "drmP.h"
   2#include "drm.h"
   3#include "nouveau_drv.h"
   4#include "nouveau_drm.h"
   5
   6static struct drm_mm_node *
   7nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size)
   8{
   9        struct drm_nouveau_private *dev_priv = dev->dev_private;
  10        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
  11        struct drm_mm_node *mem;
  12        int ret;
  13
  14        ret = drm_mm_pre_get(&pfb->tag_heap);
  15        if (ret)
  16                return NULL;
  17
  18        spin_lock(&dev_priv->tile.lock);
  19        mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0);
  20        if (mem)
  21                mem = drm_mm_get_block_atomic(mem, size, 0);
  22        spin_unlock(&dev_priv->tile.lock);
  23
  24        return mem;
  25}
  26
  27static void
  28nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node *mem)
  29{
  30        struct drm_nouveau_private *dev_priv = dev->dev_private;
  31
  32        spin_lock(&dev_priv->tile.lock);
  33        drm_mm_put_block(mem);
  34        spin_unlock(&dev_priv->tile.lock);
  35}
  36
  37void
  38nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
  39                         uint32_t size, uint32_t pitch, uint32_t flags)
  40{
  41        struct drm_nouveau_private *dev_priv = dev->dev_private;
  42        struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
  43        int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16);
  44
  45        tile->addr = addr;
  46        tile->limit = max(1u, addr + size) - 1;
  47        tile->pitch = pitch;
  48
  49        if (dev_priv->card_type == NV_20) {
  50                if (flags & NOUVEAU_GEM_TILE_ZETA) {
  51                        /*
  52                         * Allocate some of the on-die tag memory,
  53                         * used to store Z compression meta-data (most
  54                         * likely just a bitmap determining if a given
  55                         * tile is compressed or not).
  56                         */
  57                        tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256);
  58
  59                        if (tile->tag_mem) {
  60                                /* Enable Z compression */
  61                                if (dev_priv->chipset >= 0x25)
  62                                        tile->zcomp = tile->tag_mem->start |
  63                                                (bpp == 16 ?
  64                                                 NV25_PFB_ZCOMP_MODE_16 :
  65                                                 NV25_PFB_ZCOMP_MODE_32);
  66                                else
  67                                        tile->zcomp = tile->tag_mem->start |
  68                                                NV20_PFB_ZCOMP_EN |
  69                                                (bpp == 16 ? 0 :
  70                                                 NV20_PFB_ZCOMP_MODE_32);
  71                        }
  72
  73                        tile->addr |= 3;
  74                } else {
  75                        tile->addr |= 1;
  76                }
  77
  78        } else {
  79                tile->addr |= 1 << 31;
  80        }
  81}
  82
  83void
  84nv10_fb_free_tile_region(struct drm_device *dev, int i)
  85{
  86        struct drm_nouveau_private *dev_priv = dev->dev_private;
  87        struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
  88
  89        if (tile->tag_mem) {
  90                nv20_fb_free_tag(dev, tile->tag_mem);
  91                tile->tag_mem = NULL;
  92        }
  93
  94        tile->addr = tile->limit = tile->pitch = tile->zcomp = 0;
  95}
  96
  97void
  98nv10_fb_set_tile_region(struct drm_device *dev, int i)
  99{
 100        struct drm_nouveau_private *dev_priv = dev->dev_private;
 101        struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
 102
 103        nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
 104        nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
 105        nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
 106
 107        if (dev_priv->card_type == NV_20)
 108                nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp);
 109}
 110
 111int
 112nv10_fb_init(struct drm_device *dev)
 113{
 114        struct drm_nouveau_private *dev_priv = dev->dev_private;
 115        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
 116        int i;
 117
 118        pfb->num_tiles = NV10_PFB_TILE__SIZE;
 119
 120        if (dev_priv->card_type == NV_20)
 121                drm_mm_init(&pfb->tag_heap, 0,
 122                            (dev_priv->chipset >= 0x25 ?
 123                             64 * 1024 : 32 * 1024));
 124
 125        /* Turn all the tiling regions off. */
 126        for (i = 0; i < pfb->num_tiles; i++)
 127                pfb->set_tile_region(dev, i);
 128
 129        return 0;
 130}
 131
 132void
 133nv10_fb_takedown(struct drm_device *dev)
 134{
 135        struct drm_nouveau_private *dev_priv = dev->dev_private;
 136        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
 137        int i;
 138
 139        for (i = 0; i < pfb->num_tiles; i++)
 140                pfb->free_tile_region(dev, i);
 141
 142        if (dev_priv->card_type == NV_20)
 143                drm_mm_takedown(&pfb->tag_heap);
 144}
 145