linux/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012 Red Hat Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: Ben Skeggs
  23 */
  24
  25#include <subdev/fb.h>
  26
  27#include "nv04.h"
  28
  29static int
  30nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
  31                  struct nouveau_oclass *oclass, void *data, u32 size,
  32                  struct nouveau_object **pobject)
  33{
  34        struct nv04_instmem_priv *priv = (void *)engine;
  35        struct nv04_instobj_priv *node;
  36        int ret, align;
  37
  38        align = (unsigned long)data;
  39        if (!align)
  40                align = 1;
  41
  42        ret = nouveau_instobj_create(parent, engine, oclass, &node);
  43        *pobject = nv_object(node);
  44        if (ret)
  45                return ret;
  46
  47        ret = nouveau_mm_head(&priv->heap, 1, size, size, align, &node->mem);
  48        if (ret)
  49                return ret;
  50
  51        node->base.addr = node->mem->offset;
  52        node->base.size = node->mem->length;
  53        return 0;
  54}
  55
  56static void
  57nv04_instobj_dtor(struct nouveau_object *object)
  58{
  59        struct nv04_instmem_priv *priv = (void *)object->engine;
  60        struct nv04_instobj_priv *node = (void *)object;
  61        nouveau_mm_free(&priv->heap, &node->mem);
  62        nouveau_instobj_destroy(&node->base);
  63}
  64
  65static u32
  66nv04_instobj_rd32(struct nouveau_object *object, u32 addr)
  67{
  68        struct nv04_instobj_priv *node = (void *)object;
  69        return nv_ro32(object->engine, node->mem->offset + addr);
  70}
  71
  72static void
  73nv04_instobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
  74{
  75        struct nv04_instobj_priv *node = (void *)object;
  76        nv_wo32(object->engine, node->mem->offset + addr, data);
  77}
  78
  79static struct nouveau_oclass
  80nv04_instobj_oclass = {
  81        .ofuncs = &(struct nouveau_ofuncs) {
  82                .ctor = nv04_instobj_ctor,
  83                .dtor = nv04_instobj_dtor,
  84                .init = _nouveau_instobj_init,
  85                .fini = _nouveau_instobj_fini,
  86                .rd32 = nv04_instobj_rd32,
  87                .wr32 = nv04_instobj_wr32,
  88        },
  89};
  90
  91int
  92nv04_instmem_alloc(struct nouveau_instmem *imem, struct nouveau_object *parent,
  93                   u32 size, u32 align, struct nouveau_object **pobject)
  94{
  95        struct nouveau_object *engine = nv_object(imem);
  96        struct nv04_instmem_priv *priv = (void *)(imem);
  97        int ret;
  98
  99        ret = nouveau_object_ctor(parent, engine, &nv04_instobj_oclass,
 100                                  (void *)(unsigned long)align, size, pobject);
 101        if (ret)
 102                return ret;
 103
 104        /* INSTMEM itself creates objects to reserve (and preserve across
 105         * suspend/resume) various fixed data locations, each one of these
 106         * takes a reference on INSTMEM itself, causing it to never be
 107         * freed.  We drop all the self-references here to avoid this.
 108         */
 109        if (unlikely(!priv->created))
 110                atomic_dec(&engine->refcount);
 111
 112        return 0;
 113}
 114
 115static int
 116nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 117                  struct nouveau_oclass *oclass, void *data, u32 size,
 118                  struct nouveau_object **pobject)
 119{
 120        struct nv04_instmem_priv *priv;
 121        int ret;
 122
 123        ret = nouveau_instmem_create(parent, engine, oclass, &priv);
 124        *pobject = nv_object(priv);
 125        if (ret)
 126                return ret;
 127
 128        /* PRAMIN aperture maps over the end of VRAM, reserve it */
 129        priv->base.reserved = 512 * 1024;
 130        priv->base.alloc    = nv04_instmem_alloc;
 131
 132        ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1);
 133        if (ret)
 134                return ret;
 135
 136        /* 0x00000-0x10000: reserve for probable vbios image */
 137        ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0, 0, &priv->vbios);
 138        if (ret)
 139                return ret;
 140
 141        /* 0x10000-0x18000: reserve for RAMHT */
 142        ret = nouveau_ramht_new(parent, NULL, 0x08000, 0, &priv->ramht);
 143        if (ret)
 144                return ret;
 145
 146        /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */
 147        ret = nouveau_gpuobj_new(parent, NULL, 0x00800, 0,
 148                                 NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
 149        if (ret)
 150                return ret;
 151
 152        /* 0x18800-0x18a00: reserve for RAMRO */
 153        ret = nouveau_gpuobj_new(parent, NULL, 0x00200, 0, 0, &priv->ramro);
 154        if (ret)
 155                return ret;
 156
 157        priv->created = true;
 158        return 0;
 159}
 160
 161void
 162nv04_instmem_dtor(struct nouveau_object *object)
 163{
 164        struct nv04_instmem_priv *priv = (void *)object;
 165        nouveau_gpuobj_ref(NULL, &priv->ramfc);
 166        nouveau_gpuobj_ref(NULL, &priv->ramro);
 167        nouveau_ramht_ref(NULL, &priv->ramht);
 168        nouveau_gpuobj_ref(NULL, &priv->vbios);
 169        nouveau_mm_fini(&priv->heap);
 170        if (priv->iomem)
 171                iounmap(priv->iomem);
 172        nouveau_instmem_destroy(&priv->base);
 173}
 174
 175static u32
 176nv04_instmem_rd32(struct nouveau_object *object, u32 addr)
 177{
 178        return nv_rd32(object, 0x700000 + addr);
 179}
 180
 181static void
 182nv04_instmem_wr32(struct nouveau_object *object, u32 addr, u32 data)
 183{
 184        return nv_wr32(object, 0x700000 + addr, data);
 185}
 186
 187struct nouveau_oclass
 188nv04_instmem_oclass = {
 189        .handle = NV_SUBDEV(INSTMEM, 0x04),
 190        .ofuncs = &(struct nouveau_ofuncs) {
 191                .ctor = nv04_instmem_ctor,
 192                .dtor = nv04_instmem_dtor,
 193                .init = _nouveau_instmem_init,
 194                .fini = _nouveau_instmem_fini,
 195                .rd32 = nv04_instmem_rd32,
 196                .wr32 = nv04_instmem_wr32,
 197        },
 198};
 199