From 861d21074bbb141b0cc165a61c11f571571cda12 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Jul 2012 19:05:01 +1000 Subject: drm/nouveau/fb: merge fb/vram and port to subdev interfaces Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c | 2 +- drivers/gpu/drm/nouveau/core/engine/graph/nv10.c | 4 +- drivers/gpu/drm/nouveau/core/engine/graph/nv20.c | 2 +- drivers/gpu/drm/nouveau/core/engine/graph/nv40.c | 5 +- drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c | 7 +- drivers/gpu/drm/nouveau/core/include/subdev/fb.h | 137 ++++++++ drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h | 33 ++ drivers/gpu/drm/nouveau/core/include/subdev/vm.h | 5 +- drivers/gpu/drm/nouveau/core/subdev/device/nv04.c | 3 + drivers/gpu/drm/nouveau/core/subdev/device/nv10.c | 9 + drivers/gpu/drm/nouveau/core/subdev/device/nv20.c | 5 + drivers/gpu/drm/nouveau/core/subdev/device/nv30.c | 6 + drivers/gpu/drm/nouveau/core/subdev/device/nv40.c | 17 + drivers/gpu/drm/nouveau/core/subdev/device/nv50.c | 15 + drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c | 18 + drivers/gpu/drm/nouveau/core/subdev/device/nve0.c | 6 + drivers/gpu/drm/nouveau/core/subdev/fb/base.c | 130 +++++++ drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c | 139 ++++++-- drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c | 186 +++++----- drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c | 208 ++++++----- drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c | 114 +++--- drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c | 261 ++++++++------ drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c | 384 ++++++++++++++++----- drivers/gpu/drm/nouveau/core/subdev/fb/nv50_vram.c | 243 ------------- drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c | 252 ++++++++++---- drivers/gpu/drm/nouveau/core/subdev/fb/nvc0_vram.c | 167 --------- drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c | 10 +- drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c | 91 +++++ drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c | 1 + drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c | 6 +- 30 files changed, 1497 insertions(+), 969 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/core/include/subdev/fb.h create mode 100644 drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h create mode 100644 drivers/gpu/drm/nouveau/core/subdev/fb/base.c delete mode 100644 drivers/gpu/drm/nouveau/core/subdev/fb/nv50_vram.c delete mode 100644 drivers/gpu/drm/nouveau/core/subdev/fb/nvc0_vram.c create mode 100644 drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c (limited to 'drivers/gpu/drm/nouveau/core') diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c index 3079f08..23ae459 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c @@ -163,7 +163,7 @@ nv40_fifo_init(struct drm_device *dev, int engine) break; default: nv_wr32(dev, 0x002230, 0x00000000); - nv_wr32(dev, 0x002220, ((dev_priv->vram_size - 512 * 1024 + + nv_wr32(dev, 0x002220, ((nvfb_vram_size(dev) - 512 * 1024 + dev_priv->ramfc->pinst) >> 16) | 0x00030000); break; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c index 19e303b..d006658 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c @@ -895,9 +895,7 @@ nv10_graph_context_del(struct nouveau_channel *chan, int engine) static void nv10_graph_set_tile_region(struct drm_device *dev, int i) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - + struct nouveau_fb_tile *tile = nvfb_tile(dev, i); nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV10_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c index 718ecf7..dd31156 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c @@ -472,7 +472,7 @@ static void nv20_graph_set_tile_region(struct drm_device *dev, int i) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + struct nouveau_fb_tile *tile = nvfb_tile(dev, i); nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 4ad9759..ab3af6d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -125,7 +125,7 @@ static void nv40_graph_set_tile_region(struct drm_device *dev, int i) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + struct nouveau_fb_tile *tile = nvfb_tile(dev, i); switch (dev_priv->chipset) { case 0x40: @@ -178,7 +178,6 @@ nv40_graph_init(struct drm_device *dev, int engine) { struct nv40_graph_engine *pgraph = nv_engine(dev, engine); struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; uint32_t vramsz; int i, j; @@ -280,7 +279,7 @@ nv40_graph_init(struct drm_device *dev, int engine) } /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->num_tiles; i++) + for (i = 0; i < nvfb_tile_nr(dev); i++) nv40_graph_set_tile_region(dev, i); /* begin RAM config */ diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c index 4a14a67..eb5455f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c @@ -128,7 +128,6 @@ nv31_mpeg_object_new(struct nouveau_channel *chan, int engine, static int nv31_mpeg_init(struct drm_device *dev, int engine) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); int i; @@ -138,7 +137,7 @@ nv31_mpeg_init(struct drm_device *dev, int engine) nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) + for (i = 0; i < nvfb_tile_nr(dev); i++) pmpeg->base.set_tile_region(dev, i); /* PMPEG init */ @@ -235,9 +234,7 @@ nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) static void nv31_vpe_set_tile_region(struct drm_device *dev, int i) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - + struct nouveau_fb_tile *tile = nvfb_tile(dev, i); nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h new file mode 100644 index 0000000..91dbdc1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h @@ -0,0 +1,137 @@ +#ifndef __NOUVEAU_FB_H__ +#define __NOUVEAU_FB_H__ + +#ifndef XXX_THIS_IS_A_HACK +#include +#include +#endif +#include +#include + +/* memory type/access flags, do not match hardware values */ +#define NV_MEM_ACCESS_RO 1 +#define NV_MEM_ACCESS_WO 2 +#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO) +#define NV_MEM_ACCESS_SYS 4 +#define NV_MEM_ACCESS_VM 8 +#define NV_MEM_ACCESS_NOSNOOP 16 + +#define NV_MEM_TARGET_VRAM 0 +#define NV_MEM_TARGET_PCI 1 +#define NV_MEM_TARGET_PCI_NOSNOOP 2 +#define NV_MEM_TARGET_VM 3 +#define NV_MEM_TARGET_GART 4 + +#define NV_MEM_TYPE_VM 0x7f +#define NV_MEM_COMP_VM 0x03 + +struct nouveau_mem { + struct drm_device *dev; + + struct nouveau_vma bar_vma; + struct nouveau_vma vma[2]; + u8 page_shift; + + struct nouveau_mm_node *tag; + struct list_head regions; + dma_addr_t *pages; + u32 memtype; + u64 offset; + u64 size; + struct sg_table *sg; +}; + +struct nouveau_fb_tile { + struct nouveau_mm_node *tag; + u32 addr; + u32 limit; + u32 pitch; + u32 zcomp; +}; + +#ifndef XXX_THIS_IS_A_HACK +struct nouveau_fb { + struct nouveau_subdev base; + + bool (*memtype_valid)(struct nouveau_fb *, u32 memtype); + + struct { + enum { + NV_MEM_TYPE_UNKNOWN = 0, + NV_MEM_TYPE_STOLEN, + NV_MEM_TYPE_SGRAM, + NV_MEM_TYPE_SDRAM, + NV_MEM_TYPE_DDR1, + NV_MEM_TYPE_DDR2, + NV_MEM_TYPE_DDR3, + NV_MEM_TYPE_GDDR2, + NV_MEM_TYPE_GDDR3, + NV_MEM_TYPE_GDDR4, + NV_MEM_TYPE_GDDR5 + } type; + u64 stolen; + u64 size; + int ranks; + + 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 **); + } ram; + + struct nouveau_mm vram; + struct nouveau_mm tags; + + struct { + struct nouveau_fb_tile region[16]; + int regions; + void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); + void (*fini)(struct nouveau_fb *, int i, + struct nouveau_fb_tile *); + void (*prog)(struct nouveau_fb *, int i, + struct nouveau_fb_tile *); + } tile; +}; + +static inline struct nouveau_fb * +nouveau_fb(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB]; +} + +#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 *); +void nouveau_fb_destroy(struct nouveau_fb *); +int nouveau_fb_init(struct nouveau_fb *); +#define nouveau_fb_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +void _nouveau_fb_dtor(struct nouveau_object *); +int _nouveau_fb_init(struct nouveau_object *); +#define _nouveau_fb_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv04_fb_oclass; +extern struct nouveau_oclass nv10_fb_oclass; +extern struct nouveau_oclass nv20_fb_oclass; +extern struct nouveau_oclass nv30_fb_oclass; +extern struct nouveau_oclass nv40_fb_oclass; +extern struct nouveau_oclass nv50_fb_oclass; +extern struct nouveau_oclass nvc0_fb_oclass; + +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_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +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 *); + +void nv50_fb_vram_del(struct nouveau_fb *, struct nouveau_mem **); +void nv50_fb_trap(struct nouveau_fb *, int display); +#endif + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h new file mode 100644 index 0000000..f351f63 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h @@ -0,0 +1,33 @@ +#ifndef __NOUVEAU_LTCG_H__ +#define __NOUVEAU_LTCG_H__ + +#include +#include + +struct nouveau_ltcg { + struct nouveau_subdev base; +}; + +static inline struct nouveau_ltcg * +nouveau_ltcg(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_LTCG]; +} + +#define nouveau_ltcg_create(p,e,o,d) \ + nouveau_subdev_create_((p), (e), (o), 0, "PLTCG", "level2", \ + sizeof(**d), (void **)d) +#define nouveau_ltcg_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_ltcg_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_ltcg_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +#define _nouveau_ltcg_dtor _nouveau_subdev_dtor +#define _nouveau_ltcg_init _nouveau_subdev_init +#define _nouveau_ltcg_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nvc0_ltcg_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h index 7c1fc21..6d3764b 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h @@ -25,11 +25,10 @@ #ifndef __NOUVEAU_VM_H__ #define __NOUVEAU_VM_H__ -#include "drmP.h" - -#include "nouveau_drv.h" #include +struct nouveau_mem; + struct nouveau_vm_pgt { struct nouveau_gpuobj *obj[2]; u32 refcount[2]; diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c index aa43bd5..66b7156 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c @@ -29,6 +29,7 @@ #include #include #include +#include int nv04_identify(struct nouveau_device *device) @@ -41,6 +42,7 @@ nv04_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; break; case 0x05: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -49,6 +51,7 @@ nv04_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; break; default: nv_fatal(device, "unknown RIVA chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c index 1926c33..cf81479 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c @@ -30,6 +30,7 @@ #include #include #include +#include int nv10_identify(struct nouveau_device *device) @@ -43,6 +44,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_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; break; case 0x15: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -52,6 +54,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_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; break; case 0x16: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -61,6 +64,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_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; break; case 0x1a: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -70,6 +74,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; break; case 0x11: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -79,6 +84,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_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; break; case 0x17: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -88,6 +94,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_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; break; case 0x1f: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -97,6 +104,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; break; case 0x18: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -106,6 +114,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_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; break; default: nv_fatal(device, "unknown Celsius chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c index 88729c3..e97280c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c @@ -30,6 +30,7 @@ #include #include #include +#include int nv20_identify(struct nouveau_device *device) @@ -43,6 +44,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; break; case 0x25: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -52,6 +54,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; break; case 0x28: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -61,6 +64,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; break; case 0x2a: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -70,6 +74,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; break; default: nv_fatal(device, "unknown Kelvin chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c index 4feea88..ddd3ab6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c @@ -30,6 +30,7 @@ #include #include #include +#include int nv30_identify(struct nouveau_device *device) @@ -43,6 +44,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; break; case 0x35: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -52,6 +54,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; break; case 0x31: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -61,6 +64,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; break; case 0x36: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -70,6 +74,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; break; case 0x34: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -79,6 +84,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; break; default: nv_fatal(device, "unknown Rankine chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c index 8f68361..c7ea921 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c @@ -30,6 +30,7 @@ #include #include #include +#include int nv40_identify(struct nouveau_device *device) @@ -43,6 +44,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x41: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -52,6 +54,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x42: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -61,6 +64,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x43: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -70,6 +74,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x45: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -79,6 +84,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x47: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -88,6 +94,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x49: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -97,6 +104,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x4b: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -106,6 +114,7 @@ nv40_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 ] = &nv40_fb_oclass; break; case 0x44: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -115,6 +124,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; case 0x46: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -124,6 +134,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; case 0x4a: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -133,6 +144,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; case 0x4c: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -142,6 +154,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; case 0x4e: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -151,6 +164,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; case 0x63: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -160,6 +174,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; case 0x67: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -169,6 +184,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; case 0x68: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -178,6 +194,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; break; default: nv_fatal(device, "unknown Curie chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c index e844525..e60cdf2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c @@ -30,6 +30,7 @@ #include #include #include +#include int nv50_identify(struct nouveau_device *device) @@ -43,6 +44,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0x84: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -52,6 +54,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0x86: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -61,6 +64,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0x92: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -70,6 +74,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0x94: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -79,6 +84,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0x96: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -88,6 +94,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0x98: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -97,6 +104,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0xa0: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -106,6 +114,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0xaa: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -115,6 +124,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0xac: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -124,6 +134,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0xa3: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -133,6 +144,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0xa5: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -142,6 +154,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0xa8: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -151,6 +164,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; case 0xaf: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -160,6 +174,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; break; default: nv_fatal(device, "unknown Tesla chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c index 56d1950..8de6730 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include int nvc0_identify(struct nouveau_device *device) @@ -43,6 +45,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xc4: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -52,6 +56,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xc3: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -61,6 +67,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xce: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -70,6 +78,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xcf: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -79,6 +89,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xc1: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -88,6 +100,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xc8: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -97,6 +111,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xd9: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -106,6 +122,8 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; default: nv_fatal(device, "unknown Fermi chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c index ab5e052..919a102 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include int nve0_identify(struct nouveau_device *device) @@ -43,6 +45,8 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; case 0xe7: device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; @@ -52,6 +56,8 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; break; default: nv_fatal(device, "unknown Kepler chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c new file mode 100644 index 0000000..f0086de --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c @@ -0,0 +1,130 @@ +/* + * Copyright 2012 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/fb.h" +#include "subdev/bios.h" +#include "subdev/bios/bit.h" + +int +nouveau_fb_bios_memtype(struct nouveau_bios *bios) +{ + struct bit_entry M; + u8 ramcfg; + + ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2; + if (!bit_entry(bios, 'M', &M) && M.version == 2 && M.length >= 5) { + u16 table = nv_ro16(bios, M.offset + 3); + u8 version = nv_ro08(bios, table + 0); + u8 header = nv_ro08(bios, table + 1); + u8 record = nv_ro08(bios, table + 2); + u8 entries = nv_ro08(bios, table + 3); + if (table && version == 0x10 && ramcfg < entries) { + u16 entry = table + header + (ramcfg * record); + switch (nv_ro08(bios, entry) & 0x0f) { + case 0: return NV_MEM_TYPE_DDR2; + case 1: return NV_MEM_TYPE_DDR3; + case 2: return NV_MEM_TYPE_GDDR3; + case 3: return NV_MEM_TYPE_GDDR5; + default: + break; + } + + } + } + + return NV_MEM_TYPE_UNKNOWN; +} + +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); +} + +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]); + + if (pfb->tags.block_size) + nouveau_mm_fini(&pfb->tags); + + if (pfb->vram.block_size) + 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_created(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", + }; + + if (pfb->ram.size == 0) { + nv_fatal(pfb, "no vram detected!!\n"); + return -ERANGE; + } + + 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; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c index eef4844..eb06836 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c @@ -1,55 +1,130 @@ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include +/* + * Copyright 2012 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 + */ -int -nv04_fb_vram_init(struct drm_device *dev) +#include + +#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 { + struct nouveau_fb base; +}; + +bool +nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) +{ + if (!(tile_flags & 0xff00)) + return true; + + return false; +} + +static int +nv04_fb_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 boot0 = nv_rd32(dev, NV04_PFB_BOOT_0); + struct nv04_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + /* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows + * nvidia reading PFB_CFG_0, then writing back its original value. + * (which was 0x701114 in this case) + */ + nv_wr32(priv, NV04_PFB_CFG0, 0x1114); + return 0; +} +static int +nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_fb_priv *priv; + u32 boot0; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + boot0 = nv_rd32(priv, NV04_PFB_BOOT_0); if (boot0 & 0x00000100) { - dev_priv->vram_size = ((boot0 >> 12) & 0xf) * 2 + 2; - dev_priv->vram_size *= 1024 * 1024; + 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: - dev_priv->vram_size = 32 * 1024 * 1024; + priv->base.ram.size = 32 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: - dev_priv->vram_size = 16 * 1024 * 1024; + priv->base.ram.size = 16 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: - dev_priv->vram_size = 8 * 1024 * 1024; + priv->base.ram.size = 8 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: - dev_priv->vram_size = 4 * 1024 * 1024; + priv->base.ram.size = 4 * 1024 * 1024; break; } } if ((boot0 & 0x00000038) <= 0x10) - dev_priv->vram_type = NV_MEM_TYPE_SGRAM; + priv->base.ram.type = NV_MEM_TYPE_SGRAM; else - dev_priv->vram_type = NV_MEM_TYPE_SDRAM; + priv->base.ram.type = NV_MEM_TYPE_SDRAM; - return 0; -} - -int -nv04_fb_init(struct drm_device *dev) -{ - /* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows - * nvidia reading PFB_CFG_0, then writing back its original value. - * (which was 0x701114 in this case) - */ - nv_wr32(dev, NV04_PFB_CFG0, 0x1114); - return 0; + priv->base.memtype_valid = nv04_fb_memtype_valid; + return nouveau_fb_created(&priv->base); } -void -nv04_fb_takedown(struct drm_device *dev) -{ -} +struct nouveau_oclass +nv04_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = nv04_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c index 09af63b..f037a42 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c @@ -1,104 +1,120 @@ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include - -void -nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch, uint32_t flags) +/* + * 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 + +struct nv10_fb_priv { + struct nouveau_fb base; +}; + +static void +nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, + u32 flags, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - tile->addr = 0x80000000 | addr; tile->limit = max(1u, addr + size) - 1; tile->pitch = pitch; } -void -nv10_fb_free_tile_region(struct drm_device *dev, int i) +static void +nv10_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - - tile->addr = tile->limit = tile->pitch = tile->zcomp = 0; + tile->addr = 0; + tile->limit = 0; + tile->pitch = 0; + tile->zcomp = 0; } void -nv10_fb_set_tile_region(struct drm_device *dev, int i) +nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - - nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); - nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); - nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); + nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); + nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); + nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); } -int -nv1a_fb_vram_init(struct drm_device *dev) +static int +nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct pci_dev *bridge; - uint32_t mem, mib; - - bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); - if (!bridge) { - NV_ERROR(dev, "no bridge device\n"); - return 0; - } - - if (dev_priv->chipset == 0x1a) { - pci_read_config_dword(bridge, 0x7c, &mem); - mib = ((mem >> 6) & 31) + 1; + struct nouveau_device *device = nv_device(parent); + struct nv10_fb_priv *priv; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + 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 { - pci_read_config_dword(bridge, 0x84, &mem); - mib = ((mem >> 4) & 127) + 1; - } + 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; - dev_priv->vram_size = mib * 1024 * 1024; - return 0; -} - -int -nv10_fb_vram_init(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 fifo_data = nv_rd32(dev, NV04_PFB_FIFO_DATA); - u32 cfg0 = nv_rd32(dev, 0x100200); - - dev_priv->vram_size = fifo_data & NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; - - if (cfg0 & 0x00000001) - dev_priv->vram_type = NV_MEM_TYPE_DDR1; - else - dev_priv->vram_type = NV_MEM_TYPE_SDRAM; - - return 0; -} - -int -nv10_fb_init(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - int i; - - /* Turn all the tiling regions off. */ - pfb->num_tiles = NV10_PFB_TILE__SIZE; - for (i = 0; i < pfb->num_tiles; i++) - pfb->set_tile_region(dev, i); + priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000; + } - return 0; + priv->base.memtype_valid = nv04_fb_memtype_valid; + 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); } -void -nv10_fb_takedown(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - int i; - - for (i = 0; i < pfb->num_tiles; i++) - pfb->free_tile_region(dev, i); -} +struct nouveau_oclass +nv10_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = _nouveau_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c index a7f056c..4b3578f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c @@ -1,49 +1,41 @@ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include - -static struct drm_mm_node * -nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct drm_mm_node *mem; - int ret; - - ret = drm_mm_pre_get(&pfb->tag_heap); - if (ret) - return NULL; - - spin_lock(&dev_priv->tile.lock); - mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0); - if (mem) - mem = drm_mm_get_block_atomic(mem, size, 0); - spin_unlock(&dev_priv->tile.lock); - - return mem; -} +/* + * 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 + +struct nv20_fb_priv { + struct nouveau_fb base; +}; static void -nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node **pmem) +nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, + u32 flags, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_mm_node *mem = *pmem; - if (mem) { - spin_lock(&dev_priv->tile.lock); - drm_mm_put_block(mem); - spin_unlock(&dev_priv->tile.lock); - *pmem = NULL; - } -} - -void -nv20_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch, uint32_t flags) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16); + struct nouveau_device *device = nv_device(pfb); + int bpp = (flags & 2) ? 32 : 16; tile->addr = 0x00000001 | addr; tile->limit = max(1u, addr + size) - 1; @@ -53,20 +45,20 @@ nv20_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, * compression meta-data (most likely just a bitmap determining * if a given tile is compressed or not). */ - if (flags & NOUVEAU_GEM_TILE_ZETA) { - tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256); - if (tile->tag_mem) { + size /= 256; + if (flags & 4) { + if (!nouveau_mm_head(&pfb->tags, 1, size, size, 1, &tile->tag)) { /* Enable Z compression */ - tile->zcomp = tile->tag_mem->start; - if (dev_priv->chipset >= 0x25) { + tile->zcomp = tile->tag->offset; + if (device->chipset >= 0x25) { if (bpp == 16) - tile->zcomp |= NV25_PFB_ZCOMP_MODE_16; + tile->zcomp |= 0x00100000; else - tile->zcomp |= NV25_PFB_ZCOMP_MODE_32; + tile->zcomp |= 0x00200000; } else { - tile->zcomp |= NV20_PFB_ZCOMP_EN; + tile->zcomp |= 0x80000000; if (bpp != 16) - tile->zcomp |= NV20_PFB_ZCOMP_MODE_32; + tile->zcomp |= 0x04000000; } } @@ -74,75 +66,71 @@ nv20_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, } } -void -nv20_fb_free_tile_region(struct drm_device *dev, int i) +static void +nv20_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - - tile->addr = tile->limit = tile->pitch = tile->zcomp = 0; - nv20_fb_free_tag(dev, &tile->tag_mem); + tile->addr = 0; + tile->limit = 0; + tile->pitch = 0; + tile->zcomp = 0; + nouveau_mm_free(&pfb->tags, &tile->tag); } -void -nv20_fb_set_tile_region(struct drm_device *dev, int i) +static void +nv20_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - - nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); - nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); - nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); - nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp); + nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); + nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); + nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); + nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp); } -int -nv20_fb_vram_init(struct drm_device *dev) +static int +nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 mem_size = nv_rd32(dev, 0x10020c); - u32 pbus1218 = nv_rd32(dev, 0x001218); + struct nouveau_device *device = nv_device(parent); + struct nv20_fb_priv *priv; + u32 pbus1218; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - dev_priv->vram_size = mem_size & 0xff000000; + pbus1218 = nv_rd32(priv, 0x001218); switch (pbus1218 & 0x00000300) { - case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: dev_priv->vram_type = NV_MEM_TYPE_GDDR2; break; + 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; - return 0; -} - -int -nv20_fb_init(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - int i; - - if (dev_priv->chipset >= 0x25) - drm_mm_init(&pfb->tag_heap, 0, 64 * 1024); + if (device->chipset >= 0x25) + ret = nouveau_mm_init(&priv->base.tags, 0, 64 * 1024, 1); else - drm_mm_init(&pfb->tag_heap, 0, 32 * 1024); - - /* Turn all the tiling regions off. */ - pfb->num_tiles = NV10_PFB_TILE__SIZE; - for (i = 0; i < pfb->num_tiles; i++) - pfb->set_tile_region(dev, i); - - return 0; + 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.tile.regions = 8; + priv->base.tile.init = nv20_fb_tile_init; + priv->base.tile.fini = nv20_fb_tile_fini; + priv->base.tile.prog = nv20_fb_tile_prog; + return nouveau_fb_created(&priv->base); } -void -nv20_fb_takedown(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - int i; - - for (i = 0; i < pfb->num_tiles; i++) - pfb->free_tile_region(dev, i); - - drm_mm_takedown(&pfb->tag_heap); -} +struct nouveau_oclass +nv20_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x20), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv20_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = _nouveau_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c index 30639a0..cba67bc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c @@ -24,50 +24,47 @@ * */ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include +#include + +struct nv30_fb_priv { + struct nouveau_fb base; +}; void -nv30_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch, uint32_t flags) +nv30_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, + u32 flags, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - tile->addr = addr | 1; tile->limit = max(1u, addr + size) - 1; tile->pitch = pitch; } void -nv30_fb_free_tile_region(struct drm_device *dev, int i) +nv30_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - - tile->addr = tile->limit = tile->pitch = 0; + tile->addr = 0; + tile->limit = 0; + tile->pitch = 0; } static int -calc_bias(struct drm_device *dev, int k, int i, int j) +calc_bias(struct nv30_fb_priv *priv, int k, int i, int j) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - int b = (dev_priv->chipset > 0x30 ? - nv_rd32(dev, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : + struct nouveau_device *device = nv_device(priv); + int b = (device->chipset > 0x30 ? + nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : 0) & 0xf; return 2 * (b & 0x8 ? b - 0x10 : b); } static int -calc_ref(struct drm_device *dev, int l, int k, int i) +calc_ref(struct nv30_fb_priv *priv, int l, int k, int i) { int j, x = 0; for (j = 0; j < 4; j++) { - int m = (l >> (8 * i) & 0xff) + calc_bias(dev, k, i, j); + int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j); x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j); } @@ -75,42 +72,77 @@ calc_ref(struct drm_device *dev, int l, int k, int i) return x; } -int -nv30_fb_init(struct drm_device *dev) +static int +nv30_fb_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - int i, j; - - pfb->num_tiles = NV10_PFB_TILE__SIZE; + struct nouveau_device *device = nv_device(object); + struct nv30_fb_priv *priv = (void *)object; + int ret, i, j; - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->num_tiles; i++) - pfb->set_tile_region(dev, i); + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; /* Init the memory timing regs at 0x10037c/0x1003ac */ - if (dev_priv->chipset == 0x30 || - dev_priv->chipset == 0x31 || - dev_priv->chipset == 0x35) { + if (device->chipset == 0x30 || + device->chipset == 0x31 || + device->chipset == 0x35) { /* Related to ROP count */ - int n = (dev_priv->chipset == 0x31 ? 2 : 4); - int l = nv_rd32(dev, 0x1003d0); + int n = (device->chipset == 0x31 ? 2 : 4); + int l = nv_rd32(priv, 0x1003d0); for (i = 0; i < n; i++) { for (j = 0; j < 3; j++) - nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j, - calc_ref(dev, l, 0, j)); + nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j, + calc_ref(priv, l, 0, j)); for (j = 0; j < 2; j++) - nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j, - calc_ref(dev, l, 1, j)); + nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j, + calc_ref(priv, l, 1, j)); } } return 0; } -void -nv30_fb_takedown(struct drm_device *dev) +static int +nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { + struct nv30_fb_priv *priv; + u32 pbus1218; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + 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.tile.regions = 8; + priv->base.tile.init = nv30_fb_tile_init; + priv->base.tile.fini = nv30_fb_tile_fini; + priv->base.tile.prog = nv10_fb_tile_prog; + return nouveau_fb_created(&priv->base); } + +struct nouveau_oclass +nv30_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x30), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv30_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = nv30_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c index e08c2e1..84aa71c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c @@ -1,55 +1,83 @@ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include - -void -nv40_fb_set_tile_region(struct drm_device *dev, int i) +/* + * 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 + +struct nv40_fb_priv { + struct nouveau_fb base; +}; + +static inline int +nv44_graph_class(struct nouveau_device *device) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + if ((device->chipset & 0xf0) == 0x60) + return 1; - switch (dev_priv->chipset) { - case 0x40: - nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); - nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); - nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); - break; + return !(0x0baf & (1 << (device->chipset & 0x0f))); +} - default: - nv_wr32(dev, NV40_PFB_TLIMIT(i), tile->limit); - nv_wr32(dev, NV40_PFB_TSIZE(i), tile->pitch); - nv_wr32(dev, NV40_PFB_TILE(i), tile->addr); - break; - } +static void +nv40_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) +{ + nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit); + nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch); + nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr); } static void -nv40_fb_init_gart(struct drm_device *dev) +nv40_fb_init_gart(struct nv40_fb_priv *priv) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; +#if 0 + struct nouveau_gpuobj *gart = ndev->gart_info.sg_ctxdma; - if (dev_priv->gart_info.type != NOUVEAU_GART_HW) { - nv_wr32(dev, 0x100800, 0x00000001); + if (ndev->gart_info.type != NOUVEAU_GART_HW) { +#endif + nv_wr32(priv, 0x100800, 0x00000001); +#if 0 return; } - nv_wr32(dev, 0x100800, gart->pinst | 0x00000002); - nv_mask(dev, 0x10008c, 0x00000100, 0x00000100); - nv_wr32(dev, 0x100820, 0x00000000); + nv_wr32(ndev, 0x100800, gart->pinst | 0x00000002); + nv_mask(ndev, 0x10008c, 0x00000100, 0x00000100); + nv_wr32(ndev, 0x100820, 0x00000000); +#endif } static void -nv44_fb_init_gart(struct drm_device *dev) +nv44_fb_init_gart(struct nv40_fb_priv *priv) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; +#if 0 + struct nouveau_gpuobj *gart = ndev->gart_info.sg_ctxdma; u32 vinst; - if (dev_priv->gart_info.type != NOUVEAU_GART_HW) { - nv_wr32(dev, 0x100850, 0x80000000); - nv_wr32(dev, 0x100800, 0x00000001); + if (ndev->gart_info.type != NOUVEAU_GART_HW) { +#endif + nv_wr32(priv, 0x100850, 0x80000000); + nv_wr32(priv, 0x100800, 0x00000001); +#if 0 return; } @@ -57,24 +85,60 @@ nv44_fb_init_gart(struct drm_device *dev) * must be allocated on 512KiB alignment, and not exceed * a total size of 512KiB for this to work correctly */ - vinst = nv_rd32(dev, 0x10020c); + vinst = nv_rd32(ndev, 0x10020c); vinst -= ((gart->pinst >> 19) + 1) << 19; - nv_wr32(dev, 0x100850, 0x80000000); - nv_wr32(dev, 0x100818, dev_priv->gart_info.dummy.addr); + nv_wr32(ndev, 0x100850, 0x80000000); + nv_wr32(ndev, 0x100818, ndev->gart_info.dummy.addr); + + nv_wr32(ndev, 0x100804, ndev->gart_info.aper_size); + nv_wr32(ndev, 0x100850, 0x00008000); + nv_mask(ndev, 0x10008c, 0x00000200, 0x00000200); + nv_wr32(ndev, 0x100820, 0x00000000); + nv_wr32(ndev, 0x10082c, 0x00000001); + nv_wr32(ndev, 0x100800, vinst | 0x00000010); +#endif +} + +static int +nv40_fb_init(struct nouveau_object *object) +{ + struct nv40_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + switch (nv_device(priv)->chipset) { + case 0x40: + case 0x45: + nv_mask(priv, 0x10033c, 0x00008000, 0x00000000); + break; + default: + if (nv44_graph_class(nv_device(priv))) + nv44_fb_init_gart(priv); + else + nv40_fb_init_gart(priv); + break; + } - nv_wr32(dev, 0x100804, dev_priv->gart_info.aper_size); - nv_wr32(dev, 0x100850, 0x00008000); - nv_mask(dev, 0x10008c, 0x00000200, 0x00000200); - nv_wr32(dev, 0x100820, 0x00000000); - nv_wr32(dev, 0x10082c, 0x00000001); - nv_wr32(dev, 0x100800, vinst | 0x00000010); + return 0; } -int -nv40_fb_vram_init(struct drm_device *dev) +static int +nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_device *device = nv_device(parent); + struct nv40_fb_priv *priv; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; /* 0x001218 is actually present on a few other NV4X I looked at, * and even contains sane values matching 0x100474. From looking @@ -82,82 +146,73 @@ nv40_fb_vram_init(struct drm_device *dev) * So, I chose to use the same regs I've seen NVIDIA reading around * the memory detection, hopefully that'll get us the right numbers */ - if (dev_priv->chipset == 0x40) { - u32 pbus1218 = nv_rd32(dev, 0x001218); + if (device->chipset == 0x40) { + u32 pbus1218 = nv_rd32(priv, 0x001218); switch (pbus1218 & 0x00000300) { - case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: dev_priv->vram_type = NV_MEM_TYPE_DDR2; break; + 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; } } else - if (dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) { - u32 pfb914 = nv_rd32(dev, 0x100914); + if (device->chipset == 0x49 || device->chipset == 0x4b) { + u32 pfb914 = nv_rd32(priv, 0x100914); switch (pfb914 & 0x00000003) { - case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break; - case 0x00000001: dev_priv->vram_type = NV_MEM_TYPE_DDR2; break; - case 0x00000002: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break; + 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; } } else - if (dev_priv->chipset != 0x4e) { - u32 pfb474 = nv_rd32(dev, 0x100474); + if (device->chipset != 0x4e) { + u32 pfb474 = nv_rd32(priv, 0x100474); if (pfb474 & 0x00000004) - dev_priv->vram_type = NV_MEM_TYPE_GDDR3; + priv->base.ram.type = NV_MEM_TYPE_GDDR3; if (pfb474 & 0x00000002) - dev_priv->vram_type = NV_MEM_TYPE_DDR2; + priv->base.ram.type = NV_MEM_TYPE_DDR2; if (pfb474 & 0x00000001) - dev_priv->vram_type = NV_MEM_TYPE_DDR1; + priv->base.ram.type = NV_MEM_TYPE_DDR1; } else { - dev_priv->vram_type = NV_MEM_TYPE_STOLEN; + priv->base.ram.type = NV_MEM_TYPE_STOLEN; } - dev_priv->vram_size = nv_rd32(dev, 0x10020c) & 0xff000000; - return 0; -} - -int -nv40_fb_init(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - uint32_t tmp; - int i; - - if (dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { - if (nv44_graph_class(dev)) - nv44_fb_init_gart(dev); - else - nv40_fb_init_gart(dev); - } + priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000; - switch (dev_priv->chipset) { + priv->base.memtype_valid = nv04_fb_memtype_valid; + switch (device->chipset) { case 0x40: case 0x45: - tmp = nv_rd32(dev, NV10_PFB_CLOSE_PAGE2); - nv_wr32(dev, NV10_PFB_CLOSE_PAGE2, tmp & ~(1 << 15)); - pfb->num_tiles = NV10_PFB_TILE__SIZE; + priv->base.tile.regions = 8; break; - case 0x46: /* G72 */ - case 0x47: /* G70 */ - case 0x49: /* G71 */ - case 0x4b: /* G73 */ - case 0x4c: /* C51 (G7X version) */ - pfb->num_tiles = NV40_PFB_TILE__SIZE_1; + case 0x46: + case 0x47: + case 0x49: + case 0x4b: + case 0x4c: + priv->base.tile.regions = 15; break; default: - pfb->num_tiles = NV40_PFB_TILE__SIZE_0; + priv->base.tile.regions = 12; break; } - - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->num_tiles; i++) - pfb->set_tile_region(dev, i); - - return 0; + priv->base.tile.init = nv30_fb_tile_init; + priv->base.tile.fini = nv30_fb_tile_fini; + if (device->chipset == 0x40) + priv->base.tile.prog = nv10_fb_tile_prog; + else + priv->base.tile.prog = nv40_fb_tile_prog; + + return nouveau_fb_created(&priv->base); } -void -nv40_fb_takedown(struct drm_device *dev) -{ -} + +struct nouveau_oclass +nv40_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = nv40_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index a145b1c..eaf18fb 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -1,119 +1,335 @@ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include -#include +/* + * Copyright 2012 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 +#include + +#include +#include struct nv50_fb_priv { + struct nouveau_fb base; struct page *r100c08_page; dma_addr_t r100c08; }; -static void -nv50_fb_destroy(struct drm_device *dev) +static int types[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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 +}; + +static bool +nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct nv50_fb_priv *priv = pfb->priv; + return types[(memtype & 0xff00) >> 8] != 0; +} - if (drm_mm_initialized(&pfb->tag_heap)) - drm_mm_takedown(&pfb->tag_heap); +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; - if (priv->r100c08_page) { - pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - __free_page(priv->r100c08_page); + 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; } - kfree(priv); - pfb->priv = NULL; + 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; } -static int -nv50_fb_create(struct drm_device *dev) +void +nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct nv50_fb_priv *priv; - u32 tagmem; - int ret; + struct nv50_fb_priv *priv = (void *)pfb; + struct nouveau_mm_node *this; + struct nouveau_mem *mem; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - pfb->priv = priv; + mem = *pmem; + *pmem = NULL; + if (unlikely(mem == NULL)) + return; - priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!priv->r100c08_page) { - nv50_fb_destroy(dev); - return -ENOMEM; + 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); } - priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) { - nv50_fb_destroy(dev); - return -EFAULT; + nouveau_mm_free(&priv->base.tags, &mem->tag); + mutex_unlock(&pfb->base.mutex); + + 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++; } - tagmem = nv_rd32(dev, 0x100320); - NV_DEBUG(dev, "%d tags available\n", tagmem); - ret = drm_mm_init(&pfb->tag_heap, 0, tagmem); - if (ret) { - nv50_fb_destroy(dev); - return ret; + 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)); } - return 0; + rblock_size = rowsize; + if (rt & 1) + rblock_size *= 3; + + nv_debug(priv, "rblock %d bytes\n", rblock_size); + return rblock_size; } -int -nv50_fb_init(struct drm_device *dev) +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 drm_nouveau_private *dev_priv = dev->dev_private; + 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; - if (!dev_priv->engine.fb.priv) { - ret = nv50_fb_create(dev); + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + 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); + if (tags) { + 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; + 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, + 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(device->pdev, priv->r100c08)) + nv_warn(priv, "failed 0x100c08 page map\n"); + } else { + nv_warn(priv, "failed 0x100c08 page alloc\n"); } - priv = dev_priv->engine.fb.priv; + + priv->base.memtype_valid = nv50_fb_memtype_valid; + priv->base.ram.get = nv50_fb_vram_new; + priv->base.ram.put = nv50_fb_vram_del; + return nouveau_fb_created(&priv->base); +} + +static void +nv50_fb_dtor(struct nouveau_object *object) +{ + struct nouveau_device *device = nv_device(object); + struct nv50_fb_priv *priv = (void *)object; + + if (priv->r100c08_page) { + pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + __free_page(priv->r100c08_page); + } + + nouveau_mm_fini(&priv->base.vram); + nouveau_fb_destroy(&priv->base); +} + +static int +nv50_fb_init(struct nouveau_object *object) +{ + struct nouveau_device *device = nv_device(object); + struct nv50_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; /* Not a clue what this is exactly. Without pointing it at a * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) * cause IOMMU "read from address 0" errors (rh#561267) */ - nv_wr32(dev, 0x100c08, priv->r100c08 >> 8); + nv_wr32(priv, 0x100c08, priv->r100c08 >> 8); /* This is needed to get meaningful information from 100c90 * on traps. No idea what these values mean exactly. */ - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: - nv_wr32(dev, 0x100c90, 0x000707ff); + nv_wr32(priv, 0x100c90, 0x000707ff); break; case 0xa3: case 0xa5: case 0xa8: - nv_wr32(dev, 0x100c90, 0x000d0fff); + nv_wr32(priv, 0x100c90, 0x000d0fff); break; case 0xaf: - nv_wr32(dev, 0x100c90, 0x089d1fff); + nv_wr32(priv, 0x100c90, 0x089d1fff); break; default: - nv_wr32(dev, 0x100c90, 0x001d07ff); + nv_wr32(priv, 0x100c90, 0x001d07ff); break; } return 0; } -void -nv50_fb_takedown(struct drm_device *dev) -{ - nv50_fb_destroy(dev); -} +struct nouveau_oclass +nv50_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fb_ctor, + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .fini = _nouveau_fb_fini, + }, +}; static struct nouveau_enum vm_dispatch_subclients[] = { { 0x00000000, "GRCTX", NULL }, @@ -211,47 +427,32 @@ static struct nouveau_enum vm_fault[] = { }; void -nv50_fb_vm_trap(struct drm_device *dev, int display) +nv50_fb_trap(struct nouveau_fb *pfb, int display) { - struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_device *device = nv_device(pfb); + struct nv50_fb_priv *priv = (void *)pfb; const struct nouveau_enum *en, *cl; - unsigned long flags; - u32 trap[6], idx, chinst; + u32 trap[6], idx, chan; u8 st0, st1, st2, st3; - int i, ch; + int i; - idx = nv_rd32(dev, 0x100c90); + idx = nv_rd32(priv, 0x100c90); if (!(idx & 0x80000000)) return; idx &= 0x00ffffff; for (i = 0; i < 6; i++) { - nv_wr32(dev, 0x100c90, idx | i << 24); - trap[i] = nv_rd32(dev, 0x100c94); + nv_wr32(priv, 0x100c90, idx | i << 24); + trap[i] = nv_rd32(priv, 0x100c94); } - nv_wr32(dev, 0x100c90, idx | 0x80000000); + nv_wr32(priv, 0x100c90, idx | 0x80000000); if (!display) return; - /* lookup channel id */ - chinst = (trap[2] << 16) | trap[1]; - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (ch = 0; ch < pfifo->channels; ch++) { - struct nouveau_channel *chan = dev_priv->channels.ptr[ch]; - - if (!chan || !chan->ramin) - continue; - - if (chinst == chan->ramin->vinst >> 12) - break; - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - /* decode status bits into something more useful */ - if (dev_priv->chipset < 0xa3 || - dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) { + if (device->chipset < 0xa3 || + device->chipset == 0xaa || device->chipset == 0xac) { st0 = (trap[0] & 0x0000000f) >> 0; st1 = (trap[0] & 0x000000f0) >> 4; st2 = (trap[0] & 0x00000f00) >> 8; @@ -262,10 +463,11 @@ nv50_fb_vm_trap(struct drm_device *dev, int display) st2 = (trap[0] & 0x00ff0000) >> 16; st3 = (trap[0] & 0xff000000) >> 24; } + chan = (trap[2] << 16) | trap[1]; - NV_INFO(dev, "VM: trapped %s at 0x%02x%04x%04x on ch %d [0x%08x] ", - (trap[5] & 0x00000100) ? "read" : "write", - trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, ch, chinst); + nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x ", + (trap[5] & 0x00000100) ? "read" : "write", + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan); en = nouveau_enum_find(vm_engine, st0); if (en) diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50_vram.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50_vram.c deleted file mode 100644 index 84b99b6..0000000 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50_vram.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2010 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 "drmP.h" -#include "nouveau_drv.h" -#include - -static int types[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, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 -}; - -bool -nv50_vram_flags_valid(struct drm_device *dev, u32 tile_flags) -{ - int type = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8; - - if (likely(type < ARRAY_SIZE(types) && types[type])) - return true; - return false; -} - -void -nv50_vram_del(struct drm_device *dev, struct nouveau_mem **pmem) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_mm *mm = &dev_priv->engine.vram.mm; - struct nouveau_mm_node *this; - struct nouveau_mem *mem; - - mem = *pmem; - *pmem = NULL; - if (unlikely(mem == NULL)) - return; - - mutex_lock(&mm->mutex); - while (!list_empty(&mem->regions)) { - this = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); - - list_del(&this->rl_entry); - nouveau_mm_free(mm, &this); - } - - if (mem->tag) { - drm_mm_put_block(mem->tag); - mem->tag = NULL; - } - mutex_unlock(&mm->mutex); - - kfree(mem); -} - -int -nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, - u32 memtype, struct nouveau_mem **pmem) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_mm *mm = &dev_priv->engine.vram.mm; - struct nouveau_mm_node *r; - struct nouveau_mem *mem; - int comp = (memtype & 0x300) >> 8; - int type = (memtype & 0x07f); - int back = (memtype & 0x800); - int ret; - - size >>= 12; - align >>= 12; - ncmin >>= 12; - if (!ncmin) - ncmin = size; - - mem = kzalloc(sizeof(*mem), GFP_KERNEL); - if (!mem) - return -ENOMEM; - - mutex_lock(&mm->mutex); - if (comp) { - if (align == 16) { - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - int n = (size >> 4) * comp; - - mem->tag = drm_mm_search_free(&pfb->tag_heap, n, 0, 0); - if (mem->tag) - mem->tag = drm_mm_get_block(mem->tag, n, 0); - } - - if (unlikely(!mem->tag)) - comp = 0; - } - - INIT_LIST_HEAD(&mem->regions); - mem->dev = dev_priv->dev; - mem->memtype = (comp << 7) | type; - mem->size = size; - - type = types[type]; - do { - if (back) - ret = nouveau_mm_tail(mm, type, size, ncmin, align, &r); - else - ret = nouveau_mm_head(mm, type, size, ncmin, align, &r); - - if (ret) { - mutex_unlock(&mm->mutex); - nv50_vram_del(dev, &mem); - return ret; - } - - list_add_tail(&r->rl_entry, &mem->regions); - size -= r->length; - } while (size); - mutex_unlock(&mm->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_vram_rblock(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int i, parts, colbits, rowbitsa, rowbitsb, banks; - u64 rowsize, predicted; - u32 r0, r4, rt, ru, rblock_size; - - r0 = nv_rd32(dev, 0x100200); - r4 = nv_rd32(dev, 0x100204); - rt = nv_rd32(dev, 0x100250); - ru = nv_rd32(dev, 0x001540); - NV_DEBUG(dev, "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 != dev_priv->vram_size) { - NV_WARN(dev, "memory controller reports %dMiB VRAM\n", - (u32)(dev_priv->vram_size >> 20)); - NV_WARN(dev, "we calculated %dMiB VRAM\n", - (u32)(predicted >> 20)); - } - - rblock_size = rowsize; - if (rt & 1) - rblock_size *= 3; - - NV_DEBUG(dev, "rblock %d bytes\n", rblock_size); - return rblock_size; -} - -int -nv50_vram_init(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_vram_engine *vram = &dev_priv->engine.vram; - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 pfb714 = nv_rd32(dev, 0x100714); - u32 rblock, length; - - switch (pfb714 & 0x00000007) { - case 0: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break; - case 1: - if (nouveau_mem_vbios_type(dev) == NV_MEM_TYPE_DDR3) - dev_priv->vram_type = NV_MEM_TYPE_DDR3; - else - dev_priv->vram_type = NV_MEM_TYPE_DDR2; - break; - case 2: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break; - case 3: dev_priv->vram_type = NV_MEM_TYPE_GDDR4; break; - case 4: dev_priv->vram_type = NV_MEM_TYPE_GDDR5; break; - default: - break; - } - - dev_priv->vram_rank_B = !!(nv_rd32(dev, 0x100200) & 0x4); - dev_priv->vram_size = nv_rd32(dev, 0x10020c); - dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; - dev_priv->vram_size &= 0xffffffff00ULL; - - /* IGPs, no funky reordering happens here, they don't have VRAM */ - if (dev_priv->chipset == 0xaa || - dev_priv->chipset == 0xac || - dev_priv->chipset == 0xaf) { - dev_priv->vram_sys_base = (u64)nv_rd32(dev, 0x100e10) << 12; - rblock = 4096 >> 12; - } else { - rblock = nv50_vram_rblock(dev) >> 12; - } - - length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; - - return nouveau_mm_init(&vram->mm, rsvd_head, length, rblock); -} - -void -nv50_vram_fini(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_vram_engine *vram = &dev_priv->engine.vram; - - nouveau_mm_fini(&vram->mm); -} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c index f054331..9f59f2b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Red Hat Inc. + * Copyright 2012 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"), @@ -22,114 +22,224 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include +#include +#include struct nvc0_fb_priv { + struct nouveau_fb base; struct page *r100c10_page; dma_addr_t r100c10; }; -static inline void -nvc0_mfb_subp_isr(struct drm_device *dev, int unit, int subp) +/* 0 = unsupported + * 1 = non-compressed + * 3 = compressed + */ +static const u8 types[256] = { + 1, 1, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, + 3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, + 3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3, + 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0 +}; + +static bool +nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) { - u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); - u32 stat = nv_rd32(dev, subp_base + 0x020); + u8 memtype = (tile_flags & 0x0000ff00) >> 8; + return likely((types[memtype] == 1)); +} - if (stat) { - NV_INFO(dev, "PMFB%d_SUBP%d: 0x%08x\n", unit, subp, stat); - nv_wr32(dev, subp_base + 0x020, stat); - } +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; + + 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->memtype = type; + mem->size = size; + + mutex_lock(&mm->mutex); + 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(&mm->mutex); + pfb->ram.put(pfb, &mem); + return ret; + } + + list_add_tail(&r->rl_entry, &mem->regions); + size -= r->length; + } while (size); + mutex_unlock(&mm->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_mfb_isr(struct drm_device *dev) +static int +nvc0_fb_init(struct nouveau_object *object) { - u32 units = nv_rd32(dev, 0x00017c); - while (units) { - u32 subp, unit = ffs(units) - 1; - for (subp = 0; subp < 2; subp++) - nvc0_mfb_subp_isr(dev, unit, subp); - units &= ~(1 << unit); - } + struct nvc0_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; - /* we do something horribly wrong and upset PMFB a lot, so mask off - * interrupts from it after the first one until it's fixed - */ - nv_mask(dev, 0x000640, 0x02000000, 0x00000000); + nv_wr32(priv, 0x100c10, priv->r100c10 >> 8); + return 0; } static void -nvc0_fb_destroy(struct drm_device *dev) +nvc0_fb_dtor(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct nvc0_fb_priv *priv = pfb->priv; - - nouveau_irq_unregister(dev, 25); + struct nouveau_device *device = nv_device(object); + struct nvc0_fb_priv *priv = (void *)object; if (priv->r100c10_page) { - pci_unmap_page(dev->pdev, priv->r100c10, PAGE_SIZE, + pci_unmap_page(device->pdev, priv->r100c10, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); __free_page(priv->r100c10_page); } - kfree(priv); - pfb->priv = NULL; + nouveau_fb_destroy(&priv->base); } static int -nvc0_fb_create(struct drm_device *dev) +nvc0_vram_detect(struct nvc0_fb_priv *priv) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct nvc0_fb_priv *priv; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - pfb->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; + } + } - priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!priv->r100c10_page) { - nvc0_fb_destroy(dev); - return -ENOMEM; + /* 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); } - priv->r100c10 = pci_map_page(dev->pdev, priv->r100c10_page, 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, priv->r100c10)) { - nvc0_fb_destroy(dev); - return -EFAULT; + /* 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; } - nouveau_irq_register(dev, 25, nvc0_mfb_isr); return 0; } -int -nvc0_fb_init(struct drm_device *dev) +static int +nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_device *device = nv_device(parent); struct nvc0_fb_priv *priv; int ret; - if (!dev_priv->engine.fb.priv) { - ret = nvc0_fb_create(dev); - if (ret) - return ret; - } - priv = dev_priv->engine.fb.priv; + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_wr32(dev, 0x100c10, priv->r100c10 >> 8); - nv_mask(dev, 0x17e820, 0x00100000, 0x00000000); /* NV_PLTCG_INTR_EN */ - return 0; -} + priv->base.memtype_valid = nvc0_fb_memtype_valid; + priv->base.ram.get = nvc0_fb_vram_new; + priv->base.ram.put = nv50_fb_vram_del; -void -nvc0_fb_takedown(struct drm_device *dev) -{ - nvc0_fb_destroy(dev); + ret = nvc0_vram_detect(priv); + if (ret) + return ret; + + priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!priv->r100c10_page) + return -ENOMEM; + + priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(device->pdev, priv->r100c10)) + return -EFAULT; + + return nouveau_fb_created(&priv->base); } + + +struct nouveau_oclass +nvc0_fb_oclass = { + .handle = NV_SUBDEV(FB, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_fb_ctor, + .dtor = nvc0_fb_dtor, + .init = nvc0_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0_vram.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0_vram.c deleted file mode 100644 index f363234..0000000 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0_vram.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2010 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 "drmP.h" -#include "nouveau_drv.h" -#include - -/* 0 = unsupported - * 1 = non-compressed - * 3 = compressed - */ -static const u8 types[256] = { - 1, 1, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, - 3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, - 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, - 3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3, - 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0 -}; - -bool -nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags) -{ - u8 memtype = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8; - return likely((types[memtype] == 1)); -} - -int -nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, - u32 memtype, struct nouveau_mem **pmem) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_mm *mm = &dev_priv->engine.vram.mm; - struct nouveau_mm_node *r; - struct nouveau_mem *mem; - int type = (memtype & 0x0ff); - int back = (memtype & 0x800); - 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->dev = dev_priv->dev; - mem->memtype = type; - mem->size = size; - - mutex_lock(&mm->mutex); - 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(&mm->mutex); - nv50_vram_del(dev, &mem); - return ret; - } - - list_add_tail(&r->rl_entry, &mem->regions); - size -= r->length; - } while (size); - mutex_unlock(&mm->mutex); - - r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); - mem->offset = (u64)r->offset << 12; - *pmem = mem; - return 0; -} - -int -nvc0_vram_init(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_vram_engine *vram = &dev_priv->engine.vram; - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 parts = nv_rd32(dev, 0x022438); - u32 pmask = nv_rd32(dev, 0x022554); - u32 bsize = nv_rd32(dev, 0x10f20c); - u32 offset, length; - bool uniform = true; - int ret, part; - - NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800)); - NV_DEBUG(dev, "parts 0x%08x mask 0x%08x\n", parts, pmask); - - dev_priv->vram_type = nouveau_mem_vbios_type(dev); - dev_priv->vram_rank_B = !!(nv_rd32(dev, 0x10f200) & 0x00000004); - - /* read amount of vram attached to each memory controller */ - for (part = 0; part < parts; part++) { - if (!(pmask & (1 << part))) { - u32 psize = nv_rd32(dev, 0x11020c + (part * 0x1000)); - if (psize != bsize) { - if (psize < bsize) - bsize = psize; - uniform = false; - } - - NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize); - dev_priv->vram_size += (u64)psize << 20; - } - } - - /* if all controllers have the same amount attached, there's no holes */ - if (uniform) { - offset = rsvd_head; - length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; - return nouveau_mm_init(&vram->mm, offset, length, 1); - } - - /* otherwise, address lowest common amount from 0GiB */ - ret = nouveau_mm_init(&vram->mm, rsvd_head, (bsize << 8) * parts, 1); - if (ret) - return ret; - - /* and the rest starting from (8GiB + common_size) */ - offset = (0x0200000000ULL >> 12) + (bsize << 8); - length = (dev_priv->vram_size >> 12) - (bsize << 8) - rsvd_tail; - - ret = nouveau_mm_init(&vram->mm, offset, length, 0); - if (ret) { - nouveau_mm_fini(&vram->mm); - return ret; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c index 5965eb7..24d077a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c @@ -310,8 +310,6 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, struct nouveau_channel *chan, u32 size, u32 align) { struct drm_device *dev = gpuobj->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct nv50_gpuobj_node *node = NULL; int ret; @@ -323,7 +321,7 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, struct nouveau_channel *chan, size = (size + 4095) & ~4095; align = max(align, (u32)4096); - ret = vram->get(dev, size, align, 0, 0x800, &node->vram); + ret = nvfb_vram_get(dev, size, align, 0, 0x800, &node->vram); if (ret) { kfree(node); return ret; @@ -339,7 +337,7 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, struct nouveau_channel *chan, ret = nouveau_vm_get(chan->vm, size, 12, flags, &node->chan_vma); if (ret) { - vram->put(dev, &node->vram); + nvfb_vram_put(dev, &node->vram); kfree(node); return ret; } @@ -357,8 +355,6 @@ void nv50_instmem_put(struct nouveau_gpuobj *gpuobj) { struct drm_device *dev = gpuobj->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct nv50_gpuobj_node *node; node = gpuobj->node; @@ -368,7 +364,7 @@ nv50_instmem_put(struct nouveau_gpuobj *gpuobj) nouveau_vm_unmap(&node->chan_vma); nouveau_vm_put(&node->chan_vma); } - vram->put(dev, &node->vram); + nvfb_vram_put(dev, &node->vram); kfree(node); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c new file mode 100644 index 0000000..7c2840c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c @@ -0,0 +1,91 @@ +/* + * Copyright 2012 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 + +struct nvc0_ltcg_priv { + struct nouveau_ltcg base; +}; + +static void +nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp) +{ + u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); + u32 stat = nv_rd32(priv, subp_base + 0x020); + + if (stat) { + nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat); + nv_wr32(priv, subp_base + 0x020, stat); + } +} + +static void +nvc0_ltcg_intr(struct nouveau_subdev *subdev) +{ + struct nvc0_ltcg_priv *priv = (void *)subdev; + u32 units; + + units = nv_rd32(priv, 0x00017c); + while (units) { + u32 subp, unit = ffs(units) - 1; + for (subp = 0; subp < 2; subp++) + nvc0_ltcg_subp_isr(priv, unit, subp); + units &= ~(1 << unit); + } + + /* we do something horribly wrong and upset PMFB a lot, so mask off + * interrupts from it after the first one until it's fixed + */ + nv_mask(priv, 0x000640, 0x02000000, 0x00000000); +} + +static int +nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_ltcg_priv *priv; + int ret; + + ret = nouveau_ltcg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + + nv_subdev(priv)->intr = nvc0_ltcg_intr; + return 0; +} + +struct nouveau_oclass +nvc0_ltcg_oclass = { + .handle = NV_SUBDEV(LTCG, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_ltcg_ctor, + .dtor = _nouveau_ltcg_dtor, + .init = _nouveau_ltcg_init, + .fini = _nouveau_ltcg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c index 3fa39bb..bd9e9946 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c @@ -38,6 +38,7 @@ nvc0_mc_intr[] = { { 0x00008000, NVDEV_ENGINE_BSP }, { 0x00100000, NVDEV_SUBDEV_TIMER }, { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x02000000, NVDEV_SUBDEV_LTCG }, { 0x04000000, NVDEV_ENGINE_DISP }, { 0x80000000, NVDEV_ENGINE_SW }, {}, diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c index eeac72f..7e46826d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c @@ -80,8 +80,8 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, /* IGPs don't have real VRAM, re-target to stolen system memory */ target = 0; - if (dev_priv->vram_sys_base) { - phys += dev_priv->vram_sys_base; + if (nvfb_vram_sys_base(dev_priv->dev)) { + phys += nvfb_vram_sys_base(dev_priv->dev); target = 3; } @@ -103,7 +103,7 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, phys += block << (vma->node->type - 3); cnt -= block; if (comp) { - u32 tag = mem->tag->start + ((delta >> 16) * comp); + u32 tag = mem->tag->offset + ((delta >> 16) * comp); offset_h |= (tag << 17); delta += block << (vma->node->type - 3); } -- cgit v1.1