summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/core/subdev/fb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev/fb')
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/base.c125
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c54
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c20
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c32
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c26
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c25
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c23
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c25
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c15
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c199
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c143
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/priv.h87
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c95
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c61
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c63
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c65
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c64
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c62
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c64
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c55
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c232
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c186
30 files changed, 1239 insertions, 625 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
index d62045f454b2..821cd75b86a3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
@@ -57,7 +57,57 @@ nouveau_fb_bios_memtype(struct nouveau_bios *bios)
}
int
-nouveau_fb_preinit(struct nouveau_fb *pfb)
+_nouveau_fb_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nouveau_fb *pfb = (void *)object;
+ int ret;
+
+ ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
+ if (ret && suspend)
+ return ret;
+
+ return nouveau_subdev_fini(&pfb->base, suspend);
+}
+
+int
+_nouveau_fb_init(struct nouveau_object *object)
+{
+ struct nouveau_fb *pfb = (void *)object;
+ int ret, i;
+
+ ret = nouveau_subdev_init(&pfb->base);
+ if (ret)
+ return ret;
+
+ ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < pfb->tile.regions; i++)
+ pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
+
+ return 0;
+}
+
+void
+_nouveau_fb_dtor(struct nouveau_object *object)
+{
+ struct nouveau_fb *pfb = (void *)object;
+ int i;
+
+ for (i = 0; i < pfb->tile.regions; i++)
+ pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
+ nouveau_mm_fini(&pfb->tags);
+ nouveau_mm_fini(&pfb->vram);
+
+ nouveau_object_ref(NULL, (struct nouveau_object **)&pfb->ram);
+ nouveau_subdev_destroy(&pfb->base);
+}
+
+int
+nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, struct nouveau_oclass *ramcls,
+ int length, void **pobject)
{
static const char *name[] = {
[NV_MEM_TYPE_UNKNOWN] = "unknown",
@@ -72,69 +122,42 @@ nouveau_fb_preinit(struct nouveau_fb *pfb)
[NV_MEM_TYPE_GDDR4 ] = "GDDR4",
[NV_MEM_TYPE_GDDR5 ] = "GDDR5",
};
- int ret, tags;
+ struct nouveau_object *ram;
+ struct nouveau_fb *pfb;
+ int ret;
- tags = pfb->ram.init(pfb);
- if (tags < 0 || !pfb->ram.size) {
+ ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PFB", "fb",
+ length, pobject);
+ pfb = *pobject;
+ if (ret)
+ return ret;
+
+ ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb),
+ ramcls, NULL, 0, &ram);
+ if (ret) {
nv_fatal(pfb, "error detecting memory configuration!!\n");
- return (tags < 0) ? tags : -ERANGE;
+ return ret;
}
+ atomic_dec(&ram->parent->refcount);
+ atomic_dec(&ram->engine->refcount);
+ pfb->ram = (void *)ram;
+
if (!nouveau_mm_initialised(&pfb->vram)) {
- ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram.size >> 12, 1);
+ ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1);
if (ret)
return ret;
}
if (!nouveau_mm_initialised(&pfb->tags)) {
- ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1);
+ ret = nouveau_mm_init(&pfb->tags, 0, pfb->ram->tags ?
+ ++pfb->ram->tags : 0, 1);
if (ret)
return ret;
}
- nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]);
- nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20));
- nv_info(pfb, " ZCOMP: %d tags\n", tags);
+ nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]);
+ nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20));
+ nv_info(pfb, " ZCOMP: %d tags\n", pfb->ram->tags);
return 0;
}
-
-void
-nouveau_fb_destroy(struct nouveau_fb *pfb)
-{
- int i;
-
- for (i = 0; i < pfb->tile.regions; i++)
- pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
- nouveau_mm_fini(&pfb->tags);
- nouveau_mm_fini(&pfb->vram);
-
- nouveau_subdev_destroy(&pfb->base);
-}
-
-void
-_nouveau_fb_dtor(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object;
- nouveau_fb_destroy(pfb);
-}
-int
-nouveau_fb_init(struct nouveau_fb *pfb)
-{
- int ret, i;
-
- ret = nouveau_subdev_init(&pfb->base);
- if (ret)
- return ret;
-
- for (i = 0; i < pfb->tile.regions; i++)
- pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
-
- return 0;
-}
-
-int
-_nouveau_fb_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object;
- return nouveau_fb_init(pfb);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
index 6e369f85361e..1f103c7b89fa 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
@@ -22,24 +22,8 @@
* Authors: Ben Skeggs
*/
-#include <subdev/fb.h>
+#include "priv.h"
-#define NV04_PFB_BOOT_0 0x00100000
-# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
-# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
-# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
-# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
-# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
#define NV04_PFB_CFG0 0x00100200
struct nv04_fb_priv {
@@ -56,37 +40,6 @@ nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
}
static int
-nv04_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
- if (boot0 & 0x00000100) {
- pfb->ram.size = ((boot0 >> 12) & 0xf) * 2 + 2;
- pfb->ram.size *= 1024 * 1024;
- } else {
- switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
- case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
- pfb->ram.size = 32 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
- pfb->ram.size = 16 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
- pfb->ram.size = 8 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
- pfb->ram.size = 4 * 1024 * 1024;
- break;
- }
- }
-
- if ((boot0 & 0x00000038) <= 0x10)
- pfb->ram.type = NV_MEM_TYPE_SGRAM;
- else
- pfb->ram.type = NV_MEM_TYPE_SDRAM;
- return 0;
-}
-
-static int
nv04_fb_init(struct nouveau_object *object)
{
struct nv04_fb_priv *priv = (void *)object;
@@ -112,14 +65,13 @@ nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv04_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv04_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv04_fb_vram_init;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
index edbbe26e858d..be069b5306b6 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
@@ -24,25 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv10_fb_priv {
struct nouveau_fb base;
};
-static int
-nv10_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 cfg0 = nv_rd32(pfb, 0x100200);
- if (cfg0 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
- else
- pfb->ram.type = NV_MEM_TYPE_SDRAM;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- return 0;
-}
-
void
nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
@@ -78,18 +65,17 @@ nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv10_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv10_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv10_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv10_fb_tile_init;
priv->base.tile.fini = nv10_fb_tile_fini;
priv->base.tile.prog = nv10_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
index 48366841db4a..57a2af0079b3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
@@ -24,38 +24,13 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv1a_fb_priv {
struct nouveau_fb base;
};
static int
-nv1a_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct pci_dev *bridge;
- u32 mem, mib;
-
- bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
- if (!bridge) {
- nv_fatal(pfb, "no bridge device\n");
- return -ENODEV;
- }
-
- if (nv_device(pfb)->chipset == 0x1a) {
- pci_read_config_dword(bridge, 0x7c, &mem);
- mib = ((mem >> 6) & 31) + 1;
- } else {
- pci_read_config_dword(bridge, 0x84, &mem);
- mib = ((mem >> 4) & 127) + 1;
- }
-
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- pfb->ram.size = mib * 1024 * 1024;
- return 0;
-}
-
-static int
nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -63,18 +38,17 @@ nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv1a_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv1a_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv1a_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv10_fb_tile_init;
priv->base.tile.fini = nv10_fb_tile_fini;
priv->base.tile.prog = nv10_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
index 5d14612a2c8e..b18c4e63bb47 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
@@ -24,29 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv20_fb_priv {
struct nouveau_fb base;
};
-int
-nv20_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
-
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: pfb->ram.type = NV_MEM_TYPE_GDDR2; break;
- }
- pfb->ram.size = (nv_rd32(pfb, 0x10020c) & 0xff000000);
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-
- return nv_rd32(pfb, 0x100320);
-}
-
void
nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
@@ -65,7 +48,7 @@ nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
else tile->zcomp = 0x04000000; /* Z24S8 */
@@ -105,19 +88,18 @@ nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv20_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv20_fb_tile_init;
priv->base.tile.comp = nv20_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
index 0042ace6bef9..32ccabf10c45 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv25_fb_priv {
struct nouveau_fb base;
@@ -35,7 +35,7 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
else tile->zcomp = 0x00200000; /* Z24S8 */
@@ -54,19 +54,18 @@ nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv25_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv20_fb_tile_init;
priv->base.tile.comp = nv25_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
index a7ba0d048aec..bef756d43d33 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv30_fb_priv {
struct nouveau_fb base;
@@ -54,7 +54,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
else tile->zcomp |= 0x02000000; /* Z24S8 */
@@ -132,19 +132,18 @@ nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv30_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv30_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
index 092f6f4f3521..097d8e3824f2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv35_fb_priv {
struct nouveau_fb base;
@@ -35,7 +35,7 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
else tile->zcomp |= 0x08000000; /* Z24S8 */
@@ -55,19 +55,18 @@ nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv35_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv35_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
index 797ab3b821b9..9d6d9df896d9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv36_fb_priv {
struct nouveau_fb base;
@@ -35,7 +35,7 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
else tile->zcomp |= 0x20000000; /* Z24S8 */
@@ -55,19 +55,18 @@ nv36_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv36_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv36_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
index 65e131b90f37..33b4393a7829 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
@@ -24,34 +24,18 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv40_fb_priv {
struct nouveau_fb base;
};
-static int
-nv40_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
- }
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
void
nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x80);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x100);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x100);
if ( (flags & 2) &&
!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */
@@ -85,19 +69,18 @@ nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv40_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv40_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv40_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
index e9e5a08c41a1..02cd83789cd4 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
@@ -24,28 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv41_fb_priv {
struct nouveau_fb base;
};
-int
-nv41_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- if (pfb474 & 0x00000004)
- pfb->ram.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
void
nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
@@ -78,19 +62,18 @@ nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv41_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv41_fb_vram_init;
priv->base.tile.regions = 12;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
index ae89b5006f7a..c5246c29f293 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
@@ -24,27 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv44_fb_priv {
struct nouveau_fb base;
};
-int
-nv44_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- if (pfb474 & 0x00000004)
- pfb->ram.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- return 0;
-}
-
static void
nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
@@ -87,18 +72,17 @@ nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv44_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv44_fb_vram_init;
priv->base.tile.regions = 12;
priv->base.tile.init = nv44_fb_tile_init;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
index 589b93ea2994..e2b57909bfca 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv46_fb_priv {
struct nouveau_fb base;
@@ -52,18 +52,17 @@ nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv46_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv44_fb_vram_init;
priv->base.tile.regions = 15;
priv->base.tile.init = nv46_fb_tile_init;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
index 818bba35b368..fe6a2278621d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv47_fb_priv {
struct nouveau_fb base;
@@ -38,19 +38,18 @@ nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv47_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv41_fb_vram_init;
priv->base.tile.regions = 15;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
index 84a31af16ab4..5eca99b8c7e2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
@@ -24,30 +24,13 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv49_fb_priv {
struct nouveau_fb base;
};
static int
-nv49_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb914 = nv_rd32(pfb, 0x100914);
-
- switch (pfb914 & 0x00000003) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000001: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
- case 0x00000002: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000003: break;
- }
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
-static int
nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -55,20 +38,18 @@ nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv49_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv49_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv49_fb_vram_init;
priv->base.tile.regions = 15;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
-
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
index 797fd558170b..1190b78a1e91 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
@@ -24,21 +24,13 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv4e_fb_priv {
struct nouveau_fb base;
};
static int
-nv4e_fb_vram_init(struct nouveau_fb *pfb)
-{
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- return 0;
-}
-
-static int
nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -46,18 +38,17 @@ nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv4e_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv4e_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv4e_fb_vram_init;
priv->base.tile.regions = 12;
priv->base.tile.init = nv46_fb_tile_init;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
index 0772ec978165..da614ec5564b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
@@ -27,7 +27,7 @@
#include <core/engctx.h>
#include <core/object.h>
-#include <subdev/fb.h>
+#include "priv.h"
#include <subdev/bios.h>
struct nv50_fb_priv {
@@ -36,7 +36,8 @@ struct nv50_fb_priv {
dma_addr_t r100c08;
};
-static int types[0x80] = {
+int
+nv50_fb_memtype[0x80] = {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
@@ -50,192 +51,7 @@ static int types[0x80] = {
static bool
nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
{
- return types[(memtype & 0xff00) >> 8] != 0;
-}
-
-static u32
-nv50_fb_vram_rblock(struct nouveau_fb *pfb)
-{
- int i, parts, colbits, rowbitsa, rowbitsb, banks;
- u64 rowsize, predicted;
- u32 r0, r4, rt, ru, rblock_size;
-
- r0 = nv_rd32(pfb, 0x100200);
- r4 = nv_rd32(pfb, 0x100204);
- rt = nv_rd32(pfb, 0x100250);
- ru = nv_rd32(pfb, 0x001540);
- nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
-
- for (i = 0, parts = 0; i < 8; i++) {
- if (ru & (0x00010000 << i))
- parts++;
- }
-
- colbits = (r4 & 0x0000f000) >> 12;
- rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
- rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
- banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
-
- rowsize = parts * banks * (1 << colbits) * 8;
- predicted = rowsize << rowbitsa;
- if (r0 & 0x00000004)
- predicted += rowsize << rowbitsb;
-
- if (predicted != pfb->ram.size) {
- nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
- (u32)(pfb->ram.size >> 20));
- }
-
- rblock_size = rowsize;
- if (rt & 1)
- rblock_size *= 3;
-
- nv_debug(pfb, "rblock %d bytes\n", rblock_size);
- return rblock_size;
-}
-
-static int
-nv50_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct nouveau_device *device = nv_device(pfb);
- struct nouveau_bios *bios = nouveau_bios(device);
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 size, tags = 0;
- int ret;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c);
- pfb->ram.size = (pfb->ram.size & 0xffffff00) |
- ((pfb->ram.size & 0x000000ff) << 32);
-
- size = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
- switch (device->chipset) {
- case 0xaa:
- case 0xac:
- case 0xaf: /* IGPs, no reordering, no real VRAM */
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
- if (ret)
- return ret;
-
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- pfb->ram.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
- break;
- default:
- switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
- case 0: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 1:
- if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
- pfb->ram.type = NV_MEM_TYPE_DDR3;
- else
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- break;
- case 2: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 3: pfb->ram.type = NV_MEM_TYPE_GDDR4; break;
- case 4: pfb->ram.type = NV_MEM_TYPE_GDDR5; break;
- default:
- break;
- }
-
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
- nv50_fb_vram_rblock(pfb) >> 12);
- if (ret)
- return ret;
-
- pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
- tags = nv_rd32(pfb, 0x100320);
- break;
- }
-
- return tags;
-}
-
-static int
-nv50_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **pmem)
-{
- struct nv50_fb_priv *priv = (void *)pfb;
- struct nouveau_mm *heap = &priv->base.vram;
- struct nouveau_mm *tags = &priv->base.tags;
- struct nouveau_mm_node *r;
- struct nouveau_mem *mem;
- int comp = (memtype & 0x300) >> 8;
- int type = (memtype & 0x07f);
- int back = (memtype & 0x800);
- int min, max, ret;
-
- max = (size >> 12);
- min = ncmin ? (ncmin >> 12) : max;
- align >>= 12;
-
- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- mutex_lock(&pfb->base.mutex);
- if (comp) {
- if (align == 16) {
- int n = (max >> 4) * comp;
-
- ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
- if (ret)
- mem->tag = NULL;
- }
-
- if (unlikely(!mem->tag))
- comp = 0;
- }
-
- INIT_LIST_HEAD(&mem->regions);
- mem->memtype = (comp << 7) | type;
- mem->size = max;
-
- type = types[type];
- do {
- if (back)
- ret = nouveau_mm_tail(heap, type, max, min, align, &r);
- else
- ret = nouveau_mm_head(heap, type, max, min, align, &r);
- if (ret) {
- mutex_unlock(&pfb->base.mutex);
- pfb->ram.put(pfb, &mem);
- return ret;
- }
-
- list_add_tail(&r->rl_entry, &mem->regions);
- max -= r->length;
- } while (max);
- mutex_unlock(&pfb->base.mutex);
-
- r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
- mem->offset = (u64)r->offset << 12;
- *pmem = mem;
- return 0;
-}
-
-void
-nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
- struct nv50_fb_priv *priv = (void *)pfb;
- struct nouveau_mm_node *this;
- struct nouveau_mem *mem;
-
- mem = *pmem;
- *pmem = NULL;
- if (unlikely(mem == NULL))
- return;
-
- mutex_lock(&pfb->base.mutex);
- while (!list_empty(&mem->regions)) {
- this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
-
- list_del(&this->rl_entry);
- nouveau_mm_free(&priv->base.vram, &this);
- }
-
- nouveau_mm_free(&priv->base.tags, &mem->tag);
- mutex_unlock(&pfb->base.mutex);
-
- kfree(mem);
+ return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
}
static const struct nouveau_enum vm_dispatch_subclients[] = {
@@ -432,7 +248,7 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv50_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv50_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
@@ -449,11 +265,8 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
}
priv->base.memtype_valid = nv50_fb_memtype_valid;
- priv->base.ram.init = nv50_fb_vram_init;
- priv->base.ram.get = nv50_fb_vram_new;
- priv->base.ram.put = nv50_fb_vram_del;
nv_subdev(priv)->intr = nv50_fb_intr;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
static void
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
index 86ad59203c8b..f35d76fd746d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
@@ -22,9 +22,7 @@
* Authors: Ben Skeggs
*/
-#include <subdev/fb.h>
-#include <subdev/ltcg.h>
-#include <subdev/bios.h>
+#include "priv.h"
struct nvc0_fb_priv {
struct nouveau_fb base;
@@ -34,7 +32,6 @@ struct nvc0_fb_priv {
extern const u8 nvc0_pte_storage_type_map[256];
-
static bool
nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
{
@@ -43,137 +40,6 @@ nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
}
static int
-nvc0_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 parts = nv_rd32(pfb, 0x022438);
- u32 pmask = nv_rd32(pfb, 0x022554);
- u32 bsize = nv_rd32(pfb, 0x10f20c);
- u32 offset, length;
- bool uniform = true;
- int ret, part;
-
- nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
- nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
-
- pfb->ram.type = nouveau_fb_bios_memtype(bios);
- pfb->ram.ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
-
- /* read amount of vram attached to each memory controller */
- for (part = 0; part < parts; part++) {
- if (!(pmask & (1 << part))) {
- u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
- if (psize != bsize) {
- if (psize < bsize)
- bsize = psize;
- uniform = false;
- }
-
- nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
- pfb->ram.size += (u64)psize << 20;
- }
- }
-
- /* if all controllers have the same amount attached, there's no holes */
- if (uniform) {
- offset = rsvd_head;
- length = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
- return nouveau_mm_init(&pfb->vram, offset, length, 1);
- }
-
- /* otherwise, address lowest common amount from 0GiB */
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1);
- if (ret)
- return ret;
-
- /* and the rest starting from (8GiB + common_size) */
- offset = (0x0200000000ULL >> 12) + (bsize << 8);
- length = (pfb->ram.size >> 12) - (bsize << 8) - rsvd_tail;
-
- ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
- if (ret) {
- nouveau_mm_fini(&pfb->vram);
- return ret;
- }
-
- return 0;
-}
-
-static int
-nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **pmem)
-{
- struct nouveau_mm *mm = &pfb->vram;
- struct nouveau_mm_node *r;
- struct nouveau_mem *mem;
- int type = (memtype & 0x0ff);
- int back = (memtype & 0x800);
- int ret;
- const bool comp = nvc0_pte_storage_type_map[type] != type;
-
- size >>= 12;
- align >>= 12;
- ncmin >>= 12;
- if (!ncmin)
- ncmin = size;
-
- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&mem->regions);
- mem->size = size;
-
- mutex_lock(&pfb->base.mutex);
- if (comp) {
- struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent);
-
- /* compression only works with lpages */
- if (align == (1 << (17 - 12))) {
- int n = size >> 5;
- ltcg->tags_alloc(ltcg, n, &mem->tag);
- }
- if (unlikely(!mem->tag))
- type = nvc0_pte_storage_type_map[type];
- }
- mem->memtype = type;
-
- do {
- if (back)
- ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
- else
- ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
- if (ret) {
- mutex_unlock(&pfb->base.mutex);
- pfb->ram.put(pfb, &mem);
- return ret;
- }
-
- list_add_tail(&r->rl_entry, &mem->regions);
- size -= r->length;
- } while (size);
- mutex_unlock(&pfb->base.mutex);
-
- r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
- mem->offset = (u64)r->offset << 12;
- *pmem = mem;
- return 0;
-}
-
-static void
-nvc0_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
- struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent);
-
- if ((*pmem)->tag)
- ltcg->tags_free(ltcg, &(*pmem)->tag);
-
- nv50_fb_vram_del(pfb, pmem);
-}
-
-static int
nvc0_fb_init(struct nouveau_object *object)
{
struct nvc0_fb_priv *priv = (void *)object;
@@ -212,15 +78,12 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nvc0_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nvc0_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nvc0_fb_memtype_valid;
- priv->base.ram.init = nvc0_fb_vram_init;
- priv->base.ram.get = nvc0_fb_vram_new;
- priv->base.ram.put = nvc0_fb_vram_del;
priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (priv->r100c10_page) {
@@ -231,7 +94,7 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return -EFAULT;
}
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
new file mode 100644
index 000000000000..6c974dd83e8b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
@@ -0,0 +1,87 @@
+#ifndef __NVKM_FB_PRIV_H__
+#define __NVKM_FB_PRIV_H__
+
+#include <subdev/fb.h>
+
+#define nouveau_ram_create(p,e,o,d) \
+ nouveau_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d)
+#define nouveau_ram_destroy(p) \
+ nouveau_object_destroy(&(p)->base)
+#define nouveau_ram_init(p) \
+ nouveau_object_init(&(p)->base)
+#define nouveau_ram_fini(p,s) \
+ nouveau_object_fini(&(p)->base, (s))
+
+#define _nouveau_ram_dtor nouveau_object_destroy
+#define _nouveau_ram_init nouveau_object_init
+#define _nouveau_ram_fini nouveau_object_fini
+
+extern struct nouveau_oclass nv04_ram_oclass;
+extern struct nouveau_oclass nv10_ram_oclass;
+extern struct nouveau_oclass nv1a_ram_oclass;
+extern struct nouveau_oclass nv20_ram_oclass;
+extern struct nouveau_oclass nv40_ram_oclass;
+extern struct nouveau_oclass nv41_ram_oclass;
+extern struct nouveau_oclass nv44_ram_oclass;
+extern struct nouveau_oclass nv49_ram_oclass;
+extern struct nouveau_oclass nv4e_ram_oclass;
+extern struct nouveau_oclass nv50_ram_oclass;
+extern struct nouveau_oclass nvc0_ram_oclass;
+
+#define nouveau_fb_create(p,e,c,r,d) \
+ nouveau_fb_create_((p), (e), (c), (r), sizeof(**d), (void **)d)
+#define nouveau_fb_destroy(p) ({ \
+ struct nouveau_fb *pfb = (p); \
+ _nouveau_fb_dtor(nv_object(pfb)); \
+})
+#define nouveau_fb_init(p) ({ \
+ struct nouveau_fb *pfb = (p); \
+ _nouveau_fb_init(nv_object(pfb)); \
+})
+#define nouveau_fb_fini(p,s) ({ \
+ struct nouveau_fb *pfb = (p); \
+ _nouveau_fb_fini(nv_object(pfb), (s)); \
+})
+
+int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, struct nouveau_oclass *,
+ int length, void **pobject);
+void _nouveau_fb_dtor(struct nouveau_object *);
+int _nouveau_fb_init(struct nouveau_object *);
+int _nouveau_fb_fini(struct nouveau_object *, bool);
+
+struct nouveau_bios;
+int nouveau_fb_bios_memtype(struct nouveau_bios *);
+
+bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
+
+void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int nv30_fb_init(struct nouveau_object *);
+void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
+ struct nouveau_fb_tile *);
+
+int nv41_fb_init(struct nouveau_object *);
+void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int nv44_fb_init(struct nouveau_object *);
+void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+extern int nv50_fb_memtype[0x80];
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
new file mode 100644
index 000000000000..e781080d3327
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NV04_PFB_BOOT_0 0x00100000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
+# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
+# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
+# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
+# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
+
+#include "priv.h"
+
+static int
+nv04_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (boot0 & 0x00000100) {
+ ram->size = ((boot0 >> 12) & 0xf) * 2 + 2;
+ ram->size *= 1024 * 1024;
+ } else {
+ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+ ram->size = 32 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+ ram->size = 16 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+ ram->size = 8 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+ ram->size = 4 * 1024 * 1024;
+ break;
+ }
+ }
+
+ if ((boot0 & 0x00000038) <= 0x10)
+ ram->type = NV_MEM_TYPE_SGRAM;
+ else
+ ram->type = NV_MEM_TYPE_SDRAM;
+ return 0;
+}
+
+struct nouveau_oclass
+nv04_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv04_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
new file mode 100644
index 000000000000..8311f3774edf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv10_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 cfg0 = nv_rd32(pfb, 0x100200);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (cfg0 & 0x00000001)
+ ram->type = NV_MEM_TYPE_DDR1;
+ else
+ ram->type = NV_MEM_TYPE_SDRAM;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ return 0;
+}
+
+
+struct nouveau_oclass
+nv10_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv10_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
new file mode 100644
index 000000000000..d0caddfb9db0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv1a_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ struct pci_dev *bridge;
+ u32 mem, mib;
+ int ret;
+
+ bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+ if (!bridge) {
+ nv_fatal(pfb, "no bridge device\n");
+ return -ENODEV;
+ }
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (nv_device(pfb)->chipset == 0x1a) {
+ pci_read_config_dword(bridge, 0x7c, &mem);
+ mib = ((mem >> 6) & 31) + 1;
+ } else {
+ pci_read_config_dword(bridge, 0x84, &mem);
+ mib = ((mem >> 4) & 127) + 1;
+ }
+
+ ram->type = NV_MEM_TYPE_STOLEN;
+ ram->size = mib * 1024 * 1024;
+ return 0;
+}
+
+struct nouveau_oclass
+nv1a_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv1a_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
new file mode 100644
index 000000000000..fdc11bba226d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv20_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pbus1218 = nv_rd32(pfb, 0x001218);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break;
+ }
+ ram->size = (nv_rd32(pfb, 0x10020c) & 0xff000000);
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+struct nouveau_oclass
+nv20_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv20_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
new file mode 100644
index 000000000000..ee49ac4dbdb6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pbus1218 = nv_rd32(pfb, 0x001218);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: ram->type = NV_MEM_TYPE_DDR2; break;
+ }
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+
+struct nouveau_oclass
+nv40_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv40_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
new file mode 100644
index 000000000000..1dab7e12abab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pfb474 = nv_rd32(pfb, 0x100474);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (pfb474 & 0x00000004)
+ ram->type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ ram->type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ ram->type = NV_MEM_TYPE_DDR1;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+struct nouveau_oclass
+nv41_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv41_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
new file mode 100644
index 000000000000..25fff842e5c1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pfb474 = nv_rd32(pfb, 0x100474);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (pfb474 & 0x00000004)
+ ram->type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ ram->type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ ram->type = NV_MEM_TYPE_DDR1;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ return 0;
+}
+
+struct nouveau_oclass
+nv44_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv44_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
new file mode 100644
index 000000000000..19e3a9a63a02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pfb914 = nv_rd32(pfb, 0x100914);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pfb914 & 0x00000003) {
+ case 0x00000000: pfb->ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break;
+ case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000003: break;
+ }
+
+ pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ pfb->ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+struct nouveau_oclass
+nv49_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv49_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
new file mode 100644
index 000000000000..7192aa6e5577
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ pfb->ram->type = NV_MEM_TYPE_STOLEN;
+ return 0;
+}
+
+struct nouveau_oclass
+nv4e_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv4e_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
new file mode 100644
index 000000000000..af5aa7ee8ad9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <core/mm.h>
+#include "priv.h"
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+ struct nouveau_mm_node *this;
+ struct nouveau_mem *mem;
+
+ mem = *pmem;
+ *pmem = NULL;
+ if (unlikely(mem == NULL))
+ return;
+
+ mutex_lock(&pfb->base.mutex);
+ while (!list_empty(&mem->regions)) {
+ this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
+
+ list_del(&this->rl_entry);
+ nouveau_mm_free(&pfb->vram, &this);
+ }
+
+ nouveau_mm_free(&pfb->tags, &mem->tag);
+ mutex_unlock(&pfb->base.mutex);
+
+ kfree(mem);
+}
+
+static int
+nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nouveau_mem **pmem)
+{
+ struct nouveau_mm *heap = &pfb->vram;
+ struct nouveau_mm *tags = &pfb->tags;
+ struct nouveau_mm_node *r;
+ struct nouveau_mem *mem;
+ int comp = (memtype & 0x300) >> 8;
+ int type = (memtype & 0x07f);
+ int back = (memtype & 0x800);
+ int min, max, ret;
+
+ max = (size >> 12);
+ min = ncmin ? (ncmin >> 12) : max;
+ align >>= 12;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ mutex_lock(&pfb->base.mutex);
+ if (comp) {
+ if (align == 16) {
+ int n = (max >> 4) * comp;
+
+ ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
+ if (ret)
+ mem->tag = NULL;
+ }
+
+ if (unlikely(!mem->tag))
+ comp = 0;
+ }
+
+ INIT_LIST_HEAD(&mem->regions);
+ mem->memtype = (comp << 7) | type;
+ mem->size = max;
+
+ type = nv50_fb_memtype[type];
+ do {
+ if (back)
+ ret = nouveau_mm_tail(heap, type, max, min, align, &r);
+ else
+ ret = nouveau_mm_head(heap, type, max, min, align, &r);
+ if (ret) {
+ mutex_unlock(&pfb->base.mutex);
+ pfb->ram->put(pfb, &mem);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &mem->regions);
+ max -= r->length;
+ } while (max);
+ mutex_unlock(&pfb->base.mutex);
+
+ r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
+ mem->offset = (u64)r->offset << 12;
+ *pmem = mem;
+ return 0;
+}
+
+static u32
+nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
+{
+ int i, parts, colbits, rowbitsa, rowbitsb, banks;
+ u64 rowsize, predicted;
+ u32 r0, r4, rt, ru, rblock_size;
+
+ r0 = nv_rd32(pfb, 0x100200);
+ r4 = nv_rd32(pfb, 0x100204);
+ rt = nv_rd32(pfb, 0x100250);
+ ru = nv_rd32(pfb, 0x001540);
+ nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+ for (i = 0, parts = 0; i < 8; i++) {
+ if (ru & (0x00010000 << i))
+ parts++;
+ }
+
+ colbits = (r4 & 0x0000f000) >> 12;
+ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+ banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
+
+ rowsize = parts * banks * (1 << colbits) * 8;
+ predicted = rowsize << rowbitsa;
+ if (r0 & 0x00000004)
+ predicted += rowsize << rowbitsb;
+
+ if (predicted != ram->size) {
+ nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
+ (u32)(ram->size >> 20));
+ }
+
+ rblock_size = rowsize;
+ if (rt & 1)
+ rblock_size *= 3;
+
+ nv_debug(pfb, "rblock %d bytes\n", rblock_size);
+ return rblock_size;
+}
+
+static int
+nv50_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 datasize,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_device *device = nv_device(pfb);
+ struct nouveau_bios *bios = nouveau_bios(device);
+ struct nouveau_ram *ram;
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ u32 size;
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ ram->size = nv_rd32(pfb, 0x10020c);
+ ram->size = (ram->size & 0xffffff00) |
+ ((ram->size & 0x000000ff) << 32);
+
+ size = (ram->size >> 12) - rsvd_head - rsvd_tail;
+ switch (device->chipset) {
+ case 0xaa:
+ case 0xac:
+ case 0xaf: /* IGPs, no reordering, no real VRAM */
+ ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
+ if (ret)
+ return ret;
+
+ ram->type = NV_MEM_TYPE_STOLEN;
+ ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+ break;
+ default:
+ switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
+ case 0: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 1:
+ if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
+ ram->type = NV_MEM_TYPE_DDR3;
+ else
+ ram->type = NV_MEM_TYPE_DDR2;
+ break;
+ case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
+ case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
+ default:
+ break;
+ }
+
+ ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
+ nv50_fb_vram_rblock(pfb, ram) >> 12);
+ if (ret)
+ return ret;
+
+ ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ break;
+ }
+
+ ram->get = nv50_ram_get;
+ ram->put = nv50_ram_put;
+ return 0;
+}
+
+struct nouveau_oclass
+nv50_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv50_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
new file mode 100644
index 000000000000..9c3634acbb9d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/ltcg.h>
+
+#include "priv.h"
+
+extern const u8 nvc0_pte_storage_type_map[256];
+
+void
+nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+ struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+
+ if ((*pmem)->tag)
+ ltcg->tags_free(ltcg, &(*pmem)->tag);
+
+ nv50_ram_put(pfb, pmem);
+}
+
+int
+nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nouveau_mem **pmem)
+{
+ struct nouveau_mm *mm = &pfb->vram;
+ struct nouveau_mm_node *r;
+ struct nouveau_mem *mem;
+ int type = (memtype & 0x0ff);
+ int back = (memtype & 0x800);
+ const bool comp = nvc0_pte_storage_type_map[type] != type;
+ int ret;
+
+ size >>= 12;
+ align >>= 12;
+ ncmin >>= 12;
+ if (!ncmin)
+ ncmin = size;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&mem->regions);
+ mem->size = size;
+
+ mutex_lock(&pfb->base.mutex);
+ if (comp) {
+ struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+
+ /* compression only works with lpages */
+ if (align == (1 << (17 - 12))) {
+ int n = size >> 5;
+ ltcg->tags_alloc(ltcg, n, &mem->tag);
+ }
+
+ if (unlikely(!mem->tag))
+ type = nvc0_pte_storage_type_map[type];
+ }
+ mem->memtype = type;
+
+ do {
+ if (back)
+ ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
+ else
+ ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
+ if (ret) {
+ mutex_unlock(&pfb->base.mutex);
+ pfb->ram->put(pfb, &mem);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &mem->regions);
+ size -= r->length;
+ } while (size);
+ mutex_unlock(&pfb->base.mutex);
+
+ r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
+ mem->offset = (u64)r->offset << 12;
+ *pmem = mem;
+ return 0;
+}
+
+static int
+nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_bios *bios = nouveau_bios(pfb);
+ struct nouveau_ram *ram;
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ u32 parts = nv_rd32(pfb, 0x022438);
+ u32 pmask = nv_rd32(pfb, 0x022554);
+ u32 bsize = nv_rd32(pfb, 0x10f20c);
+ u32 offset, length;
+ bool uniform = true;
+ int ret, part;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
+ nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+ ram->type = nouveau_fb_bios_memtype(bios);
+ ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
+
+ /* read amount of vram attached to each memory controller */
+ for (part = 0; part < parts; part++) {
+ if (!(pmask & (1 << part))) {
+ u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
+ if (psize != bsize) {
+ if (psize < bsize)
+ bsize = psize;
+ uniform = false;
+ }
+
+ nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
+ ram->size += (u64)psize << 20;
+ }
+ }
+
+ /* if all controllers have the same amount attached, there's no holes */
+ if (uniform) {
+ offset = rsvd_head;
+ length = (ram->size >> 12) - rsvd_head - rsvd_tail;
+ ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
+ } else {
+ /* otherwise, address lowest common amount from 0GiB */
+ ret = nouveau_mm_init(&pfb->vram, rsvd_head,
+ (bsize << 8) * parts, 1);
+ if (ret)
+ return ret;
+
+ /* and the rest starting from (8GiB + common_size) */
+ offset = (0x0200000000ULL >> 12) + (bsize << 8);
+ length = (ram->size >> 12) - (bsize << 8) - rsvd_tail;
+
+ ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
+ if (ret)
+ nouveau_mm_fini(&pfb->vram);
+ }
+
+ if (ret)
+ return ret;
+
+ ram->get = nvc0_ram_get;
+ ram->put = nvc0_ram_put;
+ return 0;
+}
+
+struct nouveau_oclass
+nvc0_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};