Commit dac1558d authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/fb: create tag heap from common code for all relevant chipsets

A nv2x bug wrt hardcoded tag counts is now also fixed as a side-effect.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 268d5a30
......@@ -64,6 +64,7 @@ nouveau-y += core/subdev/devinit/nv50.o
nouveau-y += core/subdev/fb/base.o
nouveau-y += core/subdev/fb/nv04.o
nouveau-y += core/subdev/fb/nv10.o
nouveau-y += core/subdev/fb/nv1a.o
nouveau-y += core/subdev/fb/nv20.o
nouveau-y += core/subdev/fb/nv25.o
nouveau-y += core/subdev/fb/nv30.o
......
......@@ -71,6 +71,7 @@ struct nouveau_fb {
u64 size;
int ranks;
int (*init)(struct nouveau_fb *);
int (*get)(struct nouveau_fb *, u64 size, u32 align,
u32 size_nc, u32 type, struct nouveau_mem **);
void (*put)(struct nouveau_fb *, struct nouveau_mem **);
......@@ -101,7 +102,7 @@ nouveau_fb(void *obj)
#define nouveau_fb_create(p,e,c,d) \
nouveau_subdev_create((p), (e), (c), 0, "PFB", "fb", (d))
int nouveau_fb_created(struct nouveau_fb *);
int nouveau_fb_preinit(struct nouveau_fb *);
void nouveau_fb_destroy(struct nouveau_fb *);
int nouveau_fb_init(struct nouveau_fb *);
#define nouveau_fb_fini(p,s) \
......@@ -113,6 +114,7 @@ int _nouveau_fb_init(struct nouveau_object *);
extern struct nouveau_oclass nv04_fb_oclass;
extern struct nouveau_oclass nv10_fb_oclass;
extern struct nouveau_oclass nv1a_fb_oclass;
extern struct nouveau_oclass nv20_fb_oclass;
extern struct nouveau_oclass nv25_fb_oclass;
extern struct nouveau_oclass nv30_fb_oclass;
......@@ -132,6 +134,12 @@ 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 *);
int nv20_fb_vram_init(struct nouveau_fb *);
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 *);
......@@ -142,9 +150,11 @@ void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nouveau_fb_tile *);
void nv30_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
int nv41_fb_vram_init(struct nouveau_fb *);
int nv41_fb_init(struct nouveau_object *);
void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
int nv44_fb_vram_init(struct nouveau_fb *);
int nv44_fb_init(struct nouveau_object *);
void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
......
......@@ -105,7 +105,7 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
......@@ -159,7 +159,7 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
......
......@@ -57,25 +57,45 @@ nouveau_fb_bios_memtype(struct nouveau_bios *bios)
}
int
nouveau_fb_init(struct nouveau_fb *pfb)
nouveau_fb_preinit(struct nouveau_fb *pfb)
{
int ret, i;
static const char *name[] = {
[NV_MEM_TYPE_UNKNOWN] = "unknown",
[NV_MEM_TYPE_STOLEN ] = "stolen system memory",
[NV_MEM_TYPE_SGRAM ] = "SGRAM",
[NV_MEM_TYPE_SDRAM ] = "SDRAM",
[NV_MEM_TYPE_DDR1 ] = "DDR1",
[NV_MEM_TYPE_DDR2 ] = "DDR2",
[NV_MEM_TYPE_DDR3 ] = "DDR3",
[NV_MEM_TYPE_GDDR2 ] = "GDDR2",
[NV_MEM_TYPE_GDDR3 ] = "GDDR3",
[NV_MEM_TYPE_GDDR4 ] = "GDDR4",
[NV_MEM_TYPE_GDDR5 ] = "GDDR5",
};
int ret, tags;
ret = nouveau_subdev_init(&pfb->base);
if (ret)
return ret;
tags = pfb->ram.init(pfb);
if (tags < 0 || !pfb->ram.size) {
nv_fatal(pfb, "error detecting memory configuration!!\n");
return (tags < 0) ? tags : -ERANGE;
}
for (i = 0; i < pfb->tile.regions; i++)
pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
if (!nouveau_mm_initialised(&pfb->vram)) {
ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram.size >> 12, 1);
if (ret)
return ret;
}
return 0;
}
if (!nouveau_mm_initialised(&pfb->tags) && tags) {
ret = nouveau_mm_init(&pfb->tags, 0, ++tags, 1);
if (ret)
return ret;
}
int
_nouveau_fb_init(struct nouveau_object *object)
{
struct nouveau_fb *pfb = (void *)object;
return nouveau_fb_init(pfb);
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);
return 0;
}
void
......@@ -97,30 +117,24 @@ _nouveau_fb_dtor(struct nouveau_object *object)
struct nouveau_fb *pfb = (void *)object;
nouveau_fb_destroy(pfb);
}
int
nouveau_fb_created(struct nouveau_fb *pfb)
nouveau_fb_init(struct nouveau_fb *pfb)
{
static const char *name[] = {
[NV_MEM_TYPE_UNKNOWN] = "unknown",
[NV_MEM_TYPE_STOLEN ] = "stolen system memory",
[NV_MEM_TYPE_SGRAM ] = "SGRAM",
[NV_MEM_TYPE_SDRAM ] = "SDRAM",
[NV_MEM_TYPE_DDR1 ] = "DDR1",
[NV_MEM_TYPE_DDR2 ] = "DDR2",
[NV_MEM_TYPE_DDR3 ] = "DDR3",
[NV_MEM_TYPE_GDDR2 ] = "GDDR2",
[NV_MEM_TYPE_GDDR3 ] = "GDDR3",
[NV_MEM_TYPE_GDDR4 ] = "GDDR4",
[NV_MEM_TYPE_GDDR5 ] = "GDDR5",
};
int ret, i;
if (pfb->ram.size == 0) {
nv_fatal(pfb, "no vram detected!!\n");
return -ERANGE;
}
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]);
nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]);
nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20));
return 0;
}
int
_nouveau_fb_init(struct nouveau_object *object)
{
struct nouveau_fb *pfb = (void *)object;
return nouveau_fb_init(pfb);
}
......@@ -55,6 +55,37 @@ nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
return false;
}
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)
{
......@@ -79,7 +110,6 @@ nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_object **pobject)
{
struct nv04_fb_priv *priv;
u32 boot0;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -87,35 +117,9 @@ nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
boot0 = nv_rd32(priv, NV04_PFB_BOOT_0);
if (boot0 & 0x00000100) {
priv->base.ram.size = ((boot0 >> 12) & 0xf) * 2 + 2;
priv->base.ram.size *= 1024 * 1024;
} else {
switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
priv->base.ram.size = 32 * 1024 * 1024;
break;
case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
priv->base.ram.size = 16 * 1024 * 1024;
break;
case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
priv->base.ram.size = 8 * 1024 * 1024;
break;
case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
priv->base.ram.size = 4 * 1024 * 1024;
break;
}
}
if ((boot0 & 0x00000038) <= 0x10)
priv->base.ram.type = NV_MEM_TYPE_SGRAM;
else
priv->base.ram.type = NV_MEM_TYPE_SDRAM;
priv->base.memtype_valid = nv04_fb_memtype_valid;
return nouveau_fb_created(&priv->base);
priv->base.ram.init = nv04_fb_vram_init;
return nouveau_fb_preinit(&priv->base);
}
struct nouveau_oclass
......
......@@ -30,7 +30,20 @@ struct nv10_fb_priv {
struct nouveau_fb base;
};
static void
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)
{
......@@ -39,7 +52,7 @@ nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
tile->pitch = pitch;
}
static void
void
nv10_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
tile->addr = 0;
......@@ -48,7 +61,7 @@ nv10_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
tile->zcomp = 0;
}
static void
void
nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
......@@ -62,7 +75,6 @@ nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv10_fb_priv *priv;
int ret;
......@@ -71,42 +83,13 @@ nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
if (device->chipset == 0x1a || device->chipset == 0x1f) {
struct pci_dev *bridge;
u32 mem, mib;
bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
if (!bridge) {
nv_fatal(device, "no bridge device\n");
return 0;
}
if (device->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;
}
priv->base.ram.type = NV_MEM_TYPE_STOLEN;
priv->base.ram.size = mib * 1024 * 1024;
} else {
u32 cfg0 = nv_rd32(priv, 0x100200);
if (cfg0 & 0x00000001)
priv->base.ram.type = NV_MEM_TYPE_DDR1;
else
priv->base.ram.type = NV_MEM_TYPE_SDRAM;
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
}
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_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
struct nouveau_oclass
......
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include <subdev/fb.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)
{
struct nv1a_fb_priv *priv;
int ret;
ret = nouveau_fb_create(parent, engine, 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);
}
struct nouveau_oclass
nv1a_fb_oclass = {
.handle = NV_SUBDEV(FB, 0x1a),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv1a_fb_ctor,
.dtor = _nouveau_fb_dtor,
.init = _nouveau_fb_init,
.fini = _nouveau_fb_fini,
},
};
......@@ -30,6 +30,22 @@ 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;
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)
......@@ -92,9 +108,7 @@ nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv20_fb_priv *priv;
u32 pbus1218;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -102,29 +116,14 @@ nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pbus1218 = nv_rd32(priv, 0x001218);
switch (pbus1218 & 0x00000300) {
case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break;
}
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
if (device->chipset >= 0x25)
ret = nouveau_mm_init(&priv->base.tags, 0, 64 * 1024, 1);
else
ret = nouveau_mm_init(&priv->base.tags, 0, 32 * 1024, 1);
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_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
struct nouveau_oclass
......
......@@ -60,9 +60,7 @@ nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv25_fb_priv *priv;
u32 pbus1218;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -70,29 +68,14 @@ nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pbus1218 = nv_rd32(priv, 0x001218);
switch (pbus1218 & 0x00000300) {
case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break;
}
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
if (device->chipset >= 0x25)
ret = nouveau_mm_init(&priv->base.tags, 0, 64 * 1024, 1);
else
ret = nouveau_mm_init(&priv->base.tags, 0, 32 * 1024, 1);
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_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
struct nouveau_oclass
......
......@@ -123,7 +123,6 @@ nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_object **pobject)
{
struct nv30_fb_priv *priv;
u32 pbus1218;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -131,22 +130,14 @@ nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pbus1218 = nv_rd32(priv, 0x001218);
switch (pbus1218 & 0x00000300) {
case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break;
}
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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 = nv30_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
struct nouveau_oclass
......
......@@ -43,7 +43,6 @@ nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_object **pobject)
{
struct nv35_fb_priv *priv;
u32 pbus1218;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -51,22 +50,14 @@ nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pbus1218 = nv_rd32(priv, 0x001218);
switch (pbus1218 & 0x00000300) {
case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break;
}
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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 = nv30_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
struct nouveau_oclass
......
......@@ -30,6 +30,21 @@ 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;
return nv_rd32(pfb, 0x100320);
}
static void
nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
......@@ -56,9 +71,7 @@ nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv40_fb_priv *priv;
u32 pbus1218;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -66,23 +79,14 @@ nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pbus1218 = nv_rd32(priv, 0x001218);
switch (pbus1218 & 0x00000300) {
case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_DDR2; break;
}
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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 = nv30_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
......
......@@ -30,6 +30,21 @@ 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;
return nv_rd32(pfb, 0x100320);
}
void
nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
......@@ -59,9 +74,7 @@ nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv41_fb_priv *priv;
u32 pfb474;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -69,22 +82,13 @@ nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pfb474 = nv_rd32(priv, 0x100474);
if (pfb474 & 0x00000004)
priv->base.ram.type = NV_MEM_TYPE_GDDR3;
if (pfb474 & 0x00000002)
priv->base.ram.type = NV_MEM_TYPE_DDR2;
if (pfb474 & 0x00000001)
priv->base.ram.type = NV_MEM_TYPE_DDR1;
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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.fini = nv30_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
......
......@@ -30,6 +30,21 @@ 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)
......@@ -69,9 +84,7 @@ nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv44_fb_priv *priv;
u32 pfb474;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -79,22 +92,13 @@ nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pfb474 = nv_rd32(priv, 0x100474);
if (pfb474 & 0x00000004)
priv->base.ram.type = NV_MEM_TYPE_GDDR3;
if (pfb474 & 0x00000002)
priv->base.ram.type = NV_MEM_TYPE_DDR2;
if (pfb474 & 0x00000001)
priv->base.ram.type = NV_MEM_TYPE_DDR1;
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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 = nv30_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
......
......@@ -49,9 +49,7 @@ nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv46_fb_priv *priv;
u32 pfb474;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -59,22 +57,13 @@ nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pfb474 = nv_rd32(priv, 0x100474);
if (pfb474 & 0x00000004)
priv->base.ram.type = NV_MEM_TYPE_GDDR3;
if (pfb474 & 0x00000002)
priv->base.ram.type = NV_MEM_TYPE_DDR2;
if (pfb474 & 0x00000001)
priv->base.ram.type = NV_MEM_TYPE_DDR1;
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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 = nv30_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
......
......@@ -35,9 +35,7 @@ nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nv47_fb_priv *priv;
u32 pfb474;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -45,22 +43,13 @@ nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pfb474 = nv_rd32(priv, 0x100474);
if (pfb474 & 0x00000004)
priv->base.ram.type = NV_MEM_TYPE_GDDR3;
if (pfb474 & 0x00000002)
priv->base.ram.type = NV_MEM_TYPE_DDR2;
if (pfb474 & 0x00000001)
priv->base.ram.type = NV_MEM_TYPE_DDR1;
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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.fini = nv30_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
......
......@@ -30,14 +30,28 @@ 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;
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)
{
struct nouveau_device *device = nv_device(parent);
struct nv49_fb_priv *priv;
u32 pfb914;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -45,23 +59,14 @@ nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
pfb914 = nv_rd32(priv, 0x100914);
switch (pfb914 & 0x00000003) {
case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
case 0x00000001: priv->base.ram.type = NV_MEM_TYPE_DDR2; break;
case 0x00000002: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
case 0x00000003: break;
}
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
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.fini = nv30_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
......
......@@ -30,12 +30,19 @@ 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)
{
struct nouveau_device *device = nv_device(parent);
struct nv4e_fb_priv *priv;
int ret;
......@@ -44,17 +51,15 @@ nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
priv->base.ram.type = NV_MEM_TYPE_STOLEN;
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 = nv30_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
struct nouveau_oclass
nv4e_fb_oclass = {
.handle = NV_SUBDEV(FB, 0x4e),
......
......@@ -51,6 +51,101 @@ 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;
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;
break;
}
return nv_rd32(pfb, 0x100320);
}
static int
nv50_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
u32 memtype, struct nouveau_mem **pmem)
......@@ -140,58 +235,13 @@ nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
kfree(mem);
}
static u32
nv50_vram_rblock(struct nv50_fb_priv *priv)
{
int i, parts, colbits, rowbitsa, rowbitsb, banks;
u64 rowsize, predicted;
u32 r0, r4, rt, ru, rblock_size;
r0 = nv_rd32(priv, 0x100200);
r4 = nv_rd32(priv, 0x100204);
rt = nv_rd32(priv, 0x100250);
ru = nv_rd32(priv, 0x001540);
nv_debug(priv, "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 != priv->base.ram.size) {
nv_warn(priv, "memory controller reports %d MiB VRAM\n",
(u32)(priv->base.ram.size >> 20));
}
rblock_size = rowsize;
if (rt & 1)
rblock_size *= 3;
nv_debug(priv, "rblock %d bytes\n", rblock_size);
return rblock_size;
}
static int
nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
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 */
struct nv50_fb_priv *priv;
u32 tags;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
......@@ -199,54 +249,6 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
switch (nv_rd32(priv, 0x100714) & 0x00000007) {
case 0: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
case 1:
if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
priv->base.ram.type = NV_MEM_TYPE_DDR3;
else
priv->base.ram.type = NV_MEM_TYPE_DDR2;
break;
case 2: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
case 3: priv->base.ram.type = NV_MEM_TYPE_GDDR4; break;
case 4: priv->base.ram.type = NV_MEM_TYPE_GDDR5; break;
default:
break;
}
priv->base.ram.size = nv_rd32(priv, 0x10020c);
priv->base.ram.size = (priv->base.ram.size & 0xffffff00) |
((priv->base.ram.size & 0x000000ff) << 32);
tags = nv_rd32(priv, 0x100320);
ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1);
if (ret)
return ret;
nv_debug(priv, "%d compression tags\n", tags);
size = (priv->base.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(&priv->base.vram, rsvd_head, size, 1);
if (ret)
return ret;
priv->base.ram.stolen = (u64)nv_rd32(priv, 0x100e10) << 12;
priv->base.ram.type = NV_MEM_TYPE_STOLEN;
break;
default:
ret = nouveau_mm_init(&priv->base.vram, rsvd_head, size,
nv50_vram_rblock(priv) >> 12);
if (ret)
return ret;
priv->base.ram.ranks = (nv_rd32(priv, 0x100200) & 0x4) ? 2 : 1;
break;
}
priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (priv->r100c08_page) {
priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page,
......@@ -259,9 +261,10 @@ 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;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
static void
......
......@@ -61,6 +61,65 @@ nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
return likely((types[memtype] == 1));
}
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)
......@@ -138,66 +197,6 @@ nvc0_fb_dtor(struct nouveau_object *object)
nouveau_fb_destroy(&priv->base);
}
static int
nvc0_vram_detect(struct nvc0_fb_priv *priv)
{
struct nouveau_bios *bios = nouveau_bios(priv);
struct nouveau_fb *pfb = &priv->base;
const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
u32 parts = nv_rd32(priv, 0x022438);
u32 pmask = nv_rd32(priv, 0x022554);
u32 bsize = nv_rd32(priv, 0x10f20c);
u32 offset, length;
bool uniform = true;
int ret, part;
nv_debug(priv, "0x100800: 0x%08x\n", nv_rd32(priv, 0x100800));
nv_debug(priv, "parts 0x%08x mask 0x%08x\n", parts, pmask);
priv->base.ram.type = nouveau_fb_bios_memtype(bios);
priv->base.ram.ranks = (nv_rd32(priv, 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(priv, 0x11020c + (part * 0x1000));
if (psize != bsize) {
if (psize < bsize)
bsize = psize;
uniform = false;
}
nv_debug(priv, "%d: mem_amount 0x%08x\n", part, psize);
priv->base.ram.size += (u64)psize << 20;
}
}
/* if all controllers have the same amount attached, there's no holes */
if (uniform) {
offset = rsvd_head;
length = (priv->base.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 = (priv->base.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_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
......@@ -213,13 +212,10 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
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 = nv50_fb_vram_del;
ret = nvc0_vram_detect(priv);
if (ret)
return ret;
priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!priv->r100c10_page)
return -ENOMEM;
......@@ -229,7 +225,7 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (pci_dma_mapping_error(device->pdev, priv->r100c10))
return -EFAULT;
return nouveau_fb_created(&priv->base);
return nouveau_fb_preinit(&priv->base);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment