diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-07-20 08:17:34 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-10-03 13:12:56 +1000 |
commit | ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69 (patch) | |
tree | 07cad59be501458e6ae1304b7c0352e322ac3387 /drivers/gpu/drm/nouveau/core/engine | |
parent | ac1499d9573f4aadd1d2beac11fe23af8ce90c24 (diff) | |
download | op-kernel-dev-ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69.zip op-kernel-dev-ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69.tar.gz |
drm/nouveau: port all engines to new engine module format
This is a HUGE commit, but it's not nearly as bad as it looks - any problems
can be isolated to a particular chipset and engine combination. It was
simply too difficult to port each one at a time, the compat layers are
*already* ridiculous.
Most of the changes here are simply to the glue, the process for each of the
engine modules was to start with a standard skeleton and copy+paste the old
code into the appropriate places, fixing up variable names etc as needed.
v2: Marcin Slusarz <marcin.slusarz@gmail.com>
- fix find/replace bug in license header
v3: Ben Skeggs <bskeggs@redhat.com>
- bump indirect pushbuf size to 8KiB, 4KiB barely enough for userspace and
left no space for kernel's requirements during GEM pushbuf submission.
- fix duplicate assignments noticed by clang
v4: Marcin Slusarz <marcin.slusarz@gmail.com>
- add sparse annotations to nv04_fifo_pause/nv04_fifo_start
- use ioread32_native/iowrite32_native for fifo control registers
v5: Ben Skeggs <bskeggs@redhat.com>
- rebase on v3.6-rc4, modified to keep copy engine fix intact
- nv10/fence: unmap fence bo before destroying
- fixed fermi regression when using nvidia gr fuc
- fixed typo in supported dma_mask checking
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/engine')
55 files changed, 10811 insertions, 6761 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c index 4b80931..66f7dfd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.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,61 +22,154 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include "nouveau_util.h" -#include <core/ramht.h> +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> -/*XXX: This stub is currently used on NV98+ also, as soon as this becomes - * more than just an enable/disable stub this needs to be split out to - * nv98_bsp.c... - */ +#include <engine/bsp.h> + +struct nv84_bsp_priv { + struct nouveau_bsp base; +}; -struct nv84_bsp_engine { - struct nouveau_exec_engine base; +struct nv84_bsp_chan { + struct nouveau_bsp_chan base; }; +/******************************************************************************* + * BSP object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv84_bsp_sclass[] = { + {}, +}; + +/******************************************************************************* + * BSP context + ******************************************************************************/ + static int -nv84_bsp_fini(struct drm_device *dev, int engine, bool suspend) +nv84_bsp_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - if (!(nv_rd32(dev, 0x000200) & 0x00008000)) - return 0; + struct nv84_bsp_chan *priv; + int ret; + + ret = nouveau_bsp_context_create(parent, engine, oclass, NULL, + 0, 0, 0, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_mask(dev, 0x000200, 0x00008000, 0x00000000); return 0; } +static void +nv84_bsp_context_dtor(struct nouveau_object *object) +{ + struct nv84_bsp_chan *priv = (void *)object; + nouveau_bsp_context_destroy(&priv->base); +} + static int -nv84_bsp_init(struct drm_device *dev, int engine) +nv84_bsp_context_init(struct nouveau_object *object) { - nv_mask(dev, 0x000200, 0x00008000, 0x00000000); - nv_mask(dev, 0x000200, 0x00008000, 0x00008000); + struct nv84_bsp_chan *priv = (void *)object; + int ret; + + ret = nouveau_bsp_context_init(&priv->base); + if (ret) + return ret; + return 0; } +static int +nv84_bsp_context_fini(struct nouveau_object *object, bool suspend) +{ + struct nv84_bsp_chan *priv = (void *)object; + return nouveau_bsp_context_fini(&priv->base, suspend); +} + +static struct nouveau_oclass +nv84_bsp_cclass = { + .handle = NV_ENGCTX(BSP, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_bsp_context_ctor, + .dtor = nv84_bsp_context_dtor, + .init = nv84_bsp_context_init, + .fini = nv84_bsp_context_fini, + .rd32 = _nouveau_bsp_context_rd32, + .wr32 = _nouveau_bsp_context_wr32, + }, +}; + +/******************************************************************************* + * BSP engine/subdev functions + ******************************************************************************/ + static void -nv84_bsp_destroy(struct drm_device *dev, int engine) +nv84_bsp_intr(struct nouveau_subdev *subdev) { - struct nv84_bsp_engine *pbsp = nv_engine(dev, engine); +} - NVOBJ_ENGINE_DEL(dev, BSP); +static int +nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv84_bsp_priv *priv; + int ret; + + ret = nouveau_bsp_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - kfree(pbsp); + nv_subdev(priv)->unit = 0x04008000; + nv_subdev(priv)->intr = nv84_bsp_intr; + nv_engine(priv)->cclass = &nv84_bsp_cclass; + nv_engine(priv)->sclass = nv84_bsp_sclass; + return 0; } -int -nv84_bsp_create(struct drm_device *dev) +static void +nv84_bsp_dtor(struct nouveau_object *object) { - struct nv84_bsp_engine *pbsp; + struct nv84_bsp_priv *priv = (void *)object; + nouveau_bsp_destroy(&priv->base); +} - pbsp = kzalloc(sizeof(*pbsp), GFP_KERNEL); - if (!pbsp) - return -ENOMEM; +static int +nv84_bsp_init(struct nouveau_object *object) +{ + struct nv84_bsp_priv *priv = (void *)object; + int ret; - pbsp->base.destroy = nv84_bsp_destroy; - pbsp->base.init = nv84_bsp_init; - pbsp->base.fini = nv84_bsp_fini; + ret = nouveau_bsp_init(&priv->base); + if (ret) + return ret; - NVOBJ_ENGINE_ADD(dev, BSP, &pbsp->base); return 0; } + +static int +nv84_bsp_fini(struct nouveau_object *object, bool suspend) +{ + struct nv84_bsp_priv *priv = (void *)object; + return nouveau_bsp_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv84_bsp_oclass = { + .handle = NV_ENGINE(BSP, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_bsp_ctor, + .dtor = nv84_bsp_dtor, + .init = nv84_bsp_init, + .fini = nv84_bsp_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c index 9150c5e..debb828 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.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,112 +22,75 @@ * Authors: Ben Skeggs */ -#include <linux/firmware.h> -#include "drmP.h" -#include "nouveau_drv.h" -#include "nouveau_util.h" -#include <core/ramht.h> -#include "fuc/nva3.fuc.h" - -struct nva3_copy_engine { - struct nouveau_exec_engine base; -}; - -static int -nva3_copy_context_new(struct nouveau_channel *chan, int engine) -{ - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *ramin = chan->ramin; - struct nouveau_gpuobj *ctx = NULL; - int ret; - - NV_DEBUG(dev, "ch%d\n", chan->id); +#include <core/os.h> +#include <core/enum.h> +#include <core/class.h> +#include <core/engctx.h> - ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &ctx); - if (ret) - return ret; +#include <subdev/fb.h> +#include <subdev/vm.h> - nv_wo32(ramin, 0xc0, 0x00190000); - nv_wo32(ramin, 0xc4, ctx->addr + ctx->size - 1); - nv_wo32(ramin, 0xc8, ctx->addr); - nv_wo32(ramin, 0xcc, 0x00000000); - nv_wo32(ramin, 0xd0, 0x00000000); - nv_wo32(ramin, 0xd4, 0x00000000); - nvimem_flush(dev); +#include <engine/copy.h> - nvvm_engref(chan->vm, engine, 1); - chan->engctx[engine] = ctx; - return 0; -} - -static int -nva3_copy_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) -{ - struct nouveau_gpuobj *ctx = chan->engctx[engine]; +#include "fuc/nva3.fuc.h" - /* fuc engine doesn't need an object, our ramht code does.. */ - ctx->engine = 3; - ctx->class = class; - return nouveau_ramht_insert(chan, handle, ctx); -} +struct nva3_copy_priv { + struct nouveau_copy base; +}; -static void -nva3_copy_context_del(struct nouveau_channel *chan, int engine) -{ - struct nouveau_gpuobj *ctx = chan->engctx[engine]; - int i; +struct nva3_copy_chan { + struct nouveau_copy_chan base; +}; - for (i = 0xc0; i <= 0xd4; i += 4) - nv_wo32(chan->ramin, i, 0x00000000); +/******************************************************************************* + * Copy object classes + ******************************************************************************/ - nvvm_engref(chan->vm, engine, -1); - nouveau_gpuobj_ref(NULL, &ctx); - chan->engctx[engine] = ctx; -} +static struct nouveau_oclass +nva3_copy_sclass[] = { + { 0x85b5, &nouveau_object_ofuncs }, + {} +}; -static void -nva3_copy_tlb_flush(struct drm_device *dev, int engine) -{ - nv50_vm_flush_engine(dev, 0x0d); -} +/******************************************************************************* + * PCOPY context + ******************************************************************************/ static int -nva3_copy_init(struct drm_device *dev, int engine) +nva3_copy_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - int i; - - nv_mask(dev, 0x000200, 0x00002000, 0x00000000); - nv_mask(dev, 0x000200, 0x00002000, 0x00002000); - nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */ - - /* upload ucode */ - nv_wr32(dev, 0x1041c0, 0x01000000); - for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++) - nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]); + struct nva3_copy_chan *priv; + int ret; - nv_wr32(dev, 0x104180, 0x01000000); - for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) { - if ((i & 0x3f) == 0) - nv_wr32(dev, 0x104188, i >> 6); - nv_wr32(dev, 0x104184, nva3_pcopy_code[i]); - } + ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, 0, + NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - /* start it running */ - nv_wr32(dev, 0x10410c, 0x00000000); - nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */ - nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */ return 0; } -static int -nva3_copy_fini(struct drm_device *dev, int engine, bool suspend) -{ - nv_mask(dev, 0x104048, 0x00000003, 0x00000000); - nv_wr32(dev, 0x104014, 0xffffffff); - return 0; -} +static struct nouveau_oclass +nva3_copy_cclass = { + .handle = NV_ENGCTX(COPY0, 0xa3), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nva3_copy_context_ctor, + .dtor = _nouveau_copy_context_dtor, + .init = _nouveau_copy_context_init, + .fini = _nouveau_copy_context_fini, + .rd32 = _nouveau_copy_context_rd32, + .wr32 = _nouveau_copy_context_wr32, + + }, +}; + +/******************************************************************************* + * PCOPY engine/subdev functions + ******************************************************************************/ static struct nouveau_enum nva3_copy_isr_error_name[] = { { 0x0001, "ILLEGAL_MTHD" }, @@ -137,65 +100,114 @@ static struct nouveau_enum nva3_copy_isr_error_name[] = { }; static void -nva3_copy_isr(struct drm_device *dev) +nva3_copy_intr(struct nouveau_subdev *subdev) { - u32 dispatch = nv_rd32(dev, 0x10401c); - u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16); - u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff; - u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff; - u32 addr = nv_rd32(dev, 0x104040) >> 16; + struct nva3_copy_priv *priv = (void *)subdev; + u32 dispatch = nv_rd32(priv, 0x10401c); + u32 stat = nv_rd32(priv, 0x104008) & dispatch & ~(dispatch >> 16); + u32 inst = nv_rd32(priv, 0x104050) & 0x3fffffff; + u32 ssta = nv_rd32(priv, 0x104040) & 0x0000ffff; + u32 addr = nv_rd32(priv, 0x104040) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_rd32(dev, 0x104044); - int chid = nv50_graph_isr_chid(dev, inst); + u32 data = nv_rd32(priv, 0x104044); if (stat & 0x00000040) { - NV_INFO(dev, "PCOPY: DISPATCH_ERROR ["); + nv_error(priv, "DISPATCH_ERROR ["); nouveau_enum_print(nva3_copy_isr_error_name, ssta); - printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n", - chid, inst, subc, mthd, data); - nv_wr32(dev, 0x104004, 0x00000040); + printk("] ch 0x%08x subc %d mthd 0x%04x data 0x%08x\n", + inst, subc, mthd, data); + nv_wr32(priv, 0x104004, 0x00000040); stat &= ~0x00000040; } if (stat) { - NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat); - nv_wr32(dev, 0x104004, stat); + nv_error(priv, "unhandled intr 0x%08x\n", stat); + nv_wr32(priv, 0x104004, stat); } - nv50_fb_vm_trap(dev, 1); + + nv50_fb_trap(nouveau_fb(priv), 1); } -static void -nva3_copy_destroy(struct drm_device *dev, int engine) +static int +nva3_copy_tlb_flush(struct nouveau_engine *engine) { - struct nva3_copy_engine *pcopy = nv_engine(dev, engine); + nv50_vm_flush_engine(&engine->base, 0x0d); + return 0; +} - nouveau_irq_unregister(dev, 22); +static int +nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + bool enable = (nv_device(parent)->chipset != 0xaf); + struct nva3_copy_priv *priv; + int ret; - NVOBJ_ENGINE_DEL(dev, COPY0); - kfree(pcopy); + ret = nouveau_copy_create(parent, engine, oclass, enable, 0, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00802000; + nv_subdev(priv)->intr = nva3_copy_intr; + nv_engine(priv)->cclass = &nva3_copy_cclass; + nv_engine(priv)->sclass = nva3_copy_sclass; + nv_engine(priv)->tlb_flush = nva3_copy_tlb_flush; + return 0; } -int -nva3_copy_create(struct drm_device *dev) +static int +nva3_copy_init(struct nouveau_object *object) { - struct nva3_copy_engine *pcopy; + struct nva3_copy_priv *priv = (void *)object; + int ret, i; - pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL); - if (!pcopy) - return -ENOMEM; + ret = nouveau_copy_init(&priv->base); + if (ret) + return ret; - pcopy->base.destroy = nva3_copy_destroy; - pcopy->base.init = nva3_copy_init; - pcopy->base.fini = nva3_copy_fini; - pcopy->base.context_new = nva3_copy_context_new; - pcopy->base.context_del = nva3_copy_context_del; - pcopy->base.object_new = nva3_copy_object_new; - pcopy->base.tlb_flush = nva3_copy_tlb_flush; + /* disable all interrupts */ + nv_wr32(priv, 0x104014, 0xffffffff); - nouveau_irq_register(dev, 22, nva3_copy_isr); + /* upload ucode */ + nv_wr32(priv, 0x1041c0, 0x01000000); + for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++) + nv_wr32(priv, 0x1041c4, nva3_pcopy_data[i]); + + nv_wr32(priv, 0x104180, 0x01000000); + for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(priv, 0x104188, i >> 6); + nv_wr32(priv, 0x104184, nva3_pcopy_code[i]); + } - NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base); - NVOBJ_CLASS(dev, 0x85b5, COPY0); + /* start it running */ + nv_wr32(priv, 0x10410c, 0x00000000); + nv_wr32(priv, 0x104104, 0x00000000); /* ENTRY */ + nv_wr32(priv, 0x104100, 0x00000002); /* TRIGGER */ return 0; } + +static int +nva3_copy_fini(struct nouveau_object *object, bool suspend) +{ + struct nva3_copy_priv *priv = (void *)object; + + nv_mask(priv, 0x104048, 0x00000003, 0x00000000); + nv_wr32(priv, 0x104014, 0xffffffff); + + return nouveau_copy_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nva3_copy_oclass = { + .handle = NV_ENGINE(COPY0, 0xa3), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nva3_copy_ctor, + .dtor = _nouveau_copy_dtor, + .init = nva3_copy_init, + .fini = nva3_copy_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c index f39de5a..ecc8faa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/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,138 +22,86 @@ * Authors: Ben Skeggs */ -#include <linux/firmware.h> -#include "drmP.h" -#include "nouveau_drv.h" -#include "nouveau_util.h" -#include <core/ramht.h> +#include <core/os.h> +#include <core/enum.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <engine/copy.h> + #include "fuc/nvc0.fuc.h" -struct nvc0_copy_engine { - struct nouveau_exec_engine base; - u32 irq; - u32 pmc; - u32 fuc; - u32 ctx; +struct nvc0_copy_priv { + struct nouveau_copy base; }; struct nvc0_copy_chan { - struct nouveau_gpuobj *mem; - struct nouveau_vma vma; + struct nouveau_copy_chan base; }; -static int -nvc0_copy_context_new(struct nouveau_channel *chan, int engine) -{ - struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine); - struct nvc0_copy_chan *cctx; - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *ramin = chan->ramin; - int ret; - - cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL); - if (!cctx) - return -ENOMEM; +/******************************************************************************* + * Copy object classes + ******************************************************************************/ - ret = nouveau_gpuobj_new(dev, NULL, 256, 256, - NVOBJ_FLAG_ZERO_ALLOC, &cctx->mem); - if (ret) - return ret; +static struct nouveau_oclass +nvc0_copy0_sclass[] = { + { 0x90b5, &nouveau_object_ofuncs }, + {}, +}; - ret = nouveau_gpuobj_map_vm(cctx->mem, chan->vm, NV_MEM_ACCESS_RW, - &cctx->vma); - if (ret) - return ret; +static struct nouveau_oclass +nvc0_copy1_sclass[] = { + { 0x90b8, &nouveau_object_ofuncs }, + {}, +}; - nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(cctx->vma.offset)); - nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(cctx->vma.offset)); - nvimem_flush(dev); - return 0; -} +/******************************************************************************* + * PCOPY context + ******************************************************************************/ static int -nvc0_copy_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) -{ - return 0; -} - -static void -nvc0_copy_context_del(struct nouveau_channel *chan, int engine) +nvc0_copy_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine); - struct nvc0_copy_chan *cctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - u32 inst; - - inst = (chan->ramin->addr >> 12); - inst |= 0x40000000; - - /* disable fifo access */ - nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000); - /* mark channel as unloaded if it's currently active */ - if (nv_rd32(dev, pcopy->fuc + 0x050) == inst) - nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000); - /* mark next channel as invalid if it's about to be loaded */ - if (nv_rd32(dev, pcopy->fuc + 0x054) == inst) - nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000); - /* restore fifo access */ - nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003); - - nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000); - nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000); - - nouveau_gpuobj_unmap(&cctx->vma); - nouveau_gpuobj_ref(NULL, &cctx->mem); - - kfree(cctx); - chan->engctx[engine] = NULL; -} - -static int -nvc0_copy_init(struct drm_device *dev, int engine) -{ - struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); - int i; - - nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000); - nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc); - nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff); - - nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000); - for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++) - nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]); + struct nvc0_copy_chan *priv; + int ret; - nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000); - for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) { - if ((i & 0x3f) == 0) - nv_wr32(dev, pcopy->fuc + 0x188, i >> 6); - nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]); - } + ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, + 256, NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0); - nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000); - nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */ - nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */ return 0; } -static int -nvc0_copy_fini(struct drm_device *dev, int engine, bool suspend) -{ - struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); +static struct nouveau_ofuncs +nvc0_copy_context_ofuncs = { + .ctor = nvc0_copy_context_ctor, + .dtor = _nouveau_copy_context_dtor, + .init = _nouveau_copy_context_init, + .fini = _nouveau_copy_context_fini, + .rd32 = _nouveau_copy_context_rd32, + .wr32 = _nouveau_copy_context_wr32, +}; - nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000); +static struct nouveau_oclass +nvc0_copy0_cclass = { + .handle = NV_ENGCTX(COPY0, 0xc0), + .ofuncs = &nvc0_copy_context_ofuncs, +}; - /* trigger fuc context unload */ - nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000); - nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000); - nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008); - nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000); +static struct nouveau_oclass +nvc0_copy1_cclass = { + .handle = NV_ENGCTX(COPY1, 0xc0), + .ofuncs = &nvc0_copy_context_ofuncs, +}; - nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff); - return 0; -} +/******************************************************************************* + * PCOPY engine/subdev functions + ******************************************************************************/ static struct nouveau_enum nvc0_copy_isr_error_name[] = { { 0x0001, "ILLEGAL_MTHD" }, @@ -163,93 +111,145 @@ static struct nouveau_enum nvc0_copy_isr_error_name[] = { }; static void -nvc0_copy_isr(struct drm_device *dev, int engine) +nvc0_copy_intr(struct nouveau_subdev *subdev) { - struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); - u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c); - u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16); - u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12; - u32 chid = nvc0_graph_isr_chid(dev, inst); - u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff; - u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16; + int idx = nv_engidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0; + struct nvc0_copy_priv *priv = (void *)subdev; + u32 disp = nv_rd32(priv, 0x10401c + (idx * 0x1000)); + u32 intr = nv_rd32(priv, 0x104008 + (idx * 0x1000)); + u32 stat = intr & disp & ~(disp >> 16); + u64 inst = nv_rd32(priv, 0x104050 + (idx * 0x1000)) & 0x0fffffff; + u32 ssta = nv_rd32(priv, 0x104040 + (idx * 0x1000)) & 0x0000ffff; + u32 addr = nv_rd32(priv, 0x104040 + (idx * 0x1000)) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_rd32(dev, pcopy->fuc + 0x044); + u32 data = nv_rd32(priv, 0x104044 + (idx * 0x1000)); if (stat & 0x00000040) { - NV_INFO(dev, "PCOPY: DISPATCH_ERROR ["); + nv_error(priv, "DISPATCH_ERROR ["); nouveau_enum_print(nvc0_copy_isr_error_name, ssta); - printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n", - chid, inst, subc, mthd, data); - nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040); + printk("] ch 0x%010llx subc %d mthd 0x%04x data 0x%08x\n", + (u64)inst << 12, subc, mthd, data); + nv_wr32(priv, 0x104004 + (idx * 0x1000), 0x00000040); stat &= ~0x00000040; } if (stat) { - NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat); - nv_wr32(dev, pcopy->fuc + 0x004, stat); + nv_error(priv, "unhandled intr 0x%08x\n", stat); + nv_wr32(priv, 0x104004 + (idx * 0x1000), stat); } } -static void -nvc0_copy_isr_0(struct drm_device *dev) +static int +nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0); -} + struct nvc0_copy_priv *priv; + int ret; -static void -nvc0_copy_isr_1(struct drm_device *dev) -{ - nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1); + if (nv_rd32(parent, 0x022500) & 0x00000100) + return -ENODEV; + + ret = nouveau_copy_create(parent, engine, oclass, true, 0, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000040; + nv_subdev(priv)->intr = nvc0_copy_intr; + nv_engine(priv)->cclass = &nvc0_copy0_cclass; + nv_engine(priv)->sclass = nvc0_copy0_sclass; + return 0; } -static void -nvc0_copy_destroy(struct drm_device *dev, int engine) +static int +nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); + struct nvc0_copy_priv *priv; + int ret; - nouveau_irq_unregister(dev, pcopy->irq); + if (nv_rd32(parent, 0x022500) & 0x00000200) + return -ENODEV; - if (engine == NVOBJ_ENGINE_COPY0) - NVOBJ_ENGINE_DEL(dev, COPY0); - else - NVOBJ_ENGINE_DEL(dev, COPY1); - kfree(pcopy); + ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000080; + nv_subdev(priv)->intr = nvc0_copy_intr; + nv_engine(priv)->cclass = &nvc0_copy1_cclass; + nv_engine(priv)->sclass = nvc0_copy1_sclass; + return 0; } -int -nvc0_copy_create(struct drm_device *dev, int engine) +static int +nvc0_copy_init(struct nouveau_object *object) { - struct nvc0_copy_engine *pcopy; - - pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL); - if (!pcopy) - return -ENOMEM; - - pcopy->base.destroy = nvc0_copy_destroy; - pcopy->base.init = nvc0_copy_init; - pcopy->base.fini = nvc0_copy_fini; - pcopy->base.context_new = nvc0_copy_context_new; - pcopy->base.context_del = nvc0_copy_context_del; - pcopy->base.object_new = nvc0_copy_object_new; - - if (engine == 0) { - pcopy->irq = 5; - pcopy->pmc = 0x00000040; - pcopy->fuc = 0x104000; - pcopy->ctx = 0x0230; - nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0); - NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base); - NVOBJ_CLASS(dev, 0x90b5, COPY0); - } else { - pcopy->irq = 6; - pcopy->pmc = 0x00000080; - pcopy->fuc = 0x105000; - pcopy->ctx = 0x0240; - nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1); - NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base); - NVOBJ_CLASS(dev, 0x90b8, COPY1); + int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0; + struct nvc0_copy_priv *priv = (void *)object; + int ret, i; + + ret = nouveau_copy_init(&priv->base); + if (ret) + return ret; + + /* disable all interrupts */ + nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff); + + /* upload ucode */ + nv_wr32(priv, 0x1041c0 + (idx * 0x1000), 0x01000000); + for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++) + nv_wr32(priv, 0x1041c4 + (idx * 0x1000), nvc0_pcopy_data[i]); + + nv_wr32(priv, 0x104180 + (idx * 0x1000), 0x01000000); + for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(priv, 0x104188 + (idx * 0x1000), i >> 6); + nv_wr32(priv, 0x104184 + (idx * 0x1000), nvc0_pcopy_code[i]); } + /* start it running */ + nv_wr32(priv, 0x104084 + (idx * 0x1000), idx); + nv_wr32(priv, 0x10410c + (idx * 0x1000), 0x00000000); + nv_wr32(priv, 0x104104 + (idx * 0x1000), 0x00000000); /* ENTRY */ + nv_wr32(priv, 0x104100 + (idx * 0x1000), 0x00000002); /* TRIGGER */ return 0; } + +static int +nvc0_copy_fini(struct nouveau_object *object, bool suspend) +{ + int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0; + struct nvc0_copy_priv *priv = (void *)object; + + nv_mask(priv, 0x104048 + (idx * 0x1000), 0x00000003, 0x00000000); + nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff); + + return nouveau_copy_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nvc0_copy0_oclass = { + .handle = NV_ENGINE(COPY0, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_copy0_ctor, + .dtor = _nouveau_copy_dtor, + .init = nvc0_copy_init, + .fini = nvc0_copy_fini, + }, +}; + +struct nouveau_oclass +nvc0_copy1_oclass = { + .handle = NV_ENGINE(COPY1, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_copy1_ctor, + .dtor = _nouveau_copy_dtor, + .init = nvc0_copy_init, + .fini = nvc0_copy_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c index 63051ab..a0e5e39 100644 --- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c @@ -1,5 +1,5 @@ /* - * Copyright 2010 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,99 +22,106 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include "nouveau_util.h" -#include <core/ramht.h> +#include <core/os.h> +#include <core/enum.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/gpuobj.h> -struct nv84_crypt_engine { - struct nouveau_exec_engine base; +#include <subdev/fb.h> + +#include <engine/crypt.h> + +struct nv84_crypt_priv { + struct nouveau_crypt base; }; +struct nv84_crypt_chan { + struct nouveau_crypt_chan base; +}; + +/******************************************************************************* + * Crypt object classes + ******************************************************************************/ + static int -nv84_crypt_context_new(struct nouveau_channel *chan, int engine) +nv84_crypt_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *ramin = chan->ramin; - struct nouveau_gpuobj *ctx; + struct nouveau_gpuobj *obj; int ret; - NV_DEBUG(dev, "ch%d\n", chan->id); - - ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &ctx); + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent, + 16, 16, 0, &obj); + *pobject = nv_object(obj); if (ret) return ret; - nv_wo32(ramin, 0xa0, 0x00190000); - nv_wo32(ramin, 0xa4, ctx->addr + ctx->size - 1); - nv_wo32(ramin, 0xa8, ctx->addr); - nv_wo32(ramin, 0xac, 0); - nv_wo32(ramin, 0xb0, 0); - nv_wo32(ramin, 0xb4, 0); - nvimem_flush(dev); - - nvvm_engref(chan->vm, engine, 1); - chan->engctx[engine] = ctx; + nv_wo32(obj, 0x00, nv_mclass(obj)); + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); + nv_wo32(obj, 0x0c, 0x00000000); return 0; } -static void -nv84_crypt_context_del(struct nouveau_channel *chan, int engine) -{ - struct nouveau_gpuobj *ctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - u32 inst; - - inst = (chan->ramin->addr >> 12); - inst |= 0x80000000; - - /* mark context as invalid if still on the hardware, not - * doing this causes issues the next time PCRYPT is used, - * unsurprisingly :) - */ - nv_wr32(dev, 0x10200c, 0x00000000); - if (nv_rd32(dev, 0x102188) == inst) - nv_mask(dev, 0x102188, 0x80000000, 0x00000000); - if (nv_rd32(dev, 0x10218c) == inst) - nv_mask(dev, 0x10218c, 0x80000000, 0x00000000); - nv_wr32(dev, 0x10200c, 0x00000010); - - nouveau_gpuobj_ref(NULL, &ctx); - - nvvm_engref(chan->vm, engine, -1); - chan->engctx[engine] = NULL; -} +static struct nouveau_ofuncs +nv84_crypt_ofuncs = { + .ctor = nv84_crypt_object_ctor, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, +}; + +static struct nouveau_oclass +nv84_crypt_sclass[] = { + { 0x74c1, &nv84_crypt_ofuncs }, + {} +}; + +/******************************************************************************* + * PCRYPT context + ******************************************************************************/ static int -nv84_crypt_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +nv84_crypt_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *obj = NULL; + struct nv84_crypt_chan *priv; int ret; - ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); + ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256, + 0, NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); if (ret) return ret; - obj->engine = 5; - obj->class = class; - nv_wo32(obj, 0x00, class); - nvimem_flush(dev); - - ret = nouveau_ramht_insert(chan, handle, obj); - nouveau_gpuobj_ref(NULL, &obj); - return ret; + return 0; } -static void -nv84_crypt_tlb_flush(struct drm_device *dev, int engine) -{ - nv50_vm_flush_engine(dev, 0x0a); -} +static struct nouveau_oclass +nv84_crypt_cclass = { + .handle = NV_ENGCTX(CRYPT, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_crypt_context_ctor, + .dtor = _nouveau_crypt_context_dtor, + .init = _nouveau_crypt_context_init, + .fini = _nouveau_crypt_context_fini, + .rd32 = _nouveau_crypt_context_rd32, + .wr32 = _nouveau_crypt_context_wr32, + }, +}; + +/******************************************************************************* + * PCRYPT engine/subdev functions + ******************************************************************************/ -static struct nouveau_bitfield nv84_crypt_intr[] = { +static struct nouveau_bitfield nv84_crypt_intr_mask[] = { { 0x00000001, "INVALID_STATE" }, { 0x00000002, "ILLEGAL_MTHD" }, { 0x00000004, "ILLEGAL_CLASS" }, @@ -124,79 +131,78 @@ static struct nouveau_bitfield nv84_crypt_intr[] = { }; static void -nv84_crypt_isr(struct drm_device *dev) +nv84_crypt_intr(struct nouveau_subdev *subdev) { - u32 stat = nv_rd32(dev, 0x102130); - u32 mthd = nv_rd32(dev, 0x102190); - u32 data = nv_rd32(dev, 0x102194); - u64 inst = (u64)(nv_rd32(dev, 0x102188) & 0x7fffffff) << 12; - int show = nouveau_ratelimit(); - int chid = nv50_graph_isr_chid(dev, inst); - - if (show) { - NV_INFO(dev, "PCRYPT:"); - nouveau_bitfield_print(nv84_crypt_intr, stat); - printk(KERN_CONT " ch %d (0x%010llx) mthd 0x%04x data 0x%08x\n", - chid, inst, mthd, data); + struct nv84_crypt_priv *priv = (void *)subdev; + u32 stat = nv_rd32(priv, 0x102130); + u32 mthd = nv_rd32(priv, 0x102190); + u32 data = nv_rd32(priv, 0x102194); + u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff; + + if (stat) { + nv_error(priv, ""); + nouveau_bitfield_print(nv84_crypt_intr_mask, stat); + printk(" ch 0x%010llx mthd 0x%04x data 0x%08x\n", + (u64)inst << 12, mthd, data); } - nv_wr32(dev, 0x102130, stat); - nv_wr32(dev, 0x10200c, 0x10); + nv_wr32(priv, 0x102130, stat); + nv_wr32(priv, 0x10200c, 0x10); - nv50_fb_vm_trap(dev, show); + nv50_fb_trap(nouveau_fb(priv), 1); } static int -nv84_crypt_fini(struct drm_device *dev, int engine, bool suspend) +nv84_crypt_tlb_flush(struct nouveau_engine *engine) { - nv_wr32(dev, 0x102140, 0x00000000); + nv50_vm_flush_engine(&engine->base, 0x0a); return 0; } static int -nv84_crypt_init(struct drm_device *dev, int engine) +nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - nv_mask(dev, 0x000200, 0x00004000, 0x00000000); - nv_mask(dev, 0x000200, 0x00004000, 0x00004000); + struct nv84_crypt_priv *priv; + int ret; - nv_wr32(dev, 0x102130, 0xffffffff); - nv_wr32(dev, 0x102140, 0xffffffbf); + ret = nouveau_crypt_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_wr32(dev, 0x10200c, 0x00000010); + nv_subdev(priv)->unit = 0x00004000; + nv_subdev(priv)->intr = nv84_crypt_intr; + nv_engine(priv)->cclass = &nv84_crypt_cclass; + nv_engine(priv)->sclass = nv84_crypt_sclass; + nv_engine(priv)->tlb_flush = nv84_crypt_tlb_flush; return 0; } -static void -nv84_crypt_destroy(struct drm_device *dev, int engine) -{ - struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine); - - NVOBJ_ENGINE_DEL(dev, CRYPT); - - nouveau_irq_unregister(dev, 14); - kfree(pcrypt); -} - -int -nv84_crypt_create(struct drm_device *dev) +static int +nv84_crypt_init(struct nouveau_object *object) { - struct nv84_crypt_engine *pcrypt; - - pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL); - if (!pcrypt) - return -ENOMEM; - - pcrypt->base.destroy = nv84_crypt_destroy; - pcrypt->base.init = nv84_crypt_init; - pcrypt->base.fini = nv84_crypt_fini; - pcrypt->base.context_new = nv84_crypt_context_new; - pcrypt->base.context_del = nv84_crypt_context_del; - pcrypt->base.object_new = nv84_crypt_object_new; - pcrypt->base.tlb_flush = nv84_crypt_tlb_flush; + struct nv84_crypt_priv *priv = (void *)object; + int ret; - nouveau_irq_register(dev, 14, nv84_crypt_isr); + ret = nouveau_crypt_init(&priv->base); + if (ret) + return ret; - NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base); - NVOBJ_CLASS (dev, 0x74c1, CRYPT); + nv_wr32(priv, 0x102130, 0xffffffff); + nv_wr32(priv, 0x102140, 0xffffffbf); + nv_wr32(priv, 0x10200c, 0x00000010); return 0; } + +struct nouveau_oclass +nv84_crypt_oclass = { + .handle = NV_ENGINE(CRYPT, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_crypt_ctor, + .dtor = _nouveau_crypt_dtor, + .init = nv84_crypt_init, + .fini = _nouveau_crypt_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c index c9adc1b..559a1b1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.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,124 +22,74 @@ * Authors: Ben Skeggs */ -#include "drmP.h" +#include <core/os.h> +#include <core/enum.h> +#include <core/class.h> +#include <core/engctx.h> -#include "nouveau_drv.h" -#include "nouveau_util.h" -#include <core/ramht.h> +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/crypt.h> #include "fuc/nv98.fuc.h" struct nv98_crypt_priv { - struct nouveau_exec_engine base; + struct nouveau_crypt base; }; struct nv98_crypt_chan { - struct nouveau_gpuobj *mem; + struct nouveau_crypt_chan base; }; -static int -nv98_crypt_context_new(struct nouveau_channel *chan, int engine) -{ - struct drm_device *dev = chan->dev; - struct nv98_crypt_priv *priv = nv_engine(dev, engine); - struct nv98_crypt_chan *cctx; - int ret; - - cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL); - if (!cctx) - return -ENOMEM; - - nvvm_engref(chan->vm, engine, 1); - - ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &cctx->mem); - if (ret) - goto error; - - nv_wo32(chan->ramin, 0xa0, 0x00190000); - nv_wo32(chan->ramin, 0xa4, cctx->mem->addr + cctx->mem->size - 1); - nv_wo32(chan->ramin, 0xa8, cctx->mem->addr); - nv_wo32(chan->ramin, 0xac, 0x00000000); - nv_wo32(chan->ramin, 0xb0, 0x00000000); - nv_wo32(chan->ramin, 0xb4, 0x00000000); - nvimem_flush(dev); - -error: - if (ret) - priv->base.context_del(chan, engine); - return ret; -} - -static void -nv98_crypt_context_del(struct nouveau_channel *chan, int engine) -{ - struct nv98_crypt_chan *cctx = chan->engctx[engine]; - int i; - - for (i = 0xa0; i < 0xb4; i += 4) - nv_wo32(chan->ramin, i, 0x00000000); +/******************************************************************************* + * Crypt object classes + ******************************************************************************/ - nouveau_gpuobj_ref(NULL, &cctx->mem); +static struct nouveau_oclass +nv98_crypt_sclass[] = { + { 0x88b4, &nouveau_object_ofuncs }, + {}, +}; - nvvm_engref(chan->vm, engine, -1); - chan->engctx[engine] = NULL; - kfree(cctx); -} +/******************************************************************************* + * PCRYPT context + ******************************************************************************/ static int -nv98_crypt_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +nv98_crypt_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv98_crypt_chan *cctx = chan->engctx[engine]; - - /* fuc engine doesn't need an object, our ramht code does.. */ - cctx->mem->engine = 5; - cctx->mem->class = class; - return nouveau_ramht_insert(chan, handle, cctx->mem); -} + struct nv98_crypt_chan *priv; + int ret; -static void -nv98_crypt_tlb_flush(struct drm_device *dev, int engine) -{ - nv50_vm_flush_engine(dev, 0x0a); -} + ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256, + 256, NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; -static int -nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend) -{ - nv_mask(dev, 0x000200, 0x00004000, 0x00000000); return 0; } -static int -nv98_crypt_init(struct drm_device *dev, int engine) -{ - int i; - - /* reset! */ - nv_mask(dev, 0x000200, 0x00004000, 0x00000000); - nv_mask(dev, 0x000200, 0x00004000, 0x00004000); - - /* wait for exit interrupt to signal */ - nv_wait(dev, 0x087008, 0x00000010, 0x00000010); - nv_wr32(dev, 0x087004, 0x00000010); - - /* upload microcode code and data segments */ - nv_wr32(dev, 0x087ff8, 0x00100000); - for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++) - nv_wr32(dev, 0x087ff4, nv98_pcrypt_code[i]); - - nv_wr32(dev, 0x087ff8, 0x00000000); - for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++) - nv_wr32(dev, 0x087ff4, nv98_pcrypt_data[i]); +static struct nouveau_oclass +nv98_crypt_cclass = { + .handle = NV_ENGCTX(CRYPT, 0x98), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv98_crypt_context_ctor, + .dtor = _nouveau_crypt_context_dtor, + .init = _nouveau_crypt_context_init, + .fini = _nouveau_crypt_context_fini, + .rd32 = _nouveau_crypt_context_rd32, + .wr32 = _nouveau_crypt_context_wr32, + }, +}; - /* start it running */ - nv_wr32(dev, 0x08710c, 0x00000000); - nv_wr32(dev, 0x087104, 0x00000000); /* ENTRY */ - nv_wr32(dev, 0x087100, 0x00000002); /* TRIGGER */ - return 0; -} +/******************************************************************************* + * PCRYPT engine/subdev functions + ******************************************************************************/ static struct nouveau_enum nv98_crypt_isr_error_name[] = { { 0x0000, "ILLEGAL_MTHD" }, @@ -150,65 +100,100 @@ static struct nouveau_enum nv98_crypt_isr_error_name[] = { }; static void -nv98_crypt_isr(struct drm_device *dev) +nv98_crypt_intr(struct nouveau_subdev *subdev) { - u32 disp = nv_rd32(dev, 0x08701c); - u32 stat = nv_rd32(dev, 0x087008) & disp & ~(disp >> 16); - u32 inst = nv_rd32(dev, 0x087050) & 0x3fffffff; - u32 ssta = nv_rd32(dev, 0x087040) & 0x0000ffff; - u32 addr = nv_rd32(dev, 0x087040) >> 16; + struct nv98_crypt_priv *priv = (void *)subdev; + u32 disp = nv_rd32(priv, 0x08701c); + u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16); + u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff; + u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff; + u32 addr = nv_rd32(priv, 0x087040) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_rd32(dev, 0x087044); - int chid = nv50_graph_isr_chid(dev, inst); + u32 data = nv_rd32(priv, 0x087044); if (stat & 0x00000040) { - NV_INFO(dev, "PCRYPT: DISPATCH_ERROR ["); + nv_error(priv, "DISPATCH_ERROR ["); nouveau_enum_print(nv98_crypt_isr_error_name, ssta); - printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n", - chid, inst, subc, mthd, data); - nv_wr32(dev, 0x087004, 0x00000040); + printk("] ch 0x%08x subc %d mthd 0x%04x data 0x%08x\n", + inst, subc, mthd, data); + nv_wr32(priv, 0x087004, 0x00000040); stat &= ~0x00000040; } if (stat) { - NV_INFO(dev, "PCRYPT: unhandled intr 0x%08x\n", stat); - nv_wr32(dev, 0x087004, stat); + nv_error(priv, "unhandled intr 0x%08x\n", stat); + nv_wr32(priv, 0x087004, stat); } - nv50_fb_vm_trap(dev, 1); + nv50_fb_trap(nouveau_fb(priv), 1); } -static void -nv98_crypt_destroy(struct drm_device *dev, int engine) +static int +nv98_crypt_tlb_flush(struct nouveau_engine *engine) { - struct nv98_crypt_priv *priv = nv_engine(dev, engine); - - nouveau_irq_unregister(dev, 14); - NVOBJ_ENGINE_DEL(dev, CRYPT); - kfree(priv); + nv50_vm_flush_engine(&engine->base, 0x0a); + return 0; } -int -nv98_crypt_create(struct drm_device *dev) +static int +nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { struct nv98_crypt_priv *priv; + int ret; + + ret = nouveau_crypt_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00004000; + nv_subdev(priv)->intr = nv98_crypt_intr; + nv_engine(priv)->cclass = &nv98_crypt_cclass; + nv_engine(priv)->sclass = nv98_crypt_sclass; + nv_engine(priv)->tlb_flush = nv98_crypt_tlb_flush; + return 0; +} + +static int +nv98_crypt_init(struct nouveau_object *object) +{ + struct nv98_crypt_priv *priv = (void *)object; + int ret, i; + + ret = nouveau_crypt_init(&priv->base); + if (ret) + return ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + /* wait for exit interrupt to signal */ + nv_wait(priv, 0x087008, 0x00000010, 0x00000010); + nv_wr32(priv, 0x087004, 0x00000010); - priv->base.destroy = nv98_crypt_destroy; - priv->base.init = nv98_crypt_init; - priv->base.fini = nv98_crypt_fini; - priv->base.context_new = nv98_crypt_context_new; - priv->base.context_del = nv98_crypt_context_del; - priv->base.object_new = nv98_crypt_object_new; - priv->base.tlb_flush = nv98_crypt_tlb_flush; + /* upload microcode code and data segments */ + nv_wr32(priv, 0x087ff8, 0x00100000); + for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++) + nv_wr32(priv, 0x087ff4, nv98_pcrypt_code[i]); - nouveau_irq_register(dev, 14, nv98_crypt_isr); + nv_wr32(priv, 0x087ff8, 0x00000000); + for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++) + nv_wr32(priv, 0x087ff4, nv98_pcrypt_data[i]); - NVOBJ_ENGINE_ADD(dev, CRYPT, &priv->base); - NVOBJ_CLASS(dev, 0x88b4, CRYPT); + /* start it running */ + nv_wr32(priv, 0x08710c, 0x00000000); + nv_wr32(priv, 0x087104, 0x00000000); /* ENTRY */ + nv_wr32(priv, 0x087100, 0x00000002); /* TRIGGER */ return 0; } + +struct nouveau_oclass +nv98_crypt_oclass = { + .handle = NV_ENGINE(CRYPT, 0x98), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv98_crypt_ctor, + .dtor = _nouveau_crypt_dtor, + .init = nv98_crypt_init, + .fini = _nouveau_crypt_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c new file mode 100644 index 0000000..1c919f2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c @@ -0,0 +1,90 @@ +/* + * 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 <engine/disp.h> + +struct nv04_disp_priv { + struct nouveau_disp base; +}; + +static struct nouveau_oclass +nv04_disp_sclass[] = { + {}, +}; + +static void +nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc) +{ + struct nouveau_disp *disp = &priv->base; + if (disp->vblank.notify) + disp->vblank.notify(disp->vblank.data, crtc); +} + +static void +nv04_disp_intr(struct nouveau_subdev *subdev) +{ + struct nv04_disp_priv *priv = (void *)subdev; + u32 crtc0 = nv_rd32(priv, 0x600100); + u32 crtc1 = nv_rd32(priv, 0x602100); + + if (crtc0 & 0x00000001) { + nv04_disp_intr_vblank(priv, 0); + nv_wr32(priv, 0x600100, 0x00000001); + } + + if (crtc1 & 0x00000001) { + nv04_disp_intr_vblank(priv, 1); + nv_wr32(priv, 0x602100, 0x00000001); + } +} + +static int +nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_disp_priv *priv; + int ret; + + ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY", + "display", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->sclass = nv04_disp_sclass; + nv_subdev(priv)->intr = nv04_disp_intr; + return 0; +} + +struct nouveau_oclass +nv04_disp_oclass = { + .handle = NV_ENGINE(DISP, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_disp_ctor, + .dtor = _nouveau_disp_dtor, + .init = _nouveau_disp_init, + .fini = _nouveau_disp_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c new file mode 100644 index 0000000..16a9afb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -0,0 +1,125 @@ +/* + * 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 <engine/software.h> +#include <engine/disp.h> + +struct nv50_disp_priv { + struct nouveau_disp base; +}; + +static struct nouveau_oclass +nv50_disp_sclass[] = { + {}, +}; + +static void +nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) +{ + struct nouveau_disp *disp = &priv->base; + struct nouveau_software_chan *chan, *temp; + unsigned long flags; + + spin_lock_irqsave(&disp->vblank.lock, flags); + list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) { + if (chan->vblank.crtc != crtc) + continue; + + nv_wr32(priv, 0x001704, chan->vblank.channel); + nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); + + if (nv_device(priv)->chipset == 0x50) { + nv_wr32(priv, 0x001570, chan->vblank.offset); + nv_wr32(priv, 0x001574, chan->vblank.value); + } else { + if (nv_device(priv)->chipset >= 0xc0) { + nv_wr32(priv, 0x06000c, + upper_32_bits(chan->vblank.offset)); + } + nv_wr32(priv, 0x060010, chan->vblank.offset); + nv_wr32(priv, 0x060014, chan->vblank.value); + } + + list_del(&chan->vblank.head); + if (disp->vblank.put) + disp->vblank.put(disp->vblank.data, crtc); + } + spin_unlock_irqrestore(&disp->vblank.lock, flags); + + if (disp->vblank.notify) + disp->vblank.notify(disp->vblank.data, crtc); +} + +static void +nv50_disp_intr(struct nouveau_subdev *subdev) +{ + struct nv50_disp_priv *priv = (void *)subdev; + u32 stat1 = nv_rd32(priv, 0x610024); + + if (stat1 & 0x00000004) { + nv50_disp_intr_vblank(priv, 0); + nv_wr32(priv, 0x610024, 0x00000004); + stat1 &= ~0x00000004; + } + + if (stat1 & 0x00000008) { + nv50_disp_intr_vblank(priv, 1); + nv_wr32(priv, 0x610024, 0x00000008); + stat1 &= ~0x00000008; + } + +} + +static int +nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_disp_priv *priv; + int ret; + + ret = nouveau_disp_create(parent, engine, oclass, "PDISP", + "display", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->sclass = nv50_disp_sclass; + nv_subdev(priv)->intr = nv50_disp_intr; + + INIT_LIST_HEAD(&priv->base.vblank.list); + spin_lock_init(&priv->base.vblank.lock); + return 0; +} + +struct nouveau_oclass +nv50_disp_oclass = { + .handle = NV_ENGINE(DISP, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_disp_ctor, + .dtor = _nouveau_disp_dtor, + .init = _nouveau_disp_init, + .fini = _nouveau_disp_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c new file mode 100644 index 0000000..d93efbc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -0,0 +1,118 @@ +/* + * 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/bar.h> + +#include <engine/software.h> +#include <engine/disp.h> + +struct nvd0_disp_priv { + struct nouveau_disp base; +}; + +static struct nouveau_oclass +nvd0_disp_sclass[] = { + {}, +}; + +static void +nvd0_disp_intr_vblank(struct nvd0_disp_priv *priv, int crtc) +{ + struct nouveau_bar *bar = nouveau_bar(priv); + struct nouveau_disp *disp = &priv->base; + struct nouveau_software_chan *chan, *temp; + unsigned long flags; + + spin_lock_irqsave(&disp->vblank.lock, flags); + list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) { + if (chan->vblank.crtc != crtc) + continue; + + nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); + bar->flush(bar); + nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset)); + nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); + nv_wr32(priv, 0x060014, chan->vblank.value); + + list_del(&chan->vblank.head); + if (disp->vblank.put) + disp->vblank.put(disp->vblank.data, crtc); + } + spin_unlock_irqrestore(&disp->vblank.lock, flags); + + if (disp->vblank.notify) + disp->vblank.notify(disp->vblank.data, crtc); +} + +static void +nvd0_disp_intr(struct nouveau_subdev *subdev) +{ + struct nvd0_disp_priv *priv = (void *)subdev; + u32 intr = nv_rd32(priv, 0x610088); + int i; + + for (i = 0; i < 4; i++) { + u32 mask = 0x01000000 << i; + if (mask & intr) { + u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); + if (stat & 0x00000001) + nvd0_disp_intr_vblank(priv, i); + nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); + nv_rd32(priv, 0x6100c0 + (i * 0x800)); + } + } +} + +static int +nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvd0_disp_priv *priv; + int ret; + + ret = nouveau_disp_create(parent, engine, oclass, "PDISP", + "display", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->sclass = nvd0_disp_sclass; + nv_subdev(priv)->intr = nvd0_disp_intr; + + INIT_LIST_HEAD(&priv->base.vblank.list); + spin_lock_init(&priv->base.vblank.lock); + return 0; +} + +struct nouveau_oclass +nvd0_disp_oclass = { + .handle = NV_ENGINE(DISP, 0xd0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvd0_disp_ctor, + .dtor = _nouveau_disp_dtor, + .init = _nouveau_disp_init, + .fini = _nouveau_disp_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c new file mode 100644 index 0000000..e1f013d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c @@ -0,0 +1,87 @@ +/* + * 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 <core/object.h> +#include <core/class.h> + +#include <subdev/fb.h> +#include <engine/dmaobj.h> + +int +nouveau_dmaobj_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + void *data, u32 size, int len, void **pobject) +{ + struct nv_dma_class *args = data; + struct nouveau_dmaobj *object; + int ret; + + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_object_create_(parent, engine, oclass, 0, len, pobject); + object = *pobject; + if (ret) + return ret; + + switch (args->flags & NV_DMA_TARGET_MASK) { + case NV_DMA_TARGET_VM: + object->target = NV_MEM_TARGET_VM; + break; + case NV_DMA_TARGET_VRAM: + object->target = NV_MEM_TARGET_VRAM; + break; + case NV_DMA_TARGET_PCI: + object->target = NV_MEM_TARGET_PCI; + break; + case NV_DMA_TARGET_PCI_US: + case NV_DMA_TARGET_AGP: + object->target = NV_MEM_TARGET_PCI_NOSNOOP; + break; + default: + return -EINVAL; + } + + switch (args->flags & NV_DMA_ACCESS_MASK) { + case NV_DMA_ACCESS_VM: + object->access = NV_MEM_ACCESS_VM; + break; + case NV_DMA_ACCESS_RD: + object->access = NV_MEM_ACCESS_RO; + break; + case NV_DMA_ACCESS_WR: + object->access = NV_MEM_ACCESS_WO; + break; + case NV_DMA_ACCESS_RDWR: + object->access = NV_MEM_ACCESS_RW; + break; + default: + return -EINVAL; + } + + object->start = args->start; + object->limit = args->limit; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c new file mode 100644 index 0000000..b0d3651 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c @@ -0,0 +1,176 @@ +/* + * 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 <core/gpuobj.h> + +#include <subdev/fb.h> +#include <subdev/vm/nv04.h> + +#include <engine/dmaobj.h> + +struct nv04_dmaeng_priv { + struct nouveau_dmaeng base; +}; + +struct nv04_dmaobj_priv { + struct nouveau_dmaobj base; +}; + +static int +nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng, + struct nouveau_object *parent, + struct nouveau_dmaobj *dmaobj, + struct nouveau_gpuobj **pgpuobj) +{ + struct nouveau_gpuobj *gpuobj; + u32 flags0 = nv_mclass(dmaobj); + u32 flags2 = 0x00000000; + u32 offset = (dmaobj->start & 0xfffff000); + u32 adjust = (dmaobj->start & 0x00000fff); + u32 length = dmaobj->limit - dmaobj->start; + int ret; + + if (dmaobj->target == NV_MEM_TARGET_VM) { + gpuobj = nv04_vmmgr(dmaeng)->vm->pgt[0].obj[0]; + if (dmaobj->start == 0) + return nouveau_gpuobj_dup(parent, gpuobj, pgpuobj); + + offset = nv_ro32(gpuobj, 8 + (offset >> 10)); + offset &= 0xfffff000; + dmaobj->target = NV_MEM_TARGET_PCI; + dmaobj->access = NV_MEM_ACCESS_RW; + } + + switch (dmaobj->target) { + case NV_MEM_TARGET_VRAM: + flags0 |= 0x00003000; + break; + case NV_MEM_TARGET_PCI: + flags0 |= 0x00023000; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + flags0 |= 0x00033000; + break; + default: + return -EINVAL; + } + + switch (dmaobj->access) { + case NV_MEM_ACCESS_RO: + flags0 |= 0x00004000; + break; + case NV_MEM_ACCESS_WO: + flags0 |= 0x00008000; + case NV_MEM_ACCESS_RW: + flags2 |= 0x00000002; + break; + default: + return -EINVAL; + } + + ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); + *pgpuobj = gpuobj; + if (ret == 0) { + nv_wo32(*pgpuobj, 0x00, flags0 | (adjust << 20)); + nv_wo32(*pgpuobj, 0x04, length); + nv_wo32(*pgpuobj, 0x08, flags2 | offset); + nv_wo32(*pgpuobj, 0x0c, flags2 | offset); + } + + return ret; +} + +static int +nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_dmaeng *dmaeng = (void *)engine; + struct nv04_dmaobj_priv *dmaobj; + struct nouveau_gpuobj *gpuobj; + int ret; + + ret = nouveau_dmaobj_create(parent, engine, oclass, + data, size, &dmaobj); + *pobject = nv_object(dmaobj); + if (ret) + return ret; + + switch (nv_mclass(parent)) { + case 0x006e: + ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj); + nouveau_object_ref(NULL, pobject); + *pobject = nv_object(gpuobj); + break; + default: + break; + } + + return ret; +} + +static struct nouveau_ofuncs +nv04_dmaobj_ofuncs = { + .ctor = nv04_dmaobj_ctor, + .dtor = _nouveau_dmaobj_dtor, + .init = _nouveau_dmaobj_init, + .fini = _nouveau_dmaobj_fini, +}; + +static struct nouveau_oclass +nv04_dmaobj_sclass[] = { + { 0x0002, &nv04_dmaobj_ofuncs }, + { 0x0003, &nv04_dmaobj_ofuncs }, + { 0x003d, &nv04_dmaobj_ofuncs }, + {} +}; + +static int +nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_dmaeng_priv *priv; + int ret; + + ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.base.sclass = nv04_dmaobj_sclass; + priv->base.bind = nv04_dmaobj_bind; + return 0; +} + +struct nouveau_oclass +nv04_dmaeng_oclass = { + .handle = NV_ENGINE(DMAOBJ, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_dmaeng_ctor, + .dtor = _nouveau_dmaeng_dtor, + .init = _nouveau_dmaeng_init, + .fini = _nouveau_dmaeng_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c new file mode 100644 index 0000000..8207ac9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c @@ -0,0 +1,168 @@ +/* + * 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 <core/gpuobj.h> + +#include <subdev/fb.h> +#include <engine/dmaobj.h> + +struct nv50_dmaeng_priv { + struct nouveau_dmaeng base; +}; + +struct nv50_dmaobj_priv { + struct nouveau_dmaobj base; +}; + +static int +nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng, + struct nouveau_object *parent, + struct nouveau_dmaobj *dmaobj, + struct nouveau_gpuobj **pgpuobj) +{ + u32 flags = nv_mclass(dmaobj); + int ret; + + switch (dmaobj->target) { + case NV_MEM_TARGET_VM: + flags |= 0x00000000; + flags |= 0x60000000; /* COMPRESSION_USEVM */ + flags |= 0x1fc00000; /* STORAGE_TYPE_USEVM */ + break; + case NV_MEM_TARGET_VRAM: + flags |= 0x00010000; + flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */ + break; + case NV_MEM_TARGET_PCI: + flags |= 0x00020000; + flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */ + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + flags |= 0x00030000; + flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */ + break; + default: + return -EINVAL; + } + + switch (dmaobj->access) { + case NV_MEM_ACCESS_VM: + break; + case NV_MEM_ACCESS_RO: + flags |= 0x00040000; + break; + case NV_MEM_ACCESS_WO: + case NV_MEM_ACCESS_RW: + flags |= 0x00080000; + break; + } + + ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); + if (ret == 0) { + nv_wo32(*pgpuobj, 0x00, flags); + nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit)); + nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start)); + nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 | + upper_32_bits(dmaobj->start)); + nv_wo32(*pgpuobj, 0x10, 0x00000000); + nv_wo32(*pgpuobj, 0x14, 0x00000000); + } + + return ret; +} + +static int +nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_dmaeng *dmaeng = (void *)engine; + struct nv50_dmaobj_priv *dmaobj; + struct nouveau_gpuobj *gpuobj; + int ret; + + ret = nouveau_dmaobj_create(parent, engine, oclass, + data, size, &dmaobj); + *pobject = nv_object(dmaobj); + if (ret) + return ret; + + switch (nv_mclass(parent)) { + case 0x506f: + case 0x826f: + ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj); + nouveau_object_ref(NULL, pobject); + *pobject = nv_object(gpuobj); + break; + default: + break; + } + + return ret; +} + +static struct nouveau_ofuncs +nv50_dmaobj_ofuncs = { + .ctor = nv50_dmaobj_ctor, + .dtor = _nouveau_dmaobj_dtor, + .init = _nouveau_dmaobj_init, + .fini = _nouveau_dmaobj_fini, +}; + +static struct nouveau_oclass +nv50_dmaobj_sclass[] = { + { 0x0002, &nv50_dmaobj_ofuncs }, + { 0x0003, &nv50_dmaobj_ofuncs }, + { 0x003d, &nv50_dmaobj_ofuncs }, + {} +}; + +static int +nv50_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_dmaeng_priv *priv; + int ret; + + ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.base.sclass = nv50_dmaobj_sclass; + priv->base.bind = nv50_dmaobj_bind; + return 0; +} + +struct nouveau_oclass +nv50_dmaeng_oclass = { + .handle = NV_ENGINE(DMAOBJ, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_dmaeng_ctor, + .dtor = _nouveau_dmaeng_dtor, + .init = _nouveau_dmaeng_init, + .fini = _nouveau_dmaeng_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c new file mode 100644 index 0000000..5baa086 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c @@ -0,0 +1,99 @@ +/* + * 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 <core/gpuobj.h> + +#include <subdev/fb.h> +#include <engine/dmaobj.h> + +struct nvc0_dmaeng_priv { + struct nouveau_dmaeng base; +}; + +struct nvc0_dmaobj_priv { + struct nouveau_dmaobj base; +}; + +static int +nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_dmaobj_priv *dmaobj; + int ret; + + ret = nouveau_dmaobj_create(parent, engine, oclass, data, size, &dmaobj); + *pobject = nv_object(dmaobj); + if (ret) + return ret; + + if (dmaobj->base.target != NV_MEM_TARGET_VM || dmaobj->base.start) + return -EINVAL; + + return 0; +} + +static struct nouveau_ofuncs +nvc0_dmaobj_ofuncs = { + .ctor = nvc0_dmaobj_ctor, + .dtor = _nouveau_dmaobj_dtor, + .init = _nouveau_dmaobj_init, + .fini = _nouveau_dmaobj_fini, +}; + +static struct nouveau_oclass +nvc0_dmaobj_sclass[] = { + { 0x0002, &nvc0_dmaobj_ofuncs }, + { 0x0003, &nvc0_dmaobj_ofuncs }, + { 0x003d, &nvc0_dmaobj_ofuncs }, + {} +}; + +static int +nvc0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_dmaeng_priv *priv; + int ret; + + ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.base.sclass = nvc0_dmaobj_sclass; + return 0; +} + +struct nouveau_oclass +nvc0_dmaeng_oclass = { + .handle = NV_ENGINE(DMAOBJ, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_dmaeng_ctor, + .dtor = _nouveau_dmaeng_dtor, + .init = _nouveau_dmaeng_init, + .fini = _nouveau_dmaeng_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c new file mode 100644 index 0000000..edeb76e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c @@ -0,0 +1,165 @@ +/* + * 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 <core/object.h> +#include <core/handle.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> + +int +nouveau_fifo_channel_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + int bar, u32 addr, u32 size, u32 pushbuf, + u32 engmask, int len, void **ptr) +{ + struct nouveau_device *device = nv_device(engine); + struct nouveau_fifo *priv = (void *)engine; + struct nouveau_fifo_chan *chan; + struct nouveau_dmaeng *dmaeng; + unsigned long flags; + int ret; + + /* create base object class */ + ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL, + engmask, len, ptr); + chan = *ptr; + if (ret) + return ret; + + /* validate dma object representing push buffer */ + chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf); + if (!chan->pushdma) + return -ENOENT; + + dmaeng = (void *)chan->pushdma->base.engine; + switch (chan->pushdma->base.oclass->handle) { + case 0x0002: + case 0x003d: + break; + default: + return -EINVAL; + } + + if (dmaeng->bind) { + ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu); + if (ret) + return ret; + } + + /* find a free fifo channel */ + spin_lock_irqsave(&priv->lock, flags); + for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) { + if (!priv->channel[chan->chid]) { + priv->channel[chan->chid] = nv_object(chan); + break; + } + } + spin_unlock_irqrestore(&priv->lock, flags); + + if (chan->chid == priv->max) { + nv_error(priv, "no free channels\n"); + return -ENOSPC; + } + + /* map fifo control registers */ + chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr + + (chan->chid * size), size); + if (!chan->user) + return -EFAULT; + + chan->size = size; + return 0; +} + +void +nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan) +{ + struct nouveau_fifo *priv = (void *)nv_object(chan)->engine; + unsigned long flags; + + iounmap(chan->user); + + spin_lock_irqsave(&priv->lock, flags); + priv->channel[chan->chid] = NULL; + spin_unlock_irqrestore(&priv->lock, flags); + + nouveau_gpuobj_ref(NULL, &chan->pushgpu); + nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma); + nouveau_namedb_destroy(&chan->base); +} + +void +_nouveau_fifo_channel_dtor(struct nouveau_object *object) +{ + struct nouveau_fifo_chan *chan = (void *)object; + nouveau_fifo_channel_destroy(chan); +} + +u32 +_nouveau_fifo_channel_rd32(struct nouveau_object *object, u32 addr) +{ + struct nouveau_fifo_chan *chan = (void *)object; + return ioread32_native(chan->user + addr); +} + +void +_nouveau_fifo_channel_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + struct nouveau_fifo_chan *chan = (void *)object; + iowrite32_native(data, chan->user + addr); +} + +void +nouveau_fifo_destroy(struct nouveau_fifo *priv) +{ + kfree(priv->channel); + nouveau_engine_destroy(&priv->base); +} + +int +nouveau_fifo_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + int min, int max, int length, void **pobject) +{ + struct nouveau_fifo *priv; + int ret; + + ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO", + "fifo", length, pobject); + priv = *pobject; + if (ret) + return ret; + + priv->min = min; + priv->max = max; + priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL); + if (!priv->channel) + return -ENOMEM; + + spin_lock_init(&priv->lock); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c index 6ab7eb0..8b7513f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c @@ -1,44 +1,45 @@ /* - * Copyright (C) 2012 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> -#include "nouveau_util.h" +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/namedb.h> +#include <core/handle.h> #include <core/ramht.h> -#include "nouveau_software.h" - -static struct ramfc_desc { - unsigned bits:6; - unsigned ctxs:5; - unsigned ctxp:8; - unsigned regs:5; - unsigned regp; -} nv04_ramfc[] = { + +#include <subdev/instmem.h> +#include <subdev/instmem/nv04.h> +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/fifo.h> + +#include "nv04.h" + +static struct ramfc_desc +nv04_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, @@ -50,283 +51,360 @@ static struct ramfc_desc { {} }; -struct nv04_fifo_priv { - struct nouveau_fifo_priv base; - struct ramfc_desc *ramfc_desc; - struct nouveau_gpuobj *ramro; - struct nouveau_gpuobj *ramfc; -}; +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ -struct nv04_fifo_chan { - struct nouveau_fifo_chan base; - u32 ramfc; -}; - -bool -nv04_fifo_cache_pull(struct drm_device *dev, bool enable) +int +nv04_fifo_object_attach(struct nouveau_object *parent, + struct nouveau_object *object, u32 handle) { - int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable); - - if (!enable) { - /* In some cases the PFIFO puller may be left in an - * inconsistent state if you try to stop it when it's - * busy translating handles. Sometimes you get a - * PFIFO_CACHE_ERROR, sometimes it just fails silently - * sending incorrect instance offsets to PGRAPH after - * it's started up again. To avoid the latter we - * invalidate the most recently calculated instance. - */ - if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0, - NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0)) - NV_ERROR(dev, "Timeout idling the PFIFO puller.\n"); - - if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) & - NV04_PFIFO_CACHE1_PULL0_HASH_FAILED) - nv_wr32(dev, NV03_PFIFO_INTR_0, - NV_PFIFO_INTR_CACHE_ERROR); - - nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); + struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; + u32 context, chid = chan->base.chid; + int ret; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->addr >> 4; + else + context = 0x00000004; /* just non-zero */ + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW: + context |= 0x00000000; + break; + case NVDEV_ENGINE_GR: + context |= 0x00010000; + break; + case NVDEV_ENGINE_MPEG: + context |= 0x00020000; + break; + default: + return -EINVAL; } - return pull & 1; + context |= 0x80000000; /* valid */ + context |= chid << 24; + + mutex_lock(&nv_subdev(priv)->mutex); + ret = nouveau_ramht_insert(priv->ramht, chid, handle, context); + mutex_unlock(&nv_subdev(priv)->mutex); + return ret; +} + +void +nv04_fifo_object_detach(struct nouveau_object *parent, int cookie) +{ + struct nv04_fifo_priv *priv = (void *)parent->engine; + mutex_lock(&nv_subdev(priv)->mutex); + nouveau_ramht_remove(priv->ramht, cookie); + mutex_unlock(&nv_subdev(priv)->mutex); } static int -nv04_fifo_context_new(struct nouveau_channel *chan, int engine) +nv04_fifo_chan_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv04_fifo_priv *priv = nv_engine(dev, engine); - struct nv04_fifo_chan *fctx; - unsigned long flags; + struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo_chan *chan; + struct nv_channel_dma_class *args = data; int ret; - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; + if (size < sizeof(*args)) + return -EINVAL; - fctx->ramfc = chan->id * 32; + ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000, + 0x10000, args->pushbuf, + (1 << NVDEV_ENGINE_DMAOBJ) | + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; - /* map channel control registers */ - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV03_USER(chan->id), PAGE_SIZE); - if (!chan->user) { - ret = -ENOMEM; - goto error; - } + nv_parent(chan)->object_attach = nv04_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + chan->ramfc = chan->base.chid * 32; - /* initialise default fifo context */ - nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x08, chan->pushbuf->addr >> 4); - nv_wo32(priv->ramfc, fctx->ramfc + 0x10, + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); + nv_wo32(priv->ramfc, chan->ramfc + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + return 0; +} + +void +nv04_fifo_chan_dtor(struct nouveau_object *object) +{ + struct nv04_fifo_priv *priv = (void *)object->engine; + struct nv04_fifo_chan *chan = (void *)object; + struct ramfc_desc *c = priv->ramfc_desc; - /* enable dma mode on the channel */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id)); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + do { + nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000); + } while ((++c)->bits); + + nouveau_fifo_channel_destroy(&chan->base); +} -error: +int +nv04_fifo_chan_init(struct nouveau_object *object) +{ + struct nv04_fifo_priv *priv = (void *)object->engine; + struct nv04_fifo_chan *chan = (void *)object; + u32 mask = 1 << chan->base.chid; + unsigned long flags; + int ret; + + ret = nouveau_fifo_channel_init(&chan->base); if (ret) - priv->base.base.context_del(chan, engine); - return ret; + return ret; + + spin_lock_irqsave(&priv->base.lock, flags); + nv_mask(priv, NV04_PFIFO_MODE, mask, mask); + spin_unlock_irqrestore(&priv->base.lock, flags); + return 0; } -void -nv04_fifo_context_del(struct nouveau_channel *chan, int engine) +int +nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv04_fifo_priv *priv = nv_engine(chan->dev, engine); - struct nv04_fifo_chan *fctx = chan->engctx[engine]; - struct ramfc_desc *c = priv->ramfc_desc; + struct nv04_fifo_priv *priv = (void *)object->engine; + struct nv04_fifo_chan *chan = (void *)object; + struct nouveau_gpuobj *fctx = priv->ramfc; + struct ramfc_desc *c; unsigned long flags; - int chid; + u32 data = chan->ramfc; + u32 chid; /* prevent fifo context switches */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_wr32(dev, NV03_PFIFO_CACHES, 0); + spin_lock_irqsave(&priv->base.lock, flags); + nv_wr32(priv, NV03_PFIFO_CACHES, 0); /* if this channel is active, replace it with a null context */ - chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels; - if (chid == chan->id) { - nv_mask(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0); - nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); + chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; + if (chid == chan->base.chid) { + nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0); + nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); + c = priv->ramfc_desc; do { - u32 mask = ((1ULL << c->bits) - 1) << c->regs; - nv_mask(dev, c->regp, mask, 0x00000000); - nv_wo32(priv->ramfc, fctx->ramfc + c->ctxp, 0x00000000); + u32 rm = ((1ULL << c->bits) - 1) << c->regs; + u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; + u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs; + u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm); + nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); + } while ((++c)->bits); + + c = priv->ramfc_desc; + do { + nv_wr32(priv, c->regp, 0x00000000); } while ((++c)->bits); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); } /* restore normal operation, after disabling dma mode */ - nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0); - nv_wr32(dev, NV03_PFIFO_CACHES, 1); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - - /* clean up */ - nouveau_gpuobj_ref(NULL, &chan->ramfc); /*XXX: nv40 */ - if (chan->user) { - iounmap(chan->user); - chan->user = NULL; - } + nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); + nv_wr32(priv, NV03_PFIFO_CACHES, 1); + spin_unlock_irqrestore(&priv->base.lock, flags); + + return nouveau_fifo_channel_fini(&chan->base, suspend); } +static struct nouveau_ofuncs +nv04_fifo_ofuncs = { + .ctor = nv04_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; + +static struct nouveau_oclass +nv04_fifo_sclass[] = { + { 0x006e, &nv04_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ + int -nv04_fifo_init(struct drm_device *dev, int engine) +nv04_fifo_context_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 nv04_fifo_priv *priv = nv_engine(dev, engine); - int i; + struct nv04_fifo_base *base; + int ret; - nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0); - nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO); + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; - nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + return 0; +} - nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((dev_priv->ramht->bits - 9) << 16) | - (dev_priv->ramht->gpuobj->addr >> 8)); - nv_wr32(dev, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - nv_wr32(dev, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8); +static struct nouveau_oclass +nv04_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fifo_context_ctor, + .dtor = _nouveau_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels); +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ - nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff); +void +nv04_fifo_pause(struct nouveau_fifo *pfifo, unsigned long *pflags) +__acquires(priv->base.lock) +{ + struct nv04_fifo_priv *priv = (void *)pfifo; + unsigned long flags; - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(dev, NV03_PFIFO_CACHES, 1); + spin_lock_irqsave(&priv->base.lock, flags); + *pflags = flags; + + nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000); + nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000); + + /* in some cases the puller may be left in an inconsistent state + * if you try to stop it while it's busy translating handles. + * sometimes you get a CACHE_ERROR, sometimes it just fails + * silently; sending incorrect instance offsets to PGRAPH after + * it's started up again. + * + * to avoid this, we invalidate the most recently calculated + * instance. + */ + if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0, + NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000)) + nv_warn(priv, "timeout idling puller\n"); + + if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) & + NV04_PFIFO_CACHE1_PULL0_HASH_FAILED) + nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); + + nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000); +} - for (i = 0; i < priv->base.channels; i++) { - if (dev_priv->channels.ptr[i]) - nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i)); - } +void +nv04_fifo_start(struct nouveau_fifo *pfifo, unsigned long *pflags) +__releases(priv->base.lock) +{ + struct nv04_fifo_priv *priv = (void *)pfifo; + unsigned long flags = *pflags; - return 0; + nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); + nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001); + + spin_unlock_irqrestore(&priv->base.lock, flags); } -int -nv04_fifo_fini(struct drm_device *dev, int engine, bool suspend) +static const char * +nv_dma_state_err(u32 state) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv04_fifo_priv *priv = nv_engine(dev, engine); - struct nouveau_channel *chan; - int chid; - - /* prevent context switches and halt fifo operation */ - nv_wr32(dev, NV03_PFIFO_CACHES, 0); - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 0); - - /* store current fifo context in ramfc */ - chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels; - chan = dev_priv->channels.ptr[chid]; - if (suspend && chid != priv->base.channels && chan) { - struct nv04_fifo_chan *fctx = chan->engctx[engine]; - struct nouveau_gpuobj *ctx = priv->ramfc; - struct ramfc_desc *c = priv->ramfc_desc; - do { - u32 rm = ((1ULL << c->bits) - 1) << c->regs; - u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; - u32 rv = (nv_rd32(dev, c->regp) & rm) >> c->regs; - u32 cv = (nv_ro32(ctx, c->ctxp + fctx->ramfc) & ~cm); - nv_wo32(ctx, c->ctxp + fctx->ramfc, cv | (rv << c->ctxs)); - } while ((++c)->bits); - } - - nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0x00000000); - return 0; + static const char * const desc[] = { + "NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE", + "INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK" + }; + return desc[(state >> 29) & 0x7]; } static bool -nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) +nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data) { - struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = NULL; - struct nouveau_gpuobj *obj; - unsigned long flags; + struct nv04_fifo_chan *chan = NULL; + struct nouveau_handle *bind; const int subc = (addr >> 13) & 0x7; const int mthd = addr & 0x1ffc; bool handled = false; + unsigned long flags; u32 engine; - spin_lock_irqsave(&dev_priv->channels.lock, flags); - if (likely(chid >= 0 && chid < pfifo->channels)) - chan = dev_priv->channels.ptr[chid]; + spin_lock_irqsave(&priv->base.lock, flags); + if (likely(chid >= priv->base.min && chid <= priv->base.max)) + chan = (void *)priv->base.channel[chid]; if (unlikely(!chan)) goto out; switch (mthd) { - case 0x0000: /* bind object to subchannel */ - obj = nouveau_ramht_find(chan, data); - if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW)) + case 0x0000: + bind = nouveau_namedb_get(nv_namedb(chan), data); + if (unlikely(!bind)) break; - engine = 0x0000000f << (subc * 4); + if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) { + engine = 0x0000000f << (subc * 4); + chan->subc[subc] = data; + handled = true; + + nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0); + } - nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000); - handled = true; + nouveau_namedb_put(bind); break; default: - engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE); + engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE); if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) break; - if (!nouveau_gpuobj_mthd_call(chan, nouveau_software_class(dev), - mthd, data)) - handled = true; + bind = nouveau_namedb_get(nv_namedb(chan), chan->subc[subc]); + if (likely(bind)) { + if (!nv_call(bind->object, mthd, data)) + handled = true; + nouveau_namedb_put(bind); + } break; } out: - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + spin_unlock_irqrestore(&priv->base.lock, flags); return handled; } -static const char *nv_dma_state_err(u32 state) -{ - static const char * const desc[] = { - "NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE", - "INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK" - }; - return desc[(state >> 29) & 0x7]; -} - void -nv04_fifo_isr(struct drm_device *dev) +nv04_fifo_intr(struct nouveau_subdev *subdev) { - 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(subdev); + struct nv04_fifo_priv *priv = (void *)subdev; uint32_t status, reassign; int cnt = 0; - reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; - while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { + reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1; + while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { uint32_t chid, get; - nv_wr32(dev, NV03_PFIFO_CACHES, 0); + nv_wr32(priv, NV03_PFIFO_CACHES, 0); - chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & pfifo->channels; - get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); + chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; + get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET); if (status & NV_PFIFO_INTR_CACHE_ERROR) { uint32_t mthd, data; @@ -340,86 +418,85 @@ nv04_fifo_isr(struct drm_device *dev) */ ptr = (get & 0x7ff) >> 2; - if (dev_priv->card_type < NV_40) { - mthd = nv_rd32(dev, + if (device->card_type < NV_40) { + mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(dev, + data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr)); } else { - mthd = nv_rd32(dev, + mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(dev, + data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr)); } - if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) { - NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " - "Mthd 0x%04x Data 0x%08x\n", + if (!nv04_fifo_swmthd(priv, chid, mthd, data)) { + nv_info(priv, "CACHE_ERROR - Ch %d/%d " + "Mthd 0x%04x Data 0x%08x\n", chid, (mthd >> 13) & 7, mthd & 0x1ffc, data); } - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); - nv_wr32(dev, NV03_PFIFO_INTR_0, + nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0); + nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, + nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1); + nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, + nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1); + nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0); - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, - nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, + nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); + nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); status &= ~NV_PFIFO_INTR_CACHE_ERROR; } if (status & NV_PFIFO_INTR_DMA_PUSHER) { - u32 dma_get = nv_rd32(dev, 0x003244); - u32 dma_put = nv_rd32(dev, 0x003240); - u32 push = nv_rd32(dev, 0x003220); - u32 state = nv_rd32(dev, 0x003228); - - if (dev_priv->card_type == NV_50) { - u32 ho_get = nv_rd32(dev, 0x003328); - u32 ho_put = nv_rd32(dev, 0x003320); - u32 ib_get = nv_rd32(dev, 0x003334); - u32 ib_put = nv_rd32(dev, 0x003330); - - if (nouveau_ratelimit()) - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " - "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " - "State 0x%08x (err: %s) Push 0x%08x\n", - chid, ho_get, dma_get, ho_put, - dma_put, ib_get, ib_put, state, - nv_dma_state_err(state), - push); + u32 dma_get = nv_rd32(priv, 0x003244); + u32 dma_put = nv_rd32(priv, 0x003240); + u32 push = nv_rd32(priv, 0x003220); + u32 state = nv_rd32(priv, 0x003228); + + if (device->card_type == NV_50) { + u32 ho_get = nv_rd32(priv, 0x003328); + u32 ho_put = nv_rd32(priv, 0x003320); + u32 ib_get = nv_rd32(priv, 0x003334); + u32 ib_put = nv_rd32(priv, 0x003330); + + nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x " + "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " + "State 0x%08x (err: %s) Push 0x%08x\n", + chid, ho_get, dma_get, ho_put, + dma_put, ib_get, ib_put, state, + nv_dma_state_err(state), + push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ - nv_wr32(dev, 0x003364, 0x00000000); + nv_wr32(priv, 0x003364, 0x00000000); if (dma_get != dma_put || ho_get != ho_put) { - nv_wr32(dev, 0x003244, dma_put); - nv_wr32(dev, 0x003328, ho_put); + nv_wr32(priv, 0x003244, dma_put); + nv_wr32(priv, 0x003328, ho_put); } else if (ib_get != ib_put) { - nv_wr32(dev, 0x003334, ib_put); + nv_wr32(priv, 0x003334, ib_put); } } else { - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " + nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%08x " "Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n", chid, dma_get, dma_put, state, nv_dma_state_err(state), push); if (dma_get != dma_put) - nv_wr32(dev, 0x003244, dma_put); + nv_wr32(priv, 0x003244, dma_put); } - nv_wr32(dev, 0x003228, 0x00000000); - nv_wr32(dev, 0x003220, 0x00000001); - nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); + nv_wr32(priv, 0x003228, 0x00000000); + nv_wr32(priv, 0x003220, 0x00000001); + nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); status &= ~NV_PFIFO_INTR_DMA_PUSHER; } @@ -427,81 +504,118 @@ nv04_fifo_isr(struct drm_device *dev) uint32_t sem; status &= ~NV_PFIFO_INTR_SEMAPHORE; - nv_wr32(dev, NV03_PFIFO_INTR_0, + nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); - sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); - nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE); + nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); } - if (dev_priv->card_type == NV_50) { + if (device->card_type == NV_50) { if (status & 0x00000010) { - nv50_fb_vm_trap(dev, nouveau_ratelimit()); + nv50_fb_trap(nouveau_fb(priv), 1); status &= ~0x00000010; - nv_wr32(dev, 0x002100, 0x00000010); + nv_wr32(priv, 0x002100, 0x00000010); } } if (status) { - if (nouveau_ratelimit()) - NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", - status, chid); - nv_wr32(dev, NV03_PFIFO_INTR_0, status); + nv_info(priv, "unknown intr 0x%08x, ch %d\n", + status, chid); + nv_wr32(priv, NV03_PFIFO_INTR_0, status); status = 0; } - nv_wr32(dev, NV03_PFIFO_CACHES, reassign); + nv_wr32(priv, NV03_PFIFO_CACHES, reassign); } if (status) { - NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt); - nv_wr32(dev, 0x2140, 0); - nv_wr32(dev, 0x140, 0); + nv_info(priv, "still angry after %d spins, halt\n", cnt); + nv_wr32(priv, 0x002140, 0); + nv_wr32(priv, 0x000140, 0); } - nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); + nv_wr32(priv, 0x000100, 0x00000100); } -void -nv04_fifo_destroy(struct drm_device *dev, int engine) +static int +nv04_fifo_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 nv04_fifo_priv *priv = nv_engine(dev, engine); + struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_fifo_priv *priv; + int ret; - nouveau_irq_unregister(dev, 8); + ret = nouveau_fifo_create(parent, engine, oclass, 0, 15, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nouveau_ramht_ref(imem->ramht, &priv->ramht); + nouveau_gpuobj_ref(imem->ramro, &priv->ramro); + nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc); + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nv04_fifo_intr; + nv_engine(priv)->cclass = &nv04_fifo_cclass; + nv_engine(priv)->sclass = nv04_fifo_sclass; + priv->base.pause = nv04_fifo_pause; + priv->base.start = nv04_fifo_start; + priv->ramfc_desc = nv04_ramfc; + return 0; +} +void +nv04_fifo_dtor(struct nouveau_object *object) +{ + struct nv04_fifo_priv *priv = (void *)object; nouveau_gpuobj_ref(NULL, &priv->ramfc); nouveau_gpuobj_ref(NULL, &priv->ramro); - - dev_priv->eng[engine] = NULL; - kfree(priv); + nouveau_ramht_ref(NULL, &priv->ramht); + nouveau_fifo_destroy(&priv->base); } int -nv04_fifo_create(struct drm_device *dev) +nv04_fifo_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv04_fifo_priv *priv; + struct nv04_fifo_priv *priv = (void *)object; + int ret; + + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); + nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro); - nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc); + nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((priv->ramht->bits - 9) << 16) | + (priv->ramht->base.addr >> 8)); + nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); + nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8); - priv->base.base.destroy = nv04_fifo_destroy; - priv->base.base.init = nv04_fifo_init; - priv->base.base.fini = nv04_fifo_fini; - priv->base.base.context_new = nv04_fifo_context_new; - priv->base.base.context_del = nv04_fifo_context_del; - priv->base.channels = 15; - priv->ramfc_desc = nv04_ramfc; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); - nouveau_irq_register(dev, 8, nv04_fifo_isr); + nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); + nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); + + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(priv, NV03_PFIFO_CACHES, 1); return 0; } + +struct nouveau_oclass +nv04_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fifo_ctor, + .dtor = nv04_fifo_dtor, + .init = nv04_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h new file mode 100644 index 0000000..496a4b4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h @@ -0,0 +1,178 @@ +#ifndef __NV04_FIFO_H__ +#define __NV04_FIFO_H__ + +#include <engine/fifo.h> + +#define NV04_PFIFO_DELAY_0 0x00002040 +#define NV04_PFIFO_DMA_TIMESLICE 0x00002044 +#define NV04_PFIFO_NEXT_CHANNEL 0x00002050 +#define NV03_PFIFO_INTR_0 0x00002100 +#define NV03_PFIFO_INTR_EN_0 0x00002140 +# define NV_PFIFO_INTR_CACHE_ERROR (1<<0) +# define NV_PFIFO_INTR_RUNOUT (1<<4) +# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8) +# define NV_PFIFO_INTR_DMA_PUSHER (1<<12) +# define NV_PFIFO_INTR_DMA_PT (1<<16) +# define NV_PFIFO_INTR_SEMAPHORE (1<<20) +# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24) +#define NV03_PFIFO_RAMHT 0x00002210 +#define NV03_PFIFO_RAMFC 0x00002214 +#define NV03_PFIFO_RAMRO 0x00002218 +#define NV40_PFIFO_RAMFC 0x00002220 +#define NV03_PFIFO_CACHES 0x00002500 +#define NV04_PFIFO_MODE 0x00002504 +#define NV04_PFIFO_DMA 0x00002508 +#define NV04_PFIFO_SIZE 0x0000250c +#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4) +#define NV50_PFIFO_CTX_TABLE__SIZE 128 +#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31) +#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30) +#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF +#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF +#define NV03_PFIFO_CACHE0_PUSH0 0x00003000 +#define NV03_PFIFO_CACHE0_PULL0 0x00003040 +#define NV04_PFIFO_CACHE0_PULL0 0x00003050 +#define NV04_PFIFO_CACHE0_PULL1 0x00003054 +#define NV03_PFIFO_CACHE1_PUSH0 0x00003200 +#define NV03_PFIFO_CACHE1_PUSH1 0x00003204 +#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8) +#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16) +#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f +#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f +#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f +#define NV03_PFIFO_CACHE1_PUT 0x00003210 +#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220 +#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000 +# define NV_PFIFO_CACHE1_ENDIAN 0x80000000 +# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF +# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000 +#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228 +#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c +#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230 +#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240 +#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244 +#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248 +#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C +#define NV03_PFIFO_CACHE1_PULL0 0x00003240 +#define NV04_PFIFO_CACHE1_PULL0 0x00003250 +# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010 +# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000 +#define NV03_PFIFO_CACHE1_PULL1 0x00003250 +#define NV04_PFIFO_CACHE1_PULL1 0x00003254 +#define NV04_PFIFO_CACHE1_HASH 0x00003258 +#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260 +#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264 +#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268 +#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C +#define NV03_PFIFO_CACHE1_GET 0x00003270 +#define NV04_PFIFO_CACHE1_ENGINE 0x00003280 +#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0 +#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0 +#define NV40_PFIFO_UNK32E4 0x000032E4 +#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8)) +#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8)) +#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8)) +#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8)) + +struct ramfc_desc { + unsigned bits:6; + unsigned ctxs:5; + unsigned ctxp:8; + unsigned regs:5; + unsigned regp; +}; + +struct nv04_fifo_priv { + struct nouveau_fifo base; + struct ramfc_desc *ramfc_desc; + struct nouveau_ramht *ramht; + struct nouveau_gpuobj *ramro; + struct nouveau_gpuobj *ramfc; +}; + +struct nv04_fifo_base { + struct nouveau_fifo_base base; +}; + +struct nv04_fifo_chan { + struct nouveau_fifo_chan base; + u32 subc[8]; + u32 ramfc; +}; + +int nv04_fifo_object_attach(struct nouveau_object *, + struct nouveau_object *, u32); +void nv04_fifo_object_detach(struct nouveau_object *, int); + +void nv04_fifo_chan_dtor(struct nouveau_object *); +int nv04_fifo_chan_init(struct nouveau_object *); +int nv04_fifo_chan_fini(struct nouveau_object *, bool suspend); + +int nv04_fifo_context_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); + +void nv04_fifo_dtor(struct nouveau_object *); +int nv04_fifo_init(struct nouveau_object *); +void nv04_fifo_pause(struct nouveau_fifo *, unsigned long *); +void nv04_fifo_start(struct nouveau_fifo *, unsigned long *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c index 2d38fa8..391fefa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c @@ -1,43 +1,42 @@ /* - * Copyright (C) 2012 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> -#include "nouveau_util.h" +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> #include <core/ramht.h> -static struct ramfc_desc { - unsigned bits:6; - unsigned ctxs:5; - unsigned ctxp:8; - unsigned regs:5; - unsigned regp; -} nv10_ramfc[] = { +#include <subdev/instmem.h> +#include <subdev/instmem/nv04.h> +#include <subdev/fb.h> + +#include <engine/fifo.h> + +#include "nv04.h" + +static struct ramfc_desc +nv10_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -50,87 +49,122 @@ static struct ramfc_desc { {} }; -struct nv10_fifo_priv { - struct nouveau_fifo_priv base; - struct ramfc_desc *ramfc_desc; - struct nouveau_gpuobj *ramro; - struct nouveau_gpuobj *ramfc; -}; - -struct nv10_fifo_chan { - struct nouveau_fifo_chan base; - u32 ramfc; -}; +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ static int -nv10_fifo_context_new(struct nouveau_channel *chan, int engine) +nv10_fifo_chan_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv10_fifo_priv *priv = nv_engine(dev, engine); - struct nv10_fifo_chan *fctx; - unsigned long flags; + struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo_chan *chan; + struct nv_channel_dma_class *args = data; int ret; - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; - - fctx->ramfc = chan->id * 32; - - /* map channel control registers */ - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV03_USER(chan->id), PAGE_SIZE); - if (!chan->user) { - ret = -ENOMEM; - goto error; - } - - /* initialise default fifo context */ - nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4); - nv_wo32(priv->ramfc, fctx->ramfc + 0x14, + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000, + 0x10000, args->pushbuf, + (1 << NVDEV_ENGINE_DMAOBJ) | + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + nv_parent(chan)->object_attach = nv04_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + chan->ramfc = chan->base.chid * 32; + + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nv_wo32(priv->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + return 0; +} - /* enable dma mode on the channel */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id)); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +static struct nouveau_ofuncs +nv10_fifo_ofuncs = { + .ctor = nv10_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; -error: - if (ret) - priv->base.base.context_del(chan, engine); - return ret; -} +static struct nouveau_oclass +nv10_fifo_sclass[] = { + { 0x006e, &nv10_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ + +static struct nouveau_oclass +nv10_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fifo_context_ctor, + .dtor = _nouveau_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; + +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ -int -nv10_fifo_create(struct drm_device *dev) +static int +nv10_fifo_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 nv10_fifo_priv *priv; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro); - nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc); - - priv->base.base.destroy = nv04_fifo_destroy; - priv->base.base.init = nv04_fifo_init; - priv->base.base.fini = nv04_fifo_fini; - priv->base.base.context_new = nv10_fifo_context_new; - priv->base.base.context_del = nv04_fifo_context_del; - priv->base.channels = 31; - priv->ramfc_desc = nv10_ramfc; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; + struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_fifo_priv *priv; + int ret; - nouveau_irq_register(dev, 8, nv04_fifo_isr); + ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nouveau_ramht_ref(imem->ramht, &priv->ramht); + nouveau_gpuobj_ref(imem->ramro, &priv->ramro); + nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc); + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nv04_fifo_intr; + nv_engine(priv)->cclass = &nv10_fifo_cclass; + nv_engine(priv)->sclass = nv10_fifo_sclass; + priv->base.pause = nv04_fifo_pause; + priv->base.start = nv04_fifo_start; + priv->ramfc_desc = nv10_ramfc; return 0; } + +struct nouveau_oclass +nv10_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_fifo_ctor, + .dtor = nv04_fifo_dtor, + .init = nv04_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c index 2f700a15e..3b9d6c9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c @@ -1,43 +1,42 @@ /* - * Copyright (C) 2012 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> -#include "nouveau_util.h" +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> #include <core/ramht.h> -static struct ramfc_desc { - unsigned bits:6; - unsigned ctxs:5; - unsigned ctxp:8; - unsigned regs:5; - unsigned regp; -} nv17_ramfc[] = { +#include <subdev/instmem.h> +#include <subdev/instmem/nv04.h> +#include <subdev/fb.h> + +#include <engine/fifo.h> + +#include "nv04.h" + +static struct ramfc_desc +nv17_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -55,124 +54,154 @@ static struct ramfc_desc { {} }; -struct nv17_fifo_priv { - struct nouveau_fifo_priv base; - struct ramfc_desc *ramfc_desc; - struct nouveau_gpuobj *ramro; - struct nouveau_gpuobj *ramfc; -}; - -struct nv17_fifo_chan { - struct nouveau_fifo_chan base; - u32 ramfc; -}; +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ static int -nv17_fifo_context_new(struct nouveau_channel *chan, int engine) +nv17_fifo_chan_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv17_fifo_priv *priv = nv_engine(dev, engine); - struct nv17_fifo_chan *fctx; - unsigned long flags; + struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo_chan *chan; + struct nv_channel_dma_class *args = data; int ret; - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; - - fctx->ramfc = chan->id * 64; - - /* map channel control registers */ - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV03_USER(chan->id), PAGE_SIZE); - if (!chan->user) { - ret = -ENOMEM; - goto error; - } - - /* initialise default fifo context */ - nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4); - nv_wo32(priv->ramfc, fctx->ramfc + 0x14, + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000, + 0x10000, args->pushbuf, + (1 << NVDEV_ENGINE_DMAOBJ) | + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR) | + (1 << NVDEV_ENGINE_MPEG), /* NV31- */ + &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + nv_parent(chan)->object_attach = nv04_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + chan->ramfc = chan->base.chid * 64; + + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nv_wo32(priv->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + return 0; +} - /* enable dma mode on the channel */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id)); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +static struct nouveau_ofuncs +nv17_fifo_ofuncs = { + .ctor = nv17_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; -error: - if (ret) - priv->base.base.context_del(chan, engine); - return ret; -} +static struct nouveau_oclass +nv17_fifo_sclass[] = { + { 0x006e, &nv17_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ + +static struct nouveau_oclass +nv17_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x17), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fifo_context_ctor, + .dtor = _nouveau_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; + +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ static int -nv17_fifo_init(struct drm_device *dev, int engine) +nv17_fifo_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 nv17_fifo_priv *priv = nv_engine(dev, engine); - int i; + struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_fifo_priv *priv; + int ret; - nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0); - nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO); + ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nouveau_ramht_ref(imem->ramht, &priv->ramht); + nouveau_gpuobj_ref(imem->ramro, &priv->ramro); + nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc); + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nv04_fifo_intr; + nv_engine(priv)->cclass = &nv17_fifo_cclass; + nv_engine(priv)->sclass = nv17_fifo_sclass; + priv->base.pause = nv04_fifo_pause; + priv->base.start = nv04_fifo_start; + priv->ramfc_desc = nv17_ramfc; + return 0; +} - nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); +static int +nv17_fifo_init(struct nouveau_object *object) +{ + struct nv04_fifo_priv *priv = (void *)object; + int ret; - nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((dev_priv->ramht->bits - 9) << 16) | - (dev_priv->ramht->gpuobj->addr >> 8)); - nv_wr32(dev, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - nv_wr32(dev, NV03_PFIFO_RAMFC, 0x00010000 | - priv->ramfc->addr >> 8); + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels); + nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); + nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((priv->ramht->bits - 9) << 16) | + (priv->ramht->base.addr >> 8)); + nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); + nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(dev, NV03_PFIFO_CACHES, 1); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); - for (i = 0; i < priv->base.channels; i++) { - if (dev_priv->channels.ptr[i]) - nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i)); - } + nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); + nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(priv, NV03_PFIFO_CACHES, 1); return 0; } -int -nv17_fifo_create(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv17_fifo_priv *priv; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro); - nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc); - - priv->base.base.destroy = nv04_fifo_destroy; - priv->base.base.init = nv17_fifo_init; - priv->base.base.fini = nv04_fifo_fini; - priv->base.base.context_new = nv17_fifo_context_new; - priv->base.base.context_del = nv04_fifo_context_del; - priv->base.channels = 31; - priv->ramfc_desc = nv17_ramfc; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; - - nouveau_irq_register(dev, 8, nv04_fifo_isr); - return 0; -} +struct nouveau_oclass +nv17_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0x17), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv17_fifo_ctor, + .dtor = nv04_fifo_dtor, + .init = nv17_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c index 65a670f..43d5c9e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c @@ -1,43 +1,42 @@ /* - * Copyright (C) 2012 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> -#include "nouveau_util.h" +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> #include <core/ramht.h> -static struct ramfc_desc { - unsigned bits:6; - unsigned ctxs:5; - unsigned ctxp:8; - unsigned regs:5; - unsigned regp; -} nv40_ramfc[] = { +#include <subdev/instmem.h> +#include <subdev/instmem/nv04.h> +#include <subdev/fb.h> + +#include <engine/fifo.h> + +#include "nv04.h" + +static struct ramfc_desc +nv40_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -63,148 +62,287 @@ static struct ramfc_desc { {} }; -struct nv40_fifo_priv { - struct nouveau_fifo_priv base; - struct ramfc_desc *ramfc_desc; - struct nouveau_gpuobj *ramro; - struct nouveau_gpuobj *ramfc; -}; +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ -struct nv40_fifo_chan { - struct nouveau_fifo_chan base; - u32 ramfc; -}; +static int +nv40_fifo_object_attach(struct nouveau_object *parent, + struct nouveau_object *object, u32 handle) +{ + struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; + u32 context, chid = chan->base.chid; + int ret; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->addr >> 4; + else + context = 0x00000004; /* just non-zero */ + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW: + context |= 0x00000000; + break; + case NVDEV_ENGINE_GR: + context |= 0x00100000; + break; + case NVDEV_ENGINE_MPEG: + context |= 0x00200000; + break; + default: + return -EINVAL; + } + + context |= chid << 23; + + mutex_lock(&nv_subdev(priv)->mutex); + ret = nouveau_ramht_insert(priv->ramht, chid, handle, context); + mutex_unlock(&nv_subdev(priv)->mutex); + return ret; +} static int -nv40_fifo_context_new(struct nouveau_channel *chan, int engine) +nv40_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *engctx) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv40_fifo_priv *priv = nv_engine(dev, engine); - struct nv40_fifo_chan *fctx; + struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; unsigned long flags; - int ret; + u32 reg, ctx; + + switch (nv_engidx(engctx->engine)) { + case NVDEV_ENGINE_SW: + return 0; + case NVDEV_ENGINE_GR: + reg = 0x32e0; + ctx = 0x38; + break; + case NVDEV_ENGINE_MPEG: + reg = 0x330c; + ctx = 0x54; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&priv->base.lock, flags); + nv_mask(priv, 0x002500, 0x00000001, 0x00000000); - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; + if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid) + nv_wr32(priv, reg, nv_gpuobj(engctx)->addr >> 4); + nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_gpuobj(engctx)->addr >> 4); + + nv_mask(priv, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&priv->base.lock, flags); + return 0; +} - fctx->ramfc = chan->id * 128; +static int +nv40_fifo_context_detach(struct nouveau_object *parent, bool suspend, + struct nouveau_object *engctx) +{ + struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; + unsigned long flags; + u32 reg, ctx; - /* map channel control registers */ - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV03_USER(chan->id), PAGE_SIZE); - if (!chan->user) { - ret = -ENOMEM; - goto error; + switch (nv_engidx(engctx->engine)) { + case NVDEV_ENGINE_SW: + return 0; + case NVDEV_ENGINE_GR: + reg = 0x32e0; + ctx = 0x38; + break; + case NVDEV_ENGINE_MPEG: + reg = 0x330c; + ctx = 0x54; + break; + default: + return -EINVAL; } - /* initialise default fifo context */ - nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base); - nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4); - nv_wo32(priv->ramfc, fctx->ramfc + 0x18, 0x30000000 | + spin_lock_irqsave(&priv->base.lock, flags); + nv_mask(priv, 0x002500, 0x00000001, 0x00000000); + + if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid) + nv_wr32(priv, reg, 0x00000000); + nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000); + + nv_mask(priv, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&priv->base.lock, flags); + return 0; +} + +static int +nv40_fifo_chan_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo_chan *chan; + struct nv_channel_dma_class *args = data; + int ret; + + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x1000, args->pushbuf, + (1 << NVDEV_ENGINE_DMAOBJ) | + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR) | + (1 << NVDEV_ENGINE_MPEG), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + nv_parent(chan)->context_attach = nv40_fifo_context_attach; + nv_parent(chan)->context_detach = nv40_fifo_context_detach; + nv_parent(chan)->object_attach = nv40_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + chan->ramfc = chan->base.chid * 128; + + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nv_wo32(priv->ramfc, fctx->ramfc + 0x3c, 0x0001ffff); + nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff); + return 0; +} + +static struct nouveau_ofuncs +nv40_fifo_ofuncs = { + .ctor = nv40_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; + +static struct nouveau_oclass +nv40_fifo_sclass[] = { + { 0x006e, &nv40_fifo_ofuncs }, + {} +}; - /* enable dma mode on the channel */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id)); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ - /*XXX: remove this later, need fifo engine context commit hook */ - nouveau_gpuobj_ref(priv->ramfc, &chan->ramfc); +static struct nouveau_oclass +nv40_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fifo_context_ctor, + .dtor = _nouveau_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; -error: +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ + +static int +nv40_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_fifo_priv *priv; + int ret; + + ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv); + *pobject = nv_object(priv); if (ret) - priv->base.base.context_del(chan, engine); - return ret; + return ret; + + nouveau_ramht_ref(imem->ramht, &priv->ramht); + nouveau_gpuobj_ref(imem->ramro, &priv->ramro); + nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc); + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nv04_fifo_intr; + nv_engine(priv)->cclass = &nv40_fifo_cclass; + nv_engine(priv)->sclass = nv40_fifo_sclass; + priv->base.pause = nv04_fifo_pause; + priv->base.start = nv04_fifo_start; + priv->ramfc_desc = nv40_ramfc; + return 0; } static int -nv40_fifo_init(struct drm_device *dev, int engine) +nv40_fifo_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv40_fifo_priv *priv = nv_engine(dev, engine); - int i; + struct nv04_fifo_priv *priv = (void *)object; + struct nouveau_fb *pfb = nouveau_fb(object); + int ret; - nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0); - nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO); + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; - nv_wr32(dev, 0x002040, 0x000000ff); - nv_wr32(dev, 0x002044, 0x2101ffff); - nv_wr32(dev, 0x002058, 0x00000001); + nv_wr32(priv, 0x002040, 0x000000ff); + nv_wr32(priv, 0x002044, 0x2101ffff); + nv_wr32(priv, 0x002058, 0x00000001); - nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((dev_priv->ramht->bits - 9) << 16) | - (dev_priv->ramht->gpuobj->addr >> 8)); - nv_wr32(dev, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); + nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((priv->ramht->bits - 9) << 16) | + (priv->ramht->base.addr >> 8)); + nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - switch (dev_priv->chipset) { + switch (nv_device(priv)->chipset) { case 0x47: case 0x49: case 0x4b: - nv_wr32(dev, 0x002230, 0x00000001); + nv_wr32(priv, 0x002230, 0x00000001); case 0x40: case 0x41: case 0x42: case 0x43: case 0x45: case 0x48: - nv_wr32(dev, 0x002220, 0x00030002); + nv_wr32(priv, 0x002220, 0x00030002); break; default: - nv_wr32(dev, 0x002230, 0x00000000); - nv_wr32(dev, 0x002220, ((nvfb_vram_size(dev) - 512 * 1024 + + nv_wr32(priv, 0x002230, 0x00000000); + nv_wr32(priv, 0x002220, ((pfb->ram.size - 512 * 1024 + priv->ramfc->addr) >> 16) | - 0x00030000); + 0x00030000); break; } - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); - nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff); - - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(dev, NV03_PFIFO_CACHES, 1); - - for (i = 0; i < priv->base.channels; i++) { - if (dev_priv->channels.ptr[i]) - nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i)); - } + nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); + nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(priv, NV03_PFIFO_CACHES, 1); return 0; } -int -nv40_fifo_create(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv40_fifo_priv *priv; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro); - nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc); - - priv->base.base.destroy = nv04_fifo_destroy; - priv->base.base.init = nv40_fifo_init; - priv->base.base.fini = nv04_fifo_fini; - priv->base.base.context_new = nv40_fifo_context_new; - priv->base.base.context_del = nv04_fifo_context_del; - priv->base.channels = 31; - priv->ramfc_desc = nv40_ramfc; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; - - nouveau_irq_register(dev, 8, nv04_fifo_isr); - return 0; -} +struct nouveau_oclass +nv40_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_fifo_ctor, + .dtor = nv04_fifo_dtor, + .init = nv40_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c index 7b5b159..4914c3b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c @@ -1,126 +1,123 @@ /* - * Copyright (C) 2012 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> +#include <core/client.h> +#include <core/engctx.h> #include <core/ramht.h> +#include <core/class.h> +#include <core/math.h> -struct nv50_fifo_priv { - struct nouveau_fifo_priv base; - struct nouveau_gpuobj *playlist[2]; - int cur_playlist; -}; +#include <subdev/timer.h> +#include <subdev/bar.h> -struct nv50_fifo_chan { - struct nouveau_fifo_chan base; -}; +#include <engine/dmaobj.h> +#include <engine/fifo.h> + +#include "nv50.h" + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ void -nv50_fifo_playlist_update(struct drm_device *dev) +nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) { - struct nv50_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); + struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_gpuobj *cur; int i, p; cur = priv->playlist[priv->cur_playlist]; priv->cur_playlist = !priv->cur_playlist; - for (i = 0, p = 0; i < priv->base.channels; i++) { - if (nv_rd32(dev, 0x002600 + (i * 4)) & 0x80000000) + for (i = priv->base.min, p = 0; i < priv->base.max; i++) { + if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000) nv_wo32(cur, p++ * 4, i); } - nvimem_flush(dev); + bar->flush(bar); - nv_wr32(dev, 0x0032f4, cur->addr >> 12); - nv_wr32(dev, 0x0032ec, p); - nv_wr32(dev, 0x002500, 0x00000101); + nv_wr32(priv, 0x0032f4, cur->addr >> 12); + nv_wr32(priv, 0x0032ec, p); + nv_wr32(priv, 0x002500, 0x00000101); } static int -nv50_fifo_context_new(struct nouveau_channel *chan, int engine) +nv50_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *object) { - struct nv50_fifo_priv *priv = nv_engine(chan->dev, engine); - struct nv50_fifo_chan *fctx; - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4; - u64 instance = chan->ramin->addr >> 12; - unsigned long flags; - int ret = 0, i; - - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; - nvvm_engref(chan->vm, engine, 1); - - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV50_USER(chan->id), PAGE_SIZE); - if (!chan->user) { - ret = -ENOMEM; - goto error; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nv50_fifo_base *base = (void *)parent->parent; + struct nouveau_gpuobj *ectx = (void *)object; + u64 limit = ectx->addr + ectx->size - 1; + u64 start = ectx->addr; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0000; break; + case NVDEV_ENGINE_MPEG : addr = 0x0060; break; + default: + return -EINVAL; } - for (i = 0; i < 0x100; i += 4) - nv_wo32(chan->ramin, i, 0x00000000); - nv_wo32(chan->ramin, 0x3c, 0x403f6078); - nv_wo32(chan->ramin, 0x40, 0x00000000); - nv_wo32(chan->ramin, 0x44, 0x01003fff); - nv_wo32(chan->ramin, 0x48, chan->pushbuf->node->offset >> 4); - nv_wo32(chan->ramin, 0x50, lower_32_bits(ib_offset)); - nv_wo32(chan->ramin, 0x54, upper_32_bits(ib_offset) | - drm_order(chan->dma.ib_max + 1) << 16); - nv_wo32(chan->ramin, 0x60, 0x7fffffff); - nv_wo32(chan->ramin, 0x78, 0x00000000); - nv_wo32(chan->ramin, 0x7c, 0x30000001); - nv_wo32(chan->ramin, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - - nvimem_flush(dev); - - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance); - nv50_fifo_playlist_update(dev); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - -error: - if (ret) - priv->base.base.context_del(chan, engine); - return ret; + nv_wo32(base->eng, addr + 0x00, 0x00190000); + nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); + nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); + nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nv_wo32(base->eng, addr + 0x10, 0x00000000); + nv_wo32(base->eng, addr + 0x14, 0x00000000); + bar->flush(bar); + return 0; } -static bool -nv50_fifo_kickoff(struct nouveau_channel *chan) +static int +nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend, + struct nouveau_object *object) { - struct drm_device *dev = chan->dev; - bool done = true; - u32 me; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nv50_fifo_priv *priv = (void *)parent->engine; + struct nv50_fifo_base *base = (void *)parent->parent; + struct nv50_fifo_chan *chan = (void *)parent; + u32 addr, me; + int ret = 0; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0000; break; + case NVDEV_ENGINE_MPEG : addr = 0x0060; break; + default: + return -EINVAL; + } + + nv_wo32(base->eng, addr + 0x00, 0x00000000); + nv_wo32(base->eng, addr + 0x04, 0x00000000); + nv_wo32(base->eng, addr + 0x08, 0x00000000); + nv_wo32(base->eng, addr + 0x0c, 0x00000000); + nv_wo32(base->eng, addr + 0x10, 0x00000000); + nv_wo32(base->eng, addr + 0x14, 0x00000000); + bar->flush(bar); /* HW bug workaround: * @@ -134,159 +131,308 @@ nv50_fifo_kickoff(struct nouveau_channel *chan) * there's also a "ignore these engines" bitmask reg we can use * if we hit the issue there.. */ - - /* PME: make sure engine is enabled */ - me = nv_mask(dev, 0x00b860, 0x00000001, 0x00000001); + me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001); /* do the kickoff... */ - nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12); - if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) { - NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id); - done = false; + nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); + if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { + nv_error(priv, "channel %d unload timeout\n", chan->base.chid); + if (suspend) + ret = -EBUSY; } - /* restore any engine states we changed, and exit */ - nv_wr32(dev, 0x00b860, me); - return done; + nv_wr32(priv, 0x00b860, me); + return ret; } -static void -nv50_fifo_context_del(struct nouveau_channel *chan, int engine) +static int +nv50_fifo_object_attach(struct nouveau_object *parent, + struct nouveau_object *object, u32 handle) { - struct nv50_fifo_chan *fctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - unsigned long flags; - - /* remove channel from playlist, will context switch if active */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000); - nv50_fifo_playlist_update(dev); - - /* tell any engines on this channel to unload their contexts */ - nv50_fifo_kickoff(chan); - - nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - - /* clean up */ - if (chan->user) { - iounmap(chan->user); - chan->user = NULL; + struct nv50_fifo_chan *chan = (void *)parent; + u32 context; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->node->offset >> 4; + else + context = 0x00000004; /* just non-zero */ + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00100000; break; + case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; + default: + return -EINVAL; } - nvvm_engref(chan->vm, engine, -1); - chan->engctx[engine] = NULL; - kfree(fctx); + return nouveau_ramht_insert(chan->ramht, 0, handle, context); +} + +void +nv50_fifo_object_detach(struct nouveau_object *parent, int cookie) +{ + struct nv50_fifo_chan *chan = (void *)parent; + nouveau_ramht_remove(chan->ramht, cookie); } static int -nv50_fifo_init(struct drm_device *dev, int engine) +nv50_fifo_chan_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 instance; - int i; - - nv_mask(dev, 0x000200, 0x00000100, 0x00000000); - nv_mask(dev, 0x000200, 0x00000100, 0x00000100); - nv_wr32(dev, 0x00250c, 0x6f3cfc34); - nv_wr32(dev, 0x002044, 0x01003fff); - - nv_wr32(dev, 0x002100, 0xffffffff); - nv_wr32(dev, 0x002140, 0xffffffff); - - for (i = 0; i < 128; i++) { - struct nouveau_channel *chan = dev_priv->channels.ptr[i]; - if (chan && chan->engctx[engine]) - instance = 0x80000000 | chan->ramin->addr >> 12; - else - instance = 0x00000000; - nv_wr32(dev, 0x002600 + (i * 4), instance); - } + struct nv_channel_ind_class *args = data; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo_chan *chan; + u64 ioffset, ilength; + int ret; + + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x2000, args->pushbuf, + (1 << NVDEV_ENGINE_DMAOBJ) | + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR) | + (1 << NVDEV_ENGINE_MPEG), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; - nv50_fifo_playlist_update(dev); + nv_parent(chan)->context_attach = nv50_fifo_context_attach; + nv_parent(chan)->context_detach = nv50_fifo_context_detach; + nv_parent(chan)->object_attach = nv50_fifo_object_attach; + nv_parent(chan)->object_detach = nv50_fifo_object_detach; - nv_wr32(dev, 0x003200, 1); - nv_wr32(dev, 0x003250, 1); - nv_wr32(dev, 0x002500, 1); + ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht); + if (ret) + return ret; + + ioffset = args->ioffset; + ilength = log2i(args->ilength / 8); + + nv_wo32(base->ramfc, 0x3c, 0x403f6078); + nv_wo32(base->ramfc, 0x44, 0x01003fff); + nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); + nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nv_wo32(base->ramfc, 0x60, 0x7fffffff); + nv_wo32(base->ramfc, 0x78, 0x00000000); + nv_wo32(base->ramfc, 0x7c, 0x30000001); + nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->base.node->offset >> 4)); + bar->flush(bar); return 0; } +void +nv50_fifo_chan_dtor(struct nouveau_object *object) +{ + struct nv50_fifo_chan *chan = (void *)object; + nouveau_ramht_ref(NULL, &chan->ramht); + nouveau_fifo_channel_destroy(&chan->base); +} + static int -nv50_fifo_fini(struct drm_device *dev, int engine, bool suspend) +nv50_fifo_chan_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_fifo_priv *priv = nv_engine(dev, engine); - int i; - - /* set playlist length to zero, fifo will unload context */ - nv_wr32(dev, 0x0032ec, 0); - - /* tell all connected engines to unload their contexts */ - for (i = 0; i < priv->base.channels; i++) { - struct nouveau_channel *chan = dev_priv->channels.ptr[i]; - if (chan && !nv50_fifo_kickoff(chan)) - return -EBUSY; - } + struct nv50_fifo_priv *priv = (void *)object->engine; + struct nv50_fifo_base *base = (void *)object->parent; + struct nv50_fifo_chan *chan = (void *)object; + struct nouveau_gpuobj *ramfc = base->ramfc; + u32 chid = chan->base.chid; + int ret; - nv_wr32(dev, 0x002140, 0); + ret = nouveau_fifo_channel_init(&chan->base); + if (ret) + return ret; + + nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); + nv50_fifo_playlist_update(priv); return 0; } -void -nv50_fifo_tlb_flush(struct drm_device *dev, int engine) +int +nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend) { - nv50_vm_flush_engine(dev, 5); + struct nv50_fifo_priv *priv = (void *)object->engine; + struct nv50_fifo_chan *chan = (void *)object; + u32 chid = chan->base.chid; + + /* remove channel from playlist, fifo will unload context */ + nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000); + nv50_fifo_playlist_update(priv); + nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000); + + return nouveau_fifo_channel_fini(&chan->base, suspend); } -void -nv50_fifo_destroy(struct drm_device *dev, int engine) +static struct nouveau_ofuncs +nv50_fifo_ofuncs = { + .ctor = nv50_fifo_chan_ctor, + .dtor = nv50_fifo_chan_dtor, + .init = nv50_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; + +static struct nouveau_oclass +nv50_fifo_sclass[] = { + { 0x506f, &nv50_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ + +static int +nv50_fifo_context_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 nv50_fifo_priv *priv = nv_engine(dev, engine); + struct nv50_fifo_base *base; + int ret; - nouveau_irq_unregister(dev, 8); + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; - nouveau_gpuobj_ref(NULL, &priv->playlist[0]); - nouveau_gpuobj_ref(NULL, &priv->playlist[1]); + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1200, 0, + NVOBJ_FLAG_ZERO_ALLOC, &base->eng); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0, 0, + &base->pgd); + if (ret) + return ret; + + ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; - dev_priv->eng[engine] = NULL; - kfree(priv); + return 0; } -int -nv50_fifo_create(struct drm_device *dev) +void +nv50_fifo_context_dtor(struct nouveau_object *object) +{ + struct nv50_fifo_base *base = (void *)object; + nouveau_vm_ref(NULL, &base->vm, base->pgd); + nouveau_gpuobj_ref(NULL, &base->pgd); + nouveau_gpuobj_ref(NULL, &base->eng); + nouveau_gpuobj_ref(NULL, &base->ramfc); + nouveau_gpuobj_ref(NULL, &base->cache); + nouveau_fifo_context_destroy(&base->base); +} + +static struct nouveau_oclass +nv50_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fifo_context_ctor, + .dtor = nv50_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; + +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ + +static int +nv50_fifo_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 nv50_fifo_priv *priv; int ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->base.base.destroy = nv50_fifo_destroy; - priv->base.base.init = nv50_fifo_init; - priv->base.base.fini = nv50_fifo_fini; - priv->base.base.context_new = nv50_fifo_context_new; - priv->base.base.context_del = nv50_fifo_context_del; - priv->base.base.tlb_flush = nv50_fifo_tlb_flush; - priv->base.channels = 127; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; - - ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]); + ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); + *pobject = nv_object(priv); if (ret) - goto error; + return ret; - ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]); + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[0]); if (ret) - goto error; + return ret; - nouveau_irq_register(dev, 8, nv04_fifo_isr); -error: + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[1]); if (ret) - priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO); - return ret; + return ret; + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nv04_fifo_intr; + nv_engine(priv)->cclass = &nv50_fifo_cclass; + nv_engine(priv)->sclass = nv50_fifo_sclass; + return 0; +} + +void +nv50_fifo_dtor(struct nouveau_object *object) +{ + struct nv50_fifo_priv *priv = (void *)object; + + nouveau_gpuobj_ref(NULL, &priv->playlist[1]); + nouveau_gpuobj_ref(NULL, &priv->playlist[0]); + + nouveau_fifo_destroy(&priv->base); } + +int +nv50_fifo_init(struct nouveau_object *object) +{ + struct nv50_fifo_priv *priv = (void *)object; + int ret, i; + + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; + + nv_mask(priv, 0x000200, 0x00000100, 0x00000000); + nv_mask(priv, 0x000200, 0x00000100, 0x00000100); + nv_wr32(priv, 0x00250c, 0x6f3cfc34); + nv_wr32(priv, 0x002044, 0x01003fff); + + nv_wr32(priv, 0x002100, 0xffffffff); + nv_wr32(priv, 0x002140, 0xffffffff); + + for (i = 0; i < 128; i++) + nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); + nv50_fifo_playlist_update(priv); + + nv_wr32(priv, 0x003200, 0x00000001); + nv_wr32(priv, 0x003250, 0x00000001); + nv_wr32(priv, 0x002500, 0x00000001); + return 0; +} + +struct nouveau_oclass +nv50_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fifo_ctor, + .dtor = nv50_fifo_dtor, + .init = nv50_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h new file mode 100644 index 0000000..3a9ceb3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h @@ -0,0 +1,36 @@ +#ifndef __NV50_FIFO_H__ +#define __NV50_FIFO_H__ + +struct nv50_fifo_priv { + struct nouveau_fifo base; + struct nouveau_gpuobj *playlist[2]; + int cur_playlist; +}; + +struct nv50_fifo_base { + struct nouveau_fifo_base base; + struct nouveau_gpuobj *ramfc; + struct nouveau_gpuobj *cache; + struct nouveau_gpuobj *eng; + struct nouveau_gpuobj *pgd; + struct nouveau_vm *vm; +}; + +struct nv50_fifo_chan { + struct nouveau_fifo_chan base; + u32 subc[8]; + struct nouveau_ramht *ramht; +}; + +void nv50_fifo_playlist_update(struct nv50_fifo_priv *); + +void nv50_fifo_object_detach(struct nouveau_object *, int); +void nv50_fifo_chan_dtor(struct nouveau_object *); +int nv50_fifo_chan_fini(struct nouveau_object *, bool); + +void nv50_fifo_context_dtor(struct nouveau_object *); + +void nv50_fifo_dtor(struct nouveau_object *); +int nv50_fifo_init(struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c index 63a4941..765affb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c @@ -1,249 +1,343 @@ /* - * Copyright (C) 2012 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> +#include <core/os.h> +#include <core/client.h> +#include <core/engctx.h> #include <core/ramht.h> +#include <core/class.h> +#include <core/math.h> -struct nv84_fifo_priv { - struct nouveau_fifo_priv base; - struct nouveau_gpuobj *playlist[2]; - int cur_playlist; -}; +#include <subdev/timer.h> +#include <subdev/bar.h> -struct nv84_fifo_chan { - struct nouveau_fifo_chan base; - struct nouveau_gpuobj *ramfc; - struct nouveau_gpuobj *cache; -}; +#include <engine/dmaobj.h> +#include <engine/fifo.h> + +#include "nv50.h" + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ static int -nv84_fifo_context_new(struct nouveau_channel *chan, int engine) +nv84_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *object) { - struct nv84_fifo_priv *priv = nv_engine(chan->dev, engine); - struct nv84_fifo_chan *fctx; - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4; - u64 instance; - unsigned long flags; - int ret; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nv50_fifo_base *base = (void *)parent->parent; + struct nouveau_gpuobj *ectx = (void *)object; + u64 limit = ectx->addr + ectx->size - 1; + u64 start = ectx->addr; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0020; break; + case NVDEV_ENGINE_MPEG : addr = 0x0060; break; + case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break; + case NVDEV_ENGINE_COPY0: addr = 0x00c0; break; + default: + return -EINVAL; + } - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; - nvvm_engref(chan->vm, engine, 1); + nv_wo32(base->eng, addr + 0x00, 0x00190000); + nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); + nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); + nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nv_wo32(base->eng, addr + 0x10, 0x00000000); + nv_wo32(base->eng, addr + 0x14, 0x00000000); + bar->flush(bar); + return 0; +} - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV50_USER(chan->id), PAGE_SIZE); - if (!chan->user) { - ret = -ENOMEM; - goto error; +static int +nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend, + struct nouveau_object *object) +{ + struct nouveau_bar *bar = nouveau_bar(parent); + struct nv50_fifo_priv *priv = (void *)parent->engine; + struct nv50_fifo_base *base = (void *)parent->parent; + struct nv50_fifo_chan *chan = (void *)parent; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0020; break; + case NVDEV_ENGINE_MPEG : addr = 0x0060; break; + case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break; + case NVDEV_ENGINE_COPY0: addr = 0x00c0; break; + default: + return -EINVAL; } - ret = nouveau_gpuobj_new(dev, chan, 256, 256, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc); - if (ret) - goto error; - - instance = fctx->ramfc->addr >> 8; + nv_wo32(base->eng, addr + 0x00, 0x00000000); + nv_wo32(base->eng, addr + 0x04, 0x00000000); + nv_wo32(base->eng, addr + 0x08, 0x00000000); + nv_wo32(base->eng, addr + 0x0c, 0x00000000); + nv_wo32(base->eng, addr + 0x10, 0x00000000); + nv_wo32(base->eng, addr + 0x14, 0x00000000); + bar->flush(bar); + + nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); + if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { + nv_error(priv, "channel %d unload timeout\n", chan->base.chid); + if (suspend) + return -EBUSY; + } + return 0; +} - ret = nouveau_gpuobj_new(dev, chan, 4096, 1024, 0, &fctx->cache); - if (ret) - goto error; - - nv_wo32(fctx->ramfc, 0x3c, 0x403f6078); - nv_wo32(fctx->ramfc, 0x40, 0x00000000); - nv_wo32(fctx->ramfc, 0x44, 0x01003fff); - nv_wo32(fctx->ramfc, 0x48, chan->pushbuf->node->offset >> 4); - nv_wo32(fctx->ramfc, 0x50, lower_32_bits(ib_offset)); - nv_wo32(fctx->ramfc, 0x54, upper_32_bits(ib_offset) | - drm_order(chan->dma.ib_max + 1) << 16); - nv_wo32(fctx->ramfc, 0x60, 0x7fffffff); - nv_wo32(fctx->ramfc, 0x78, 0x00000000); - nv_wo32(fctx->ramfc, 0x7c, 0x30000001); - nv_wo32(fctx->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nv_wo32(fctx->ramfc, 0x88, fctx->cache->addr >> 10); - nv_wo32(fctx->ramfc, 0x98, chan->ramin->addr >> 12); +static int +nv84_fifo_object_attach(struct nouveau_object *parent, + struct nouveau_object *object, u32 handle) +{ + struct nv50_fifo_chan *chan = (void *)parent; + u32 context; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->node->offset >> 4; + else + context = 0x00000004; /* just non-zero */ + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00100000; break; + case NVDEV_ENGINE_MPEG : + case NVDEV_ENGINE_PPP : context |= 0x00200000; break; + case NVDEV_ENGINE_ME : + case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break; + case NVDEV_ENGINE_VP : context |= 0x00400000; break; + case NVDEV_ENGINE_CRYPT : + case NVDEV_ENGINE_UNK1C1: context |= 0x00500000; break; + case NVDEV_ENGINE_BSP : context |= 0x00600000; break; + default: + return -EINVAL; + } - nv_wo32(chan->ramin, 0x00, chan->id); - nv_wo32(chan->ramin, 0x04, fctx->ramfc->addr >> 8); + return nouveau_ramht_insert(chan->ramht, 0, handle, context); +} - nvimem_flush(dev); +static int +nv84_fifo_chan_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_bar *bar = nouveau_bar(parent); + struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo_chan *chan; + struct nv_channel_ind_class *args = data; + u64 ioffset, ilength; + int ret; - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance); - nv50_fifo_playlist_update(dev); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x2000, args->pushbuf, + (1 << NVDEV_ENGINE_DMAOBJ) | + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR) | + (1 << NVDEV_ENGINE_MPEG) | + (1 << NVDEV_ENGINE_ME) | + (1 << NVDEV_ENGINE_VP) | + (1 << NVDEV_ENGINE_CRYPT) | + (1 << NVDEV_ENGINE_BSP) | + (1 << NVDEV_ENGINE_PPP) | + (1 << NVDEV_ENGINE_COPY0) | + (1 << NVDEV_ENGINE_UNK1C1), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; -error: + ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht); if (ret) - priv->base.base.context_del(chan, engine); - return ret; + return ret; + + nv_parent(chan)->context_attach = nv84_fifo_context_attach; + nv_parent(chan)->context_detach = nv84_fifo_context_detach; + nv_parent(chan)->object_attach = nv84_fifo_object_attach; + nv_parent(chan)->object_detach = nv50_fifo_object_detach; + + ioffset = args->ioffset; + ilength = log2i(args->ilength / 8); + + nv_wo32(base->ramfc, 0x3c, 0x403f6078); + nv_wo32(base->ramfc, 0x44, 0x01003fff); + nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); + nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nv_wo32(base->ramfc, 0x60, 0x7fffffff); + nv_wo32(base->ramfc, 0x78, 0x00000000); + nv_wo32(base->ramfc, 0x7c, 0x30000001); + nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->base.node->offset >> 4)); + nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); + nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); + bar->flush(bar); + return 0; } -static void -nv84_fifo_context_del(struct nouveau_channel *chan, int engine) +static int +nv84_fifo_chan_init(struct nouveau_object *object) { - struct nv84_fifo_chan *fctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - unsigned long flags; - u32 save; + struct nv50_fifo_priv *priv = (void *)object->engine; + struct nv50_fifo_base *base = (void *)object->parent; + struct nv50_fifo_chan *chan = (void *)object; + struct nouveau_gpuobj *ramfc = base->ramfc; + u32 chid = chan->base.chid; + int ret; + + ret = nouveau_fifo_channel_init(&chan->base); + if (ret) + return ret; - /* remove channel from playlist, will context switch if active */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000); - nv50_fifo_playlist_update(dev); + nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); + nv50_fifo_playlist_update(priv); + return 0; +} - save = nv_mask(dev, 0x002520, 0x0000003f, 0x15); +static struct nouveau_ofuncs +nv84_fifo_ofuncs = { + .ctor = nv84_fifo_chan_ctor, + .dtor = nv50_fifo_chan_dtor, + .init = nv84_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; - /* tell any engines on this channel to unload their contexts */ - nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12); - if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) - NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id); +static struct nouveau_oclass +nv84_fifo_sclass[] = { + { 0x826f, &nv84_fifo_ofuncs }, + {} +}; - nv_wr32(dev, 0x002520, save); +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ - nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +int +nv84_fifo_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_fifo_base *base; + int ret; - /* clean up */ - if (chan->user) { - iounmap(chan->user); - chan->user = NULL; - } + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; - nouveau_gpuobj_ref(NULL, &fctx->ramfc); - nouveau_gpuobj_ref(NULL, &fctx->cache); + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0, + NVOBJ_FLAG_ZERO_ALLOC, &base->eng); + if (ret) + return ret; - nvvm_engref(chan->vm, engine, -1); - chan->engctx[engine] = NULL; - kfree(fctx); -} + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0, + 0, &base->pgd); + if (ret) + return ret; -static int -nv84_fifo_init(struct drm_device *dev, int engine) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv84_fifo_chan *fctx; - u32 instance; - int i; - - nv_mask(dev, 0x000200, 0x00000100, 0x00000000); - nv_mask(dev, 0x000200, 0x00000100, 0x00000100); - nv_wr32(dev, 0x00250c, 0x6f3cfc34); - nv_wr32(dev, 0x002044, 0x01003fff); - - nv_wr32(dev, 0x002100, 0xffffffff); - nv_wr32(dev, 0x002140, 0xffffffff); - - for (i = 0; i < 128; i++) { - struct nouveau_channel *chan = dev_priv->channels.ptr[i]; - if (chan && (fctx = chan->engctx[engine])) - instance = 0x80000000 | fctx->ramfc->addr >> 8; - else - instance = 0x00000000; - nv_wr32(dev, 0x002600 + (i * 4), instance); - } + ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; - nv50_fifo_playlist_update(dev); + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1000, 0x400, + NVOBJ_FLAG_ZERO_ALLOC, &base->cache); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0100, 0x100, + NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); + if (ret) + return ret; - nv_wr32(dev, 0x003200, 1); - nv_wr32(dev, 0x003250, 1); - nv_wr32(dev, 0x002500, 1); return 0; } -static int -nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv84_fifo_priv *priv = nv_engine(dev, engine); - int i; - u32 save; - - /* set playlist length to zero, fifo will unload context */ - nv_wr32(dev, 0x0032ec, 0); - - save = nv_mask(dev, 0x002520, 0x0000003f, 0x15); - - /* tell all connected engines to unload their contexts */ - for (i = 0; i < priv->base.channels; i++) { - struct nouveau_channel *chan = dev_priv->channels.ptr[i]; - if (chan) - nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12); - if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) { - NV_INFO(dev, "PFIFO: channel %d unload timeout\n", i); - return -EBUSY; - } - } +static struct nouveau_oclass +nv84_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_fifo_context_ctor, + .dtor = nv50_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; - nv_wr32(dev, 0x002520, save); - nv_wr32(dev, 0x002140, 0); - return 0; -} +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ -int -nv84_fifo_create(struct drm_device *dev) +static int +nv84_fifo_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 nv84_fifo_priv *priv; + struct nv50_fifo_priv *priv; int ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->base.base.destroy = nv50_fifo_destroy; - priv->base.base.init = nv84_fifo_init; - priv->base.base.fini = nv84_fifo_fini; - priv->base.base.context_new = nv84_fifo_context_new; - priv->base.base.context_del = nv84_fifo_context_del; - priv->base.base.tlb_flush = nv50_fifo_tlb_flush; - priv->base.channels = 127; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; - - ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]); + ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); + *pobject = nv_object(priv); if (ret) - goto error; + return ret; - ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]); + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[0]); if (ret) - goto error; + return ret; - nouveau_irq_register(dev, 8, nv04_fifo_isr); -error: + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[1]); if (ret) - priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO); - return ret; + return ret; + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nv04_fifo_intr; + nv_engine(priv)->cclass = &nv84_fifo_cclass; + nv_engine(priv)->sclass = nv84_fifo_sclass; + return 0; } + +struct nouveau_oclass +nv84_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_fifo_ctor, + .dtor = nv50_fifo_dtor, + .init = nv50_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index b99d976..ef403fe 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -1,5 +1,5 @@ /* - * Copyright 2010 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,17 +22,24 @@ * Authors: Ben Skeggs */ -#include "drmP.h" +#include <core/client.h> +#include <core/handle.h> +#include <core/namedb.h> +#include <core/gpuobj.h> +#include <core/engctx.h> +#include <core/class.h> +#include <core/math.h> +#include <core/enum.h> -#include "nouveau_drv.h" -#include <core/mm.h> -#include <engine/fifo.h> -#include "nouveau_software.h" +#include <subdev/timer.h> +#include <subdev/bar.h> +#include <subdev/vm.h> -static void nvc0_fifo_isr(struct drm_device *); +#include <engine/dmaobj.h> +#include <engine/fifo.h> struct nvc0_fifo_priv { - struct nouveau_fifo_priv base; + struct nouveau_fifo base; struct nouveau_gpuobj *playlist[2]; int cur_playlist; struct { @@ -42,14 +49,24 @@ struct nvc0_fifo_priv { int spoon_nr; }; +struct nvc0_fifo_base { + struct nouveau_fifo_base base; + struct nouveau_gpuobj *pgd; + struct nouveau_vm *vm; +}; + struct nvc0_fifo_chan { struct nouveau_fifo_chan base; }; +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + static void -nvc0_fifo_playlist_update(struct drm_device *dev) +nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) { - struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); + struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_gpuobj *cur; int i, p; @@ -57,174 +74,253 @@ nvc0_fifo_playlist_update(struct drm_device *dev) priv->cur_playlist = !priv->cur_playlist; for (i = 0, p = 0; i < 128; i++) { - if (!(nv_rd32(dev, 0x3004 + (i * 8)) & 1)) + if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1)) continue; nv_wo32(cur, p + 0, i); nv_wo32(cur, p + 4, 0x00000004); p += 8; } - nvimem_flush(dev); + bar->flush(bar); - nv_wr32(dev, 0x002270, cur->addr >> 12); - nv_wr32(dev, 0x002274, 0x01f00000 | (p >> 3)); - if (!nv_wait(dev, 0x00227c, 0x00100000, 0x00000000)) - NV_ERROR(dev, "PFIFO - playlist update failed\n"); + nv_wr32(priv, 0x002270, cur->addr >> 12); + nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); + if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000)) + nv_error(priv, "playlist update failed\n"); } static int -nvc0_fifo_context_new(struct nouveau_channel *chan, int engine) +nvc0_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *object) { - struct drm_device *dev = chan->dev; - struct nvc0_fifo_priv *priv = nv_engine(dev, engine); - struct nvc0_fifo_chan *fctx; - u64 usermem = priv->user.mem->addr + chan->id * 0x1000; - u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4; - int ret, i; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nvc0_fifo_base *base = (void *)parent->parent; + struct nouveau_engctx *ectx = (void *)object; + u32 addr; + int ret; - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + case NVDEV_ENGINE_COPY0: addr = 0x0230; break; + case NVDEV_ENGINE_COPY1: addr = 0x0240; break; + default: + return -EINVAL; + } - chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) + - priv->user.bar.offset + (chan->id * 0x1000), - PAGE_SIZE); - if (!chan->user) { - ret = -ENOMEM; - goto error; + if (!ectx->vma.node) { + ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm, + NV_MEM_ACCESS_RW, &ectx->vma); + if (ret) + return ret; } - for (i = 0; i < 0x100; i += 4) - nv_wo32(chan->ramin, i, 0x00000000); - nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem)); - nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem)); - nv_wo32(chan->ramin, 0x10, 0x0000face); - nv_wo32(chan->ramin, 0x30, 0xfffff902); - nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt)); - nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 | - upper_32_bits(ib_virt)); - nv_wo32(chan->ramin, 0x54, 0x00000002); - nv_wo32(chan->ramin, 0x84, 0x20400000); - nv_wo32(chan->ramin, 0x94, 0x30000001); - nv_wo32(chan->ramin, 0x9c, 0x00000100); - nv_wo32(chan->ramin, 0xa4, 0x1f1f1f1f); - nv_wo32(chan->ramin, 0xa8, 0x1f1f1f1f); - nv_wo32(chan->ramin, 0xac, 0x0000001f); - nv_wo32(chan->ramin, 0xb8, 0xf8000000); - nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */ - nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */ - nvimem_flush(dev); - - nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 | - (chan->ramin->addr >> 12)); - nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001); - nvc0_fifo_playlist_update(dev); - -error: - if (ret) - priv->base.base.context_del(chan, engine); - return ret; + nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); + nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset)); + bar->flush(bar); + return 0; } -static void -nvc0_fifo_context_del(struct nouveau_channel *chan, int engine) +static int +nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend, + struct nouveau_object *object) { - struct nvc0_fifo_chan *fctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - - nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000); - nv_wr32(dev, 0x002634, chan->id); - if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id)) - NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634)); - nvc0_fifo_playlist_update(dev); - nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000); - - if (chan->user) { - iounmap(chan->user); - chan->user = NULL; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nvc0_fifo_priv *priv = (void *)parent->engine; + struct nvc0_fifo_base *base = (void *)parent->parent; + struct nvc0_fifo_chan *chan = (void *)parent; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + case NVDEV_ENGINE_COPY0: addr = 0x0230; break; + case NVDEV_ENGINE_COPY1: addr = 0x0240; break; + default: + return -EINVAL; } - chan->engctx[engine] = NULL; - kfree(fctx); + nv_wo32(base, addr + 0x00, 0x00000000); + nv_wo32(base, addr + 0x04, 0x00000000); + bar->flush(bar); + + nv_wr32(priv, 0x002634, chan->base.chid); + if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { + nv_error(priv, "channel %d kick timeout\n", chan->base.chid); + if (suspend) + return -EBUSY; + } + + return 0; } static int -nvc0_fifo_init(struct drm_device *dev, int engine) +nvc0_fifo_chan_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 nvc0_fifo_priv *priv = nv_engine(dev, engine); - struct nouveau_channel *chan; - int i; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nvc0_fifo_priv *priv = (void *)engine; + struct nvc0_fifo_base *base = (void *)parent; + struct nvc0_fifo_chan *chan; + struct nv_channel_ind_class *args = data; + u64 usermem, ioffset, ilength; + int ret, i; - /* reset PFIFO, enable all available PSUBFIFO areas */ - nv_mask(dev, 0x000200, 0x00000100, 0x00000000); - nv_mask(dev, 0x000200, 0x00000100, 0x00000100); - nv_wr32(dev, 0x000204, 0xffffffff); - nv_wr32(dev, 0x002204, 0xffffffff); + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 1, + priv->user.bar.offset, 0x1000, + args->pushbuf, + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR) | + (1 << NVDEV_ENGINE_COPY0) | + (1 << NVDEV_ENGINE_COPY1), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + nv_parent(chan)->context_attach = nvc0_fifo_context_attach; + nv_parent(chan)->context_detach = nvc0_fifo_context_detach; + + usermem = chan->base.chid * 0x1000; + ioffset = args->ioffset; + ilength = log2i(args->ilength / 8); + + for (i = 0; i < 0x1000; i += 4) + nv_wo32(priv->user.mem, usermem + i, 0x00000000); + + nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem)); + nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem)); + nv_wo32(base, 0x10, 0x0000face); + nv_wo32(base, 0x30, 0xfffff902); + nv_wo32(base, 0x48, lower_32_bits(ioffset)); + nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); + nv_wo32(base, 0x54, 0x00000002); + nv_wo32(base, 0x84, 0x20400000); + nv_wo32(base, 0x94, 0x30000001); + nv_wo32(base, 0x9c, 0x00000100); + nv_wo32(base, 0xa4, 0x1f1f1f1f); + nv_wo32(base, 0xa8, 0x1f1f1f1f); + nv_wo32(base, 0xac, 0x0000001f); + nv_wo32(base, 0xb8, 0xf8000000); + nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */ + nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */ + bar->flush(bar); + return 0; +} - priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204)); - NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr); +static int +nvc0_fifo_chan_init(struct nouveau_object *object) +{ + struct nouveau_gpuobj *base = nv_gpuobj(object->parent); + struct nvc0_fifo_priv *priv = (void *)object->engine; + struct nvc0_fifo_chan *chan = (void *)object; + u32 chid = chan->base.chid; + int ret; - /* assign engines to subfifos */ - if (priv->spoon_nr >= 3) { - nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */ - nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */ - nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */ - nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */ - nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */ - nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */ - } + ret = nouveau_fifo_channel_init(&chan->base); + if (ret) + return ret; - /* PSUBFIFO[n] */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ - } + nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); + nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); + nvc0_fifo_playlist_update(priv); + return 0; +} - nv_mask(dev, 0x002200, 0x00000001, 0x00000001); - nv_wr32(dev, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); +static int +nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend) +{ + struct nvc0_fifo_priv *priv = (void *)object->engine; + struct nvc0_fifo_chan *chan = (void *)object; + u32 chid = chan->base.chid; - nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ - nv_wr32(dev, 0x002100, 0xffffffff); - nv_wr32(dev, 0x002140, 0xbfffffff); + nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + nvc0_fifo_playlist_update(priv); + nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); - /* restore PFIFO context table */ - for (i = 0; i < 128; i++) { - chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->engctx[engine]) - continue; + return nouveau_fifo_channel_fini(&chan->base, suspend); +} - nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 | - (chan->ramin->addr >> 12)); - nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001); - } - nvc0_fifo_playlist_update(dev); +static struct nouveau_ofuncs +nvc0_fifo_ofuncs = { + .ctor = nvc0_fifo_chan_ctor, + .dtor = _nouveau_fifo_channel_dtor, + .init = nvc0_fifo_chan_init, + .fini = nvc0_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; - return 0; -} +static struct nouveau_oclass +nvc0_fifo_sclass[] = { + { 0x906f, &nvc0_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - instmem heap and vm setup + ******************************************************************************/ static int -nvc0_fifo_fini(struct drm_device *dev, int engine, bool suspend) +nvc0_fifo_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - int i; + struct nvc0_fifo_base *base; + int ret; - for (i = 0; i < 128; i++) { - if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1)) - continue; + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; - nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000); - nv_wr32(dev, 0x002634, i); - if (!nv_wait(dev, 0x002634, 0xffffffff, i)) { - NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n", - i, nv_rd32(dev, 0x002634)); - return -EBUSY; - } - } + ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd); + if (ret) + return ret; + + nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr)); + nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr)); + nv_wo32(base, 0x0208, 0xffffffff); + nv_wo32(base, 0x020c, 0x000000ff); + + ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; - nv_wr32(dev, 0x002140, 0x00000000); return 0; } +static void +nvc0_fifo_context_dtor(struct nouveau_object *object) +{ + struct nvc0_fifo_base *base = (void *)object; + nouveau_vm_ref(NULL, &base->vm, base->pgd); + nouveau_gpuobj_ref(NULL, &base->pgd); + nouveau_fifo_context_destroy(&base->base); +} + +static struct nouveau_oclass +nvc0_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_fifo_context_ctor, + .dtor = nvc0_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; + +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ struct nouveau_enum nvc0_fifo_fault_unit[] = { { 0x00, "PGRAPH" }, @@ -289,16 +385,16 @@ struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = { }; static void -nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit) +nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit) { - u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10)); - u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10)); - u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10)); - u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10)); + u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10)); + u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10)); + u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10)); + u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10)); u32 client = (stat & 0x00001f00) >> 8; - NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [", - (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo); + nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ? + "write" : "read", (u64)vahi << 32 | valo); nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); printk("] from "); nouveau_enum_print(nvc0_fifo_fault_unit, unit); @@ -313,165 +409,223 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit) } static int -nvc0_fifo_page_flip(struct drm_device *dev, u32 chid) +nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) { - struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = NULL; + struct nvc0_fifo_chan *chan = NULL; + struct nouveau_handle *bind; unsigned long flags; int ret = -EINVAL; - spin_lock_irqsave(&dev_priv->channels.lock, flags); - if (likely(chid >= 0 && chid < priv->base.channels)) { - chan = dev_priv->channels.ptr[chid]; - if (likely(chan)) { - struct nouveau_software_chan *swch = - chan->engctx[NVOBJ_ENGINE_SW]; - ret = swch->flip(swch->flip_data); - } + spin_lock_irqsave(&priv->base.lock, flags); + if (likely(chid >= priv->base.min && chid <= priv->base.max)) + chan = (void *)priv->base.channel[chid]; + if (unlikely(!chan)) + goto out; + + bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); + if (likely(bind)) { + if (!mthd || !nv_call(bind->object, mthd, data)) + ret = 0; + nouveau_namedb_put(bind); } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + +out: + spin_unlock_irqrestore(&priv->base.lock, flags); return ret; } static void -nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) +nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) { - u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000)); - u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f; - u32 subc = (addr & 0x00070000); + u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); + u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); + u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000)); + u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f; + u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; if (stat & 0x00200000) { if (mthd == 0x0054) { - if (!nvc0_fifo_page_flip(dev, chid)) + if (!nvc0_fifo_swmthd(priv, chid, 0x0500, 0x00000000)) show &= ~0x00200000; } } + if (stat & 0x00800000) { + if (!nvc0_fifo_swmthd(priv, chid, mthd, data)) + show &= ~0x00800000; + } + if (show) { - NV_INFO(dev, "PFIFO%d:", unit); + nv_error(priv, "SUBFIFO%d:", unit); nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); - NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n", - unit, chid, subc, mthd, data); + printk("\n"); + nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x " + "data 0x%08x\n", + unit, chid, subc, mthd, data); } - nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008); - nv_wr32(dev, 0x040108 + (unit * 0x2000), stat); + nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); + nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); } static void -nvc0_fifo_isr(struct drm_device *dev) +nvc0_fifo_intr(struct nouveau_subdev *subdev) { - u32 mask = nv_rd32(dev, 0x002140); - u32 stat = nv_rd32(dev, 0x002100) & mask; + struct nvc0_fifo_priv *priv = (void *)subdev; + u32 mask = nv_rd32(priv, 0x002140); + u32 stat = nv_rd32(priv, 0x002100) & mask; if (stat & 0x00000100) { - NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); - nv_wr32(dev, 0x002100, 0x00000100); + nv_info(priv, "unknown status 0x00000100\n"); + nv_wr32(priv, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x10000000) { - u32 units = nv_rd32(dev, 0x00259c); + u32 units = nv_rd32(priv, 0x00259c); u32 u = units; while (u) { int i = ffs(u) - 1; - nvc0_fifo_isr_vm_fault(dev, i); + nvc0_fifo_isr_vm_fault(priv, i); u &= ~(1 << i); } - nv_wr32(dev, 0x00259c, units); + nv_wr32(priv, 0x00259c, units); stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 units = nv_rd32(dev, 0x0025a0); + u32 units = nv_rd32(priv, 0x0025a0); u32 u = units; while (u) { int i = ffs(u) - 1; - nvc0_fifo_isr_subfifo_intr(dev, i); + nvc0_fifo_isr_subfifo_intr(priv, i); u &= ~(1 << i); } - nv_wr32(dev, 0x0025a0, units); + nv_wr32(priv, 0x0025a0, units); stat &= ~0x20000000; } if (stat & 0x40000000) { - NV_INFO(dev, "PFIFO: unknown status 0x40000000\n"); - nv_mask(dev, 0x002a00, 0x00000000, 0x00000000); + nv_warn(priv, "unknown status 0x40000000\n"); + nv_mask(priv, 0x002a00, 0x00000000, 0x00000000); stat &= ~0x40000000; } if (stat) { - NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); - nv_wr32(dev, 0x002100, stat); - nv_wr32(dev, 0x002140, 0); + nv_fatal(priv, "unhandled status 0x%08x\n", stat); + nv_wr32(priv, 0x002100, stat); + nv_wr32(priv, 0x002140, 0); } } +static int +nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_fifo_priv *priv; + int ret; + + ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0, + &priv->playlist[0]); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0, + &priv->playlist[1]); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 128 * 0x1000, 0x1000, 0, + &priv->user.mem); + if (ret) + return ret; + + ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, + &priv->user.bar); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nvc0_fifo_intr; + nv_engine(priv)->cclass = &nvc0_fifo_cclass; + nv_engine(priv)->sclass = nvc0_fifo_sclass; + return 0; +} + static void -nvc0_fifo_destroy(struct drm_device *dev, int engine) +nvc0_fifo_dtor(struct nouveau_object *object) { - struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_fifo_priv *priv = (void *)object; nouveau_gpuobj_unmap(&priv->user.bar); nouveau_gpuobj_ref(NULL, &priv->user.mem); - nouveau_gpuobj_ref(NULL, &priv->playlist[1]); nouveau_gpuobj_ref(NULL, &priv->playlist[0]); - dev_priv->eng[engine] = NULL; - kfree(priv); + nouveau_fifo_destroy(&priv->base); } -int -nvc0_fifo_create(struct drm_device *dev) +static int +nvc0_fifo_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvc0_fifo_priv *priv; - int ret; + struct nvc0_fifo_priv *priv = (void *)object; + int ret, i; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; - priv->base.base.destroy = nvc0_fifo_destroy; - priv->base.base.init = nvc0_fifo_init; - priv->base.base.fini = nvc0_fifo_fini; - priv->base.base.context_new = nvc0_fifo_context_new; - priv->base.base.context_del = nvc0_fifo_context_del; - priv->base.channels = 128; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; + nv_wr32(priv, 0x000204, 0xffffffff); + nv_wr32(priv, 0x002204, 0xffffffff); - ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[0]); - if (ret) - goto error; + priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204)); + nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr); - ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[1]); - if (ret) - goto error; + /* assign engines to subfifos */ + if (priv->spoon_nr >= 3) { + nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */ + nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */ + nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */ + nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */ + nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */ + nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */ + } - ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4096, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); - if (ret) - goto error; + /* PSUBFIFO[n] */ + for (i = 0; i < priv->spoon_nr; i++) { + nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + } - ret = nouveau_gpuobj_map_bar(priv->user.mem, NV_MEM_ACCESS_RW, - &priv->user.bar); - if (ret) - goto error; + nv_mask(priv, 0x002200, 0x00000001, 0x00000001); + nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); - nouveau_irq_register(dev, 8, nvc0_fifo_isr); -error: - if (ret) - priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO); - return ret; + nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ + nv_wr32(priv, 0x002100, 0xffffffff); + nv_wr32(priv, 0x002140, 0xbfffffff); + return 0; } + +struct nouveau_oclass +nvc0_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_fifo_ctor, + .dtor = nvc0_fifo_dtor, + .init = nvc0_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 0b356f1..aaff086 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -1,5 +1,5 @@ /* - * Copyright 2010 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,25 +22,30 @@ * Authors: Ben Skeggs */ -#include "drmP.h" +#include <core/client.h> +#include <core/handle.h> +#include <core/namedb.h> +#include <core/gpuobj.h> +#include <core/engctx.h> +#include <core/class.h> +#include <core/math.h> +#include <core/enum.h> -#include "nouveau_drv.h" -#include <core/mm.h> -#include <engine/fifo.h> -#include "nouveau_software.h" - -#define NVE0_FIFO_ENGINE_NUM 32 +#include <subdev/timer.h> +#include <subdev/bar.h> +#include <subdev/vm.h> -static void nve0_fifo_isr(struct drm_device *); +#include <engine/dmaobj.h> +#include <engine/fifo.h> -struct nve0_fifo_engine { +struct nve0_fifo_engn { struct nouveau_gpuobj *playlist[2]; int cur_playlist; }; struct nve0_fifo_priv { - struct nouveau_fifo_priv base; - struct nve0_fifo_engine engine[NVE0_FIFO_ENGINE_NUM]; + struct nouveau_fifo base; + struct nve0_fifo_engn engine[16]; struct { struct nouveau_gpuobj *mem; struct nouveau_vma bar; @@ -48,194 +53,286 @@ struct nve0_fifo_priv { int spoon_nr; }; +struct nve0_fifo_base { + struct nouveau_fifo_base base; + struct nouveau_gpuobj *pgd; + struct nouveau_vm *vm; +}; + struct nve0_fifo_chan { struct nouveau_fifo_chan base; u32 engine; }; +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + static void -nve0_fifo_playlist_update(struct drm_device *dev, u32 engine) +nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine) { - struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct nve0_fifo_engine *peng = &priv->engine[engine]; + struct nouveau_bar *bar = nouveau_bar(priv); + struct nve0_fifo_engn *engn = &priv->engine[engine]; struct nouveau_gpuobj *cur; u32 match = (engine << 16) | 0x00000001; - int ret, i, p; + int i, p; - cur = peng->playlist[peng->cur_playlist]; + cur = engn->playlist[engn->cur_playlist]; if (unlikely(cur == NULL)) { - ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 0x1000, 0, &cur); + int ret = nouveau_gpuobj_new(nv_object(priv)->parent, NULL, + 0x8000, 0x1000, 0, &cur); if (ret) { - NV_ERROR(dev, "PFIFO: playlist alloc failed\n"); + nv_error(priv, "playlist alloc failed\n"); return; } - peng->playlist[peng->cur_playlist] = cur; + engn->playlist[engn->cur_playlist] = cur; } - peng->cur_playlist = !peng->cur_playlist; + engn->cur_playlist = !engn->cur_playlist; - for (i = 0, p = 0; i < priv->base.channels; i++) { - u32 ctrl = nv_rd32(dev, 0x800004 + (i * 8)) & 0x001f0001; + for (i = 0, p = 0; i < priv->base.max; i++) { + u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001; if (ctrl != match) continue; nv_wo32(cur, p + 0, i); nv_wo32(cur, p + 4, 0x00000000); p += 8; } - nvimem_flush(dev); + bar->flush(bar); - nv_wr32(dev, 0x002270, cur->addr >> 12); - nv_wr32(dev, 0x002274, (engine << 20) | (p >> 3)); - if (!nv_wait(dev, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) - NV_ERROR(dev, "PFIFO: playlist %d update timeout\n", engine); + nv_wr32(priv, 0x002270, cur->addr >> 12); + nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); + if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) + nv_error(priv, "playlist %d update timeout\n", engine); } static int -nve0_fifo_context_new(struct nouveau_channel *chan, int engine) +nve0_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *object) { - struct drm_device *dev = chan->dev; - struct nve0_fifo_priv *priv = nv_engine(dev, engine); - struct nve0_fifo_chan *fctx; - u64 usermem = priv->user.mem->addr + chan->id * 512; - u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4; - int ret = 0, i; - - fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); - if (!fctx) - return -ENOMEM; - - fctx->engine = 0; /* PGRAPH */ - - /* allocate vram for control regs, map into polling area */ - chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) + - priv->user.bar.offset + (chan->id * 512), 512); - if (!chan->user) { - ret = -ENOMEM; - goto error; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nve0_fifo_base *base = (void *)parent->parent; + struct nouveau_engctx *ectx = (void *)object; + u32 addr; + int ret; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + default: + return -EINVAL; } - for (i = 0; i < 0x100; i += 4) - nv_wo32(chan->ramin, i, 0x00000000); - nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem)); - nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem)); - nv_wo32(chan->ramin, 0x10, 0x0000face); - nv_wo32(chan->ramin, 0x30, 0xfffff902); - nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt)); - nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 | - upper_32_bits(ib_virt)); - nv_wo32(chan->ramin, 0x84, 0x20400000); - nv_wo32(chan->ramin, 0x94, 0x30000001); - nv_wo32(chan->ramin, 0x9c, 0x00000100); - nv_wo32(chan->ramin, 0xac, 0x0000001f); - nv_wo32(chan->ramin, 0xe4, 0x00000000); - nv_wo32(chan->ramin, 0xe8, chan->id); - nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */ - nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */ - nvimem_flush(dev); - - nv_wr32(dev, 0x800000 + (chan->id * 8), 0x80000000 | - (chan->ramin->addr >> 12)); - nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400); - nve0_fifo_playlist_update(dev, fctx->engine); - nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400); - -error: - if (ret) - priv->base.base.context_del(chan, engine); - return ret; + if (!ectx->vma.node) { + ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm, + NV_MEM_ACCESS_RW, &ectx->vma); + if (ret) + return ret; + } + + nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); + nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset)); + bar->flush(bar); + return 0; } -static void -nve0_fifo_context_del(struct nouveau_channel *chan, int engine) +static int +nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend, + struct nouveau_object *object) { - struct nve0_fifo_chan *fctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - - nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800); - nv_wr32(dev, 0x002634, chan->id); - if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id)) - NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634)); - nve0_fifo_playlist_update(dev, fctx->engine); - nv_wr32(dev, 0x800000 + (chan->id * 8), 0x00000000); - - if (chan->user) { - iounmap(chan->user); - chan->user = NULL; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nve0_fifo_priv *priv = (void *)parent->engine; + struct nve0_fifo_base *base = (void *)parent->parent; + struct nve0_fifo_chan *chan = (void *)parent; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + default: + return -EINVAL; + } + + nv_wo32(base, addr + 0x00, 0x00000000); + nv_wo32(base, addr + 0x04, 0x00000000); + bar->flush(bar); + + nv_wr32(priv, 0x002634, chan->base.chid); + if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { + nv_error(priv, "channel %d kick timeout\n", chan->base.chid); + if (suspend) + return -EBUSY; } - chan->engctx[NVOBJ_ENGINE_FIFO] = NULL; - kfree(fctx); + return 0; } static int -nve0_fifo_init(struct drm_device *dev, int engine) +nve0_fifo_chan_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 nve0_fifo_priv *priv = nv_engine(dev, engine); - struct nve0_fifo_chan *fctx; - int i; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nve0_fifo_priv *priv = (void *)engine; + struct nve0_fifo_base *base = (void *)parent; + struct nve0_fifo_chan *chan; + struct nv_channel_ind_class *args = data; + u64 usermem, ioffset, ilength; + int ret, i; + + if (size < sizeof(*args)) + return -EINVAL; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 1, + priv->user.bar.offset, 0x200, + args->pushbuf, + (1 << NVDEV_ENGINE_SW) | + (1 << NVDEV_ENGINE_GR), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + nv_parent(chan)->context_attach = nve0_fifo_context_attach; + nv_parent(chan)->context_detach = nve0_fifo_context_detach; + + usermem = chan->base.chid * 0x200; + ioffset = args->ioffset; + ilength = log2i(args->ilength / 8); + + for (i = 0; i < 0x200; i += 4) + nv_wo32(priv->user.mem, usermem + i, 0x00000000); + + nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem)); + nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem)); + nv_wo32(base, 0x10, 0x0000face); + nv_wo32(base, 0x30, 0xfffff902); + nv_wo32(base, 0x48, lower_32_bits(ioffset)); + nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); + nv_wo32(base, 0x84, 0x20400000); + nv_wo32(base, 0x94, 0x30000001); + nv_wo32(base, 0x9c, 0x00000100); + nv_wo32(base, 0xac, 0x0000001f); + nv_wo32(base, 0xe8, chan->base.chid); + nv_wo32(base, 0xb8, 0xf8000000); + nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */ + nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */ + bar->flush(bar); + return 0; +} - /* reset PFIFO, enable all available PSUBFIFO areas */ - nv_mask(dev, 0x000200, 0x00000100, 0x00000000); - nv_mask(dev, 0x000200, 0x00000100, 0x00000100); - nv_wr32(dev, 0x000204, 0xffffffff); +static int +nve0_fifo_chan_init(struct nouveau_object *object) +{ + struct nouveau_gpuobj *base = nv_gpuobj(object->parent); + struct nve0_fifo_priv *priv = (void *)object->engine; + struct nve0_fifo_chan *chan = (void *)object; + u32 chid = chan->base.chid; + int ret; - priv->spoon_nr = hweight32(nv_rd32(dev, 0x000204)); - NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr); + ret = nouveau_fifo_channel_init(&chan->base); + if (ret) + return ret; - /* PSUBFIFO[n] */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ - } + nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); + nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + nve0_fifo_playlist_update(priv, chan->engine); + nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + return 0; +} - nv_wr32(dev, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); +static int +nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend) +{ + struct nve0_fifo_priv *priv = (void *)object->engine; + struct nve0_fifo_chan *chan = (void *)object; + u32 chid = chan->base.chid; - nv_wr32(dev, 0x002a00, 0xffffffff); - nv_wr32(dev, 0x002100, 0xffffffff); - nv_wr32(dev, 0x002140, 0xbfffffff); + nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + nve0_fifo_playlist_update(priv, chan->engine); + nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); - /* restore PFIFO context table */ - for (i = 0; i < priv->base.channels; i++) { - struct nouveau_channel *chan = dev_priv->channels.ptr[i]; - if (!chan || !(fctx = chan->engctx[engine])) - continue; + return nouveau_fifo_channel_fini(&chan->base, suspend); +} - nv_wr32(dev, 0x800000 + (i * 8), 0x80000000 | - (chan->ramin->addr >> 12)); - nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400); - nve0_fifo_playlist_update(dev, fctx->engine); - nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400); - } +static struct nouveau_ofuncs +nve0_fifo_ofuncs = { + .ctor = nve0_fifo_chan_ctor, + .dtor = _nouveau_fifo_channel_dtor, + .init = nve0_fifo_chan_init, + .fini = nve0_fifo_chan_fini, + .rd32 = _nouveau_fifo_channel_rd32, + .wr32 = _nouveau_fifo_channel_wr32, +}; - return 0; -} +static struct nouveau_oclass +nve0_fifo_sclass[] = { + { 0xa06f, &nve0_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - instmem heap and vm setup + ******************************************************************************/ static int -nve0_fifo_fini(struct drm_device *dev, int engine, bool suspend) +nve0_fifo_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nve0_fifo_priv *priv = nv_engine(dev, engine); - int i; + struct nve0_fifo_base *base; + int ret; - for (i = 0; i < priv->base.channels; i++) { - if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1)) - continue; + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base); + *pobject = nv_object(base); + if (ret) + return ret; - nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800); - nv_wr32(dev, 0x002634, i); - if (!nv_wait(dev, 0x002634, 0xffffffff, i)) { - NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n", - i, nv_rd32(dev, 0x002634)); - return -EBUSY; - } - } + ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd); + if (ret) + return ret; + + nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr)); + nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr)); + nv_wo32(base, 0x0208, 0xffffffff); + nv_wo32(base, 0x020c, 0x000000ff); + + ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; - nv_wr32(dev, 0x002140, 0x00000000); return 0; } +static void +nve0_fifo_context_dtor(struct nouveau_object *object) +{ + struct nve0_fifo_base *base = (void *)object; + nouveau_vm_ref(NULL, &base->vm, base->pgd); + nouveau_gpuobj_ref(NULL, &base->pgd); + nouveau_fifo_context_destroy(&base->base); +} + +static struct nouveau_oclass +nve0_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_fifo_context_ctor, + .dtor = nve0_fifo_context_dtor, + .init = _nouveau_fifo_context_init, + .fini = _nouveau_fifo_context_fini, + .rd32 = _nouveau_fifo_context_rd32, + .wr32 = _nouveau_fifo_context_wr32, + }, +}; + +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ + struct nouveau_enum nve0_fifo_fault_unit[] = { {} }; @@ -268,16 +365,16 @@ struct nouveau_bitfield nve0_fifo_subfifo_intr[] = { }; static void -nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit) +nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit) { - u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10)); - u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10)); - u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10)); - u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10)); + u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10)); + u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10)); + u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10)); + u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10)); u32 client = (stat & 0x00001f00) >> 8; - NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [", - (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo); + nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ? + "write" : "read", (u64)vahi << 32 | valo); nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f); printk("] from "); nouveau_enum_print(nve0_fifo_fault_unit, unit); @@ -292,160 +389,205 @@ nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit) } static int -nve0_fifo_page_flip(struct drm_device *dev, u32 chid) +nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) { - struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = NULL; + struct nve0_fifo_chan *chan = NULL; + struct nouveau_handle *bind; unsigned long flags; int ret = -EINVAL; - spin_lock_irqsave(&dev_priv->channels.lock, flags); - if (likely(chid >= 0 && chid < priv->base.channels)) { - chan = dev_priv->channels.ptr[chid]; - if (likely(chan)) { - struct nouveau_software_chan *swch = - chan->engctx[NVOBJ_ENGINE_SW]; - ret = swch->flip(swch->flip_data); - } + spin_lock_irqsave(&priv->base.lock, flags); + if (likely(chid >= priv->base.min && chid <= priv->base.max)) + chan = (void *)priv->base.channel[chid]; + if (unlikely(!chan)) + goto out; + + bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); + if (likely(bind)) { + if (!mthd || !nv_call(bind->object, mthd, data)) + ret = 0; + nouveau_namedb_put(bind); } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + +out: + spin_unlock_irqrestore(&priv->base.lock, flags); return ret; } static void -nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) +nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit) { - u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000)); - u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0xfff; - u32 subc = (addr & 0x00070000); + u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); + u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); + u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000)); + u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff; + u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; if (stat & 0x00200000) { if (mthd == 0x0054) { - if (!nve0_fifo_page_flip(dev, chid)) + if (!nve0_fifo_swmthd(priv, chid, 0x0500, 0x00000000)) show &= ~0x00200000; } } + if (stat & 0x00800000) { + if (!nve0_fifo_swmthd(priv, chid, mthd, data)) + show &= ~0x00800000; + } + if (show) { - NV_INFO(dev, "PFIFO%d:", unit); + nv_error(priv, "SUBFIFO%d:", unit); nouveau_bitfield_print(nve0_fifo_subfifo_intr, show); - NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n", - unit, chid, subc, mthd, data); + printk("\n"); + nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x " + "data 0x%08x\n", + unit, chid, subc, mthd, data); } - nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008); - nv_wr32(dev, 0x040108 + (unit * 0x2000), stat); + nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); + nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); } static void -nve0_fifo_isr(struct drm_device *dev) +nve0_fifo_intr(struct nouveau_subdev *subdev) { - u32 mask = nv_rd32(dev, 0x002140); - u32 stat = nv_rd32(dev, 0x002100) & mask; + struct nve0_fifo_priv *priv = (void *)subdev; + u32 mask = nv_rd32(priv, 0x002140); + u32 stat = nv_rd32(priv, 0x002100) & mask; if (stat & 0x00000100) { - NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); - nv_wr32(dev, 0x002100, 0x00000100); + nv_warn(priv, "unknown status 0x00000100\n"); + nv_wr32(priv, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x10000000) { - u32 units = nv_rd32(dev, 0x00259c); + u32 units = nv_rd32(priv, 0x00259c); u32 u = units; while (u) { int i = ffs(u) - 1; - nve0_fifo_isr_vm_fault(dev, i); + nve0_fifo_isr_vm_fault(priv, i); u &= ~(1 << i); } - nv_wr32(dev, 0x00259c, units); + nv_wr32(priv, 0x00259c, units); stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 units = nv_rd32(dev, 0x0025a0); + u32 units = nv_rd32(priv, 0x0025a0); u32 u = units; while (u) { int i = ffs(u) - 1; - nve0_fifo_isr_subfifo_intr(dev, i); + nve0_fifo_isr_subfifo_intr(priv, i); u &= ~(1 << i); } - nv_wr32(dev, 0x0025a0, units); + nv_wr32(priv, 0x0025a0, units); stat &= ~0x20000000; } if (stat & 0x40000000) { - NV_INFO(dev, "PFIFO: unknown status 0x40000000\n"); - nv_mask(dev, 0x002a00, 0x00000000, 0x00000000); + nv_warn(priv, "unknown status 0x40000000\n"); + nv_mask(priv, 0x002a00, 0x00000000, 0x00000000); stat &= ~0x40000000; } if (stat) { - NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); - nv_wr32(dev, 0x002100, stat); - nv_wr32(dev, 0x002140, 0); + nv_fatal(priv, "unhandled status 0x%08x\n", stat); + nv_wr32(priv, 0x002100, stat); + nv_wr32(priv, 0x002140, 0); } } +static int +nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nve0_fifo_priv *priv; + int ret; + + ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 4096 * 0x200, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); + if (ret) + return ret; + + ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, + &priv->user.bar); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nve0_fifo_intr; + nv_engine(priv)->cclass = &nve0_fifo_cclass; + nv_engine(priv)->sclass = nve0_fifo_sclass; + return 0; +} + static void -nve0_fifo_destroy(struct drm_device *dev, int engine) +nve0_fifo_dtor(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nve0_fifo_priv *priv = nv_engine(dev, engine); + struct nve0_fifo_priv *priv = (void *)object; int i; nouveau_gpuobj_unmap(&priv->user.bar); nouveau_gpuobj_ref(NULL, &priv->user.mem); - for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) { - nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]); + for (i = 0; i < ARRAY_SIZE(priv->engine); i++) { nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]); + nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]); } - dev_priv->eng[engine] = NULL; - kfree(priv); + nouveau_fifo_destroy(&priv->base); } -int -nve0_fifo_create(struct drm_device *dev) +static int +nve0_fifo_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nve0_fifo_priv *priv; - int ret; + struct nve0_fifo_priv *priv = (void *)object; + int ret, i; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; - priv->base.base.destroy = nve0_fifo_destroy; - priv->base.base.init = nve0_fifo_init; - priv->base.base.fini = nve0_fifo_fini; - priv->base.base.context_new = nve0_fifo_context_new; - priv->base.base.context_del = nve0_fifo_context_del; - priv->base.channels = 4096; - dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; + /* enable all available PSUBFIFOs */ + nv_wr32(priv, 0x000204, 0xffffffff); + priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204)); + nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr); - ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 512, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); - if (ret) - goto error; + /* PSUBFIFO[n] */ + for (i = 0; i < priv->spoon_nr; i++) { + nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + } - ret = nouveau_gpuobj_map_bar(priv->user.mem, NV_MEM_ACCESS_RW, - &priv->user.bar); - if (ret) - goto error; + nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); - nouveau_irq_register(dev, 8, nve0_fifo_isr); -error: - if (ret) - priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO); - return ret; + nv_wr32(priv, 0x002a00, 0xffffffff); + nv_wr32(priv, 0x002100, 0xffffffff); + nv_wr32(priv, 0x002140, 0xbfffffff); + return 0; } + +struct nouveau_oclass +nve0_fifo_oclass = { + .handle = NV_ENGINE(FIFO, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_fifo_ctor, + .dtor = nve0_fifo_dtor, + .init = nve0_fifo_init, + .fini = _nouveau_fifo_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h index b0795ec..e194701 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h @@ -2,7 +2,7 @@ #define __NOUVEAU_GRCTX_H__ struct nouveau_grctx { - struct drm_device *dev; + struct nouveau_device *device; enum { NOUVEAU_GRCTX_PROG, @@ -10,18 +10,18 @@ struct nouveau_grctx { } mode; void *data; - uint32_t ctxprog_max; - uint32_t ctxprog_len; - uint32_t ctxprog_reg; - int ctxprog_label[32]; - uint32_t ctxvals_pos; - uint32_t ctxvals_base; + u32 ctxprog_max; + u32 ctxprog_len; + u32 ctxprog_reg; + int ctxprog_label[32]; + u32 ctxvals_pos; + u32 ctxvals_base; }; static inline void -cp_out(struct nouveau_grctx *ctx, uint32_t inst) +cp_out(struct nouveau_grctx *ctx, u32 inst) { - uint32_t *ctxprog = ctx->data; + u32 *ctxprog = ctx->data; if (ctx->mode != NOUVEAU_GRCTX_PROG) return; @@ -31,13 +31,13 @@ cp_out(struct nouveau_grctx *ctx, uint32_t inst) } static inline void -cp_lsr(struct nouveau_grctx *ctx, uint32_t val) +cp_lsr(struct nouveau_grctx *ctx, u32 val) { cp_out(ctx, CP_LOAD_SR | val); } static inline void -cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length) +cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length) { ctx->ctxprog_reg = (reg - 0x00400000) >> 2; @@ -55,7 +55,7 @@ cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length) static inline void cp_name(struct nouveau_grctx *ctx, int name) { - uint32_t *ctxprog = ctx->data; + u32 *ctxprog = ctx->data; int i; if (ctx->mode != NOUVEAU_GRCTX_PROG) @@ -115,7 +115,7 @@ cp_pos(struct nouveau_grctx *ctx, int offset) } static inline void -gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val) +gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val) { if (ctx->mode != NOUVEAU_GRCTX_VALS) return; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c index b17506d..e45035e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c @@ -22,6 +22,8 @@ * Authors: Ben Skeggs */ +#include <core/gpuobj.h> + /* NVIDIA context programs handle a number of other conditions which are * not implemented in our versions. It's not clear why NVIDIA context * programs have this code, nor whether it's strictly necessary for @@ -109,8 +111,7 @@ #define CP_LOAD_MAGIC_NV44TCL 0x00800029 /* per-vs state (0x4497) */ #define CP_LOAD_MAGIC_NV40TCL 0x00800041 /* per-vs state (0x4097) */ -#include "drmP.h" -#include "nouveau_drv.h" +#include "nv40.h" #include "ctx.h" /* TODO: @@ -118,11 +119,10 @@ */ static int -nv40_graph_vs_count(struct drm_device *dev) +nv40_graph_vs_count(struct nouveau_device *device) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x47: case 0x49: case 0x4b: @@ -160,7 +160,7 @@ enum cp_label { static void nv40_graph_construct_general(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i; cp_ctx(ctx, 0x4000a4, 1); @@ -187,7 +187,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) cp_ctx(ctx, 0x400724, 1); gr_def(ctx, 0x400724, 0x02008821); cp_ctx(ctx, 0x400770, 3); - if (dev_priv->chipset == 0x40) { + if (device->chipset == 0x40) { cp_ctx(ctx, 0x400814, 4); cp_ctx(ctx, 0x400828, 5); cp_ctx(ctx, 0x400840, 5); @@ -208,7 +208,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) gr_def(ctx, 0x4009dc, 0x80000000); } else { cp_ctx(ctx, 0x400840, 20); - if (nv44_graph_class(ctx->dev)) { + if (nv44_graph_class(ctx->device)) { for (i = 0; i < 8; i++) gr_def(ctx, 0x400860 + (i * 4), 0x00000001); } @@ -217,21 +217,21 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) gr_def(ctx, 0x400888, 0x00000040); cp_ctx(ctx, 0x400894, 11); gr_def(ctx, 0x400894, 0x00000040); - if (!nv44_graph_class(ctx->dev)) { + if (!nv44_graph_class(ctx->device)) { for (i = 0; i < 8; i++) gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000); } cp_ctx(ctx, 0x4008e0, 2); cp_ctx(ctx, 0x4008f8, 2); - if (dev_priv->chipset == 0x4c || - (dev_priv->chipset & 0xf0) == 0x60) + if (device->chipset == 0x4c || + (device->chipset & 0xf0) == 0x60) cp_ctx(ctx, 0x4009f8, 1); } cp_ctx(ctx, 0x400a00, 73); gr_def(ctx, 0x400b0c, 0x0b0b0b0c); cp_ctx(ctx, 0x401000, 4); cp_ctx(ctx, 0x405004, 1); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x47: case 0x49: case 0x4b: @@ -240,7 +240,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) break; default: cp_ctx(ctx, 0x403440, 1); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x40: gr_def(ctx, 0x403440, 0x00000010); break; @@ -266,19 +266,19 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) static void nv40_graph_construct_state3d(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i; - if (dev_priv->chipset == 0x40) { + if (device->chipset == 0x40) { cp_ctx(ctx, 0x401880, 51); gr_def(ctx, 0x401940, 0x00000100); } else - if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 || - dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) { + if (device->chipset == 0x46 || device->chipset == 0x47 || + device->chipset == 0x49 || device->chipset == 0x4b) { cp_ctx(ctx, 0x401880, 32); for (i = 0; i < 16; i++) gr_def(ctx, 0x401880 + (i * 4), 0x00000111); - if (dev_priv->chipset == 0x46) + if (device->chipset == 0x46) cp_ctx(ctx, 0x401900, 16); cp_ctx(ctx, 0x401940, 3); } @@ -289,7 +289,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx) gr_def(ctx, 0x401978, 0xffff0000); gr_def(ctx, 0x40197c, 0x00000001); gr_def(ctx, 0x401990, 0x46400000); - if (dev_priv->chipset == 0x40) { + if (device->chipset == 0x40) { cp_ctx(ctx, 0x4019a0, 2); cp_ctx(ctx, 0x4019ac, 5); } else { @@ -297,7 +297,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx) cp_ctx(ctx, 0x4019b4, 3); } gr_def(ctx, 0x4019bc, 0xffff0000); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x46: case 0x47: case 0x49: @@ -316,7 +316,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx) for (i = 0; i < 16; i++) gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000); gr_def(ctx, 0x401a8c, 0x4b7fffff); - if (dev_priv->chipset == 0x40) { + if (device->chipset == 0x40) { cp_ctx(ctx, 0x401ab8, 3); } else { cp_ctx(ctx, 0x401ab8, 1); @@ -327,10 +327,10 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx) gr_def(ctx, 0x401ad4, 0x70605040); gr_def(ctx, 0x401ad8, 0xb8a89888); gr_def(ctx, 0x401adc, 0xf8e8d8c8); - cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1); + cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1); gr_def(ctx, 0x401b10, 0x40100000); - cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5); - gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ? + cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5); + gr_def(ctx, 0x401b28, device->chipset == 0x40 ? 0x00000004 : 0x00000000); cp_ctx(ctx, 0x401b30, 25); gr_def(ctx, 0x401b34, 0x0000ffff); @@ -341,8 +341,8 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx) gr_def(ctx, 0x401b84, 0xffffffff); gr_def(ctx, 0x401b88, 0x00ff7000); gr_def(ctx, 0x401b8c, 0x0000ffff); - if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a && - dev_priv->chipset != 0x4e) + if (device->chipset != 0x44 && device->chipset != 0x4a && + device->chipset != 0x4e) cp_ctx(ctx, 0x401b94, 1); cp_ctx(ctx, 0x401b98, 8); gr_def(ctx, 0x401b9c, 0x00ff0000); @@ -371,12 +371,12 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx) static void nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i; cp_ctx(ctx, 0x402000, 1); - cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2); - switch (dev_priv->chipset) { + cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2); + switch (device->chipset) { case 0x40: gr_def(ctx, 0x402404, 0x00000001); break; @@ -393,9 +393,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) default: gr_def(ctx, 0x402404, 0x00000021); } - if (dev_priv->chipset != 0x40) + if (device->chipset != 0x40) gr_def(ctx, 0x402408, 0x030c30c3); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x44: case 0x46: case 0x4a: @@ -408,10 +408,10 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) default: break; } - cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9); + cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9); gr_def(ctx, 0x402488, 0x3e020200); gr_def(ctx, 0x40248c, 0x00ffffff); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x40: gr_def(ctx, 0x402490, 0x60103f00); break; @@ -428,16 +428,16 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) gr_def(ctx, 0x402490, 0x0c103f00); break; } - gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ? + gr_def(ctx, 0x40249c, device->chipset <= 0x43 ? 0x00020000 : 0x00040000); cp_ctx(ctx, 0x402500, 31); gr_def(ctx, 0x402530, 0x00008100); - if (dev_priv->chipset == 0x40) + if (device->chipset == 0x40) cp_ctx(ctx, 0x40257c, 6); cp_ctx(ctx, 0x402594, 16); cp_ctx(ctx, 0x402800, 17); gr_def(ctx, 0x402800, 0x00000001); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x47: case 0x49: case 0x4b: @@ -445,7 +445,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) gr_def(ctx, 0x402864, 0x00001001); cp_ctx(ctx, 0x402870, 3); gr_def(ctx, 0x402878, 0x00000003); - if (dev_priv->chipset != 0x47) { /* belong at end!! */ + if (device->chipset != 0x47) { /* belong at end!! */ cp_ctx(ctx, 0x402900, 1); cp_ctx(ctx, 0x402940, 1); cp_ctx(ctx, 0x402980, 1); @@ -470,9 +470,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) } cp_ctx(ctx, 0x402c00, 4); - gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ? + gr_def(ctx, 0x402c00, device->chipset == 0x40 ? 0x80800001 : 0x00888001); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x47: case 0x49: case 0x4b: @@ -485,30 +485,30 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) break; default: cp_ctx(ctx, 0x402c10, 4); - if (dev_priv->chipset == 0x40) + if (device->chipset == 0x40) cp_ctx(ctx, 0x402c20, 36); else - if (dev_priv->chipset <= 0x42) + if (device->chipset <= 0x42) cp_ctx(ctx, 0x402c20, 24); else - if (dev_priv->chipset <= 0x4a) + if (device->chipset <= 0x4a) cp_ctx(ctx, 0x402c20, 16); else cp_ctx(ctx, 0x402c20, 8); - cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13); + cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13); gr_def(ctx, 0x402cd4, 0x00000005); - if (dev_priv->chipset != 0x40) + if (device->chipset != 0x40) gr_def(ctx, 0x402ce0, 0x0000ffff); break; } - cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3); - cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3); - cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev)); - for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++) + cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3); + cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3); + cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device)); + for (i = 0; i < nv40_graph_vs_count(ctx->device); i++) gr_def(ctx, 0x403420 + (i * 4), 0x00005555); - if (dev_priv->chipset != 0x40) { + if (device->chipset != 0x40) { cp_ctx(ctx, 0x403600, 1); gr_def(ctx, 0x403600, 0x00000001); } @@ -516,7 +516,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) cp_ctx(ctx, 0x403c18, 1); gr_def(ctx, 0x403c18, 0x00000001); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x46: case 0x47: case 0x49: @@ -527,7 +527,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) gr_def(ctx, 0x405c24, 0x000e3000); break; } - if (dev_priv->chipset != 0x4e) + if (device->chipset != 0x4e) cp_ctx(ctx, 0x405800, 11); cp_ctx(ctx, 0x407000, 1); } @@ -535,7 +535,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) static void nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx) { - int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684; + int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684; cp_out (ctx, 0x300000); cp_lsr (ctx, len - 4); @@ -550,32 +550,31 @@ nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx) static void nv40_graph_construct_shader(struct nouveau_grctx *ctx) { - struct drm_device *dev = ctx->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_device *device = ctx->device; struct nouveau_gpuobj *obj = ctx->data; int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset; int offset, i; - vs_nr = nv40_graph_vs_count(ctx->dev); + vs_nr = nv40_graph_vs_count(ctx->device); vs_nr_b0 = 363; - vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64; - if (dev_priv->chipset == 0x40) { + vs_nr_b1 = device->chipset == 0x40 ? 128 : 64; + if (device->chipset == 0x40) { b0_offset = 0x2200/4; /* 33a0 */ b1_offset = 0x55a0/4; /* 1500 */ vs_len = 0x6aa0/4; } else - if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) { + if (device->chipset == 0x41 || device->chipset == 0x42) { b0_offset = 0x2200/4; /* 2200 */ b1_offset = 0x4400/4; /* 0b00 */ vs_len = 0x4f00/4; } else { b0_offset = 0x1d40/4; /* 2200 */ b1_offset = 0x3f40/4; /* 0b00 : 0a40 */ - vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4; + vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4; } cp_lsr(ctx, vs_len * vs_nr + 0x300/4); - cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041); + cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041); offset = ctx->ctxvals_pos; ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len)); @@ -661,21 +660,21 @@ nv40_grctx_generate(struct nouveau_grctx *ctx) } void -nv40_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem) +nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem) { nv40_grctx_generate(&(struct nouveau_grctx) { - .dev = dev, + .device = device, .mode = NOUVEAU_GRCTX_VALS, .data = mem, }); } void -nv40_grctx_init(struct drm_device *dev, u32 *size) +nv40_grctx_init(struct nouveau_device *device, u32 *size) { u32 ctxprog[256], i; struct nouveau_grctx ctx = { - .dev = dev, + .device = device, .mode = NOUVEAU_GRCTX_PROG, .data = ctxprog, .ctxprog_max = ARRAY_SIZE(ctxprog) @@ -683,8 +682,8 @@ nv40_grctx_init(struct drm_device *dev, u32 *size) nv40_grctx_generate(&ctx); - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); + nv_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, ctxprog[i]); + nv_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c index e17c17b..552fdbd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c @@ -20,6 +20,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include <core/gpuobj.h> + #define CP_FLAG_CLEAR 0 #define CP_FLAG_SET 1 #define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0) @@ -105,8 +107,7 @@ #define CP_SEEK_1 0x00c000ff #define CP_SEEK_2 0x00c800ff -#include "drmP.h" -#include "nouveau_drv.h" +#include "nv50.h" #include "ctx.h" #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) @@ -175,32 +176,6 @@ static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx); static int nv50_grctx_generate(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; - - switch (dev_priv->chipset) { - case 0x50: - case 0x84: - case 0x86: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - case 0xa0: - case 0xa3: - case 0xa5: - case 0xa8: - case 0xaa: - case 0xac: - case 0xaf: - break; - default: - NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for " - "your NV%x card.\n", dev_priv->chipset); - NV_ERROR(ctx->dev, "Disabling acceleration. Please contact " - "the devs.\n"); - return -ENOSYS; - } - cp_set (ctx, STATE, RUNNING); cp_set (ctx, XFER_SWITCH, ENABLE); /* decide whether we're loading/unloading the context */ @@ -278,30 +253,36 @@ nv50_grctx_generate(struct nouveau_grctx *ctx) } void -nv50_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem) +nv50_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem) { nv50_grctx_generate(&(struct nouveau_grctx) { - .dev = dev, + .device = device, .mode = NOUVEAU_GRCTX_VALS, .data = mem, }); } int -nv50_grctx_init(struct drm_device *dev, u32 *data, u32 max, u32 *len, u32 *cnt) +nv50_grctx_init(struct nouveau_device *device, u32 *size) { + u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i; struct nouveau_grctx ctx = { - .dev = dev, + .device = device, .mode = NOUVEAU_GRCTX_PROG, - .data = data, - .ctxprog_max = max + .data = ctxprog, + .ctxprog_max = 512, }; - int ret; - ret = nv50_grctx_generate(&ctx); - *cnt = ctx.ctxvals_pos * 4; - *len = ctx.ctxprog_len; - return ret; + if (!ctxprog) + return -ENOMEM; + nv50_grctx_generate(&ctx); + + nv_wr32(device, 0x400324, 0); + for (i = 0; i < ctx.ctxprog_len; i++) + nv_wr32(device, 0x400328, ctxprog[i]); + *size = ctx.ctxvals_pos * 4; + kfree(ctxprog); + return 0; } /* @@ -315,36 +296,36 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx); static void nv50_graph_construct_mmio(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i, j; int offset, base; - uint32_t units = nv_rd32 (ctx->dev, 0x1540); + u32 units = nv_rd32 (ctx->device, 0x1540); /* 0800: DISPATCH */ cp_ctx(ctx, 0x400808, 7); gr_def(ctx, 0x400814, 0x00000030); cp_ctx(ctx, 0x400834, 0x32); - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { gr_def(ctx, 0x400834, 0xff400040); gr_def(ctx, 0x400838, 0xfff00080); gr_def(ctx, 0x40083c, 0xfff70090); gr_def(ctx, 0x400840, 0xffe806a8); } gr_def(ctx, 0x400844, 0x00000002); - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) gr_def(ctx, 0x400894, 0x00001000); gr_def(ctx, 0x4008e8, 0x00000003); gr_def(ctx, 0x4008ec, 0x00001000); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) cp_ctx(ctx, 0x400908, 0xb); - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) cp_ctx(ctx, 0x400908, 0xc); else cp_ctx(ctx, 0x400908, 0xe); - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) cp_ctx(ctx, 0x400b00, 0x1); - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { cp_ctx(ctx, 0x400b10, 0x1); gr_def(ctx, 0x400b10, 0x0001629d); cp_ctx(ctx, 0x400b20, 0x1); @@ -358,10 +339,10 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, 0x400c08, 0x0000fe0c); /* 1000 */ - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { cp_ctx(ctx, 0x401008, 0x4); gr_def(ctx, 0x401014, 0x00001000); - } else if (!IS_NVA3F(dev_priv->chipset)) { + } else if (!IS_NVA3F(device->chipset)) { cp_ctx(ctx, 0x401008, 0x5); gr_def(ctx, 0x401018, 0x00001000); } else { @@ -372,7 +353,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) /* 1400 */ cp_ctx(ctx, 0x401400, 0x8); cp_ctx(ctx, 0x401424, 0x3); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, 0x40142c, 0x0001fd87); else gr_def(ctx, 0x40142c, 0x00000187); @@ -382,10 +363,10 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) /* 1800: STREAMOUT */ cp_ctx(ctx, 0x401814, 0x1); gr_def(ctx, 0x401814, 0x000000ff); - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { cp_ctx(ctx, 0x40181c, 0xe); gr_def(ctx, 0x401850, 0x00000004); - } else if (dev_priv->chipset < 0xa0) { + } else if (device->chipset < 0xa0) { cp_ctx(ctx, 0x40181c, 0xf); gr_def(ctx, 0x401854, 0x00000004); } else { @@ -395,7 +376,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) /* 1C00 */ cp_ctx(ctx, 0x401c00, 0x1); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: gr_def(ctx, 0x401c00, 0x0001005f); break; @@ -424,7 +405,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) /* 2400 */ cp_ctx(ctx, 0x402400, 0x1); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) cp_ctx(ctx, 0x402408, 0x1); else cp_ctx(ctx, 0x402408, 0x2); @@ -432,21 +413,21 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) /* 2800: CSCHED */ cp_ctx(ctx, 0x402800, 0x1); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, 0x402800, 0x00000006); /* 2C00: ZCULL */ cp_ctx(ctx, 0x402c08, 0x6); - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) gr_def(ctx, 0x402c14, 0x01000000); gr_def(ctx, 0x402c18, 0x000000ff); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) cp_ctx(ctx, 0x402ca0, 0x1); else cp_ctx(ctx, 0x402ca0, 0x2); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) gr_def(ctx, 0x402ca0, 0x00000400); - else if (!IS_NVA3F(dev_priv->chipset)) + else if (!IS_NVA3F(device->chipset)) gr_def(ctx, 0x402ca0, 0x00000800); else gr_def(ctx, 0x402ca0, 0x00000400); @@ -457,14 +438,14 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, 0x403004, 0x00000001); /* 3400 */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { cp_ctx(ctx, 0x403404, 0x1); gr_def(ctx, 0x403404, 0x00000001); } /* 5000: CCACHE */ cp_ctx(ctx, 0x405000, 0x1); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: gr_def(ctx, 0x405000, 0x00300080); break; @@ -493,22 +474,22 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) cp_ctx(ctx, 0x40502c, 0x1); /* 6000? */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) cp_ctx(ctx, 0x4063e0, 0x1); /* 6800: M2MF */ - if (dev_priv->chipset < 0x90) { + if (device->chipset < 0x90) { cp_ctx(ctx, 0x406814, 0x2b); gr_def(ctx, 0x406818, 0x00000f80); gr_def(ctx, 0x406860, 0x007f0080); gr_def(ctx, 0x40689c, 0x007f0080); } else { cp_ctx(ctx, 0x406814, 0x4); - if (dev_priv->chipset == 0x98) + if (device->chipset == 0x98) gr_def(ctx, 0x406818, 0x00000f80); else gr_def(ctx, 0x406818, 0x00001f80); - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) gr_def(ctx, 0x40681c, 0x00000030); cp_ctx(ctx, 0x406830, 0x3); } @@ -517,43 +498,43 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) for (i = 0; i < 8; i++) { if (units & (1<<(i+16))) { cp_ctx(ctx, 0x407000 + (i<<8), 3); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820); - else if (dev_priv->chipset != 0xa5) + else if (device->chipset != 0xa5) gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821); else gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821); gr_def(ctx, 0x407004 + (i<<8), 0x89058001); - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { cp_ctx(ctx, 0x407010 + (i<<8), 1); - } else if (dev_priv->chipset < 0xa0) { + } else if (device->chipset < 0xa0) { cp_ctx(ctx, 0x407010 + (i<<8), 2); gr_def(ctx, 0x407010 + (i<<8), 0x00001000); gr_def(ctx, 0x407014 + (i<<8), 0x0000001f); } else { cp_ctx(ctx, 0x407010 + (i<<8), 3); gr_def(ctx, 0x407010 + (i<<8), 0x00001000); - if (dev_priv->chipset != 0xa5) + if (device->chipset != 0xa5) gr_def(ctx, 0x407014 + (i<<8), 0x000000ff); else gr_def(ctx, 0x407014 + (i<<8), 0x000001ff); } cp_ctx(ctx, 0x407080 + (i<<8), 4); - if (dev_priv->chipset != 0xa5) + if (device->chipset != 0xa5) gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa); else gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, 0x407084 + (i<<8), 0x000000c0); else gr_def(ctx, 0x407084 + (i<<8), 0x400000c0); gr_def(ctx, 0x407088 + (i<<8), 0xb7892080); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) cp_ctx(ctx, 0x407094 + (i<<8), 1); - else if (!IS_NVA3F(dev_priv->chipset)) + else if (!IS_NVA3F(device->chipset)) cp_ctx(ctx, 0x407094 + (i<<8), 3); else { cp_ctx(ctx, 0x407094 + (i<<8), 4); @@ -563,30 +544,30 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) } cp_ctx(ctx, 0x407c00, 0x3); - if (dev_priv->chipset < 0x90) + if (device->chipset < 0x90) gr_def(ctx, 0x407c00, 0x00010040); - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) gr_def(ctx, 0x407c00, 0x00390040); else gr_def(ctx, 0x407c00, 0x003d0040); gr_def(ctx, 0x407c08, 0x00000022); - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { cp_ctx(ctx, 0x407c10, 0x3); cp_ctx(ctx, 0x407c20, 0x1); cp_ctx(ctx, 0x407c2c, 0x1); } - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { cp_ctx(ctx, 0x407d00, 0x9); } else { cp_ctx(ctx, 0x407d00, 0x15); } - if (dev_priv->chipset == 0x98) + if (device->chipset == 0x98) gr_def(ctx, 0x407d08, 0x00380040); else { - if (dev_priv->chipset < 0x90) + if (device->chipset < 0x90) gr_def(ctx, 0x407d08, 0x00010040); - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) gr_def(ctx, 0x407d08, 0x00390040); else gr_def(ctx, 0x407d08, 0x003d0040); @@ -596,11 +577,11 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) /* 8000+: per-TP state */ for (i = 0; i < 10; i++) { if (units & (1<<i)) { - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) base = 0x408000 + (i<<12); else base = 0x408000 + (i<<11); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) offset = base + 0xc00; else offset = base + 0x80; @@ -609,9 +590,9 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) cp_ctx(ctx, offset + 0x08, 1); /* per-MP state */ - for (j = 0; j < (dev_priv->chipset < 0xa0 ? 2 : 4); j++) { + for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) { if (!(units & (1 << (j+24)))) continue; - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) offset = base + 0x200 + (j<<7); else offset = base + 0x100 + (j<<7); @@ -620,7 +601,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, offset + 0x04, 0x00160000); gr_def(ctx, offset + 0x08, 0x01800000); gr_def(ctx, offset + 0x18, 0x0003ffff); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: gr_def(ctx, offset + 0x1c, 0x00080000); break; @@ -651,53 +632,53 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) break; } gr_def(ctx, offset + 0x40, 0x00010401); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, offset + 0x48, 0x00000040); else gr_def(ctx, offset + 0x48, 0x00000078); gr_def(ctx, offset + 0x50, 0x000000bf); gr_def(ctx, offset + 0x58, 0x00001210); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, offset + 0x5c, 0x00000080); else gr_def(ctx, offset + 0x5c, 0x08000080); - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) gr_def(ctx, offset + 0x68, 0x0000003e); } - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) cp_ctx(ctx, base + 0x300, 0x4); else cp_ctx(ctx, base + 0x300, 0x5); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, base + 0x304, 0x00007070); - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) gr_def(ctx, base + 0x304, 0x00027070); - else if (!IS_NVA3F(dev_priv->chipset)) + else if (!IS_NVA3F(device->chipset)) gr_def(ctx, base + 0x304, 0x01127070); else gr_def(ctx, base + 0x304, 0x05127070); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) cp_ctx(ctx, base + 0x318, 1); else cp_ctx(ctx, base + 0x320, 1); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, base + 0x318, 0x0003ffff); - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) gr_def(ctx, base + 0x318, 0x03ffffff); else gr_def(ctx, base + 0x320, 0x07ffffff); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) cp_ctx(ctx, base + 0x324, 5); else cp_ctx(ctx, base + 0x328, 4); - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { cp_ctx(ctx, base + 0x340, 9); offset = base + 0x340; - } else if (!IS_NVA3F(dev_priv->chipset)) { + } else if (!IS_NVA3F(device->chipset)) { cp_ctx(ctx, base + 0x33c, 0xb); offset = base + 0x344; } else { @@ -706,12 +687,12 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) } gr_def(ctx, offset + 0x0, 0x00120407); gr_def(ctx, offset + 0x4, 0x05091507); - if (dev_priv->chipset == 0x84) + if (device->chipset == 0x84) gr_def(ctx, offset + 0x8, 0x05100202); else gr_def(ctx, offset + 0x8, 0x05010202); gr_def(ctx, offset + 0xc, 0x00030201); - if (dev_priv->chipset == 0xa3) + if (device->chipset == 0xa3) cp_ctx(ctx, base + 0x36c, 1); cp_ctx(ctx, base + 0x400, 2); @@ -720,7 +701,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, base + 0x40c, 0x0d0c0b0a); gr_def(ctx, base + 0x410, 0x00141210); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) offset = base + 0x800; else offset = base + 0x500; @@ -728,55 +709,55 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, offset + 0x0, 0x000001f0); gr_def(ctx, offset + 0x4, 0x00000001); gr_def(ctx, offset + 0x8, 0x00000003); - if (dev_priv->chipset == 0x50 || IS_NVAAF(dev_priv->chipset)) + if (device->chipset == 0x50 || IS_NVAAF(device->chipset)) gr_def(ctx, offset + 0xc, 0x00008000); gr_def(ctx, offset + 0x14, 0x00039e00); cp_ctx(ctx, offset + 0x1c, 2); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, offset + 0x1c, 0x00000040); else gr_def(ctx, offset + 0x1c, 0x00000100); gr_def(ctx, offset + 0x20, 0x00003800); - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { cp_ctx(ctx, base + 0x54c, 2); - if (!IS_NVA3F(dev_priv->chipset)) + if (!IS_NVA3F(device->chipset)) gr_def(ctx, base + 0x54c, 0x003fe006); else gr_def(ctx, base + 0x54c, 0x003fe007); gr_def(ctx, base + 0x550, 0x003fe000); } - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) offset = base + 0xa00; else offset = base + 0x680; cp_ctx(ctx, offset, 1); gr_def(ctx, offset, 0x00404040); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) offset = base + 0xe00; else offset = base + 0x700; cp_ctx(ctx, offset, 2); - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) gr_def(ctx, offset, 0x0077f005); - else if (dev_priv->chipset == 0xa5) + else if (device->chipset == 0xa5) gr_def(ctx, offset, 0x6cf7f007); - else if (dev_priv->chipset == 0xa8) + else if (device->chipset == 0xa8) gr_def(ctx, offset, 0x6cfff007); - else if (dev_priv->chipset == 0xac) + else if (device->chipset == 0xac) gr_def(ctx, offset, 0x0cfff007); else gr_def(ctx, offset, 0x0cf7f007); - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) gr_def(ctx, offset + 0x4, 0x00007fff); - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) gr_def(ctx, offset + 0x4, 0x003f7fff); else gr_def(ctx, offset + 0x4, 0x02bf7fff); cp_ctx(ctx, offset + 0x2c, 1); - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { cp_ctx(ctx, offset + 0x50, 9); gr_def(ctx, offset + 0x54, 0x000003ff); gr_def(ctx, offset + 0x58, 0x00000003); @@ -785,7 +766,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, offset + 0x64, 0x0000001f); gr_def(ctx, offset + 0x68, 0x0000000f); gr_def(ctx, offset + 0x6c, 0x0000000f); - } else if (dev_priv->chipset < 0xa0) { + } else if (device->chipset < 0xa0) { cp_ctx(ctx, offset + 0x50, 1); cp_ctx(ctx, offset + 0x70, 1); } else { @@ -797,7 +778,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) } static void -dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) { +dd_emit(struct nouveau_grctx *ctx, int num, u32 val) { int i; if (val && ctx->mode == NOUVEAU_GRCTX_VALS) for (i = 0; i < num; i++) @@ -808,7 +789,7 @@ dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) { static void nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int base, num; base = ctx->ctxvals_pos; @@ -822,7 +803,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 1); /* 00000001 SRC_LINEAR #1 */ dd_emit(ctx, 1, 0); /* 000000ff SRC_ADDRESS_HIGH */ dd_emit(ctx, 1, 0); /* 00000001 SRC_SRGB */ - if (dev_priv->chipset >= 0x94) + if (device->chipset >= 0x94) dd_emit(ctx, 1, 0); /* 00000003 eng2d UNK0258 */ dd_emit(ctx, 1, 1); /* 00000fff SRC_DEPTH */ dd_emit(ctx, 1, 0x100); /* 0000ffff SRC_HEIGHT */ @@ -851,7 +832,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 1); /* 0000007f BLOCKDIM_Z */ dd_emit(ctx, 1, 4); /* 000000ff CP_REG_ALLOC_TEMP */ dd_emit(ctx, 1, 1); /* 00000001 BLOCKDIM_DIRTY */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) dd_emit(ctx, 1, 0); /* 00000003 UNK03E8 */ dd_emit(ctx, 1, 1); /* 0000007f BLOCK_ALLOC_HALFWARPS */ dd_emit(ctx, 1, 1); /* 00000007 LOCAL_WARPS_NO_CLAMP */ @@ -863,7 +844,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 1); /* 000007ff BLOCK_ALLOC_THREADS */ /* compat 2d state */ - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { dd_emit(ctx, 4, 0); /* 0000ffff clip X, Y, W, H */ dd_emit(ctx, 1, 1); /* ffffffff chroma COLOR_FORMAT */ @@ -923,7 +904,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_IN */ /* more compat 2d state */ - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { dd_emit(ctx, 1, 1); /* ffffffff line COLOR_FORMAT */ dd_emit(ctx, 1, 0); /* ffffffff line OPERATION */ @@ -957,18 +938,18 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 0); /* 000000ff UNK12B0_2 */ dd_emit(ctx, 1, 0); /* 0000000f FP_TEXTURES_LOG2 */ dd_emit(ctx, 1, 0); /* 0000000f FP_SAMPLERS_LOG2 */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { dd_emit(ctx, 1, 0); /* ffffffff */ dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */ } else { dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */ } dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */ dd_emit(ctx, 1, 8); /* 000000ff SEMANTIC_COLOR.COLR_NR */ dd_emit(ctx, 1, 0x14); /* 000000ff SEMANTIC_COLOR.FFC0_ID */ - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { dd_emit(ctx, 1, 0); /* 000000ff SEMANTIC_LAYER */ dd_emit(ctx, 1, 0); /* 00000001 */ } else { @@ -994,7 +975,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */ dd_emit(ctx, 1, 0xcf); /* 000000ff RT_FORMAT */ dd_emit(ctx, 7, 0); /* 000000ff RT_FORMAT */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) dd_emit(ctx, 3, 0); /* 1, 1, 1 */ else dd_emit(ctx, 2, 0); /* 1, 1 */ @@ -1002,15 +983,15 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT*/ dd_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ dd_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { dd_emit(ctx, 1, 3); /* 00000003 */ dd_emit(ctx, 1, 0); /* 00000001 UNK1418. Alone. */ } - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) dd_emit(ctx, 1, 3); /* 00000003 UNK15AC */ dd_emit(ctx, 1, 1); /* ffffffff RASTERIZE_ENABLE */ dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.EXPORTS_Z */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.MULTIPLE_RESULTS */ dd_emit(ctx, 1, 0x12); /* 000000ff FP_INTERPOLANT_CTRL.COUNT */ dd_emit(ctx, 1, 0x10); /* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */ @@ -1022,16 +1003,16 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */ dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */ dd_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) dd_emit(ctx, 1, 0); /* ffffffff */ dd_emit(ctx, 1, 0); /* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */ dd_emit(ctx, 1, 0); /* ffffffff STRMOUT_ENABLE */ dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */ dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */ dd_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE*/ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) dd_emit(ctx, 8, 0); /* 00000001 */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.COMP */ dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.SIZE */ dd_emit(ctx, 1, 2); /* 00000007 VTX_ATTR_DEFINE.TYPE */ @@ -1042,20 +1023,20 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ dd_emit(ctx, 1, 0); /* 0000000f VP_TEXTURES_LOG2 */ dd_emit(ctx, 1, 0); /* 0000000f VP_SAMPLERS_LOG2 */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) dd_emit(ctx, 1, 0); /* 00000001 */ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_BACK */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) dd_emit(ctx, 1, 0); /* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */ dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) dd_emit(ctx, 1, 0); /* 00000003 */ dd_emit(ctx, 1, 0); /* 00000001 CULL_FACE_ENABLE */ dd_emit(ctx, 1, 1); /* 00000003 CULL_FACE */ dd_emit(ctx, 1, 0); /* 00000001 FRONT_FACE */ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_FRONT */ dd_emit(ctx, 1, 0x1000); /* 00007fff UNK141C */ - if (dev_priv->chipset != 0x50) { + if (device->chipset != 0x50) { dd_emit(ctx, 1, 0xe00); /* 7fff */ dd_emit(ctx, 1, 0x1000); /* 7fff */ dd_emit(ctx, 1, 0x1e00); /* 7fff */ @@ -1070,10 +1051,10 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK0 nonempty */ dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK1 nonempty */ dd_emit(ctx, 1, 0x200); /* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) dd_emit(ctx, 1, 0x200); dd_emit(ctx, 1, 0); /* 00000001 */ - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { dd_emit(ctx, 1, 1); /* 00000001 */ dd_emit(ctx, 1, 0x70); /* 000000ff */ dd_emit(ctx, 1, 0x80); /* 000000ff */ @@ -1120,7 +1101,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) num = ctx->ctxvals_pos - base; ctx->ctxvals_pos = base; - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) cp_ctx(ctx, 0x404800, num); else cp_ctx(ctx, 0x405400, num); @@ -1169,7 +1150,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) */ static void -xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) { +xf_emit(struct nouveau_grctx *ctx, int num, u32 val) { int i; if (val && ctx->mode == NOUVEAU_GRCTX_VALS) for (i = 0; i < num; i++) @@ -1201,16 +1182,16 @@ static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx); static void nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i; int offset; int size = 0; - uint32_t units = nv_rd32 (ctx->dev, 0x1540); + u32 units = nv_rd32 (ctx->device, 0x1540); offset = (ctx->ctxvals_pos+0x3f)&~0x3f; ctx->ctxvals_base = offset; - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { /* Strand 0 */ ctx->ctxvals_pos = offset; nv50_graph_construct_gene_dispatch(ctx); @@ -1280,7 +1261,7 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) /* Strand 2 */ ctx->ctxvals_pos = offset + 2; - if (dev_priv->chipset == 0xa0) + if (device->chipset == 0xa0) nv50_graph_construct_gene_unk14xx(ctx); nv50_graph_construct_gene_unk24xx(ctx); if ((ctx->ctxvals_pos-offset)/8 > size) @@ -1327,7 +1308,7 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) /* Strand 7 */ ctx->ctxvals_pos = offset + 7; - if (dev_priv->chipset == 0xa0) { + if (device->chipset == 0xa0) { if (units & (1 << 4)) nv50_graph_construct_xfer_tp(ctx); if (units & (1 << 5)) @@ -1365,24 +1346,24 @@ static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx) { /* start of strand 0 */ - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; /* SEEK */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 5, 0); - else if (!IS_NVA3F(dev_priv->chipset)) + else if (!IS_NVA3F(device->chipset)) xf_emit(ctx, 6, 0); else xf_emit(ctx, 4, 0); /* SEEK */ /* the PGRAPH's internal FIFO */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 8*3, 0); else xf_emit(ctx, 0x100*3, 0); /* and another bonus slot?!? */ xf_emit(ctx, 3, 0); /* and YET ANOTHER bonus slot? */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 3, 0); /* SEEK */ /* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */ @@ -1394,7 +1375,7 @@ nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx) /* SEEK */ xf_emit(ctx, 9, 0); /* SEEK */ - if (dev_priv->chipset < 0x90) + if (device->chipset < 0x90) xf_emit(ctx, 4, 0); /* SEEK */ xf_emit(ctx, 2, 0); @@ -1407,9 +1388,9 @@ nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx) xf_emit(ctx, 6*2, 0); xf_emit(ctx, 2, 0); /* SEEK */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 0x1c, 0); - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) xf_emit(ctx, 0x1e, 0); else xf_emit(ctx, 0x22, 0); @@ -1421,9 +1402,9 @@ static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx) { /* Strand 0, right after dispatch */ - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int smallm2mf = 0; - if (dev_priv->chipset < 0x92 || dev_priv->chipset == 0x98) + if (device->chipset < 0x92 || device->chipset == 0x98) smallm2mf = 1; /* SEEK */ xf_emit (ctx, 1, 0); /* DMA_NOTIFY instance >> 4 */ @@ -1472,10 +1453,10 @@ nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; xf_emit(ctx, 2, 0); /* RO */ xf_emit(ctx, 0x800, 0); /* ffffffff */ - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: case 0x92: case 0xa0: @@ -1540,7 +1521,7 @@ nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i; /* end of area 2 on pre-NVA0, area 1 on NVAx */ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ @@ -1550,14 +1531,14 @@ nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 1, 0x3ff); else xf_emit(ctx, 1, 0x7ff); /* 000007ff */ xf_emit(ctx, 1, 0); /* 111/113 */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ for (i = 0; i < 8; i++) { - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: case 0x86: case 0x98: @@ -1600,7 +1581,7 @@ nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; /* end of area 2 on pre-NVA0, area 1 on NVAx */ xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */ xf_emit(ctx, 1, 0); /* 00000003 VIEWPORT_CLIP_MODE */ @@ -1614,9 +1595,9 @@ nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ xf_emit(ctx, 1, 0); /* 00000007 */ xf_emit(ctx, 1, 0x1fe21); /* 0001ffff tesla UNK0FAC */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 1, 0x0fac6881); - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 1); xf_emit(ctx, 3, 0); } @@ -1625,9 +1606,9 @@ nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; /* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */ - if (dev_priv->chipset != 0x50) { + if (device->chipset != 0x50) { xf_emit(ctx, 5, 0); /* ffffffff */ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ xf_emit(ctx, 1, 0); /* 00000001 */ @@ -1643,14 +1624,14 @@ nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ xf_emit(ctx, 1, 0); /* 000000ff VP_CLIP_DISTANCE_ENABLE */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 0); /* 3ff */ xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1940 */ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */ xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 0x7f); /* 000000ff tesla UNK0FFC */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ xf_emit(ctx, 1, 1); /* 00000001 SHADE_MODEL */ @@ -1669,7 +1650,7 @@ nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx) xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ xf_emit(ctx, 1, 0); /* 0000000f */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */ else xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */ @@ -1704,11 +1685,11 @@ nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 0); /* 00000001 */ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */ - if (dev_priv->chipset != 0x50) { + if (device->chipset != 0x50) { xf_emit(ctx, 1, 0); /* ffffffff */ xf_emit(ctx, 1, 0); /* 00000001 */ xf_emit(ctx, 1, 0); /* 000003ff */ @@ -1736,7 +1717,7 @@ nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; /* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */ /* SEEK */ xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */ @@ -1774,7 +1755,7 @@ nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */ xf_emit(ctx, 1, 0); /* 00000007 */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1108 */ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ @@ -1789,7 +1770,7 @@ nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */ xf_emit(ctx, 1, 3); /* 00000003 FP_CTRL_UNK196C */ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1968 */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 0); /* 0fffffff tesla UNK1104 */ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK151C */ } @@ -1817,7 +1798,7 @@ nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i; /* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */ /* SEEK */ @@ -1829,7 +1810,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 4, 0); /* RO */ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ xf_emit(ctx, 1, 0); /* 1ff */ @@ -1860,7 +1841,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ /* SEEK */ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ @@ -1869,7 +1850,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ xf_emit(ctx, 1, 1); /* 00000001 */ /* SEEK */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 2, 4); /* 000000ff */ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ @@ -1893,20 +1874,20 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx) xf_emit(ctx, 0x10, 0); /* 00ffffff POINT_COORD_REPLACE_MAP */ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 0); /* 000003ff */ } static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int acnt = 0x10, rep, i; /* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) acnt = 0x20; /* SEEK */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { xf_emit(ctx, 1, 0); /* ffffffff tesla UNK13A4 */ xf_emit(ctx, 1, 1); /* 00000fff tesla UNK1318 */ } @@ -1923,9 +1904,9 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 0000ffff turing USER_PARAM_COUNT */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 0xb, 0); /* RO */ - else if (dev_priv->chipset >= 0xa0) + else if (device->chipset >= 0xa0) xf_emit(ctx, 0x9, 0); /* RO */ else xf_emit(ctx, 0x8, 0); /* RO */ @@ -1944,11 +1925,11 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 4); /* 000001ff UNK1A28 */ xf_emit(ctx, 1, 8); /* 000001ff UNK0DF0 */ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 1, 0x3ff); /* 3ff tesla UNK0D68 */ else xf_emit(ctx, 1, 0x7ff); /* 7ff tesla UNK0D68 */ - if (dev_priv->chipset == 0xa8) + if (device->chipset == 0xa8) xf_emit(ctx, 1, 0x1e00); /* 7fff */ /* SEEK */ xf_emit(ctx, 0xc, 0); /* RO or close */ @@ -1956,13 +1937,13 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ - if (dev_priv->chipset > 0x50 && dev_priv->chipset < 0xa0) + if (device->chipset > 0x50 && device->chipset < 0xa0) xf_emit(ctx, 2, 0); /* ffffffff */ else xf_emit(ctx, 1, 0); /* ffffffff */ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0FD8 */ /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 0x10, 0); /* 0? */ xf_emit(ctx, 2, 0); /* weird... */ xf_emit(ctx, 2, 0); /* RO */ @@ -1975,7 +1956,7 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* ffffffff VB_ELEMENT_BASE */ xf_emit(ctx, 1, 0); /* ffffffff UNK1438 */ xf_emit(ctx, acnt, 0); /* 1 tesla UNK1000 */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1118? */ /* SEEK */ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */ @@ -2013,23 +1994,23 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_LIMIT_HIGH */ xf_emit(ctx, 3, 0); /* f/1f */ /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, acnt, 0); /* f */ xf_emit(ctx, 3, 0); /* f/1f */ } /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 2, 0); /* RO */ else xf_emit(ctx, 5, 0); /* RO */ /* SEEK */ xf_emit(ctx, 1, 0); /* ffff DMA_VTXBUF */ /* SEEK */ - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { xf_emit(ctx, 0x41, 0); /* RO */ /* SEEK */ xf_emit(ctx, 0x11, 0); /* RO */ - } else if (!IS_NVA3F(dev_priv->chipset)) + } else if (!IS_NVA3F(device->chipset)) xf_emit(ctx, 0x50, 0); /* RO */ else xf_emit(ctx, 0x58, 0); /* RO */ @@ -2041,7 +2022,7 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, acnt*4, 0); /* ffffffff VTX_ATTR */ xf_emit(ctx, 4, 0); /* f/1f, 0, 0, 0 */ /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 0x1d, 0); /* RO */ else xf_emit(ctx, 0x16, 0); /* RO */ @@ -2049,21 +2030,21 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ /* SEEK */ - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) xf_emit(ctx, 8, 0); /* RO */ - else if (IS_NVA3F(dev_priv->chipset)) + else if (IS_NVA3F(device->chipset)) xf_emit(ctx, 0xc, 0); /* RO */ else xf_emit(ctx, 7, 0); /* RO */ /* SEEK */ xf_emit(ctx, 0xa, 0); /* RO */ - if (dev_priv->chipset == 0xa0) + if (device->chipset == 0xa0) rep = 0xc; else rep = 4; for (i = 0; i < rep; i++) { /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 0x20, 0); /* ffffffff */ xf_emit(ctx, 0x200, 0); /* ffffffff */ xf_emit(ctx, 4, 0); /* 7f/ff, 0, 0, 0 */ @@ -2077,7 +2058,7 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ /* SEEK */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 7, 0); /* weird... */ else xf_emit(ctx, 5, 0); /* weird... */ @@ -2086,13 +2067,13 @@ nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; /* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */ /* SEEK */ xf_emit(ctx, 2, 0); /* 0001ffff CLIP_X, CLIP_Y */ xf_emit(ctx, 2, 0); /* 0000ffff CLIP_W, CLIP_H */ xf_emit(ctx, 1, 0); /* 00000001 CLIP_ENABLE */ - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { /* this is useless on everything but the original NV50, * guess they forgot to nuke it. Or just didn't bother. */ xf_emit(ctx, 2, 0); /* 0000ffff IFC_CLIP_X, Y */ @@ -2148,7 +2129,7 @@ nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; /* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */ /* SEEK */ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */ @@ -2173,7 +2154,7 @@ nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */ /* SEEK */ xf_emit(ctx, 0x40, 0); /* ffffffff USER_PARAM */ - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: case 0x92: xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ @@ -2247,7 +2228,7 @@ nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ @@ -2277,9 +2258,9 @@ nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 3); /* 00000003 UNK16B4 */ - else if (dev_priv->chipset >= 0xa0) + else if (device->chipset >= 0xa0) xf_emit(ctx, 1, 1); /* 00000001 UNK16B4 */ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */ @@ -2293,11 +2274,11 @@ nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* ffffffff POINT_SIZE */ xf_emit(ctx, 1, 0); /* 00000001 */ xf_emit(ctx, 1, 0); /* 00000007 tesla UNK0FB4 */ - if (dev_priv->chipset != 0x50) { + if (device->chipset != 0x50) { xf_emit(ctx, 1, 0); /* 3ff */ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK1110 */ } - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */ @@ -2316,11 +2297,11 @@ nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) xf_emit(ctx, 0x1c, 0); /* RO */ - else if (IS_NVA3F(dev_priv->chipset)) + else if (IS_NVA3F(device->chipset)) xf_emit(ctx, 0x9, 0); xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ @@ -2328,13 +2309,13 @@ nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ - if (dev_priv->chipset != 0x50) { + if (device->chipset != 0x50) { xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ xf_emit(ctx, 1, 0); /* 3ff */ } /* XXX: the following block could belong either to unk1cxx, or * to STRMOUT. Rather hard to tell. */ - if (dev_priv->chipset < 0xa0) + if (device->chipset < 0xa0) xf_emit(ctx, 0x25, 0); else xf_emit(ctx, 0x3b, 0); @@ -2343,18 +2324,18 @@ nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */ xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */ } xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */ else xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */ @@ -2365,7 +2346,7 @@ nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx) xf_emit(ctx, 4, 0); /* 000000ff STRMOUT_ADDRESS_HIGH */ xf_emit(ctx, 4, 0); /* ffffffff STRMOUT_ADDRESS_LOW */ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */ } @@ -2385,12 +2366,12 @@ nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */ xf_emit(ctx, 1, 0); /* 00000007 */ xf_emit(ctx, 1, 0); /* 000003ff */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ } @@ -2398,7 +2379,7 @@ nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; /* SEEK */ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ @@ -2416,7 +2397,7 @@ nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 eng2d UNK260 */ xf_emit(ctx, 1, 0); /* ff/3ff */ xf_emit(ctx, 1, 0); /* 00000007 */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ } @@ -2424,11 +2405,11 @@ nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx) static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int magic2; - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { magic2 = 0x00003e60; - } else if (!IS_NVA3F(dev_priv->chipset)) { + } else if (!IS_NVA3F(device->chipset)) { magic2 = 0x001ffe67; } else { magic2 = 0x00087e67; @@ -2446,14 +2427,14 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ - if (dev_priv->chipset >= 0xa0 && !IS_NVAAF(dev_priv->chipset)) + if (device->chipset >= 0xa0 && !IS_NVAAF(device->chipset)) xf_emit(ctx, 1, 0x15); /* 000000ff */ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ @@ -2462,14 +2443,14 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ - if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) { + if (device->chipset == 0x86 || device->chipset == 0x92 || device->chipset == 0x98 || device->chipset >= 0xa0) { xf_emit(ctx, 3, 0); /* ff, ffffffff, ffffffff */ xf_emit(ctx, 1, 4); /* 7 */ xf_emit(ctx, 1, 0x400); /* fffffff */ xf_emit(ctx, 1, 0x300); /* ffff */ xf_emit(ctx, 1, 0x1001); /* 1fff */ - if (dev_priv->chipset != 0xa0) { - if (IS_NVA3F(dev_priv->chipset)) + if (device->chipset != 0xa0) { + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 0); /* 0000000f UNK15C8 */ else xf_emit(ctx, 1, 0x15); /* ff */ @@ -2547,7 +2528,7 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { xf_emit(ctx, 2, 0); xf_emit(ctx, 1, 0x1001); xf_emit(ctx, 0xb, 0); @@ -2564,7 +2545,7 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ xf_emit(ctx, 1, 0x11); /* 3f/7f */ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ - if (dev_priv->chipset != 0x50) { + if (device->chipset != 0x50) { xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */ xf_emit(ctx, 1, 0); /* 000000ff */ } @@ -2581,7 +2562,7 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 0); /* 00000001 tesla UNK12E4 */ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ @@ -2600,7 +2581,7 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 1, 0); /* 00000001 */ xf_emit(ctx, 1, 0); /* 000003ff */ - } else if (dev_priv->chipset >= 0xa0) { + } else if (device->chipset >= 0xa0) { xf_emit(ctx, 2, 0); /* 00000001 */ xf_emit(ctx, 1, 0); /* 00000007 */ xf_emit(ctx, 1, 0); /* 00000003 */ @@ -2614,7 +2595,7 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 4, 0); /* ffffffff CLEAR_COLOR */ xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR A R G B */ xf_emit(ctx, 1, 0); /* 00000fff eng2d UNK2B0 */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 2, 0); /* 00000001 */ xf_emit(ctx, 1, 0); /* 000003ff */ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ @@ -2628,9 +2609,9 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 1, 0); /* 00000001 UNK12E4? NVA3+ only? */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */ @@ -2659,9 +2640,9 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) static void nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int magic3; - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x50: magic3 = 0x1000; break; @@ -2681,16 +2662,16 @@ nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ xf_emit(ctx, 1, 0); /* 111/113[NVA0+] */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 0x1f, 0); /* ffffffff */ - else if (dev_priv->chipset >= 0xa0) + else if (device->chipset >= 0xa0) xf_emit(ctx, 0x0f, 0); /* ffffffff */ else xf_emit(ctx, 0x10, 0); /* fffffff VP_RESULT_MAP_1 up */ xf_emit(ctx, 2, 0); /* f/1f[NVA3], fffffff/ffffffff[NVA0+] */ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 1, 0x03020100); /* ffffffff */ else xf_emit(ctx, 1, 0x00608080); /* fffffff VP_RESULT_MAP_0 */ @@ -2733,11 +2714,11 @@ nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ xf_emit(ctx, 1, 0); /* 111/113 */ - if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96) + if (device->chipset == 0x94 || device->chipset == 0x96) xf_emit(ctx, 0x1020, 0); /* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */ - else if (dev_priv->chipset < 0xa0) + else if (device->chipset < 0xa0) xf_emit(ctx, 0xa20, 0); /* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */ - else if (!IS_NVA3F(dev_priv->chipset)) + else if (!IS_NVA3F(device->chipset)) xf_emit(ctx, 0x210, 0); /* ffffffff */ else xf_emit(ctx, 0x410, 0); /* ffffffff */ @@ -2751,12 +2732,12 @@ nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx) static void nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int magic1, magic2; - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { magic1 = 0x3ff; magic2 = 0x00003e60; - } else if (!IS_NVA3F(dev_priv->chipset)) { + } else if (!IS_NVA3F(device->chipset)) { magic1 = 0x7ff; magic2 = 0x001ffe67; } else { @@ -2766,7 +2747,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ xf_emit(ctx, 1, 0); /* ffffffff ALPHA_TEST_REF */ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000000f UNK16A0 */ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ @@ -2800,11 +2781,11 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 1); /* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */ xf_emit(ctx, 1, 0); /* 00000003 */ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1298 */ - } else if (dev_priv->chipset >= 0xa0) { + } else if (device->chipset >= 0xa0) { xf_emit(ctx, 1, 1); /* 00000001 tesla UNK16B4 */ xf_emit(ctx, 1, 0); /* 00000003 */ } else { @@ -2818,7 +2799,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ @@ -2846,7 +2827,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */ xf_emit(ctx, 1, 0xcf); /* 000000ff DRAW_COLOR_FORMAT */ xf_emit(ctx, 1, 0xcf); /* 000000ff SRC_FORMAT */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ xf_emit(ctx, 1, 0); /* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */ @@ -2870,9 +2851,9 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 1, 0); /* ff */ else xf_emit(ctx, 3, 0); /* 1, 7, 3ff */ @@ -2907,7 +2888,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ xf_emit(ctx, 1, 0); /* 00000007 */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 8, 0); /* 0000ffff DMA_COLOR */ xf_emit(ctx, 1, 0); /* 0000ffff DMA_GLOBAL */ @@ -2945,7 +2926,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ xf_emit(ctx, 1, 0); /* 00000007 */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ @@ -2974,7 +2955,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 0); /* 00000001 */ xf_emit(ctx, 1, 0); /* ffff0ff3 */ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ @@ -2988,14 +2969,14 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */ xf_emit(ctx, 1, 0); /* 7 */ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ } xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ xf_emit(ctx, 1, 0); /* ffff0ff3 */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 1, 0x0fac6881); /* fffffff */ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ @@ -3012,12 +2993,12 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 1, 0); /* 0000000f tesla UNK15C8 */ } xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { xf_emit(ctx, 3, 0); /* 7/f, 1, ffff0ff3 */ xf_emit(ctx, 1, 0xfac6881); /* fffffff */ xf_emit(ctx, 4, 0); /* 1, 1, 1, 3ff */ @@ -3027,7 +3008,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 2, 0); /* 7, f */ xf_emit(ctx, 1, 1); /* 1 */ xf_emit(ctx, 1, 0); /* 7/f */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 0x9, 0); /* 1 */ else xf_emit(ctx, 0x8, 0); /* 1 */ @@ -3041,7 +3022,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0x11); /* 7f */ xf_emit(ctx, 1, 1); /* 1 */ xf_emit(ctx, 5, 0); /* 1, 7, 3ff, 3, 7 */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ } @@ -3051,15 +3032,15 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) static void nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; xf_emit(ctx, 2, 0); /* 1 LINKED_TSC. yes, 2. */ - if (dev_priv->chipset != 0x50) + if (device->chipset != 0x50) xf_emit(ctx, 1, 0); /* 3 */ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DU_DX_INT */ xf_emit(ctx, 1, 0); /* fffff BLIT_DU_DX_FRACT */ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DV_DY_INT */ xf_emit(ctx, 1, 0); /* fffff BLIT_DV_DY_FRACT */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 1, 0); /* 3 BLIT_CONTROL */ else xf_emit(ctx, 2, 0); /* 3ff, 1 */ @@ -3071,13 +3052,13 @@ nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0x10100); /* ffffffff SRC_TIC_5 */ xf_emit(ctx, 1, 0x02800000); /* ffffffff SRC_TIC_6 */ xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_7 */ - if (dev_priv->chipset == 0x50) { + if (device->chipset == 0x50) { xf_emit(ctx, 1, 0); /* 00000001 turing UNK358 */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */ xf_emit(ctx, 1, 0); /* 00000003 turing UNK37C tesla UNK1690 */ xf_emit(ctx, 1, 0); /* 00000003 BLIT_CONTROL */ xf_emit(ctx, 1, 0); /* 00000001 turing UNK32C tesla UNK0F94 */ - } else if (!IS_NVAAF(dev_priv->chipset)) { + } else if (!IS_NVAAF(device->chipset)) { xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */ xf_emit(ctx, 1, 0); /* 00000003 */ xf_emit(ctx, 1, 0); /* 000003ff */ @@ -3097,7 +3078,7 @@ nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx) static void nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ xf_emit(ctx, 2, 0); /* 7, ffff0ff3 */ @@ -3109,7 +3090,7 @@ nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK0F98 */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ @@ -3136,8 +3117,8 @@ nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx) static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; - if (dev_priv->chipset < 0xa0) { + struct nouveau_device *device = ctx->device; + if (device->chipset < 0xa0) { nv50_graph_construct_xfer_unk84xx(ctx); nv50_graph_construct_xfer_tprop(ctx); nv50_graph_construct_xfer_tex(ctx); @@ -3153,9 +3134,9 @@ nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx) static void nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i, mpcnt = 2; - switch (dev_priv->chipset) { + switch (device->chipset) { case 0x98: case 0xaa: mpcnt = 1; @@ -3182,34 +3163,34 @@ nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0x80); /* ffffffff tesla UNK1404 */ xf_emit(ctx, 1, 0x80007004); /* ffffffff tesla UNK12B0 */ xf_emit(ctx, 1, 0x04000400); /* ffffffff */ - if (dev_priv->chipset >= 0xa0) + if (device->chipset >= 0xa0) xf_emit(ctx, 1, 0xc0); /* 00007fff tesla UNK152C */ xf_emit(ctx, 1, 0x1000); /* 0000ffff tesla UNK0D60 */ xf_emit(ctx, 1, 0); /* ff/3ff */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ - if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset == 0xa8 || IS_NVAAF(dev_priv->chipset)) { + if (device->chipset == 0x86 || device->chipset == 0x98 || device->chipset == 0xa8 || IS_NVAAF(device->chipset)) { xf_emit(ctx, 1, 0xe00); /* 7fff */ xf_emit(ctx, 1, 0x1e00); /* 7fff */ } xf_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP */ xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 2, 0x1000); /* 7fff tesla UNK141C */ xf_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP */ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */ - if (IS_NVAAF(dev_priv->chipset)) + if (IS_NVAAF(device->chipset)) xf_emit(ctx, 0xb, 0); /* RO */ - else if (dev_priv->chipset >= 0xa0) + else if (device->chipset >= 0xa0) xf_emit(ctx, 0xc, 0); /* RO */ else xf_emit(ctx, 0xa, 0); /* RO */ } xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ xf_emit(ctx, 1, 0); /* ff/3ff */ - if (dev_priv->chipset >= 0xa0) { + if (device->chipset >= 0xa0) { xf_emit(ctx, 1, 0x1fe21); /* 0003ffff tesla UNK0FAC */ } xf_emit(ctx, 3, 0); /* 7fff, 0, 0 */ @@ -3223,7 +3204,7 @@ nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */ xf_emit(ctx, 1, 0x1fe21); /* 1ffff/3ffff[NVA0+] tesla UNk0FAC */ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ xf_emit(ctx, 1, 0); /* ff/3ff */ xf_emit(ctx, 1, 0); /* 1 LINKED_TSC */ @@ -3238,7 +3219,7 @@ nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000007 */ xf_emit(ctx, 1, 0xfac6881); /* 0fffffff RT_CONTROL */ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */ - if (IS_NVA3F(dev_priv->chipset)) + if (IS_NVA3F(device->chipset)) xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ @@ -3253,7 +3234,7 @@ nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ - if (IS_NVA3F(dev_priv->chipset)) { + if (IS_NVA3F(device->chipset)) { xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */ @@ -3268,11 +3249,11 @@ nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */ xf_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */ /* XXX: demagic this part some day */ - if (dev_priv->chipset == 0x50) + if (device->chipset == 0x50) xf_emit(ctx, 0x3a0, 0); - else if (dev_priv->chipset < 0x94) + else if (device->chipset < 0x94) xf_emit(ctx, 0x3a2, 0); - else if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa) + else if (device->chipset == 0x98 || device->chipset == 0xaa) xf_emit(ctx, 0x39f, 0); else xf_emit(ctx, 0x3a3, 0); @@ -3285,15 +3266,15 @@ nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx) { - struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct nouveau_device *device = ctx->device; int i; - uint32_t offset; - uint32_t units = nv_rd32 (ctx->dev, 0x1540); + u32 offset; + u32 units = nv_rd32 (ctx->device, 0x1540); int size = 0; offset = (ctx->ctxvals_pos+0x3f)&~0x3f; - if (dev_priv->chipset < 0xa0) { + if (device->chipset < 0xa0) { for (i = 0; i < 8; i++) { ctx->ctxvals_pos = offset + i; /* that little bugger belongs to csched. No idea diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c index b19a406..c12e766 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c @@ -22,13 +22,10 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include <core/mm.h> #include "nvc0.h" void -nv_icmd(struct drm_device *priv, u32 icmd, u32 data) +nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data) { nv_wr32(priv, 0x400204, data); nv_wr32(priv, 0x400200, icmd); @@ -36,21 +33,22 @@ nv_icmd(struct drm_device *priv, u32 icmd, u32 data) } int -nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv, - struct nvc0_grctx *info) +nvc0_grctx_init(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { + struct nouveau_bar *bar = nouveau_bar(priv); + struct nouveau_object *parent = nv_object(priv); struct nouveau_gpuobj *chan; - u32 size = (0x80000 + oprv->size + 4095) & ~4095; + u32 size = (0x80000 + priv->size + 4095) & ~4095; int ret, i; /* allocate memory to for a "channel", which we'll use to generate * the default context values */ - ret = nouveau_gpuobj_new(priv, NULL, size, 0x1000, + ret = nouveau_gpuobj_new(parent, NULL, size, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &info->chan); chan = info->chan; if (ret) { - NV_ERROR(priv, "failed to allocate channel memory, %d\n", ret); + nv_error(priv, "failed to allocate channel memory, %d\n", ret); return ret; } @@ -75,32 +73,31 @@ nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv, nv_wo32(chan, 0x0210, 0x00080004); nv_wo32(chan, 0x0214, 0x00000000); - nvimem_flush(priv); + bar->flush(bar); nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8); nv_wr32(priv, 0x100cbc, 0x80000001); nv_wait(priv, 0x100c80, 0x00008000, 0x00008000); /* setup default state for mmio list construction */ - info->dev = priv; - info->data = oprv->mmio_data; - info->mmio = oprv->mmio_list; + info->data = priv->mmio_data; + info->mmio = priv->mmio_list; info->addr = 0x2000 + (i * 8); - info->priv = oprv; + info->priv = priv; info->buffer_nr = 0; - if (oprv->firmware) { + if (priv->firmware) { nv_wr32(priv, 0x409840, 0x00000030); nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12); nv_wr32(priv, 0x409504, 0x00000003); if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010)) - NV_ERROR(priv, "load_ctx timeout\n"); + nv_error(priv, "load_ctx timeout\n"); nv_wo32(chan, 0x8001c, 1); nv_wo32(chan, 0x80020, 0); nv_wo32(chan, 0x80028, 0); nv_wo32(chan, 0x8002c, 0); - nvimem_flush(priv); + bar->flush(bar); return 0; } @@ -109,7 +106,7 @@ nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv, nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12); nv_wr32(priv, 0x409504, 0x00000001); if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) { - NV_ERROR(priv, "HUB_SET_CHAN timeout\n"); + nv_error(priv, "HUB_SET_CHAN timeout\n"); nvc0_graph_ctxctl_debug(priv); nouveau_gpuobj_ref(NULL, &info->chan); return -EBUSY; @@ -135,6 +132,8 @@ nvc0_grctx_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access) void nvc0_grctx_mmio(struct nvc0_grctx *info, u32 addr, u32 data, u32 shift, u32 buf) { + struct nvc0_graph_priv *priv = info->priv; + info->mmio->addr = addr; info->mmio->data = data; info->mmio->shift = shift; @@ -143,7 +142,7 @@ nvc0_grctx_mmio(struct nvc0_grctx *info, u32 addr, u32 data, u32 shift, u32 buf) if (shift) data |= info->buffer[buf] >> shift; - nv_wr32(info->dev, addr, data); + nv_wr32(priv, addr, data); } int @@ -153,11 +152,11 @@ nvc0_grctx_fini(struct nvc0_grctx *info) int i; if (priv->firmware) { - nv_wr32(info->dev, 0x409840, 0x00000003); - nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12); - nv_wr32(info->dev, 0x409504, 0x00000009); - if (!nv_wait(info->dev, 0x409800, 0x00000001, 0x00000000)) { - NV_ERROR(info->dev, "unload_ctx timeout\n"); + nv_wr32(priv, 0x409840, 0x00000003); + nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12); + nv_wr32(priv, 0x409504, 0x00000009); + if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000000)) { + nv_error(priv, "unload_ctx timeout\n"); return -EBUSY; } @@ -165,12 +164,12 @@ nvc0_grctx_fini(struct nvc0_grctx *info) } /* HUB_FUC(CTX_SAVE) */ - nv_wr32(info->dev, 0x409840, 0x80000000); - nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12); - nv_wr32(info->dev, 0x409504, 0x00000002); - if (!nv_wait(info->dev, 0x409800, 0x80000000, 0x80000000)) { - NV_ERROR(info->dev, "HUB_CTX_SAVE timeout\n"); - nvc0_graph_ctxctl_debug(info->dev); + nv_wr32(priv, 0x409840, 0x80000000); + nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12); + nv_wr32(priv, 0x409504, 0x00000002); + if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) { + nv_error(priv, "HUB_CTX_SAVE timeout\n"); + nvc0_graph_ctxctl_debug(priv); return -EBUSY; } @@ -186,7 +185,7 @@ save: } static void -nvc0_grctx_generate_9097(struct drm_device *priv) +nvc0_grctx_generate_9097(struct nvc0_graph_priv *priv) { u32 fermi = nvc0_graph_class(priv); u32 mthd; @@ -1343,7 +1342,7 @@ nvc0_grctx_generate_9097(struct drm_device *priv) } static void -nvc0_grctx_generate_9197(struct drm_device *priv) +nvc0_grctx_generate_9197(struct nvc0_graph_priv *priv) { u32 fermi = nvc0_graph_class(priv); u32 mthd; @@ -1356,7 +1355,7 @@ nvc0_grctx_generate_9197(struct drm_device *priv) } static void -nvc0_grctx_generate_9297(struct drm_device *priv) +nvc0_grctx_generate_9297(struct nvc0_graph_priv *priv) { u32 fermi = nvc0_graph_class(priv); u32 mthd; @@ -1374,7 +1373,7 @@ nvc0_grctx_generate_9297(struct drm_device *priv) } static void -nvc0_grctx_generate_902d(struct drm_device *priv) +nvc0_grctx_generate_902d(struct nvc0_graph_priv *priv) { nv_mthd(priv, 0x902d, 0x0200, 0x000000cf); nv_mthd(priv, 0x902d, 0x0204, 0x00000001); @@ -1396,7 +1395,7 @@ nvc0_grctx_generate_902d(struct drm_device *priv) } static void -nvc0_grctx_generate_9039(struct drm_device *priv) +nvc0_grctx_generate_9039(struct nvc0_graph_priv *priv) { nv_mthd(priv, 0x9039, 0x030c, 0x00000000); nv_mthd(priv, 0x9039, 0x0310, 0x00000000); @@ -1409,12 +1408,11 @@ nvc0_grctx_generate_9039(struct drm_device *priv) } static void -nvc0_grctx_generate_90c0(struct drm_device *priv) +nvc0_grctx_generate_90c0(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = priv->dev_private; int i; - for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) { + for (i = 0; nv_device(priv)->chipset == 0xd9 && i < 4; i++) { nv_mthd(priv, 0x90c0, 0x2700 + (i * 0x40), 0x00000000); nv_mthd(priv, 0x90c0, 0x2720 + (i * 0x40), 0x00000000); nv_mthd(priv, 0x90c0, 0x2704 + (i * 0x40), 0x00000000); @@ -1430,7 +1428,7 @@ nvc0_grctx_generate_90c0(struct drm_device *priv) nv_mthd(priv, 0x90c0, 0x27ac, 0x00000000); nv_mthd(priv, 0x90c0, 0x27cc, 0x00000000); nv_mthd(priv, 0x90c0, 0x27ec, 0x00000000); - for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) { + for (i = 0; nv_device(priv)->chipset == 0xd9 && i < 4; i++) { nv_mthd(priv, 0x90c0, 0x2710 + (i * 0x40), 0x00014000); nv_mthd(priv, 0x90c0, 0x2730 + (i * 0x40), 0x00014000); nv_mthd(priv, 0x90c0, 0x2714 + (i * 0x40), 0x00000040); @@ -1458,7 +1456,7 @@ nvc0_grctx_generate_90c0(struct drm_device *priv) } static void -nvc0_grctx_generate_dispatch(struct drm_device *priv) +nvc0_grctx_generate_dispatch(struct nvc0_graph_priv *priv) { int i; @@ -1511,7 +1509,7 @@ nvc0_grctx_generate_dispatch(struct drm_device *priv) } static void -nvc0_grctx_generate_macro(struct drm_device *priv) +nvc0_grctx_generate_macro(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x404404, 0x00000000); nv_wr32(priv, 0x404408, 0x00000000); @@ -1536,7 +1534,7 @@ nvc0_grctx_generate_macro(struct drm_device *priv) } static void -nvc0_grctx_generate_m2mf(struct drm_device *priv) +nvc0_grctx_generate_m2mf(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x404604, 0x00000015); nv_wr32(priv, 0x404608, 0x00000000); @@ -1600,7 +1598,7 @@ nvc0_grctx_generate_m2mf(struct drm_device *priv) } static void -nvc0_grctx_generate_unk47xx(struct drm_device *priv) +nvc0_grctx_generate_unk47xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x404700, 0x00000000); nv_wr32(priv, 0x404704, 0x00000000); @@ -1627,16 +1625,15 @@ nvc0_grctx_generate_unk47xx(struct drm_device *priv) } static void -nvc0_grctx_generate_shaders(struct drm_device *priv) +nvc0_grctx_generate_shaders(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = priv->dev_private; - if (dev_priv->chipset == 0xd9) { + if (nv_device(priv)->chipset == 0xd9) { nv_wr32(priv, 0x405800, 0x0f8000bf); nv_wr32(priv, 0x405830, 0x02180218); nv_wr32(priv, 0x405834, 0x08000000); } else - if (dev_priv->chipset == 0xc1) { + if (nv_device(priv)->chipset == 0xc1) { nv_wr32(priv, 0x405800, 0x0f8000bf); nv_wr32(priv, 0x405830, 0x02180218); nv_wr32(priv, 0x405834, 0x00000000); @@ -1657,7 +1654,7 @@ nvc0_grctx_generate_shaders(struct drm_device *priv) } static void -nvc0_grctx_generate_unk60xx(struct drm_device *priv) +nvc0_grctx_generate_unk60xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x406020, 0x000103c1); nv_wr32(priv, 0x406028, 0x00000001); @@ -1667,25 +1664,24 @@ nvc0_grctx_generate_unk60xx(struct drm_device *priv) } static void -nvc0_grctx_generate_unk64xx(struct drm_device *priv) +nvc0_grctx_generate_unk64xx(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = priv->dev_private; nv_wr32(priv, 0x4064a8, 0x00000000); nv_wr32(priv, 0x4064ac, 0x00003fff); nv_wr32(priv, 0x4064b4, 0x00000000); nv_wr32(priv, 0x4064b8, 0x00000000); - if (dev_priv->chipset == 0xd9) + if (nv_device(priv)->chipset == 0xd9) nv_wr32(priv, 0x4064bc, 0x00000000); - if (dev_priv->chipset == 0xc1 || - dev_priv->chipset == 0xd9) { + if (nv_device(priv)->chipset == 0xc1 || + nv_device(priv)->chipset == 0xd9) { nv_wr32(priv, 0x4064c0, 0x80140078); nv_wr32(priv, 0x4064c4, 0x0086ffff); } } static void -nvc0_grctx_generate_tpbus(struct drm_device *priv) +nvc0_grctx_generate_tpbus(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x407804, 0x00000023); nv_wr32(priv, 0x40780c, 0x0a418820); @@ -1698,7 +1694,7 @@ nvc0_grctx_generate_tpbus(struct drm_device *priv) } static void -nvc0_grctx_generate_ccache(struct drm_device *priv) +nvc0_grctx_generate_ccache(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x408000, 0x00000000); nv_wr32(priv, 0x408004, 0x00000000); @@ -1711,10 +1707,9 @@ nvc0_grctx_generate_ccache(struct drm_device *priv) } static void -nvc0_grctx_generate_rop(struct drm_device *priv) +nvc0_grctx_generate_rop(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = priv->dev_private; - int chipset = dev_priv->chipset; + int chipset = nv_device(priv)->chipset; /* ROPC_BROADCAST */ nv_wr32(priv, 0x408800, 0x02802a3c); @@ -1741,10 +1736,9 @@ nvc0_grctx_generate_rop(struct drm_device *priv) } static void -nvc0_grctx_generate_gpc(struct drm_device *priv) +nvc0_grctx_generate_gpc(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = priv->dev_private; - int chipset = dev_priv->chipset; + int chipset = nv_device(priv)->chipset; int i; /* GPC_BROADCAST */ @@ -1834,10 +1828,9 @@ nvc0_grctx_generate_gpc(struct drm_device *priv) } static void -nvc0_grctx_generate_tp(struct drm_device *priv) +nvc0_grctx_generate_tp(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = priv->dev_private; - int chipset = dev_priv->chipset; + int chipset = nv_device(priv)->chipset; /* GPC_BROADCAST.TP_BROADCAST */ nv_wr32(priv, 0x419818, 0x00000000); @@ -1876,7 +1869,7 @@ nvc0_grctx_generate_tp(struct drm_device *priv) nv_wr32(priv, 0x419c04, 0x00000006); nv_wr32(priv, 0x419c08, 0x00000002); nv_wr32(priv, 0x419c20, 0x00000000); - if (dev_priv->chipset == 0xd9) { + if (nv_device(priv)->chipset == 0xd9) { nv_wr32(priv, 0x419c24, 0x00084210); nv_wr32(priv, 0x419c28, 0x3cf3cf3c); nv_wr32(priv, 0x419cb0, 0x00020048); @@ -1929,16 +1922,14 @@ nvc0_grctx_generate_tp(struct drm_device *priv) } int -nvc0_grctx_generate(struct drm_device *priv) +nvc0_grctx_generate(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = priv->dev_private; - struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR); struct nvc0_grctx info; int ret, i, gpc, tpc, id; u32 fermi = nvc0_graph_class(priv); u32 r000260, tmp; - ret = nvc0_grctx_init(priv, oprv, &info); + ret = nvc0_grctx_init(priv, &info); if (ret) return ret; @@ -1975,11 +1966,11 @@ nvc0_grctx_generate(struct drm_device *priv) mmio_list(0x419008, 0x00000000, 0, 0); mmio_list(0x418808, 0x00000000, 8, 0); mmio_list(0x41880c, 0x80000018, 0, 0); - if (dev_priv->chipset != 0xc1) { + if (nv_device(priv)->chipset != 0xc1) { tmp = 0x02180000; mmio_list(0x405830, tmp, 0, 0); - for (gpc = 0; gpc < oprv->gpc_nr; gpc++) { - for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { u32 reg = TPC_UNIT(gpc, tpc, 0x0520); mmio_list(reg, tmp, 0, 0); tmp += 0x0324; @@ -1989,13 +1980,13 @@ nvc0_grctx_generate(struct drm_device *priv) tmp = 0x02180000; mmio_list(0x405830, 0x00000218 | tmp, 0, 0); mmio_list(0x4064c4, 0x0086ffff, 0, 0); - for (gpc = 0; gpc < oprv->gpc_nr; gpc++) { - for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { u32 reg = TPC_UNIT(gpc, tpc, 0x0520); mmio_list(reg, 0x10000000 | tmp, 0, 0); tmp += 0x0324; } - for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) { + for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { u32 reg = TPC_UNIT(gpc, tpc, 0x0544); mmio_list(reg, tmp, 0, 0); tmp += 0x0324; @@ -2004,8 +1995,8 @@ nvc0_grctx_generate(struct drm_device *priv) } for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < oprv->gpc_nr; gpc++) { - if (tpc < oprv->tpc_nr[gpc]) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + if (tpc < priv->tpc_nr[gpc]) { nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id); nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); @@ -2013,14 +2004,14 @@ nvc0_grctx_generate(struct drm_device *priv) id++; } - nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), oprv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); } } tmp = 0; - for (i = 0; i < oprv->gpc_nr; i++) - tmp |= oprv->tpc_nr[i] << (i * 4); + for (i = 0; i < priv->gpc_nr; i++) + tmp |= priv->tpc_nr[i] << (i * 4); nv_wr32(priv, 0x406028, tmp); nv_wr32(priv, 0x405870, tmp); @@ -2034,13 +2025,13 @@ nvc0_grctx_generate(struct drm_device *priv) if (1) { u8 tpcnr[GPC_MAX], data[TPC_MAX]; - memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr)); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); memset(data, 0x1f, sizeof(data)); gpc = -1; - for (tpc = 0; tpc < oprv->tpc_total; tpc++) { + for (tpc = 0; tpc < priv->tpc_total; tpc++) { do { - gpc = (gpc + 1) % oprv->gpc_nr; + gpc = (gpc + 1) % priv->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; data[tpc] = gpc; @@ -2056,12 +2047,12 @@ nvc0_grctx_generate(struct drm_device *priv) u8 shift, ntpcv; /* calculate first set of magics */ - memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr)); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); gpc = -1; - for (tpc = 0; tpc < oprv->tpc_total; tpc++) { + for (tpc = 0; tpc < priv->tpc_total; tpc++) { do { - gpc = (gpc + 1) % oprv->gpc_nr; + gpc = (gpc + 1) % priv->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; @@ -2073,7 +2064,7 @@ nvc0_grctx_generate(struct drm_device *priv) /* and the second... */ shift = 0; - ntpcv = oprv->tpc_total; + ntpcv = priv->tpc_total; while (!(ntpcv & (1 << 4))) { ntpcv <<= 1; shift++; @@ -2086,22 +2077,22 @@ nvc0_grctx_generate(struct drm_device *priv) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* GPC_BROADCAST */ - nv_wr32(priv, 0x418bb8, (oprv->tpc_total << 8) | - oprv->magic_not_rop_nr); + nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | + priv->magic_not_rop_nr); for (i = 0; i < 6; i++) nv_wr32(priv, 0x418b08 + (i * 4), data[i]); /* GPC_BROADCAST.TP_BROADCAST */ - nv_wr32(priv, 0x419bd0, (oprv->tpc_total << 8) | - oprv->magic_not_rop_nr | + nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) | + priv->magic_not_rop_nr | data2[0]); nv_wr32(priv, 0x419be4, data2[1]); for (i = 0; i < 6; i++) nv_wr32(priv, 0x419b00 + (i * 4), data[i]); /* UNK78xx */ - nv_wr32(priv, 0x4078bc, (oprv->tpc_total << 8) | - oprv->magic_not_rop_nr); + nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | + priv->magic_not_rop_nr); for (i = 0; i < 6; i++) nv_wr32(priv, 0x40780c + (i * 4), data[i]); } @@ -2110,18 +2101,18 @@ nvc0_grctx_generate(struct drm_device *priv) u32 tpc_mask = 0, tpc_set = 0; u8 tpcnr[GPC_MAX], a, b; - memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr)); - for (gpc = 0; gpc < oprv->gpc_nr; gpc++) - tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + for (gpc = 0; gpc < priv->gpc_nr; gpc++) + tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8); for (i = 0, gpc = -1, b = -1; i < 32; i++) { - a = (i * (oprv->tpc_total - 1)) / 32; + a = (i * (priv->tpc_total - 1)) / 32; if (a != b) { b = a; do { - gpc = (gpc + 1) % oprv->gpc_nr; + gpc = (gpc + 1) % priv->gpc_nr; } while (!tpcnr[gpc]); - tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; tpc_set |= 1 << ((gpc * 8) + tpc); } @@ -2232,7 +2223,7 @@ nvc0_grctx_generate(struct drm_device *priv) nv_icmd(priv, 0x00000215, 0x00000040); nv_icmd(priv, 0x00000216, 0x00000040); nv_icmd(priv, 0x00000217, 0x00000040); - if (dev_priv->chipset == 0xd9) { + if (nv_device(priv)->chipset == 0xd9) { for (i = 0x0400; i <= 0x0417; i++) nv_icmd(priv, i, 0x00000040); } @@ -2244,7 +2235,7 @@ nvc0_grctx_generate(struct drm_device *priv) nv_icmd(priv, 0x0000021d, 0x0000c080); nv_icmd(priv, 0x0000021e, 0x0000c080); nv_icmd(priv, 0x0000021f, 0x0000c080); - if (dev_priv->chipset == 0xd9) { + if (nv_device(priv)->chipset == 0xd9) { for (i = 0x0440; i <= 0x0457; i++) nv_icmd(priv, i, 0x0000c080); } @@ -2810,8 +2801,8 @@ nvc0_grctx_generate(struct drm_device *priv) nv_icmd(priv, 0x0000053f, 0xffff0000); nv_icmd(priv, 0x00000585, 0x0000003f); nv_icmd(priv, 0x00000576, 0x00000003); - if (dev_priv->chipset == 0xc1 || - dev_priv->chipset == 0xd9) + if (nv_device(priv)->chipset == 0xc1 || + nv_device(priv)->chipset == 0xd9) nv_icmd(priv, 0x0000057b, 0x00000059); nv_icmd(priv, 0x00000586, 0x00000040); nv_icmd(priv, 0x00000582, 0x00000080); @@ -2913,7 +2904,7 @@ nvc0_grctx_generate(struct drm_device *priv) nv_icmd(priv, 0x00000957, 0x00000003); nv_icmd(priv, 0x0000095e, 0x20164010); nv_icmd(priv, 0x0000095f, 0x00000020); - if (dev_priv->chipset == 0xd9) + if (nv_device(priv)->chipset == 0xd9) nv_icmd(priv, 0x0000097d, 0x00000020); nv_icmd(priv, 0x00000683, 0x00000006); nv_icmd(priv, 0x00000685, 0x003fffff); @@ -3056,5 +3047,6 @@ nvc0_grctx_generate(struct drm_device *priv) nvc0_grctx_generate_90c0(priv); nv_wr32(priv, 0x000260, r000260); + return nvc0_grctx_fini(&info); } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c index e550317..6d8c639 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c @@ -22,13 +22,10 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include <core/mm.h> #include "nvc0.h" static void -nve0_grctx_generate_icmd(struct drm_device *priv) +nve0_grctx_generate_icmd(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x400208, 0x80000000); nv_icmd(priv, 0x001000, 0x00000004); @@ -916,7 +913,7 @@ nve0_grctx_generate_icmd(struct drm_device *priv) } static void -nve0_grctx_generate_a097(struct drm_device *priv) +nve0_grctx_generate_a097(struct nvc0_graph_priv *priv) { nv_mthd(priv, 0xa097, 0x0800, 0x00000000); nv_mthd(priv, 0xa097, 0x0840, 0x00000000); @@ -2146,7 +2143,7 @@ nve0_grctx_generate_a097(struct drm_device *priv) } static void -nve0_grctx_generate_902d(struct drm_device *priv) +nve0_grctx_generate_902d(struct nvc0_graph_priv *priv) { nv_mthd(priv, 0x902d, 0x0200, 0x000000cf); nv_mthd(priv, 0x902d, 0x0204, 0x00000001); @@ -2169,7 +2166,7 @@ nve0_grctx_generate_902d(struct drm_device *priv) } static void -nve0_graph_generate_unk40xx(struct drm_device *priv) +nve0_graph_generate_unk40xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x404010, 0x0); nv_wr32(priv, 0x404014, 0x0); @@ -2213,7 +2210,7 @@ nve0_graph_generate_unk40xx(struct drm_device *priv) } static void -nve0_graph_generate_unk44xx(struct drm_device *priv) +nve0_graph_generate_unk44xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x404404, 0x0); nv_wr32(priv, 0x404408, 0x0); @@ -2238,7 +2235,7 @@ nve0_graph_generate_unk44xx(struct drm_device *priv) } static void -nve0_graph_generate_unk46xx(struct drm_device *priv) +nve0_graph_generate_unk46xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x404604, 0x14); nv_wr32(priv, 0x404608, 0x0); @@ -2278,7 +2275,7 @@ nve0_graph_generate_unk46xx(struct drm_device *priv) } static void -nve0_graph_generate_unk47xx(struct drm_device *priv) +nve0_graph_generate_unk47xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x404700, 0x0); nv_wr32(priv, 0x404704, 0x0); @@ -2299,7 +2296,7 @@ nve0_graph_generate_unk47xx(struct drm_device *priv) } static void -nve0_graph_generate_unk58xx(struct drm_device *priv) +nve0_graph_generate_unk58xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x405800, 0xf8000bf); nv_wr32(priv, 0x405830, 0x2180648); @@ -2318,7 +2315,7 @@ nve0_graph_generate_unk58xx(struct drm_device *priv) } static void -nve0_graph_generate_unk60xx(struct drm_device *priv) +nve0_graph_generate_unk60xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x406020, 0x4103c1); nv_wr32(priv, 0x406028, 0x1); @@ -2328,7 +2325,7 @@ nve0_graph_generate_unk60xx(struct drm_device *priv) } static void -nve0_graph_generate_unk64xx(struct drm_device *priv) +nve0_graph_generate_unk64xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x4064a8, 0x0); nv_wr32(priv, 0x4064ac, 0x3fff); @@ -2350,13 +2347,13 @@ nve0_graph_generate_unk64xx(struct drm_device *priv) } static void -nve0_graph_generate_unk70xx(struct drm_device *priv) +nve0_graph_generate_unk70xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x407040, 0x0); } static void -nve0_graph_generate_unk78xx(struct drm_device *priv) +nve0_graph_generate_unk78xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x407804, 0x23); nv_wr32(priv, 0x40780c, 0xa418820); @@ -2369,7 +2366,7 @@ nve0_graph_generate_unk78xx(struct drm_device *priv) } static void -nve0_graph_generate_unk80xx(struct drm_device *priv) +nve0_graph_generate_unk80xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x408000, 0x0); nv_wr32(priv, 0x408004, 0x0); @@ -2382,7 +2379,7 @@ nve0_graph_generate_unk80xx(struct drm_device *priv) } static void -nve0_graph_generate_unk88xx(struct drm_device *priv) +nve0_graph_generate_unk88xx(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x408800, 0x2802a3c); nv_wr32(priv, 0x408804, 0x40); @@ -2395,7 +2392,7 @@ nve0_graph_generate_unk88xx(struct drm_device *priv) } static void -nve0_graph_generate_gpc(struct drm_device *priv) +nve0_graph_generate_gpc(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x418380, 0x16); nv_wr32(priv, 0x418400, 0x38004e00); @@ -2521,7 +2518,7 @@ nve0_graph_generate_gpc(struct drm_device *priv) } static void -nve0_graph_generate_tpc(struct drm_device *priv) +nve0_graph_generate_tpc(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x419848, 0x0); nv_wr32(priv, 0x419864, 0x129); @@ -2586,7 +2583,7 @@ nve0_graph_generate_tpc(struct drm_device *priv) } static void -nve0_graph_generate_tpcunk(struct drm_device *priv) +nve0_graph_generate_tpcunk(struct nvc0_graph_priv *priv) { nv_wr32(priv, 0x41be24, 0x6); nv_wr32(priv, 0x41bec0, 0x12180000); @@ -2604,9 +2601,8 @@ nve0_graph_generate_tpcunk(struct drm_device *priv) } int -nve0_grctx_generate(struct drm_device *priv) +nve0_grctx_generate(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR); struct nvc0_grctx info; int ret, i, gpc, tpc, id; u32 data[6] = {}, data2[2] = {}, tmp; @@ -2615,7 +2611,7 @@ nve0_grctx_generate(struct drm_device *priv) u8 tpcnr[GPC_MAX], a, b; u8 shift, ntpcv; - ret = nvc0_grctx_init(priv, oprv, &info); + ret = nvc0_grctx_init(priv, &info); if (ret) return ret; @@ -2657,17 +2653,17 @@ nve0_grctx_generate(struct drm_device *priv) mmio_list(0x419848, 0x10000000, 12, 2); mmio_list(0x405830, 0x02180648, 0, 0); mmio_list(0x4064c4, 0x0192ffff, 0, 0); - for (gpc = 0, offset = 0; gpc < oprv->gpc_nr; gpc++) { - u16 magic0 = 0x0218 * oprv->tpc_nr[gpc]; - u16 magic1 = 0x0648 * oprv->tpc_nr[gpc]; + for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) { + u16 magic0 = 0x0218 * priv->tpc_nr[gpc]; + u16 magic1 = 0x0648 * priv->tpc_nr[gpc]; magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset; magic[gpc][1] = 0x00000000 | (magic1 << 16); - offset += 0x0324 * oprv->tpc_nr[gpc]; + offset += 0x0324 * priv->tpc_nr[gpc]; } - for (gpc = 0; gpc < oprv->gpc_nr; gpc++) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0); mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0); - offset += 0x07ff * oprv->tpc_nr[gpc]; + offset += 0x07ff * priv->tpc_nr[gpc]; } mmio_list(0x17e91c, 0x06060609, 0, 0); mmio_list(0x17e920, 0x00090a05, 0, 0); @@ -2680,22 +2676,22 @@ nve0_grctx_generate(struct drm_device *priv) nv_wr32(priv, 0x419c00, 0xa); for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < oprv->gpc_nr; gpc++) { - if (tpc < oprv->tpc_nr[gpc]) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + if (tpc < priv->tpc_nr[gpc]) { nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0698), id); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x04e8), id); nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0088), id++); } - nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), oprv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); } } tmp = 0; - for (i = 0; i < oprv->gpc_nr; i++) - tmp |= oprv->tpc_nr[i] << (i * 4); + for (i = 0; i < priv->gpc_nr; i++) + tmp |= priv->tpc_nr[i] << (i * 4); nv_wr32(priv, 0x406028, tmp); nv_wr32(priv, 0x405870, tmp); @@ -2707,12 +2703,12 @@ nve0_grctx_generate(struct drm_device *priv) nv_wr32(priv, 0x40587c, 0x0); /* calculate first set of magics */ - memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr)); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); gpc = -1; - for (tpc = 0; tpc < oprv->tpc_total; tpc++) { + for (tpc = 0; tpc < priv->tpc_total; tpc++) { do { - gpc = (gpc + 1) % oprv->gpc_nr; + gpc = (gpc + 1) % priv->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; @@ -2724,7 +2720,7 @@ nve0_grctx_generate(struct drm_device *priv) /* and the second... */ shift = 0; - ntpcv = oprv->tpc_total; + ntpcv = priv->tpc_total; while (!(ntpcv & (1 << 4))) { ntpcv <<= 1; shift++; @@ -2733,13 +2729,13 @@ nve0_grctx_generate(struct drm_device *priv) data2[0] = ntpcv << 16; data2[0] |= shift << 21; data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24); - data2[0] |= oprv->tpc_total << 8; - data2[0] |= oprv->magic_not_rop_nr; + data2[0] |= priv->tpc_total << 8; + data2[0] |= priv->magic_not_rop_nr; for (i = 1; i < 7; i++) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* and write it all the various parts of PGRAPH */ - nv_wr32(priv, 0x418bb8, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr); + nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | priv->magic_not_rop_nr); for (i = 0; i < 6; i++) nv_wr32(priv, 0x418b08 + (i * 4), data[i]); @@ -2748,23 +2744,23 @@ nve0_grctx_generate(struct drm_device *priv) for (i = 0; i < 6; i++) nv_wr32(priv, 0x41bf00 + (i * 4), data[i]); - nv_wr32(priv, 0x4078bc, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr); + nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | priv->magic_not_rop_nr); for (i = 0; i < 6; i++) nv_wr32(priv, 0x40780c + (i * 4), data[i]); - memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr)); - for (gpc = 0; gpc < oprv->gpc_nr; gpc++) - tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + for (gpc = 0; gpc < priv->gpc_nr; gpc++) + tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8); for (i = 0, gpc = -1, b = -1; i < 32; i++) { - a = (i * (oprv->tpc_total - 1)) / 32; + a = (i * (priv->tpc_total - 1)) / 32; if (a != b) { b = a; do { - gpc = (gpc + 1) % oprv->gpc_nr; + gpc = (gpc + 1) % priv->gpc_nr; } while (!tpcnr[gpc]); - tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; tpc_set |= 1 << ((gpc * 8) + tpc); } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c index 7f3a275..e5b0189 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c @@ -22,19 +22,22 @@ * DEALINGS IN THE SOFTWARE. */ -#include "drmP.h" -#include "drm.h" -#include <nouveau_drm.h> -#include "nouveau_drv.h" -#include "nouveau_hw.h" -#include "nouveau_util.h" -#include <core/ramht.h> - -struct nv04_graph_engine { - struct nouveau_exec_engine base; -}; +#include <core/os.h> +#include <core/class.h> +#include <core/handle.h> +#include <core/namedb.h> + +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/timer.h> + +#include <engine/fifo.h> +#include <engine/graph.h> -static uint32_t nv04_graph_ctx_regs[] = { +#include "regs.h" + +static u32 +nv04_graph_ctx_regs[] = { 0x0040053c, 0x00400544, 0x00400540, @@ -348,205 +351,28 @@ static uint32_t nv04_graph_ctx_regs[] = { NV04_PGRAPH_DEBUG_3 }; -struct graph_state { - uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; +struct nv04_graph_priv { + struct nouveau_graph base; + struct nv04_graph_chan *chan[16]; + spinlock_t lock; }; -static struct nouveau_channel * -nv04_graph_channel(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int chid = 15; - - if (nv_rd32(dev, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) - chid = nv_rd32(dev, NV04_PGRAPH_CTX_USER) >> 24; - - if (chid > 15) - return NULL; - - return dev_priv->channels.ptr[chid]; -} - -static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) { - if (nv04_graph_ctx_regs[i] == reg) - return &ctx->nv04[i]; - } - - return NULL; -} - -static int -nv04_graph_load_context(struct nouveau_channel *chan) -{ - struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; - struct drm_device *dev = chan->dev; - uint32_t tmp; - int i; - - for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) - nv_wr32(dev, nv04_graph_ctx_regs[i], pgraph_ctx->nv04[i]); - - nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10010100); - - tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff; - nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp | chan->id << 24); - - tmp = nv_rd32(dev, NV04_PGRAPH_FFINTFC_ST2); - nv_wr32(dev, NV04_PGRAPH_FFINTFC_ST2, tmp & 0x000fffff); - - return 0; -} - -static int -nv04_graph_unload_context(struct drm_device *dev) -{ - struct nouveau_channel *chan = NULL; - struct graph_state *ctx; - uint32_t tmp; - int i; - - chan = nv04_graph_channel(dev); - if (!chan) - return 0; - ctx = chan->engctx[NVOBJ_ENGINE_GR]; - - for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) - ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]); - - nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10000000); - tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff; - tmp |= 15 << 24; - nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp); - return 0; -} - -static int -nv04_graph_context_new(struct nouveau_channel *chan, int engine) -{ - struct graph_state *pgraph_ctx; - NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id); - - pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL); - if (pgraph_ctx == NULL) - return -ENOMEM; - - *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; - - chan->engctx[engine] = pgraph_ctx; - return 0; -} - -static void -nv04_graph_context_del(struct nouveau_channel *chan, int engine) -{ - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct graph_state *pgraph_ctx = chan->engctx[engine]; - unsigned long flags; - - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - - /* Unload the context if it's the currently active one */ - if (nv04_graph_channel(dev) == chan) - nv04_graph_unload_context(dev); - - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - - /* Free the context resources */ - kfree(pgraph_ctx); - chan->engctx[engine] = NULL; -} - -int -nv04_graph_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) -{ - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *obj = NULL; - int ret; - - ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); - if (ret) - return ret; - obj->engine = 1; - obj->class = class; - -#ifdef __BIG_ENDIAN - nv_wo32(obj, 0x00, 0x00080000 | class); -#else - nv_wo32(obj, 0x00, class); -#endif - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); +struct nv04_graph_chan { + struct nouveau_object base; + int chid; + u32 nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; +}; - ret = nouveau_ramht_insert(chan, handle, obj); - nouveau_gpuobj_ref(NULL, &obj); - return ret; -} -static int -nv04_graph_init(struct drm_device *dev, int engine) +static inline struct nv04_graph_priv * +nv04_graph_priv(struct nv04_graph_chan *chan) { - uint32_t tmp; - - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & - ~NV_PMC_ENABLE_PGRAPH); - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | - NV_PMC_ENABLE_PGRAPH); - - /* Enable PGRAPH interrupts */ - nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF); - nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(dev, NV04_PGRAPH_VALID1, 0); - nv_wr32(dev, NV04_PGRAPH_VALID2, 0); - /*nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x000001FF); - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000); - /*1231C000 blob, 001 haiku*/ - /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ - nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100); - /*0x72111100 blob , 01 haiku*/ - /*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ - nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f071); - /*haiku same*/ - - /*nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ - nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); - /*haiku and blob 10d4*/ - - nv_wr32(dev, NV04_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL , 0x10000100); - tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff; - tmp |= 15 << 24; - nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp); - - /* These don't belong here, they're part of a per-channel context */ - nv_wr32(dev, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); - nv_wr32(dev, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); - - return 0; + return (void *)nv_object(chan)->engine; } -static int -nv04_graph_fini(struct drm_device *dev, int engine, bool suspend) -{ - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) { - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - return -EBUSY; - } - nv04_graph_unload_context(dev); - nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); - return 0; -} +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ /* * Software methods, why they are needed, and how they all work: @@ -623,37 +449,35 @@ nv04_graph_fini(struct drm_device *dev, int engine, bool suspend) */ static void -nv04_graph_set_ctx1(struct nouveau_channel *chan, u32 mask, u32 value) +nv04_graph_set_ctx1(struct nouveau_object *object, u32 mask, u32 value) { - struct drm_device *dev = chan->dev; - u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; - int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; + struct nv04_graph_priv *priv = (void *)object->engine; + int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; u32 tmp; - tmp = nv_ri32(dev, instance); + tmp = nv_ro32(object, 0x00); tmp &= ~mask; tmp |= value; + nv_wo32(object, 0x00, tmp); - nv_wi32(dev, instance, tmp); - nv_wr32(dev, NV04_PGRAPH_CTX_SWITCH1, tmp); - nv_wr32(dev, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); + nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp); + nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); } static void -nv04_graph_set_ctx_val(struct nouveau_channel *chan, u32 mask, u32 value) +nv04_graph_set_ctx_val(struct nouveau_object *object, u32 mask, u32 value) { - struct drm_device *dev = chan->dev; - u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; - u32 tmp, ctx1; int class, op, valid = 1; + u32 tmp, ctx1; - ctx1 = nv_ri32(dev, instance); + ctx1 = nv_ro32(object, 0x00); class = ctx1 & 0xff; op = (ctx1 >> 15) & 7; - tmp = nv_ri32(dev, instance + 0xc); + + tmp = nv_ro32(object, 0x0c); tmp &= ~mask; tmp |= value; - nv_wi32(dev, instance + 0xc, tmp); + nv_wo32(object, 0x0c, tmp); /* check for valid surf2d/surf_dst/surf_color */ if (!(tmp & 0x02000000)) @@ -685,30 +509,34 @@ nv04_graph_set_ctx_val(struct nouveau_channel *chan, u32 mask, u32 value) break; } - nv04_graph_set_ctx1(chan, 0x01000000, valid << 24); + nv04_graph_set_ctx1(object, 0x01000000, valid << 24); } static int -nv04_graph_mthd_set_operation(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_set_operation(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { + u32 class = nv_ro32(object, 0) & 0xff; + u32 data = *(u32 *)args; if (data > 5) return 1; /* Old versions of the objects only accept first three operations. */ if (data > 2 && class < 0x40) return 1; - nv04_graph_set_ctx1(chan, 0x00038000, data << 15); + nv04_graph_set_ctx1(object, 0x00038000, data << 15); /* changing operation changes set of objects needed for validation */ - nv04_graph_set_ctx_val(chan, 0, 0); + nv04_graph_set_ctx_val(object, 0, 0); return 0; } static int -nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_surf3d_clip_h(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - uint32_t min = data & 0xffff, max; - uint32_t w = data >> 16; + struct nv04_graph_priv *priv = (void *)object->engine; + u32 data = *(u32 *)args; + u32 min = data & 0xffff, max; + u32 w = data >> 16; if (min & 0x8000) /* too large */ return 1; @@ -717,17 +545,19 @@ nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(chan->dev, 0x40053c, min); - nv_wr32(chan->dev, 0x400544, max); + nv_wr32(priv, 0x40053c, min); + nv_wr32(priv, 0x400544, max); return 0; } static int -nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_surf3d_clip_v(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - uint32_t min = data & 0xffff, max; - uint32_t w = data >> 16; + struct nv04_graph_priv *priv = (void *)object->engine; + u32 data = *(u32 *)args; + u32 min = data & 0xffff, max; + u32 w = data >> 16; if (min & 0x8000) /* too large */ return 1; @@ -736,223 +566,661 @@ nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(chan->dev, 0x400540, min); - nv_wr32(chan->dev, 0x400548, max); + nv_wr32(priv, 0x400540, min); + nv_wr32(priv, 0x400548, max); return 0; } +static u16 +nv04_graph_mthd_bind_class(struct nouveau_object *object, u32 *args, u32 size) +{ + struct nouveau_instmem *imem = nouveau_instmem(object); + u32 inst = *(u32 *)args << 4; + return nv_ro32(imem, inst); +} + static int -nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_surf2d(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx1(chan, 0x00004000, 0); - nv04_graph_set_ctx_val(chan, 0x02000000, 0); + nv04_graph_set_ctx1(object, 0x00004000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0); return 0; case 0x42: - nv04_graph_set_ctx1(chan, 0x00004000, 0); - nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000); + nv04_graph_set_ctx1(object, 0x00004000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx1(chan, 0x00004000, 0); - nv04_graph_set_ctx_val(chan, 0x02000000, 0); + nv04_graph_set_ctx1(object, 0x00004000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0); return 0; case 0x42: - nv04_graph_set_ctx1(chan, 0x00004000, 0); - nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000); + nv04_graph_set_ctx1(object, 0x00004000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); return 0; case 0x52: - nv04_graph_set_ctx1(chan, 0x00004000, 0x00004000); - nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000); + nv04_graph_set_ctx1(object, 0x00004000, 0x00004000); + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv01_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x08000000, 0); + nv04_graph_set_ctx_val(object, 0x08000000, 0); return 0; case 0x18: - nv04_graph_set_ctx_val(chan, 0x08000000, 0x08000000); + nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x08000000, 0); + nv04_graph_set_ctx_val(object, 0x08000000, 0); return 0; case 0x44: - nv04_graph_set_ctx_val(chan, 0x08000000, 0x08000000); + nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_rop(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x10000000, 0); + nv04_graph_set_ctx_val(object, 0x10000000, 0); return 0; case 0x43: - nv04_graph_set_ctx_val(chan, 0x10000000, 0x10000000); + nv04_graph_set_ctx_val(object, 0x10000000, 0x10000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_beta1(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x20000000, 0); + nv04_graph_set_ctx_val(object, 0x20000000, 0); return 0; case 0x12: - nv04_graph_set_ctx_val(chan, 0x20000000, 0x20000000); + nv04_graph_set_ctx_val(object, 0x20000000, 0x20000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_beta4(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x40000000, 0); + nv04_graph_set_ctx_val(object, 0x40000000, 0); return 0; case 0x72: - nv04_graph_set_ctx_val(chan, 0x40000000, 0x40000000); + nv04_graph_set_ctx_val(object, 0x40000000, 0x40000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_surf_dst(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x02000000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0); return 0; case 0x58: - nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000); + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_surf_src(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x04000000, 0); + nv04_graph_set_ctx_val(object, 0x04000000, 0); return 0; case 0x59: - nv04_graph_set_ctx_val(chan, 0x04000000, 0x04000000); + nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_surf_color(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x02000000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0); return 0; case 0x5a: - nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000); + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv04_graph_mthd_bind_surf_zeta(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx_val(chan, 0x04000000, 0); + nv04_graph_set_ctx_val(object, 0x04000000, 0); return 0; case 0x5b: - nv04_graph_set_ctx_val(chan, 0x04000000, 0x04000000); + nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000); return 0; } return 1; } static int -nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv01_graph_mthd_bind_clip(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx1(chan, 0x2000, 0); + nv04_graph_set_ctx1(object, 0x2000, 0); return 0; case 0x19: - nv04_graph_set_ctx1(chan, 0x2000, 0x2000); + nv04_graph_set_ctx1(object, 0x2000, 0x2000); return 0; } return 1; } static int -nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +nv01_graph_mthd_bind_chroma(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { + switch (nv04_graph_mthd_bind_class(object, args, size)) { case 0x30: - nv04_graph_set_ctx1(chan, 0x1000, 0); + nv04_graph_set_ctx1(object, 0x1000, 0); return 0; /* Yes, for some reason even the old versions of objects * accept 0x57 and not 0x17. Consistency be damned. */ case 0x57: - nv04_graph_set_ctx1(chan, 0x1000, 0x1000); + nv04_graph_set_ctx1(object, 0x1000, 0x1000); return 0; } return 1; } -static struct nouveau_bitfield nv04_graph_intr[] = { +static struct nouveau_omthds +nv03_graph_gdi_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_patt }, + { 0x0188, nv04_graph_mthd_bind_rop }, + { 0x018c, nv04_graph_mthd_bind_beta1 }, + { 0x0190, nv04_graph_mthd_bind_surf_dst }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_gdi_omthds[] = { + { 0x0188, nv04_graph_mthd_bind_patt }, + { 0x018c, nv04_graph_mthd_bind_rop }, + { 0x0190, nv04_graph_mthd_bind_beta1 }, + { 0x0194, nv04_graph_mthd_bind_beta4 }, + { 0x0198, nv04_graph_mthd_bind_surf2d }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv01_graph_blit_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_chroma }, + { 0x0188, nv01_graph_mthd_bind_clip }, + { 0x018c, nv01_graph_mthd_bind_patt }, + { 0x0190, nv04_graph_mthd_bind_rop }, + { 0x0194, nv04_graph_mthd_bind_beta1 }, + { 0x0198, nv04_graph_mthd_bind_surf_dst }, + { 0x019c, nv04_graph_mthd_bind_surf_src }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_blit_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_chroma }, + { 0x0188, nv01_graph_mthd_bind_clip }, + { 0x018c, nv04_graph_mthd_bind_patt }, + { 0x0190, nv04_graph_mthd_bind_rop }, + { 0x0194, nv04_graph_mthd_bind_beta1 }, + { 0x0198, nv04_graph_mthd_bind_beta4 }, + { 0x019c, nv04_graph_mthd_bind_surf2d }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_iifc_omthds[] = { + { 0x0188, nv01_graph_mthd_bind_chroma }, + { 0x018c, nv01_graph_mthd_bind_clip }, + { 0x0190, nv04_graph_mthd_bind_patt }, + { 0x0194, nv04_graph_mthd_bind_rop }, + { 0x0198, nv04_graph_mthd_bind_beta1 }, + { 0x019c, nv04_graph_mthd_bind_beta4 }, + { 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf }, + { 0x03e4, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv01_graph_ifc_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_chroma }, + { 0x0188, nv01_graph_mthd_bind_clip }, + { 0x018c, nv01_graph_mthd_bind_patt }, + { 0x0190, nv04_graph_mthd_bind_rop }, + { 0x0194, nv04_graph_mthd_bind_beta1 }, + { 0x0198, nv04_graph_mthd_bind_surf_dst }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_ifc_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_chroma }, + { 0x0188, nv01_graph_mthd_bind_clip }, + { 0x018c, nv04_graph_mthd_bind_patt }, + { 0x0190, nv04_graph_mthd_bind_rop }, + { 0x0194, nv04_graph_mthd_bind_beta1 }, + { 0x0198, nv04_graph_mthd_bind_beta4 }, + { 0x019c, nv04_graph_mthd_bind_surf2d }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv03_graph_sifc_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_chroma }, + { 0x0188, nv01_graph_mthd_bind_patt }, + { 0x018c, nv04_graph_mthd_bind_rop }, + { 0x0190, nv04_graph_mthd_bind_beta1 }, + { 0x0194, nv04_graph_mthd_bind_surf_dst }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_sifc_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_chroma }, + { 0x0188, nv04_graph_mthd_bind_patt }, + { 0x018c, nv04_graph_mthd_bind_rop }, + { 0x0190, nv04_graph_mthd_bind_beta1 }, + { 0x0194, nv04_graph_mthd_bind_beta4 }, + { 0x0198, nv04_graph_mthd_bind_surf2d }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv03_graph_sifm_omthds[] = { + { 0x0188, nv01_graph_mthd_bind_patt }, + { 0x018c, nv04_graph_mthd_bind_rop }, + { 0x0190, nv04_graph_mthd_bind_beta1 }, + { 0x0194, nv04_graph_mthd_bind_surf_dst }, + { 0x0304, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_sifm_omthds[] = { + { 0x0188, nv04_graph_mthd_bind_patt }, + { 0x018c, nv04_graph_mthd_bind_rop }, + { 0x0190, nv04_graph_mthd_bind_beta1 }, + { 0x0194, nv04_graph_mthd_bind_beta4 }, + { 0x0198, nv04_graph_mthd_bind_surf2d }, + { 0x0304, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_surf3d_omthds[] = { + { 0x02f8, nv04_graph_mthd_surf3d_clip_h }, + { 0x02fc, nv04_graph_mthd_surf3d_clip_v }, + {} +}; + +static struct nouveau_omthds +nv03_graph_ttri_omthds[] = { + { 0x0188, nv01_graph_mthd_bind_clip }, + { 0x018c, nv04_graph_mthd_bind_surf_color }, + { 0x0190, nv04_graph_mthd_bind_surf_zeta }, + {} +}; + +static struct nouveau_omthds +nv01_graph_prim_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_clip }, + { 0x0188, nv01_graph_mthd_bind_patt }, + { 0x018c, nv04_graph_mthd_bind_rop }, + { 0x0190, nv04_graph_mthd_bind_beta1 }, + { 0x0194, nv04_graph_mthd_bind_surf_dst }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static struct nouveau_omthds +nv04_graph_prim_omthds[] = { + { 0x0184, nv01_graph_mthd_bind_clip }, + { 0x0188, nv04_graph_mthd_bind_patt }, + { 0x018c, nv04_graph_mthd_bind_rop }, + { 0x0190, nv04_graph_mthd_bind_beta1 }, + { 0x0194, nv04_graph_mthd_bind_beta4 }, + { 0x0198, nv04_graph_mthd_bind_surf2d }, + { 0x02fc, nv04_graph_mthd_set_operation }, + {} +}; + +static int +nv04_graph_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_gpuobj *obj; + int ret; + + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent, + 16, 16, 0, &obj); + *pobject = nv_object(obj); + if (ret) + return ret; + + nv_wo32(obj, 0x00, nv_mclass(obj)); +#ifdef __BIG_ENDIAN + nv_mo32(obj, 0x00, 0x00080000, 0x00080000); +#endif + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); + nv_wo32(obj, 0x0c, 0x00000000); + return 0; +} + +struct nouveau_ofuncs +nv04_graph_ofuncs = { + .ctor = nv04_graph_object_ctor, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, +}; + +static struct nouveau_oclass +nv04_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs }, /* beta1 */ + { 0x0017, &nv04_graph_ofuncs }, /* chroma */ + { 0x0018, &nv04_graph_ofuncs }, /* pattern (nv01) */ + { 0x0019, &nv04_graph_ofuncs }, /* clip */ + { 0x001c, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* line */ + { 0x001d, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* tri */ + { 0x001e, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* rect */ + { 0x001f, &nv04_graph_ofuncs, nv01_graph_blit_omthds }, + { 0x0021, &nv04_graph_ofuncs, nv01_graph_ifc_omthds }, + { 0x0030, &nv04_graph_ofuncs }, /* null */ + { 0x0036, &nv04_graph_ofuncs, nv03_graph_sifc_omthds }, + { 0x0037, &nv04_graph_ofuncs, nv03_graph_sifm_omthds }, + { 0x0038, &nv04_graph_ofuncs }, /* dvd subpicture */ + { 0x0039, &nv04_graph_ofuncs }, /* m2mf */ + { 0x0042, &nv04_graph_ofuncs }, /* surf2d */ + { 0x0043, &nv04_graph_ofuncs }, /* rop */ + { 0x0044, &nv04_graph_ofuncs }, /* pattern */ + { 0x0048, &nv04_graph_ofuncs, nv03_graph_ttri_omthds }, + { 0x004a, &nv04_graph_ofuncs, nv04_graph_gdi_omthds }, + { 0x004b, &nv04_graph_ofuncs, nv03_graph_gdi_omthds }, + { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */ + { 0x0053, &nv04_graph_ofuncs, nv04_graph_surf3d_omthds }, + { 0x0054, &nv04_graph_ofuncs }, /* ttri */ + { 0x0055, &nv04_graph_ofuncs }, /* mtri */ + { 0x0057, &nv04_graph_ofuncs }, /* chroma */ + { 0x0058, &nv04_graph_ofuncs }, /* surf_dst */ + { 0x0059, &nv04_graph_ofuncs }, /* surf_src */ + { 0x005a, &nv04_graph_ofuncs }, /* surf_color */ + { 0x005b, &nv04_graph_ofuncs }, /* surf_zeta */ + { 0x005c, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* line */ + { 0x005d, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* tri */ + { 0x005e, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* rect */ + { 0x005f, &nv04_graph_ofuncs, nv04_graph_blit_omthds }, + { 0x0060, &nv04_graph_ofuncs, nv04_graph_iifc_omthds }, + { 0x0061, &nv04_graph_ofuncs, nv04_graph_ifc_omthds }, + { 0x0064, &nv04_graph_ofuncs }, /* iifc (nv05) */ + { 0x0065, &nv04_graph_ofuncs }, /* ifc (nv05) */ + { 0x0066, &nv04_graph_ofuncs }, /* sifc (nv05) */ + { 0x0072, &nv04_graph_ofuncs }, /* beta4 */ + { 0x0076, &nv04_graph_ofuncs, nv04_graph_sifc_omthds }, + { 0x0077, &nv04_graph_ofuncs, nv04_graph_sifm_omthds }, + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static struct nv04_graph_chan * +nv04_graph_channel(struct nv04_graph_priv *priv) +{ + struct nv04_graph_chan *chan = NULL; + if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) { + int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24; + if (chid < ARRAY_SIZE(priv->chan)) + chan = priv->chan[chid]; + } + return chan; +} + +static int +nv04_graph_load_context(struct nv04_graph_chan *chan, int chid) +{ + struct nv04_graph_priv *priv = nv04_graph_priv(chan); + int i; + + for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) + nv_wr32(priv, nv04_graph_ctx_regs[i], chan->nv04[i]); + + nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100); + nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000); + return 0; +} + +static int +nv04_graph_unload_context(struct nv04_graph_chan *chan) +{ + struct nv04_graph_priv *priv = nv04_graph_priv(chan); + int i; + + for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) + chan->nv04[i] = nv_rd32(priv, nv04_graph_ctx_regs[i]); + + nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000); + nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + return 0; +} + +static void +nv04_graph_context_switch(struct nv04_graph_priv *priv) +{ + struct nv04_graph_chan *prev = NULL; + struct nv04_graph_chan *next = NULL; + unsigned long flags; + int chid; + + spin_lock_irqsave(&priv->lock, flags); + nv04_graph_idle(priv); + + /* If previous context is valid, we need to save it */ + prev = nv04_graph_channel(priv); + if (prev) + nv04_graph_unload_context(prev); + + /* load context for next channel */ + chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f; + next = priv->chan[chid]; + if (next) + nv04_graph_load_context(next, chid); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static u32 *ctx_reg(struct nv04_graph_chan *chan, u32 reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) { + if (nv04_graph_ctx_regs[i] == reg) + return &chan->nv04[i]; + } + + return NULL; +} + +static int +nv04_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_fifo_chan *fifo = (void *)parent; + struct nv04_graph_priv *priv = (void *)engine; + struct nv04_graph_chan *chan; + unsigned long flags; + int ret; + + ret = nouveau_object_create(parent, engine, oclass, 0, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->chan[fifo->chid]) { + *pobject = nv_object(priv->chan[fifo->chid]); + atomic_inc(&(*pobject)->refcount); + spin_unlock_irqrestore(&priv->lock, flags); + nouveau_object_destroy(&chan->base); + return 1; + } + + *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; + + priv->chan[fifo->chid] = chan; + chan->chid = fifo->chid; + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static void +nv04_graph_context_dtor(struct nouveau_object *object) +{ + struct nv04_graph_priv *priv = (void *)object->engine; + struct nv04_graph_chan *chan = (void *)object; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + priv->chan[chan->chid] = NULL; + spin_unlock_irqrestore(&priv->lock, flags); + + nouveau_object_destroy(&chan->base); +} + +static int +nv04_graph_context_fini(struct nouveau_object *object, bool suspend) +{ + struct nv04_graph_priv *priv = (void *)object->engine; + struct nv04_graph_chan *chan = (void *)object; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + if (nv04_graph_channel(priv) == chan) + nv04_graph_unload_context(chan); + nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&priv->lock, flags); + + return nouveau_object_fini(&chan->base, suspend); +} + +static struct nouveau_oclass +nv04_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_graph_context_ctor, + .dtor = nv04_graph_context_dtor, + .init = nouveau_object_init, + .fini = nv04_graph_context_fini, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +bool +nv04_graph_idle(void *obj) +{ + struct nouveau_graph *graph = nouveau_graph(obj); + u32 mask = 0xffffffff; + + if (nv_device(obj)->card_type == NV_40) + mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL; + + if (!nv_wait(graph, NV04_PGRAPH_STATUS, mask, 0)) { + nv_error(graph, "idle timed out with status 0x%08x\n", + nv_rd32(graph, NV04_PGRAPH_STATUS)); + return false; + } + + return true; +} + +static struct nouveau_bitfield +nv04_graph_intr_name[] = { { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, {} }; -static struct nouveau_bitfield nv04_graph_nstatus[] = { +static struct nouveau_bitfield +nv04_graph_nstatus[] = { { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, @@ -960,7 +1228,8 @@ static struct nouveau_bitfield nv04_graph_nstatus[] = { {} }; -struct nouveau_bitfield nv04_graph_nsource[] = { +struct nouveau_bitfield +nv04_graph_nsource[] = { { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" }, { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" }, { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" }, @@ -984,343 +1253,135 @@ struct nouveau_bitfield nv04_graph_nsource[] = { }; static void -nv04_graph_context_switch(struct drm_device *dev) +nv04_graph_intr(struct nouveau_subdev *subdev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = NULL; - int chid; - - nouveau_wait_for_idle(dev); - - /* If previous context is valid, we need to save it */ - nv04_graph_unload_context(dev); + struct nv04_graph_priv *priv = (void *)subdev; + struct nv04_graph_chan *chan = NULL; + struct nouveau_namedb *namedb = NULL; + struct nouveau_handle *handle = NULL; + u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + u32 chid = (addr & 0x0f000000) >> 24; + u32 subc = (addr & 0x0000e000) >> 13; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff; + u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4; + u32 show = stat; + unsigned long flags; - /* Load context for next channel */ - chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & - NV03_PFIFO_CACHE1_PUSH1_CHID_MASK; - chan = dev_priv->channels.ptr[chid]; + spin_lock_irqsave(&priv->lock, flags); + chan = priv->chan[chid]; if (chan) - nv04_graph_load_context(chan); -} - -static void -nv04_graph_isr(struct drm_device *dev) -{ - u32 stat; - - while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { - u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); - u32 chid = (addr & 0x0f000000) >> 24; - u32 subc = (addr & 0x0000e000) >> 13; - u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff; - u32 show = stat; - - if (stat & NV_PGRAPH_INTR_NOTIFY) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) - show &= ~NV_PGRAPH_INTR_NOTIFY; - } + namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); + spin_unlock_irqrestore(&priv->lock, flags); + + if (stat & NV_PGRAPH_INTR_NOTIFY) { + if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { + handle = nouveau_namedb_get_vinst(namedb, inst); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~NV_PGRAPH_INTR_NOTIFY; } + } - if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); - stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - nv04_graph_context_switch(dev); - } + if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { + nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + nv04_graph_context_switch(priv); + } - nv_wr32(dev, NV03_PGRAPH_INTR, stat); - nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); - - if (show && nouveau_ratelimit()) { - NV_INFO(dev, "PGRAPH -"); - nouveau_bitfield_print(nv04_graph_intr, show); - printk(" nsource:"); - nouveau_bitfield_print(nv04_graph_nsource, nsource); - printk(" nstatus:"); - nouveau_bitfield_print(nv04_graph_nstatus, nstatus); - printk("\n"); - NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " - "mthd 0x%04x data 0x%08x\n", - chid, subc, class, mthd, data); - } + nv_wr32(priv, NV03_PGRAPH_INTR, stat); + nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + + if (show) { + nv_error(priv, ""); + nouveau_bitfield_print(nv04_graph_intr_name, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv04_graph_nstatus, nstatus); + printk("\n"); + nv_error(priv, "ch %d/%d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, subc, class, mthd, data); } + + nouveau_namedb_put(handle); } -static void -nv04_graph_destroy(struct drm_device *dev, int engine) +static int +nv04_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv04_graph_engine *pgraph = nv_engine(dev, engine); + struct nv04_graph_priv *priv; + int ret; - nouveau_irq_unregister(dev, 12); + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - NVOBJ_ENGINE_DEL(dev, GR); - kfree(pgraph); + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv04_graph_intr; + nv_engine(priv)->cclass = &nv04_graph_cclass; + nv_engine(priv)->sclass = nv04_graph_sclass; + spin_lock_init(&priv->lock); + return 0; } -int -nv04_graph_create(struct drm_device *dev) +static int +nv04_graph_init(struct nouveau_object *object) { - struct nv04_graph_engine *pgraph; - - pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); - if (!pgraph) - return -ENOMEM; - - pgraph->base.destroy = nv04_graph_destroy; - pgraph->base.init = nv04_graph_init; - pgraph->base.fini = nv04_graph_fini; - pgraph->base.context_new = nv04_graph_context_new; - pgraph->base.context_del = nv04_graph_context_del; - pgraph->base.object_new = nv04_graph_object_new; - - NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); - nouveau_irq_register(dev, 12, nv04_graph_isr); - - /* dvd subpicture */ - NVOBJ_CLASS(dev, 0x0038, GR); - - /* m2mf */ - NVOBJ_CLASS(dev, 0x0039, GR); - - /* nv03 gdirect */ - NVOBJ_CLASS(dev, 0x004b, GR); - NVOBJ_MTHD (dev, 0x004b, 0x0184, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x004b, 0x0188, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x004b, 0x018c, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x004b, 0x0190, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x004b, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 gdirect */ - NVOBJ_CLASS(dev, 0x004a, GR); - NVOBJ_MTHD (dev, 0x004a, 0x0188, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x004a, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x004a, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x004a, 0x0194, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x004a, 0x0198, nv04_graph_mthd_bind_surf2d); - NVOBJ_MTHD (dev, 0x004a, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv01 imageblit */ - NVOBJ_CLASS(dev, 0x001f, GR); - NVOBJ_MTHD (dev, 0x001f, 0x0184, nv04_graph_mthd_bind_chroma); - NVOBJ_MTHD (dev, 0x001f, 0x0188, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x001f, 0x018c, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x001f, 0x0190, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x001f, 0x0194, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x001f, 0x0198, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x001f, 0x019c, nv04_graph_mthd_bind_surf_src); - NVOBJ_MTHD (dev, 0x001f, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 imageblit */ - NVOBJ_CLASS(dev, 0x005f, GR); - NVOBJ_MTHD (dev, 0x005f, 0x0184, nv04_graph_mthd_bind_chroma); - NVOBJ_MTHD (dev, 0x005f, 0x0188, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x005f, 0x018c, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x005f, 0x0190, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x005f, 0x0194, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x005f, 0x0198, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x005f, 0x019c, nv04_graph_mthd_bind_surf2d); - NVOBJ_MTHD (dev, 0x005f, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 iifc */ - NVOBJ_CLASS(dev, 0x0060, GR); - NVOBJ_MTHD (dev, 0x0060, 0x0188, nv04_graph_mthd_bind_chroma); - NVOBJ_MTHD (dev, 0x0060, 0x018c, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x0060, 0x0190, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x0060, 0x0194, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x0060, 0x0198, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x0060, 0x019c, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x0060, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf); - NVOBJ_MTHD (dev, 0x0060, 0x03e4, nv04_graph_mthd_set_operation); - - /* nv05 iifc */ - NVOBJ_CLASS(dev, 0x0064, GR); - - /* nv01 ifc */ - NVOBJ_CLASS(dev, 0x0021, GR); - NVOBJ_MTHD (dev, 0x0021, 0x0184, nv04_graph_mthd_bind_chroma); - NVOBJ_MTHD (dev, 0x0021, 0x0188, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x0021, 0x018c, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x0021, 0x0190, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x0021, 0x0194, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x0021, 0x0198, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x0021, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 ifc */ - NVOBJ_CLASS(dev, 0x0061, GR); - NVOBJ_MTHD (dev, 0x0061, 0x0184, nv04_graph_mthd_bind_chroma); - NVOBJ_MTHD (dev, 0x0061, 0x0188, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x0061, 0x018c, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x0061, 0x0190, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x0061, 0x0194, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x0061, 0x0198, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x0061, 0x019c, nv04_graph_mthd_bind_surf2d); - NVOBJ_MTHD (dev, 0x0061, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv05 ifc */ - NVOBJ_CLASS(dev, 0x0065, GR); - - /* nv03 sifc */ - NVOBJ_CLASS(dev, 0x0036, GR); - NVOBJ_MTHD (dev, 0x0036, 0x0184, nv04_graph_mthd_bind_chroma); - NVOBJ_MTHD (dev, 0x0036, 0x0188, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x0036, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x0036, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x0036, 0x0194, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x0036, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 sifc */ - NVOBJ_CLASS(dev, 0x0076, GR); - NVOBJ_MTHD (dev, 0x0076, 0x0184, nv04_graph_mthd_bind_chroma); - NVOBJ_MTHD (dev, 0x0076, 0x0188, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x0076, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x0076, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x0076, 0x0194, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x0076, 0x0198, nv04_graph_mthd_bind_surf2d); - NVOBJ_MTHD (dev, 0x0076, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv05 sifc */ - NVOBJ_CLASS(dev, 0x0066, GR); - - /* nv03 sifm */ - NVOBJ_CLASS(dev, 0x0037, GR); - NVOBJ_MTHD (dev, 0x0037, 0x0188, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x0037, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x0037, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x0037, 0x0194, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x0037, 0x0304, nv04_graph_mthd_set_operation); - - /* nv04 sifm */ - NVOBJ_CLASS(dev, 0x0077, GR); - NVOBJ_MTHD (dev, 0x0077, 0x0188, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x0077, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x0077, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x0077, 0x0194, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x0077, 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf); - NVOBJ_MTHD (dev, 0x0077, 0x0304, nv04_graph_mthd_set_operation); - - /* null */ - NVOBJ_CLASS(dev, 0x0030, GR); - - /* surf2d */ - NVOBJ_CLASS(dev, 0x0042, GR); - - /* rop */ - NVOBJ_CLASS(dev, 0x0043, GR); - - /* beta1 */ - NVOBJ_CLASS(dev, 0x0012, GR); - - /* beta4 */ - NVOBJ_CLASS(dev, 0x0072, GR); - - /* cliprect */ - NVOBJ_CLASS(dev, 0x0019, GR); - - /* nv01 pattern */ - NVOBJ_CLASS(dev, 0x0018, GR); - - /* nv04 pattern */ - NVOBJ_CLASS(dev, 0x0044, GR); - - /* swzsurf */ - NVOBJ_CLASS(dev, 0x0052, GR); - - /* surf3d */ - NVOBJ_CLASS(dev, 0x0053, GR); - NVOBJ_MTHD (dev, 0x0053, 0x02f8, nv04_graph_mthd_surf3d_clip_h); - NVOBJ_MTHD (dev, 0x0053, 0x02fc, nv04_graph_mthd_surf3d_clip_v); - - /* nv03 tex_tri */ - NVOBJ_CLASS(dev, 0x0048, GR); - NVOBJ_MTHD (dev, 0x0048, 0x0188, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x0048, 0x018c, nv04_graph_mthd_bind_surf_color); - NVOBJ_MTHD (dev, 0x0048, 0x0190, nv04_graph_mthd_bind_surf_zeta); - - /* tex_tri */ - NVOBJ_CLASS(dev, 0x0054, GR); - - /* multitex_tri */ - NVOBJ_CLASS(dev, 0x0055, GR); - - /* nv01 chroma */ - NVOBJ_CLASS(dev, 0x0017, GR); - - /* nv04 chroma */ - NVOBJ_CLASS(dev, 0x0057, GR); - - /* surf_dst */ - NVOBJ_CLASS(dev, 0x0058, GR); - - /* surf_src */ - NVOBJ_CLASS(dev, 0x0059, GR); - - /* surf_color */ - NVOBJ_CLASS(dev, 0x005a, GR); - - /* surf_zeta */ - NVOBJ_CLASS(dev, 0x005b, GR); - - /* nv01 line */ - NVOBJ_CLASS(dev, 0x001c, GR); - NVOBJ_MTHD (dev, 0x001c, 0x0184, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x001c, 0x0188, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x001c, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x001c, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x001c, 0x0194, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x001c, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 line */ - NVOBJ_CLASS(dev, 0x005c, GR); - NVOBJ_MTHD (dev, 0x005c, 0x0184, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x005c, 0x0188, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x005c, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x005c, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x005c, 0x0194, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x005c, 0x0198, nv04_graph_mthd_bind_surf2d); - NVOBJ_MTHD (dev, 0x005c, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv01 tri */ - NVOBJ_CLASS(dev, 0x001d, GR); - NVOBJ_MTHD (dev, 0x001d, 0x0184, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x001d, 0x0188, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x001d, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x001d, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x001d, 0x0194, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x001d, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 tri */ - NVOBJ_CLASS(dev, 0x005d, GR); - NVOBJ_MTHD (dev, 0x005d, 0x0184, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x005d, 0x0188, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x005d, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x005d, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x005d, 0x0194, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x005d, 0x0198, nv04_graph_mthd_bind_surf2d); - NVOBJ_MTHD (dev, 0x005d, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv01 rect */ - NVOBJ_CLASS(dev, 0x001e, GR); - NVOBJ_MTHD (dev, 0x001e, 0x0184, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x001e, 0x0188, nv04_graph_mthd_bind_nv01_patt); - NVOBJ_MTHD (dev, 0x001e, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x001e, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x001e, 0x0194, nv04_graph_mthd_bind_surf_dst); - NVOBJ_MTHD (dev, 0x001e, 0x02fc, nv04_graph_mthd_set_operation); - - /* nv04 rect */ - NVOBJ_CLASS(dev, 0x005e, GR); - NVOBJ_MTHD (dev, 0x005e, 0x0184, nv04_graph_mthd_bind_clip); - NVOBJ_MTHD (dev, 0x005e, 0x0188, nv04_graph_mthd_bind_nv04_patt); - NVOBJ_MTHD (dev, 0x005e, 0x018c, nv04_graph_mthd_bind_rop); - NVOBJ_MTHD (dev, 0x005e, 0x0190, nv04_graph_mthd_bind_beta1); - NVOBJ_MTHD (dev, 0x005e, 0x0194, nv04_graph_mthd_bind_beta4); - NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d); - NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation); + struct nouveau_engine *engine = nv_engine(object); + struct nv04_graph_priv *priv = (void *)engine; + int ret; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + /* Enable PGRAPH interrupts */ + nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF); + nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nv_wr32(priv, NV04_PGRAPH_VALID1, 0); + nv_wr32(priv, NV04_PGRAPH_VALID2, 0); + /*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF); + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000); + /*1231C000 blob, 001 haiku*/ + /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ + nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100); + /*0x72111100 blob , 01 haiku*/ + /*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ + nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071); + /*haiku same*/ + + /*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ + nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); + /*haiku and blob 10d4*/ + + nv_wr32(priv, NV04_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL , 0x10000100); + nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + + /* These don't belong here, they're part of a per-channel context */ + nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); + nv_wr32(priv, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); return 0; } + +struct nouveau_oclass +nv04_graph_oclass = { + .handle = NV_ENGINE(GR, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_graph_ctor, + .dtor = _nouveau_graph_dtor, + .init = nv04_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c index d006658..ce38196 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c @@ -22,27 +22,28 @@ * DEALINGS IN THE SOFTWARE. */ -#include "drmP.h" -#include "drm.h" -#include <nouveau_drm.h> -#include "nouveau_drv.h" -#include "nouveau_util.h" - -struct nv10_graph_engine { - struct nouveau_exec_engine base; -}; +#include <core/os.h> +#include <core/class.h> +#include <core/handle.h> + +#include <subdev/fb.h> + +#include <engine/fifo.h> +#include <engine/graph.h> + +#include "regs.h" struct pipe_state { - uint32_t pipe_0x0000[0x040/4]; - uint32_t pipe_0x0040[0x010/4]; - uint32_t pipe_0x0200[0x0c0/4]; - uint32_t pipe_0x4400[0x080/4]; - uint32_t pipe_0x6400[0x3b0/4]; - uint32_t pipe_0x6800[0x2f0/4]; - uint32_t pipe_0x6c00[0x030/4]; - uint32_t pipe_0x7000[0x130/4]; - uint32_t pipe_0x7400[0x0c0/4]; - uint32_t pipe_0x7800[0x0c0/4]; + u32 pipe_0x0000[0x040/4]; + u32 pipe_0x0040[0x010/4]; + u32 pipe_0x0200[0x0c0/4]; + u32 pipe_0x4400[0x080/4]; + u32 pipe_0x6400[0x3b0/4]; + u32 pipe_0x6800[0x2f0/4]; + u32 pipe_0x6c00[0x030/4]; + u32 pipe_0x7000[0x130/4]; + u32 pipe_0x7400[0x0c0/4]; + u32 pipe_0x7800[0x0c0/4]; }; static int nv10_graph_ctx_regs[] = { @@ -388,117 +389,322 @@ static int nv17_graph_ctx_regs[] = { 0x00400a04, }; -struct graph_state { +struct nv10_graph_priv { + struct nouveau_graph base; + struct nv10_graph_chan *chan[32]; + spinlock_t lock; +}; + +struct nv10_graph_chan { + struct nouveau_object base; + int chid; int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)]; int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)]; struct pipe_state pipe_state; - uint32_t lma_window[4]; + u32 lma_window[4]; }; -#define PIPE_SAVE(dev, state, addr) \ + +static inline struct nv10_graph_priv * +nv10_graph_priv(struct nv10_graph_chan *chan) +{ + return (void *)nv_object(chan)->engine; +} + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +#define PIPE_SAVE(priv, state, addr) \ do { \ int __i; \ - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - state[__i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \ + state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \ } while (0) -#define PIPE_RESTORE(dev, state, addr) \ +#define PIPE_RESTORE(priv, state, addr) \ do { \ int __i; \ - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, state[__i]); \ + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \ } while (0) -static void nv10_graph_save_pipe(struct nouveau_channel *chan) +static struct nouveau_oclass +nv10_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs }, /* clip */ + { 0x0030, &nv04_graph_ofuncs }, /* null */ + { 0x0039, &nv04_graph_ofuncs }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs }, /* rop */ + { 0x0044, &nv04_graph_ofuncs }, /* pattern */ + { 0x004a, &nv04_graph_ofuncs }, /* gdi */ + { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */ + { 0x005f, &nv04_graph_ofuncs }, /* blit */ + { 0x0062, &nv04_graph_ofuncs }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs }, /* ifc */ + { 0x009f, &nv04_graph_ofuncs }, /* blit */ + { 0x0093, &nv04_graph_ofuncs }, /* surf3d */ + { 0x0094, &nv04_graph_ofuncs }, /* ttri */ + { 0x0095, &nv04_graph_ofuncs }, /* mtri */ + { 0x0056, &nv04_graph_ofuncs }, /* celcius */ + {}, +}; + +static struct nouveau_oclass +nv15_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs }, /* clip */ + { 0x0030, &nv04_graph_ofuncs }, /* null */ + { 0x0039, &nv04_graph_ofuncs }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs }, /* rop */ + { 0x0044, &nv04_graph_ofuncs }, /* pattern */ + { 0x004a, &nv04_graph_ofuncs }, /* gdi */ + { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */ + { 0x005f, &nv04_graph_ofuncs }, /* blit */ + { 0x0062, &nv04_graph_ofuncs }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs }, /* ifc */ + { 0x009f, &nv04_graph_ofuncs }, /* blit */ + { 0x0093, &nv04_graph_ofuncs }, /* surf3d */ + { 0x0094, &nv04_graph_ofuncs }, /* ttri */ + { 0x0095, &nv04_graph_ofuncs }, /* mtri */ + { 0x0096, &nv04_graph_ofuncs }, /* celcius */ + {}, +}; + +static int +nv17_graph_mthd_lma_window(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv10_graph_chan *chan = (void *)object->parent; + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + struct pipe_state *pipe = &chan->pipe_state; + u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; + u32 xfmode0, xfmode1; + u32 data = *(u32 *)args; + int i; + + chan->lma_window[(mthd - 0x1638) / 4] = data; + + if (mthd != 0x1644) + return 0; + + nv04_graph_idle(priv); + + PIPE_SAVE(priv, pipe_0x0040, 0x0040); + PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200); + + PIPE_RESTORE(priv, chan->lma_window, 0x6790); + + nv04_graph_idle(priv); + + xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0); + xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1); + + PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(priv, pipe_0x64c0, 0x64c0); + PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0); + PIPE_SAVE(priv, pipe_0x6a80, 0x6a80); + + nv04_graph_idle(priv); + + nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000); + nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000); + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + for (i = 0; i < 4; i++) + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + for (i = 0; i < 4; i++) + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + for (i = 0; i < 3; i++) + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + for (i = 0; i < 3; i++) + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008); + + PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200); + + nv04_graph_idle(priv); + + PIPE_RESTORE(priv, pipe_0x0040, 0x0040); + + nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0); + nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1); + + PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0); + PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0); + PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80); + PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400); + + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + + nv04_graph_idle(priv); + + return 0; +} + +static int +nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd, + void *args, u32 size) { - struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; - struct pipe_state *pipe = &pgraph_ctx->pipe_state; - struct drm_device *dev = chan->dev; - - PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400); - PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200); - PIPE_SAVE(dev, pipe->pipe_0x6400, 0x6400); - PIPE_SAVE(dev, pipe->pipe_0x6800, 0x6800); - PIPE_SAVE(dev, pipe->pipe_0x6c00, 0x6c00); - PIPE_SAVE(dev, pipe->pipe_0x7000, 0x7000); - PIPE_SAVE(dev, pipe->pipe_0x7400, 0x7400); - PIPE_SAVE(dev, pipe->pipe_0x7800, 0x7800); - PIPE_SAVE(dev, pipe->pipe_0x0040, 0x0040); - PIPE_SAVE(dev, pipe->pipe_0x0000, 0x0000); + struct nv10_graph_chan *chan = (void *)object->parent; + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + + nv04_graph_idle(priv); + + nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); + nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000); + return 0; } -static void nv10_graph_load_pipe(struct nouveau_channel *chan) +static struct nouveau_omthds +nv17_celcius_omthds[] = { + { 0x1638, nv17_graph_mthd_lma_window }, + { 0x163c, nv17_graph_mthd_lma_window }, + { 0x1640, nv17_graph_mthd_lma_window }, + { 0x1644, nv17_graph_mthd_lma_window }, + { 0x1658, nv17_graph_mthd_lma_enable }, + {} +}; + +static struct nouveau_oclass +nv17_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs }, /* clip */ + { 0x0030, &nv04_graph_ofuncs }, /* null */ + { 0x0039, &nv04_graph_ofuncs }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs }, /* rop */ + { 0x0044, &nv04_graph_ofuncs }, /* pattern */ + { 0x004a, &nv04_graph_ofuncs }, /* gdi */ + { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */ + { 0x005f, &nv04_graph_ofuncs }, /* blit */ + { 0x0062, &nv04_graph_ofuncs }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs }, /* ifc */ + { 0x009f, &nv04_graph_ofuncs }, /* blit */ + { 0x0093, &nv04_graph_ofuncs }, /* surf3d */ + { 0x0094, &nv04_graph_ofuncs }, /* ttri */ + { 0x0095, &nv04_graph_ofuncs }, /* mtri */ + { 0x0099, &nv04_graph_ofuncs, nv17_celcius_omthds }, + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static struct nv10_graph_chan * +nv10_graph_channel(struct nv10_graph_priv *priv) { - struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; - struct pipe_state *pipe = &pgraph_ctx->pipe_state; - struct drm_device *dev = chan->dev; - uint32_t xfmode0, xfmode1; + struct nv10_graph_chan *chan = NULL; + if (nv_rd32(priv, 0x400144) & 0x00010000) { + int chid = nv_rd32(priv, 0x400148) >> 24; + if (chid < ARRAY_SIZE(priv->chan)) + chan = priv->chan[chid]; + } + return chan; +} + +static void +nv10_graph_save_pipe(struct nv10_graph_chan *chan) +{ + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + struct pipe_state *pipe = &chan->pipe_state; + + PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200); + PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400); + PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800); + PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00); + PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000); + PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400); + PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800); + PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040); + PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000); +} + +static void +nv10_graph_load_pipe(struct nv10_graph_chan *chan) +{ + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + struct pipe_state *pipe = &chan->pipe_state; + u32 xfmode0, xfmode1; int i; - nouveau_wait_for_idle(dev); + nv04_graph_idle(priv); /* XXX check haiku comments */ - xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1); - nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0); + xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1); + nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000); + nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000); + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); for (i = 0; i < 4; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); for (i = 0; i < 4; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); for (i = 0; i < 3; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); for (i = 0; i < 3; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008); + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008); - PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200); - nouveau_wait_for_idle(dev); + PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200); + nv04_graph_idle(priv); /* restore XFMODE */ - nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1); - PIPE_RESTORE(dev, pipe->pipe_0x6400, 0x6400); - PIPE_RESTORE(dev, pipe->pipe_0x6800, 0x6800); - PIPE_RESTORE(dev, pipe->pipe_0x6c00, 0x6c00); - PIPE_RESTORE(dev, pipe->pipe_0x7000, 0x7000); - PIPE_RESTORE(dev, pipe->pipe_0x7400, 0x7400); - PIPE_RESTORE(dev, pipe->pipe_0x7800, 0x7800); - PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400); - PIPE_RESTORE(dev, pipe->pipe_0x0000, 0x0000); - PIPE_RESTORE(dev, pipe->pipe_0x0040, 0x0040); - nouveau_wait_for_idle(dev); + nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0); + nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1); + PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400); + PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800); + PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00); + PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000); + PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400); + PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800); + PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400); + PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000); + PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040); + nv04_graph_idle(priv); } -static void nv10_graph_create_pipe(struct nouveau_channel *chan) +static void +nv10_graph_create_pipe(struct nv10_graph_chan *chan) { - struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; - struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state; - struct drm_device *dev = chan->dev; - uint32_t *fifo_pipe_state_addr; + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + struct pipe_state *pipe_state = &chan->pipe_state; + u32 *pipe_state_addr; int i; #define PIPE_INIT(addr) \ do { \ - fifo_pipe_state_addr = fifo_pipe_state->pipe_##addr; \ + pipe_state_addr = pipe_state->pipe_##addr; \ } while (0) #define PIPE_INIT_END(addr) \ do { \ - uint32_t *__end_addr = fifo_pipe_state->pipe_##addr + \ - ARRAY_SIZE(fifo_pipe_state->pipe_##addr); \ - if (fifo_pipe_state_addr != __end_addr) \ - NV_ERROR(dev, "incomplete pipe init for 0x%x : %p/%p\n", \ - addr, fifo_pipe_state_addr, __end_addr); \ + u32 *__end_addr = pipe_state->pipe_##addr + \ + ARRAY_SIZE(pipe_state->pipe_##addr); \ + if (pipe_state_addr != __end_addr) \ + nv_error(priv, "incomplete pipe init for 0x%x : %p/%p\n", \ + addr, pipe_state_addr, __end_addr); \ } while (0) -#define NV_WRITE_PIPE_INIT(value) *(fifo_pipe_state_addr++) = value +#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value PIPE_INIT(0x0200); for (i = 0; i < 48; i++) @@ -634,34 +840,36 @@ static void nv10_graph_create_pipe(struct nouveau_channel *chan) #undef NV_WRITE_PIPE_INIT } -static int nv10_graph_ctx_regs_find_offset(struct drm_device *dev, int reg) +static int +nv10_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg) { int i; for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) { if (nv10_graph_ctx_regs[i] == reg) return i; } - NV_ERROR(dev, "unknow offset nv10_ctx_regs %d\n", reg); + nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg); return -1; } -static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg) +static int +nv17_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg) { int i; for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) { if (nv17_graph_ctx_regs[i] == reg) return i; } - NV_ERROR(dev, "unknow offset nv17_ctx_regs %d\n", reg); + nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg); return -1; } -static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan, - uint32_t inst) +static void +nv10_graph_load_dma_vtxbuf(struct nv10_graph_chan *chan, int chid, u32 inst) { - struct drm_device *dev = chan->dev; - uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; - uint32_t ctx_user, ctx_switch[5]; + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; + u32 ctx_user, ctx_switch[5]; int i, subchan = -1; /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state @@ -671,7 +879,7 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan, /* Look for a celsius object */ for (i = 0; i < 8; i++) { - int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; + int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; if (class == 0x56 || class == 0x96 || class == 0x99) { subchan = i; @@ -683,168 +891,158 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan, return; /* Save the current ctx object */ - ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER); + ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER); for (i = 0; i < 5; i++) - ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i)); + ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i)); /* Save the FIFO state */ - st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2); - st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL); - st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH); - fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR); + st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2); + st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL); + st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH); + fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR); for (i = 0; i < ARRAY_SIZE(fifo); i++) - fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i); + fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i); /* Switch to the celsius subchannel */ for (i = 0; i < 5; i++) - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), - nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i))); - nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); + nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), + nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i))); + nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); /* Inject NV10TCL_DMA_VTXBUF */ - nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, - 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst); - nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, + 0x2c000000 | chid << 20 | subchan << 16 | 0x18c); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst); + nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); + nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); /* Restore the FIFO state */ for (i = 0; i < ARRAY_SIZE(fifo); i++) - nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]); + nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); /* Restore the current ctx object */ for (i = 0; i < 5; i++) - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); - nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user); + nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); + nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user); } static int -nv10_graph_load_context(struct nouveau_channel *chan) +nv10_graph_load_context(struct nv10_graph_chan *chan, int chid) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; - uint32_t tmp; + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + u32 inst; int i; for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) - nv_wr32(dev, nv10_graph_ctx_regs[i], pgraph_ctx->nv10[i]); - if (dev_priv->chipset >= 0x17) { + nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]); + + if (nv_device(priv)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) - nv_wr32(dev, nv17_graph_ctx_regs[i], - pgraph_ctx->nv17[i]); + nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]); } nv10_graph_load_pipe(chan); - nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1) - & 0xffff)); - - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER); - nv_wr32(dev, NV10_PGRAPH_CTX_USER, (tmp & 0xffffff) | chan->id << 24); - tmp = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, tmp & 0xcfffffff); + + inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff; + nv10_graph_load_dma_vtxbuf(chan, chid, inst); + + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000); return 0; } static int -nv10_graph_unload_context(struct drm_device *dev) +nv10_graph_unload_context(struct nv10_graph_chan *chan) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan; - struct graph_state *ctx; - uint32_t tmp; + struct nv10_graph_priv *priv = nv10_graph_priv(chan); int i; - chan = nv10_graph_channel(dev); - if (!chan) - return 0; - ctx = chan->engctx[NVOBJ_ENGINE_GR]; - for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) - ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]); + chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]); - if (dev_priv->chipset >= 0x17) { + if (nv_device(priv)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) - ctx->nv17[i] = nv_rd32(dev, nv17_graph_ctx_regs[i]); + chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]); } nv10_graph_save_pipe(chan); - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000); - tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; - tmp |= 31 << 24; - nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp); + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000); + nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); return 0; } static void -nv10_graph_context_switch(struct drm_device *dev) +nv10_graph_context_switch(struct nv10_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = NULL; + struct nv10_graph_chan *prev = NULL; + struct nv10_graph_chan *next = NULL; + unsigned long flags; int chid; - nouveau_wait_for_idle(dev); + spin_lock_irqsave(&priv->lock, flags); + nv04_graph_idle(priv); /* If previous context is valid, we need to save it */ - nv10_graph_unload_context(dev); + prev = nv10_graph_channel(priv); + if (prev) + nv10_graph_unload_context(prev); + + /* load context for next channel */ + chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; + next = priv->chan[chid]; + if (next) + nv10_graph_load_context(next, chid); - /* Load context for next channel */ - chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; - chan = dev_priv->channels.ptr[chid]; - if (chan && chan->engctx[NVOBJ_ENGINE_GR]) - nv10_graph_load_context(chan); + spin_unlock_irqrestore(&priv->lock, flags); } #define NV_WRITE_CTX(reg, val) do { \ - int offset = nv10_graph_ctx_regs_find_offset(dev, reg); \ + int offset = nv10_graph_ctx_regs_find_offset(priv, reg); \ if (offset > 0) \ - pgraph_ctx->nv10[offset] = val; \ + chan->nv10[offset] = val; \ } while (0) #define NV17_WRITE_CTX(reg, val) do { \ - int offset = nv17_graph_ctx_regs_find_offset(dev, reg); \ + int offset = nv17_graph_ctx_regs_find_offset(priv, reg); \ if (offset > 0) \ - pgraph_ctx->nv17[offset] = val; \ + chan->nv17[offset] = val; \ } while (0) -struct nouveau_channel * -nv10_graph_channel(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int chid = 31; - - if (nv_rd32(dev, NV10_PGRAPH_CTX_CONTROL) & 0x00010000) - chid = nv_rd32(dev, NV10_PGRAPH_CTX_USER) >> 24; - - if (chid >= 31) - return NULL; - - return dev_priv->channels.ptr[chid]; -} - static int -nv10_graph_context_new(struct nouveau_channel *chan, int engine) +nv10_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct graph_state *pgraph_ctx; - - NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id); - - pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL); - if (pgraph_ctx == NULL) - return -ENOMEM; - chan->engctx[engine] = pgraph_ctx; + struct nouveau_fifo_chan *fifo = (void *)parent; + struct nv10_graph_priv *priv = (void *)engine; + struct nv10_graph_chan *chan; + unsigned long flags; + int ret; + + ret = nouveau_object_create(parent, engine, oclass, 0, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->chan[fifo->chid]) { + *pobject = nv_object(priv->chan[fifo->chid]); + atomic_inc(&(*pobject)->refcount); + spin_unlock_irqrestore(&priv->lock, flags); + nouveau_object_destroy(&chan->base); + return 1; + } NV_WRITE_CTX(0x00400e88, 0x08000000); NV_WRITE_CTX(0x00400e9c, 0x4b7fffff); @@ -853,212 +1051,91 @@ nv10_graph_context_new(struct nouveau_channel *chan, int engine) NV_WRITE_CTX(0x00400e14, 0x00001000); NV_WRITE_CTX(0x00400e30, 0x00080008); NV_WRITE_CTX(0x00400e34, 0x00080008); - if (dev_priv->chipset >= 0x17) { + if (nv_device(priv)->chipset >= 0x17) { /* is it really needed ??? */ NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4, - nv_rd32(dev, NV10_PGRAPH_DEBUG_4)); - NV17_WRITE_CTX(0x004006b0, nv_rd32(dev, 0x004006b0)); + nv_rd32(priv, NV10_PGRAPH_DEBUG_4)); + NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0)); NV17_WRITE_CTX(0x00400eac, 0x0fff0000); NV17_WRITE_CTX(0x00400eb0, 0x0fff0000); NV17_WRITE_CTX(0x00400ec0, 0x00000080); NV17_WRITE_CTX(0x00400ed0, 0x00000080); } - NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->id << 24); + NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24); nv10_graph_create_pipe(chan); + + priv->chan[fifo->chid] = chan; + chan->chid = fifo->chid; + spin_unlock_irqrestore(&priv->lock, flags); return 0; } static void -nv10_graph_context_del(struct nouveau_channel *chan, int engine) +nv10_graph_context_dtor(struct nouveau_object *object) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct graph_state *pgraph_ctx = chan->engctx[engine]; + struct nv10_graph_priv *priv = (void *)object->engine; + struct nv10_graph_chan *chan = (void *)object; unsigned long flags; - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - - /* Unload the context if it's the currently active one */ - if (nv10_graph_channel(dev) == chan) - nv10_graph_unload_context(dev); + spin_lock_irqsave(&priv->lock, flags); + priv->chan[chan->chid] = NULL; + spin_unlock_irqrestore(&priv->lock, flags); - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - - /* Free the context resources */ - chan->engctx[engine] = NULL; - kfree(pgraph_ctx); -} - -static void -nv10_graph_set_tile_region(struct drm_device *dev, int 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); + nouveau_object_destroy(&chan->base); } static int -nv10_graph_init(struct drm_device *dev, int engine) +nv10_graph_context_fini(struct nouveau_object *object, bool suspend) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 tmp; - int i; - - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & - ~NV_PMC_ENABLE_PGRAPH); - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | - NV_PMC_ENABLE_PGRAPH); - - nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700); - /* nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ - nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); - nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | - (1<<29) | - (1<<31)); - if (dev_priv->chipset >= 0x17) { - nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x1f000000); - nv_wr32(dev, 0x400a10, 0x3ff3fb6); - nv_wr32(dev, 0x400838, 0x2f8684); - nv_wr32(dev, 0x40083c, 0x115f3f); - nv_wr32(dev, 0x004006b0, 0x40000020); - } else - nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000); + struct nv10_graph_priv *priv = (void *)object->engine; + struct nv10_graph_chan *chan = (void *)object; + unsigned long flags; - /* Turn all the tiling regions off. */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) - nv10_graph_set_tile_region(dev, i); - - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); - nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF); - - tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; - tmp |= 31 << 24; - nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp); - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); + spin_lock_irqsave(&priv->lock, flags); + nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + if (nv10_graph_channel(priv) == chan) + nv10_graph_unload_context(chan); + nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&priv->lock, flags); - return 0; + return nouveau_object_fini(&chan->base, suspend); } -static int -nv10_graph_fini(struct drm_device *dev, int engine, bool suspend) -{ - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) { - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - return -EBUSY; - } - nv10_graph_unload_context(dev); - nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); - return 0; -} - -static int -nv17_graph_mthd_lma_window(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) -{ - struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR]; - struct drm_device *dev = chan->dev; - struct pipe_state *pipe = &ctx->pipe_state; - uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; - uint32_t xfmode0, xfmode1; - int i; - - ctx->lma_window[(mthd - 0x1638) / 4] = data; - - if (mthd != 0x1644) - return 0; - - nouveau_wait_for_idle(dev); - - PIPE_SAVE(dev, pipe_0x0040, 0x0040); - PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200); - - PIPE_RESTORE(dev, ctx->lma_window, 0x6790); - - nouveau_wait_for_idle(dev); - - xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1); - - PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400); - PIPE_SAVE(dev, pipe_0x64c0, 0x64c0); - PIPE_SAVE(dev, pipe_0x6ab0, 0x6ab0); - PIPE_SAVE(dev, pipe_0x6a80, 0x6a80); - - nouveau_wait_for_idle(dev); - - nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); - for (i = 0; i < 4; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - for (i = 0; i < 4; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000); - - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); - for (i = 0; i < 3; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); - for (i = 0; i < 3; i++) - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000); - - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008); - - PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200); - - nouveau_wait_for_idle(dev); - - PIPE_RESTORE(dev, pipe_0x0040, 0x0040); - - nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1); - - PIPE_RESTORE(dev, pipe_0x64c0, 0x64c0); - PIPE_RESTORE(dev, pipe_0x6ab0, 0x6ab0); - PIPE_RESTORE(dev, pipe_0x6a80, 0x6a80); - PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400); - - nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); - nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000); - - nouveau_wait_for_idle(dev); +static struct nouveau_oclass +nv10_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_graph_context_ctor, + .dtor = nv10_graph_context_dtor, + .init = nouveau_object_init, + .fini = nv10_graph_context_fini, + }, +}; - return 0; -} +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ -static int -nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) +static void +nv10_graph_tile_prog(struct nouveau_engine *engine, int i) { - struct drm_device *dev = chan->dev; + struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i]; + struct nouveau_fifo *pfifo = nouveau_fifo(engine); + struct nv10_graph_priv *priv = (void *)engine; + unsigned long flags; - nouveau_wait_for_idle(dev); + pfifo->pause(pfifo, &flags); + nv04_graph_idle(priv); - nv_wr32(dev, NV10_PGRAPH_DEBUG_4, - nv_rd32(dev, NV10_PGRAPH_DEBUG_4) | 0x1 << 8); - nv_wr32(dev, 0x004006b0, - nv_rd32(dev, 0x004006b0) | 0x8 << 24); + nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr); - return 0; + pfifo->start(pfifo, &flags); } -struct nouveau_bitfield nv10_graph_intr[] = { +struct nouveau_bitfield nv10_graph_intr_name[] = { { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, { NV_PGRAPH_INTR_ERROR, "ERROR" }, {} @@ -1073,115 +1150,165 @@ struct nouveau_bitfield nv10_graph_nstatus[] = { }; static void -nv10_graph_isr(struct drm_device *dev) +nv10_graph_intr(struct nouveau_subdev *subdev) { - u32 stat; - - while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { - u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); - u32 chid = (addr & 0x01f00000) >> 20; - u32 subc = (addr & 0x00070000) >> 16; - u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff; - u32 show = stat; - - if (stat & NV_PGRAPH_INTR_ERROR) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) - show &= ~NV_PGRAPH_INTR_ERROR; - } - } + struct nv10_graph_priv *priv = (void *)subdev; + struct nv10_graph_chan *chan = NULL; + struct nouveau_namedb *namedb = NULL; + struct nouveau_handle *handle = NULL; + u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + u32 chid = (addr & 0x01f00000) >> 20; + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff; + u32 show = stat; + unsigned long flags; - if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); - stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - nv10_graph_context_switch(dev); + spin_lock_irqsave(&priv->lock, flags); + chan = priv->chan[chid]; + if (chan) + namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); + spin_unlock_irqrestore(&priv->lock, flags); + + if (stat & NV_PGRAPH_INTR_ERROR) { + if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { + handle = nouveau_namedb_get_class(namedb, class); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; } + } - nv_wr32(dev, NV03_PGRAPH_INTR, stat); - nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); - - if (show && nouveau_ratelimit()) { - NV_INFO(dev, "PGRAPH -"); - nouveau_bitfield_print(nv10_graph_intr, show); - printk(" nsource:"); - nouveau_bitfield_print(nv04_graph_nsource, nsource); - printk(" nstatus:"); - nouveau_bitfield_print(nv10_graph_nstatus, nstatus); - printk("\n"); - NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " - "mthd 0x%04x data 0x%08x\n", - chid, subc, class, mthd, data); - } + if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { + nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + nv10_graph_context_switch(priv); + } + + nv_wr32(priv, NV03_PGRAPH_INTR, stat); + nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + + if (show) { + nv_error(priv, ""); + nouveau_bitfield_print(nv10_graph_intr_name, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv10_graph_nstatus, nstatus); + printk("\n"); + nv_error(priv, "ch %d/%d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, subc, class, mthd, data); } + + nouveau_namedb_put(handle); } -static void -nv10_graph_destroy(struct drm_device *dev, int engine) +static int +nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv10_graph_engine *pgraph = nv_engine(dev, engine); + struct nv10_graph_priv *priv; + int ret; + + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv10_graph_intr; + nv_engine(priv)->cclass = &nv10_graph_cclass; + + if (nv_device(priv)->chipset <= 0x10) + nv_engine(priv)->sclass = nv10_graph_sclass; + else + if (nv_device(priv)->chipset < 0x17 || + nv_device(priv)->chipset == 0x1a) + nv_engine(priv)->sclass = nv15_graph_sclass; + else + nv_engine(priv)->sclass = nv17_graph_sclass; + + nv_engine(priv)->tile_prog = nv10_graph_tile_prog; + spin_lock_init(&priv->lock); + return 0; +} - nouveau_irq_unregister(dev, 12); - kfree(pgraph); +static void +nv10_graph_dtor(struct nouveau_object *object) +{ + struct nv10_graph_priv *priv = (void *)object; + nouveau_graph_destroy(&priv->base); } -int -nv10_graph_create(struct drm_device *dev) +static int +nv10_graph_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv10_graph_engine *pgraph; - - pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); - if (!pgraph) - return -ENOMEM; - - pgraph->base.destroy = nv10_graph_destroy; - pgraph->base.init = nv10_graph_init; - pgraph->base.fini = nv10_graph_fini; - pgraph->base.context_new = nv10_graph_context_new; - pgraph->base.context_del = nv10_graph_context_del; - pgraph->base.object_new = nv04_graph_object_new; - pgraph->base.set_tile_region = nv10_graph_set_tile_region; - - NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); - nouveau_irq_register(dev, 12, nv10_graph_isr); - - NVOBJ_CLASS(dev, 0x0030, GR); /* null */ - NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ - NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ - NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */ - NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ - NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ - NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ - NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ - NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ - NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ - NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ - NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ - NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ - NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */ - NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */ - NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */ - NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */ - - /* celcius */ - if (dev_priv->chipset <= 0x10) { - NVOBJ_CLASS(dev, 0x0056, GR); - } else - if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) { - NVOBJ_CLASS(dev, 0x0096, GR); + struct nouveau_engine *engine = nv_engine(object); + struct nouveau_fb *pfb = nouveau_fb(object); + struct nv10_graph_priv *priv = (void *)engine; + int ret, i; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700); + /* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ + nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); + nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); + + if (nv_device(priv)->chipset >= 0x17) { + nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000); + nv_wr32(priv, 0x400a10, 0x03ff3fb6); + nv_wr32(priv, 0x400838, 0x002f8684); + nv_wr32(priv, 0x40083c, 0x00115f3f); + nv_wr32(priv, 0x4006b0, 0x40000020); } else { - NVOBJ_CLASS(dev, 0x0099, GR); - NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window); - NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window); - NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window); - NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window); - NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable); + nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000); } + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->tile.regions; i++) + engine->tile_prog(engine, i); + + nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); + nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); + nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); + nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); + nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); + nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF); + + nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); return 0; } + +static int +nv10_graph_fini(struct nouveau_object *object, bool suspend) +{ + struct nv10_graph_priv *priv = (void *)object; + return nouveau_graph_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv10_graph_oclass = { + .handle = NV_ENGINE(GR, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_graph_ctor, + .dtor = nv10_graph_dtor, + .init = nv10_graph_init, + .fini = nv10_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c index 0d874b8b..61faef9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c @@ -1,836 +1,378 @@ -#include "drmP.h" -#include "drm.h" -#include "nouveau_drv.h" -#include <nouveau_drm.h> - -/* - * NV20 - * ----- - * There are 3 families : - * NV20 is 0x10de:0x020* - * NV25/28 is 0x10de:0x025* / 0x10de:0x028* - * NV2A is 0x10de:0x02A0 - * - * NV30 - * ----- - * There are 3 families : - * NV30/31 is 0x10de:0x030* / 0x10de:0x031* - * NV34 is 0x10de:0x032* - * NV35/36 is 0x10de:0x033* / 0x10de:0x034* - * - * Not seen in the wild, no dumps (probably NV35) : - * NV37 is 0x10de:0x00fc, 0x10de:0x00fd - * NV38 is 0x10de:0x0333, 0x10de:0x00fe - * - */ - -struct nv20_graph_engine { - struct nouveau_exec_engine base; - struct nouveau_gpuobj *ctxtab; - void (*grctx_init)(struct nouveau_gpuobj *); - u32 grctx_size; - u32 grctx_user; +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/handle.h> +#include <core/enum.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/graph.h> +#include <engine/fifo.h> + +#include "nv20.h" +#include "regs.h" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv20_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */ + { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */ + { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */ + { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */ + { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */ + { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */ + { 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */ + { 0x0097, &nv04_graph_ofuncs, NULL }, /* kelvin */ + { 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */ + { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */ + {}, }; -#define NV20_GRCTX_SIZE (3580*4) -#define NV25_GRCTX_SIZE (3529*4) -#define NV2A_GRCTX_SIZE (3500*4) +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ -#define NV30_31_GRCTX_SIZE (24392) -#define NV34_GRCTX_SIZE (18140) -#define NV35_36_GRCTX_SIZE (22396) - -int -nv20_graph_unload_context(struct drm_device *dev) +static int +nv20_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nouveau_channel *chan; - struct nouveau_gpuobj *grctx; - u32 tmp; - - chan = nv10_graph_channel(dev); - if (!chan) - return 0; - grctx = chan->engctx[NVOBJ_ENGINE_GR]; - - nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->addr >> 4); - nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER, - NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE); - - nouveau_wait_for_idle(dev); - - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000); - tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; - tmp |= 31 << 24; - nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp); - return 0; -} + struct nv20_graph_chan *chan; + int ret, i; -static void -nv20_graph_rdi(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int i, writecount = 32; - uint32_t rdi_index = 0x2c80000; - - if (dev_priv->chipset == 0x20) { - rdi_index = 0x3d0000; - writecount = 15; - } - - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index); - for (i = 0; i < writecount; i++) - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0); + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, + 0x37f0, 16, NVOBJ_FLAG_ZERO_ALLOC, + &chan); + *pobject = nv_object(chan); + if (ret) + return ret; - nouveau_wait_for_idle(dev); -} + chan->chid = nouveau_fifo_chan(parent)->chid; -static void -nv20_graph_context_init(struct nouveau_gpuobj *ctx) -{ - int i; - - nv_wo32(ctx, 0x033c, 0xffff0000); - nv_wo32(ctx, 0x03a0, 0x0fff0000); - nv_wo32(ctx, 0x03a4, 0x0fff0000); - nv_wo32(ctx, 0x047c, 0x00000101); - nv_wo32(ctx, 0x0490, 0x00000111); - nv_wo32(ctx, 0x04a8, 0x44400000); + nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24)); + nv_wo32(chan, 0x033c, 0xffff0000); + nv_wo32(chan, 0x03a0, 0x0fff0000); + nv_wo32(chan, 0x03a4, 0x0fff0000); + nv_wo32(chan, 0x047c, 0x00000101); + nv_wo32(chan, 0x0490, 0x00000111); + nv_wo32(chan, 0x04a8, 0x44400000); for (i = 0x04d4; i <= 0x04e0; i += 4) - nv_wo32(ctx, i, 0x00030303); + nv_wo32(chan, i, 0x00030303); for (i = 0x04f4; i <= 0x0500; i += 4) - nv_wo32(ctx, i, 0x00080000); + nv_wo32(chan, i, 0x00080000); for (i = 0x050c; i <= 0x0518; i += 4) - nv_wo32(ctx, i, 0x01012000); + nv_wo32(chan, i, 0x01012000); for (i = 0x051c; i <= 0x0528; i += 4) - nv_wo32(ctx, i, 0x000105b8); + nv_wo32(chan, i, 0x000105b8); for (i = 0x052c; i <= 0x0538; i += 4) - nv_wo32(ctx, i, 0x00080008); + nv_wo32(chan, i, 0x00080008); for (i = 0x055c; i <= 0x0598; i += 4) - nv_wo32(ctx, i, 0x07ff0000); - nv_wo32(ctx, 0x05a4, 0x4b7fffff); - nv_wo32(ctx, 0x05fc, 0x00000001); - nv_wo32(ctx, 0x0604, 0x00004000); - nv_wo32(ctx, 0x0610, 0x00000001); - nv_wo32(ctx, 0x0618, 0x00040000); - nv_wo32(ctx, 0x061c, 0x00010000); + nv_wo32(chan, i, 0x07ff0000); + nv_wo32(chan, 0x05a4, 0x4b7fffff); + nv_wo32(chan, 0x05fc, 0x00000001); + nv_wo32(chan, 0x0604, 0x00004000); + nv_wo32(chan, 0x0610, 0x00000001); + nv_wo32(chan, 0x0618, 0x00040000); + nv_wo32(chan, 0x061c, 0x00010000); for (i = 0x1c1c; i <= 0x248c; i += 16) { - nv_wo32(ctx, (i + 0), 0x10700ff9); - nv_wo32(ctx, (i + 4), 0x0436086c); - nv_wo32(ctx, (i + 8), 0x000c001b); + nv_wo32(chan, (i + 0), 0x10700ff9); + nv_wo32(chan, (i + 4), 0x0436086c); + nv_wo32(chan, (i + 8), 0x000c001b); } - nv_wo32(ctx, 0x281c, 0x3f800000); - nv_wo32(ctx, 0x2830, 0x3f800000); - nv_wo32(ctx, 0x285c, 0x40000000); - nv_wo32(ctx, 0x2860, 0x3f800000); - nv_wo32(ctx, 0x2864, 0x3f000000); - nv_wo32(ctx, 0x286c, 0x40000000); - nv_wo32(ctx, 0x2870, 0x3f800000); - nv_wo32(ctx, 0x2878, 0xbf800000); - nv_wo32(ctx, 0x2880, 0xbf800000); - nv_wo32(ctx, 0x34a4, 0x000fe000); - nv_wo32(ctx, 0x3530, 0x000003f8); - nv_wo32(ctx, 0x3540, 0x002fe000); + nv_wo32(chan, 0x281c, 0x3f800000); + nv_wo32(chan, 0x2830, 0x3f800000); + nv_wo32(chan, 0x285c, 0x40000000); + nv_wo32(chan, 0x2860, 0x3f800000); + nv_wo32(chan, 0x2864, 0x3f000000); + nv_wo32(chan, 0x286c, 0x40000000); + nv_wo32(chan, 0x2870, 0x3f800000); + nv_wo32(chan, 0x2878, 0xbf800000); + nv_wo32(chan, 0x2880, 0xbf800000); + nv_wo32(chan, 0x34a4, 0x000fe000); + nv_wo32(chan, 0x3530, 0x000003f8); + nv_wo32(chan, 0x3540, 0x002fe000); for (i = 0x355c; i <= 0x3578; i += 4) - nv_wo32(ctx, i, 0x001c527c); + nv_wo32(chan, i, 0x001c527c); + return 0; } -static void -nv25_graph_context_init(struct nouveau_gpuobj *ctx) +int +nv20_graph_context_init(struct nouveau_object *object) { - int i; - - nv_wo32(ctx, 0x035c, 0xffff0000); - nv_wo32(ctx, 0x03c0, 0x0fff0000); - nv_wo32(ctx, 0x03c4, 0x0fff0000); - nv_wo32(ctx, 0x049c, 0x00000101); - nv_wo32(ctx, 0x04b0, 0x00000111); - nv_wo32(ctx, 0x04c8, 0x00000080); - nv_wo32(ctx, 0x04cc, 0xffff0000); - nv_wo32(ctx, 0x04d0, 0x00000001); - nv_wo32(ctx, 0x04e4, 0x44400000); - nv_wo32(ctx, 0x04fc, 0x4b800000); - for (i = 0x0510; i <= 0x051c; i += 4) - nv_wo32(ctx, i, 0x00030303); - for (i = 0x0530; i <= 0x053c; i += 4) - nv_wo32(ctx, i, 0x00080000); - for (i = 0x0548; i <= 0x0554; i += 4) - nv_wo32(ctx, i, 0x01012000); - for (i = 0x0558; i <= 0x0564; i += 4) - nv_wo32(ctx, i, 0x000105b8); - for (i = 0x0568; i <= 0x0574; i += 4) - nv_wo32(ctx, i, 0x00080008); - for (i = 0x0598; i <= 0x05d4; i += 4) - nv_wo32(ctx, i, 0x07ff0000); - nv_wo32(ctx, 0x05e0, 0x4b7fffff); - nv_wo32(ctx, 0x0620, 0x00000080); - nv_wo32(ctx, 0x0624, 0x30201000); - nv_wo32(ctx, 0x0628, 0x70605040); - nv_wo32(ctx, 0x062c, 0xb0a09080); - nv_wo32(ctx, 0x0630, 0xf0e0d0c0); - nv_wo32(ctx, 0x0664, 0x00000001); - nv_wo32(ctx, 0x066c, 0x00004000); - nv_wo32(ctx, 0x0678, 0x00000001); - nv_wo32(ctx, 0x0680, 0x00040000); - nv_wo32(ctx, 0x0684, 0x00010000); - for (i = 0x1b04; i <= 0x2374; i += 16) { - nv_wo32(ctx, (i + 0), 0x10700ff9); - nv_wo32(ctx, (i + 4), 0x0436086c); - nv_wo32(ctx, (i + 8), 0x000c001b); - } - nv_wo32(ctx, 0x2704, 0x3f800000); - nv_wo32(ctx, 0x2718, 0x3f800000); - nv_wo32(ctx, 0x2744, 0x40000000); - nv_wo32(ctx, 0x2748, 0x3f800000); - nv_wo32(ctx, 0x274c, 0x3f000000); - nv_wo32(ctx, 0x2754, 0x40000000); - nv_wo32(ctx, 0x2758, 0x3f800000); - nv_wo32(ctx, 0x2760, 0xbf800000); - nv_wo32(ctx, 0x2768, 0xbf800000); - nv_wo32(ctx, 0x308c, 0x000fe000); - nv_wo32(ctx, 0x3108, 0x000003f8); - nv_wo32(ctx, 0x3468, 0x002fe000); - for (i = 0x3484; i <= 0x34a0; i += 4) - nv_wo32(ctx, i, 0x001c527c); -} + struct nv20_graph_priv *priv = (void *)object->engine; + struct nv20_graph_chan *chan = (void *)object; + int ret; -static void -nv2a_graph_context_init(struct nouveau_gpuobj *ctx) -{ - int i; - - nv_wo32(ctx, 0x033c, 0xffff0000); - nv_wo32(ctx, 0x03a0, 0x0fff0000); - nv_wo32(ctx, 0x03a4, 0x0fff0000); - nv_wo32(ctx, 0x047c, 0x00000101); - nv_wo32(ctx, 0x0490, 0x00000111); - nv_wo32(ctx, 0x04a8, 0x44400000); - for (i = 0x04d4; i <= 0x04e0; i += 4) - nv_wo32(ctx, i, 0x00030303); - for (i = 0x04f4; i <= 0x0500; i += 4) - nv_wo32(ctx, i, 0x00080000); - for (i = 0x050c; i <= 0x0518; i += 4) - nv_wo32(ctx, i, 0x01012000); - for (i = 0x051c; i <= 0x0528; i += 4) - nv_wo32(ctx, i, 0x000105b8); - for (i = 0x052c; i <= 0x0538; i += 4) - nv_wo32(ctx, i, 0x00080008); - for (i = 0x055c; i <= 0x0598; i += 4) - nv_wo32(ctx, i, 0x07ff0000); - nv_wo32(ctx, 0x05a4, 0x4b7fffff); - nv_wo32(ctx, 0x05fc, 0x00000001); - nv_wo32(ctx, 0x0604, 0x00004000); - nv_wo32(ctx, 0x0610, 0x00000001); - nv_wo32(ctx, 0x0618, 0x00040000); - nv_wo32(ctx, 0x061c, 0x00010000); - for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */ - nv_wo32(ctx, (i + 0), 0x10700ff9); - nv_wo32(ctx, (i + 4), 0x0436086c); - nv_wo32(ctx, (i + 8), 0x000c001b); - } - nv_wo32(ctx, 0x269c, 0x3f800000); - nv_wo32(ctx, 0x26b0, 0x3f800000); - nv_wo32(ctx, 0x26dc, 0x40000000); - nv_wo32(ctx, 0x26e0, 0x3f800000); - nv_wo32(ctx, 0x26e4, 0x3f000000); - nv_wo32(ctx, 0x26ec, 0x40000000); - nv_wo32(ctx, 0x26f0, 0x3f800000); - nv_wo32(ctx, 0x26f8, 0xbf800000); - nv_wo32(ctx, 0x2700, 0xbf800000); - nv_wo32(ctx, 0x3024, 0x000fe000); - nv_wo32(ctx, 0x30a0, 0x000003f8); - nv_wo32(ctx, 0x33fc, 0x002fe000); - for (i = 0x341c; i <= 0x3438; i += 4) - nv_wo32(ctx, i, 0x001c527c); -} + ret = nouveau_graph_context_init(&chan->base); + if (ret) + return ret; -static void -nv30_31_graph_context_init(struct nouveau_gpuobj *ctx) -{ - int i; - - nv_wo32(ctx, 0x0410, 0x00000101); - nv_wo32(ctx, 0x0424, 0x00000111); - nv_wo32(ctx, 0x0428, 0x00000060); - nv_wo32(ctx, 0x0444, 0x00000080); - nv_wo32(ctx, 0x0448, 0xffff0000); - nv_wo32(ctx, 0x044c, 0x00000001); - nv_wo32(ctx, 0x0460, 0x44400000); - nv_wo32(ctx, 0x048c, 0xffff0000); - for (i = 0x04e0; i < 0x04e8; i += 4) - nv_wo32(ctx, i, 0x0fff0000); - nv_wo32(ctx, 0x04ec, 0x00011100); - for (i = 0x0508; i < 0x0548; i += 4) - nv_wo32(ctx, i, 0x07ff0000); - nv_wo32(ctx, 0x0550, 0x4b7fffff); - nv_wo32(ctx, 0x058c, 0x00000080); - nv_wo32(ctx, 0x0590, 0x30201000); - nv_wo32(ctx, 0x0594, 0x70605040); - nv_wo32(ctx, 0x0598, 0xb8a89888); - nv_wo32(ctx, 0x059c, 0xf8e8d8c8); - nv_wo32(ctx, 0x05b0, 0xb0000000); - for (i = 0x0600; i < 0x0640; i += 4) - nv_wo32(ctx, i, 0x00010588); - for (i = 0x0640; i < 0x0680; i += 4) - nv_wo32(ctx, i, 0x00030303); - for (i = 0x06c0; i < 0x0700; i += 4) - nv_wo32(ctx, i, 0x0008aae4); - for (i = 0x0700; i < 0x0740; i += 4) - nv_wo32(ctx, i, 0x01012000); - for (i = 0x0740; i < 0x0780; i += 4) - nv_wo32(ctx, i, 0x00080008); - nv_wo32(ctx, 0x085c, 0x00040000); - nv_wo32(ctx, 0x0860, 0x00010000); - for (i = 0x0864; i < 0x0874; i += 4) - nv_wo32(ctx, i, 0x00040004); - for (i = 0x1f18; i <= 0x3088 ; i += 16) { - nv_wo32(ctx, i + 0, 0x10700ff9); - nv_wo32(ctx, i + 1, 0x0436086c); - nv_wo32(ctx, i + 2, 0x000c001b); - } - for (i = 0x30b8; i < 0x30c8; i += 4) - nv_wo32(ctx, i, 0x0000ffff); - nv_wo32(ctx, 0x344c, 0x3f800000); - nv_wo32(ctx, 0x3808, 0x3f800000); - nv_wo32(ctx, 0x381c, 0x3f800000); - nv_wo32(ctx, 0x3848, 0x40000000); - nv_wo32(ctx, 0x384c, 0x3f800000); - nv_wo32(ctx, 0x3850, 0x3f000000); - nv_wo32(ctx, 0x3858, 0x40000000); - nv_wo32(ctx, 0x385c, 0x3f800000); - nv_wo32(ctx, 0x3864, 0xbf800000); - nv_wo32(ctx, 0x386c, 0xbf800000); + nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); + return 0; } -static void -nv34_graph_context_init(struct nouveau_gpuobj *ctx) +int +nv20_graph_context_fini(struct nouveau_object *object, bool suspend) { - int i; - - nv_wo32(ctx, 0x040c, 0x01000101); - nv_wo32(ctx, 0x0420, 0x00000111); - nv_wo32(ctx, 0x0424, 0x00000060); - nv_wo32(ctx, 0x0440, 0x00000080); - nv_wo32(ctx, 0x0444, 0xffff0000); - nv_wo32(ctx, 0x0448, 0x00000001); - nv_wo32(ctx, 0x045c, 0x44400000); - nv_wo32(ctx, 0x0480, 0xffff0000); - for (i = 0x04d4; i < 0x04dc; i += 4) - nv_wo32(ctx, i, 0x0fff0000); - nv_wo32(ctx, 0x04e0, 0x00011100); - for (i = 0x04fc; i < 0x053c; i += 4) - nv_wo32(ctx, i, 0x07ff0000); - nv_wo32(ctx, 0x0544, 0x4b7fffff); - nv_wo32(ctx, 0x057c, 0x00000080); - nv_wo32(ctx, 0x0580, 0x30201000); - nv_wo32(ctx, 0x0584, 0x70605040); - nv_wo32(ctx, 0x0588, 0xb8a89888); - nv_wo32(ctx, 0x058c, 0xf8e8d8c8); - nv_wo32(ctx, 0x05a0, 0xb0000000); - for (i = 0x05f0; i < 0x0630; i += 4) - nv_wo32(ctx, i, 0x00010588); - for (i = 0x0630; i < 0x0670; i += 4) - nv_wo32(ctx, i, 0x00030303); - for (i = 0x06b0; i < 0x06f0; i += 4) - nv_wo32(ctx, i, 0x0008aae4); - for (i = 0x06f0; i < 0x0730; i += 4) - nv_wo32(ctx, i, 0x01012000); - for (i = 0x0730; i < 0x0770; i += 4) - nv_wo32(ctx, i, 0x00080008); - nv_wo32(ctx, 0x0850, 0x00040000); - nv_wo32(ctx, 0x0854, 0x00010000); - for (i = 0x0858; i < 0x0868; i += 4) - nv_wo32(ctx, i, 0x00040004); - for (i = 0x15ac; i <= 0x271c ; i += 16) { - nv_wo32(ctx, i + 0, 0x10700ff9); - nv_wo32(ctx, i + 1, 0x0436086c); - nv_wo32(ctx, i + 2, 0x000c001b); + struct nv20_graph_priv *priv = (void *)object->engine; + struct nv20_graph_chan *chan = (void *)object; + int chid = -1; + + nv_mask(priv, 0x400720, 0x00000001, 0x00000000); + if (nv_rd32(priv, 0x400144) & 0x00010000) + chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24; + if (chan->chid == chid) { + nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4); + nv_wr32(priv, 0x400788, 0x00000002); + nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); + nv_wr32(priv, 0x400144, 0x10000000); + nv_mask(priv, 0x400148, 0xff000000, 0x1f000000); } - for (i = 0x274c; i < 0x275c; i += 4) - nv_wo32(ctx, i, 0x0000ffff); - nv_wo32(ctx, 0x2ae0, 0x3f800000); - nv_wo32(ctx, 0x2e9c, 0x3f800000); - nv_wo32(ctx, 0x2eb0, 0x3f800000); - nv_wo32(ctx, 0x2edc, 0x40000000); - nv_wo32(ctx, 0x2ee0, 0x3f800000); - nv_wo32(ctx, 0x2ee4, 0x3f000000); - nv_wo32(ctx, 0x2eec, 0x40000000); - nv_wo32(ctx, 0x2ef0, 0x3f800000); - nv_wo32(ctx, 0x2ef8, 0xbf800000); - nv_wo32(ctx, 0x2f00, 0xbf800000); -} + nv_mask(priv, 0x400720, 0x00000001, 0x00000001); -static void -nv35_36_graph_context_init(struct nouveau_gpuobj *ctx) -{ - int i; - - nv_wo32(ctx, 0x040c, 0x00000101); - nv_wo32(ctx, 0x0420, 0x00000111); - nv_wo32(ctx, 0x0424, 0x00000060); - nv_wo32(ctx, 0x0440, 0x00000080); - nv_wo32(ctx, 0x0444, 0xffff0000); - nv_wo32(ctx, 0x0448, 0x00000001); - nv_wo32(ctx, 0x045c, 0x44400000); - nv_wo32(ctx, 0x0488, 0xffff0000); - for (i = 0x04dc; i < 0x04e4; i += 4) - nv_wo32(ctx, i, 0x0fff0000); - nv_wo32(ctx, 0x04e8, 0x00011100); - for (i = 0x0504; i < 0x0544; i += 4) - nv_wo32(ctx, i, 0x07ff0000); - nv_wo32(ctx, 0x054c, 0x4b7fffff); - nv_wo32(ctx, 0x0588, 0x00000080); - nv_wo32(ctx, 0x058c, 0x30201000); - nv_wo32(ctx, 0x0590, 0x70605040); - nv_wo32(ctx, 0x0594, 0xb8a89888); - nv_wo32(ctx, 0x0598, 0xf8e8d8c8); - nv_wo32(ctx, 0x05ac, 0xb0000000); - for (i = 0x0604; i < 0x0644; i += 4) - nv_wo32(ctx, i, 0x00010588); - for (i = 0x0644; i < 0x0684; i += 4) - nv_wo32(ctx, i, 0x00030303); - for (i = 0x06c4; i < 0x0704; i += 4) - nv_wo32(ctx, i, 0x0008aae4); - for (i = 0x0704; i < 0x0744; i += 4) - nv_wo32(ctx, i, 0x01012000); - for (i = 0x0744; i < 0x0784; i += 4) - nv_wo32(ctx, i, 0x00080008); - nv_wo32(ctx, 0x0860, 0x00040000); - nv_wo32(ctx, 0x0864, 0x00010000); - for (i = 0x0868; i < 0x0878; i += 4) - nv_wo32(ctx, i, 0x00040004); - for (i = 0x1f1c; i <= 0x308c ; i += 16) { - nv_wo32(ctx, i + 0, 0x10700ff9); - nv_wo32(ctx, i + 4, 0x0436086c); - nv_wo32(ctx, i + 8, 0x000c001b); - } - for (i = 0x30bc; i < 0x30cc; i += 4) - nv_wo32(ctx, i, 0x0000ffff); - nv_wo32(ctx, 0x3450, 0x3f800000); - nv_wo32(ctx, 0x380c, 0x3f800000); - nv_wo32(ctx, 0x3820, 0x3f800000); - nv_wo32(ctx, 0x384c, 0x40000000); - nv_wo32(ctx, 0x3850, 0x3f800000); - nv_wo32(ctx, 0x3854, 0x3f000000); - nv_wo32(ctx, 0x385c, 0x40000000); - nv_wo32(ctx, 0x3860, 0x3f800000); - nv_wo32(ctx, 0x3868, 0xbf800000); - nv_wo32(ctx, 0x3870, 0xbf800000); + nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000); + return nouveau_graph_context_fini(&chan->base, suspend); } -int -nv20_graph_context_new(struct nouveau_channel *chan, int engine) -{ - struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine); - struct nouveau_gpuobj *grctx = NULL; - struct drm_device *dev = chan->dev; - int ret; - - ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16, - NVOBJ_FLAG_ZERO_ALLOC, &grctx); - if (ret) - return ret; - - /* Initialise default context values */ - pgraph->grctx_init(grctx); - - /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */ - /* CTX_USER */ - nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1); +static struct nouveau_oclass +nv20_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x20), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv20_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = nv20_graph_context_init, + .fini = nv20_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; - nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->addr >> 4); - chan->engctx[engine] = grctx; - return 0; -} +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ void -nv20_graph_context_del(struct nouveau_channel *chan, int engine) +nv20_graph_tile_prog(struct nouveau_engine *engine, int i) { - struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine); - struct nouveau_gpuobj *grctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i]; + struct nouveau_fifo *pfifo = nouveau_fifo(engine); + struct nv20_graph_priv *priv = (void *)engine; unsigned long flags; - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + pfifo->pause(pfifo, &flags); + nv04_graph_idle(priv); - /* Unload the context if it's the currently active one */ - if (nv10_graph_channel(dev) == chan) - nv20_graph_unload_context(dev); + nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr); - /* Free the context resources */ - nv_wo32(pgraph->ctxtab, chan->id * 4, 0); + if (nv_device(engine)->card_type == NV_20) { + nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp); + } - nouveau_gpuobj_ref(NULL, &grctx); - chan->engctx[engine] = NULL; + pfifo->start(pfifo, &flags); } -static void -nv20_graph_set_tile_region(struct drm_device *dev, int i) +void +nv20_graph_intr(struct nouveau_subdev *subdev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - 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); - nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); - - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->limit); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->pitch); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->addr); - - if (dev_priv->card_type == NV_20) { - nv_wr32(dev, NV20_PGRAPH_ZCOMP(i), tile->zcomp); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->zcomp); + struct nv20_graph_priv *priv = (void *)subdev; + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_handle *handle = NULL; + u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + u32 chid = (addr & 0x01f00000) >> 20; + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff; + u32 inst = nv_ro32(priv->ctxtab, (chid * 4)) << 4; + u32 show = stat; + + if (stat & NV_PGRAPH_INTR_ERROR) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + handle = nouveau_engctx_lookup_class(engine, inst, class); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; + nouveau_engctx_handle_put(handle); + } } -} - -int -nv20_graph_init(struct drm_device *dev, int engine) -{ - struct nv20_graph_engine *pgraph = nv_engine(dev, engine); - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t tmp, vramsz; - int i; - - nv_wr32(dev, NV03_PMC_ENABLE, - nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); - nv_wr32(dev, NV03_PMC_ENABLE, - nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); - - nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->addr >> 4); - - nv20_graph_rdi(dev); - - nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700); - nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ - nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000); - nv_wr32(dev, 0x40009C , 0x00000040); - - if (dev_priv->chipset >= 0x25) { - nv_wr32(dev, 0x400890, 0x00a8cfff); - nv_wr32(dev, 0x400610, 0x304B1FB6); - nv_wr32(dev, 0x400B80, 0x1cbd3883); - nv_wr32(dev, 0x400B84, 0x44000000); - nv_wr32(dev, 0x400098, 0x40000080); - nv_wr32(dev, 0x400B88, 0x000000ff); - } else { - nv_wr32(dev, 0x400880, 0x0008c7df); - nv_wr32(dev, 0x400094, 0x00000005); - nv_wr32(dev, 0x400B80, 0x45eae20e); - nv_wr32(dev, 0x400B84, 0x24000000); - nv_wr32(dev, 0x400098, 0x00000040); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00038); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E10038); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030); + nv_wr32(priv, NV03_PGRAPH_INTR, stat); + nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + + if (show) { + nv_info(priv, ""); + nouveau_bitfield_print(nv10_graph_intr_name, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv10_graph_nstatus, nstatus); + printk("\n"); + nv_info(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n", + chid, subc, class, mthd, data); } +} - /* Turn all the tiling regions off. */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) - nv20_graph_set_tile_region(dev, i); - - nv_wr32(dev, 0x4009a0, nv_rd32(dev, 0x100324)); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, nv_rd32(dev, 0x100324)); - - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); - - tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) & 0x0007ff00; - nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp); - tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) | 0x00020100; - nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp); - - /* begin RAM config */ - vramsz = pci_resource_len(dev->pdev, 0) - 1; - nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1)); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG1)); - nv_wr32(dev, 0x400820, 0); - nv_wr32(dev, 0x400824, 0); - nv_wr32(dev, 0x400864, vramsz - 1); - nv_wr32(dev, 0x400868, vramsz - 1); +static int +nv20_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_priv *priv; + int ret; - /* interesting.. the below overwrites some of the tile setup above.. */ - nv_wr32(dev, 0x400B20, 0x00000000); - nv_wr32(dev, 0x400B04, 0xFFFFFFFF); + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); - nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); - nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); - nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); + ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + if (ret) + return ret; + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv20_graph_intr; + nv_engine(priv)->cclass = &nv20_graph_cclass; + nv_engine(priv)->sclass = nv20_graph_sclass; + nv_engine(priv)->tile_prog = nv20_graph_tile_prog; return 0; } -int -nv30_graph_init(struct drm_device *dev, int engine) +void +nv20_graph_dtor(struct nouveau_object *object) { - struct nv20_graph_engine *pgraph = nv_engine(dev, engine); - struct drm_nouveau_private *dev_priv = dev->dev_private; - int i; - - nv_wr32(dev, NV03_PMC_ENABLE, - nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); - nv_wr32(dev, NV03_PMC_ENABLE, - nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); - - nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->addr >> 4); - - nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(dev, 0x400890, 0x01b463ff); - nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xf2de0475); - nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); - nv_wr32(dev, 0x400B80, 0x1003d888); - nv_wr32(dev, 0x400B84, 0x0c000000); - nv_wr32(dev, 0x400098, 0x00000000); - nv_wr32(dev, 0x40009C, 0x0005ad00); - nv_wr32(dev, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ - nv_wr32(dev, 0x4000a0, 0x00000000); - nv_wr32(dev, 0x4000a4, 0x00000008); - nv_wr32(dev, 0x4008a8, 0xb784a400); - nv_wr32(dev, 0x400ba0, 0x002f8685); - nv_wr32(dev, 0x400ba4, 0x00231f3f); - nv_wr32(dev, 0x4008a4, 0x40000020); - - if (dev_priv->chipset == 0x34) { - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00200201); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000008); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000032); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00004); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000002); - } + struct nv20_graph_priv *priv = (void *)object; + nouveau_gpuobj_ref(NULL, &priv->ctxtab); + nouveau_graph_destroy(&priv->base); +} - nv_wr32(dev, 0x4000c0, 0x00000016); +int +nv20_graph_init(struct nouveau_object *object) +{ + struct nouveau_engine *engine = nv_engine(object); + struct nv20_graph_priv *priv = (void *)engine; + struct nouveau_fb *pfb = nouveau_fb(object); + u32 tmp, vramsz; + int ret, i; - /* Turn all the tiling regions off. */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) - nv20_graph_set_tile_region(dev, i); + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(dev, 0x0040075c , 0x00000001); + nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4); - /* begin RAM config */ - /* vramsz = pci_resource_len(dev->pdev, 0) - 1; */ - nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1)); - if (dev_priv->chipset != 0x34) { - nv_wr32(dev, 0x400750, 0x00EA0000); - nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x400750, 0x00EA0004); - nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG1)); + if (nv_device(priv)->chipset == 0x20) { + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000); + for (i = 0; i < 15; i++) + nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000); + nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); + } else { + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000); + for (i = 0; i < 32; i++) + nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000); + nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); } - return 0; -} + nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); -int -nv20_graph_fini(struct drm_device *dev, int engine, bool suspend) -{ - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) { - nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - return -EBUSY; - } - nv20_graph_unload_context(dev); - nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); - return 0; -} + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700); + nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ + nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000); + nv_wr32(priv, 0x40009C , 0x00000040); -static void -nv20_graph_isr(struct drm_device *dev) -{ - u32 stat; - - while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { - u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); - u32 chid = (addr & 0x01f00000) >> 20; - u32 subc = (addr & 0x00070000) >> 16; - u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff; - u32 show = stat; - - if (stat & NV_PGRAPH_INTR_ERROR) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) - show &= ~NV_PGRAPH_INTR_ERROR; - } - } + if (nv_device(priv)->chipset >= 0x25) { + nv_wr32(priv, 0x400890, 0x00a8cfff); + nv_wr32(priv, 0x400610, 0x304B1FB6); + nv_wr32(priv, 0x400B80, 0x1cbd3883); + nv_wr32(priv, 0x400B84, 0x44000000); + nv_wr32(priv, 0x400098, 0x40000080); + nv_wr32(priv, 0x400B88, 0x000000ff); - nv_wr32(dev, NV03_PGRAPH_INTR, stat); - nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); - - if (show && nouveau_ratelimit()) { - NV_INFO(dev, "PGRAPH -"); - nouveau_bitfield_print(nv10_graph_intr, show); - printk(" nsource:"); - nouveau_bitfield_print(nv04_graph_nsource, nsource); - printk(" nstatus:"); - nouveau_bitfield_print(nv10_graph_nstatus, nstatus); - printk("\n"); - NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " - "mthd 0x%04x data 0x%08x\n", - chid, subc, class, mthd, data); - } + } else { + nv_wr32(priv, 0x400880, 0x0008c7df); + nv_wr32(priv, 0x400094, 0x00000005); + nv_wr32(priv, 0x400B80, 0x45eae20e); + nv_wr32(priv, 0x400B84, 0x24000000); + nv_wr32(priv, 0x400098, 0x00000040); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030); } -} - -static void -nv20_graph_destroy(struct drm_device *dev, int engine) -{ - struct nv20_graph_engine *pgraph = nv_engine(dev, engine); - nouveau_irq_unregister(dev, 12); - nouveau_gpuobj_ref(NULL, &pgraph->ctxtab); + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->tile.regions; i++) + engine->tile_prog(engine, i); - NVOBJ_ENGINE_DEL(dev, GR); - kfree(pgraph); -} + nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324)); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324)); -int -nv20_graph_create(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv20_graph_engine *pgraph; - int ret; + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); - pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); - if (!pgraph) - return -ENOMEM; - - pgraph->base.destroy = nv20_graph_destroy; - pgraph->base.fini = nv20_graph_fini; - pgraph->base.context_new = nv20_graph_context_new; - pgraph->base.context_del = nv20_graph_context_del; - pgraph->base.object_new = nv04_graph_object_new; - pgraph->base.set_tile_region = nv20_graph_set_tile_region; - - pgraph->grctx_user = 0x0028; - if (dev_priv->card_type == NV_20) { - pgraph->base.init = nv20_graph_init; - switch (dev_priv->chipset) { - case 0x20: - pgraph->grctx_init = nv20_graph_context_init; - pgraph->grctx_size = NV20_GRCTX_SIZE; - pgraph->grctx_user = 0x0000; - break; - case 0x25: - case 0x28: - pgraph->grctx_init = nv25_graph_context_init; - pgraph->grctx_size = NV25_GRCTX_SIZE; - break; - case 0x2a: - pgraph->grctx_init = nv2a_graph_context_init; - pgraph->grctx_size = NV2A_GRCTX_SIZE; - pgraph->grctx_user = 0x0000; - break; - default: - NV_ERROR(dev, "PGRAPH: unknown chipset\n"); - kfree(pgraph); - return 0; - } - } else { - pgraph->base.init = nv30_graph_init; - switch (dev_priv->chipset) { - case 0x30: - case 0x31: - pgraph->grctx_init = nv30_31_graph_context_init; - pgraph->grctx_size = NV30_31_GRCTX_SIZE; - break; - case 0x34: - pgraph->grctx_init = nv34_graph_context_init; - pgraph->grctx_size = NV34_GRCTX_SIZE; - break; - case 0x35: - case 0x36: - pgraph->grctx_init = nv35_36_graph_context_init; - pgraph->grctx_size = NV35_36_GRCTX_SIZE; - break; - default: - NV_ERROR(dev, "PGRAPH: unknown chipset\n"); - kfree(pgraph); - return 0; - } - } + tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00; + nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); + tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100; + nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); - /* Create Context Pointer Table */ - ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC, - &pgraph->ctxtab); - if (ret) { - kfree(pgraph); - return ret; - } + /* begin RAM config */ + vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1; + nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200)); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204)); + nv_wr32(priv, 0x400820, 0); + nv_wr32(priv, 0x400824, 0); + nv_wr32(priv, 0x400864, vramsz - 1); + nv_wr32(priv, 0x400868, vramsz - 1); - NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); - nouveau_irq_register(dev, 12, nv20_graph_isr); - - NVOBJ_CLASS(dev, 0x0030, GR); /* null */ - NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ - NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ - NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ - NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ - NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ - NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ - NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ - NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ - NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ - NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ - NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ - if (dev_priv->card_type == NV_20) { - NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */ - NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */ - - /* kelvin */ - if (dev_priv->chipset < 0x25) - NVOBJ_CLASS(dev, 0x0097, GR); - else - NVOBJ_CLASS(dev, 0x0597, GR); - } else { - NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */ - NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */ - NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */ - NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */ - - /* rankine */ - if (0x00000003 & (1 << (dev_priv->chipset & 0x0f))) - NVOBJ_CLASS(dev, 0x0397, GR); - else - if (0x00000010 & (1 << (dev_priv->chipset & 0x0f))) - NVOBJ_CLASS(dev, 0x0697, GR); - else - if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f))) - NVOBJ_CLASS(dev, 0x0497, GR); - } + /* interesting.. the below overwrites some of the tile setup above.. */ + nv_wr32(priv, 0x400B20, 0x00000000); + nv_wr32(priv, 0x400B04, 0xFFFFFFFF); + nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); + nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); + nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); + nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); return 0; } + +struct nouveau_oclass +nv20_graph_oclass = { + .handle = NV_ENGINE(GR, 0x20), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv20_graph_ctor, + .dtor = nv20_graph_dtor, + .init = nv20_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h new file mode 100644 index 0000000..2bea731 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h @@ -0,0 +1,31 @@ +#ifndef __NV20_GRAPH_H__ +#define __NV20_GRAPH_H__ + +#include <core/enum.h> + +#include <engine/graph.h> +#include <engine/fifo.h> + +struct nv20_graph_priv { + struct nouveau_graph base; + struct nouveau_gpuobj *ctxtab; +}; + +struct nv20_graph_chan { + struct nouveau_graph_chan base; + int chid; +}; + +extern struct nouveau_oclass nv25_graph_sclass[]; +int nv20_graph_context_init(struct nouveau_object *); +int nv20_graph_context_fini(struct nouveau_object *, bool); + +void nv20_graph_tile_prog(struct nouveau_engine *, int); +void nv20_graph_intr(struct nouveau_subdev *); + +void nv20_graph_dtor(struct nouveau_object *); +int nv20_graph_init(struct nouveau_object *); + +int nv30_graph_init(struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c new file mode 100644 index 0000000..b2b650d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c @@ -0,0 +1,167 @@ +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/enum.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/graph.h> + +#include "nv20.h" +#include "regs.h" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +struct nouveau_oclass +nv25_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */ + { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */ + { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */ + { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */ + { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */ + { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */ + { 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */ + { 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */ + { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */ + { 0x0597, &nv04_graph_ofuncs, NULL }, /* kelvin */ + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static int +nv25_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_chan *chan; + int ret, i; + + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x3724, + 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->chid = nouveau_fifo_chan(parent)->chid; + + nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); + nv_wo32(chan, 0x035c, 0xffff0000); + nv_wo32(chan, 0x03c0, 0x0fff0000); + nv_wo32(chan, 0x03c4, 0x0fff0000); + nv_wo32(chan, 0x049c, 0x00000101); + nv_wo32(chan, 0x04b0, 0x00000111); + nv_wo32(chan, 0x04c8, 0x00000080); + nv_wo32(chan, 0x04cc, 0xffff0000); + nv_wo32(chan, 0x04d0, 0x00000001); + nv_wo32(chan, 0x04e4, 0x44400000); + nv_wo32(chan, 0x04fc, 0x4b800000); + for (i = 0x0510; i <= 0x051c; i += 4) + nv_wo32(chan, i, 0x00030303); + for (i = 0x0530; i <= 0x053c; i += 4) + nv_wo32(chan, i, 0x00080000); + for (i = 0x0548; i <= 0x0554; i += 4) + nv_wo32(chan, i, 0x01012000); + for (i = 0x0558; i <= 0x0564; i += 4) + nv_wo32(chan, i, 0x000105b8); + for (i = 0x0568; i <= 0x0574; i += 4) + nv_wo32(chan, i, 0x00080008); + for (i = 0x0598; i <= 0x05d4; i += 4) + nv_wo32(chan, i, 0x07ff0000); + nv_wo32(chan, 0x05e0, 0x4b7fffff); + nv_wo32(chan, 0x0620, 0x00000080); + nv_wo32(chan, 0x0624, 0x30201000); + nv_wo32(chan, 0x0628, 0x70605040); + nv_wo32(chan, 0x062c, 0xb0a09080); + nv_wo32(chan, 0x0630, 0xf0e0d0c0); + nv_wo32(chan, 0x0664, 0x00000001); + nv_wo32(chan, 0x066c, 0x00004000); + nv_wo32(chan, 0x0678, 0x00000001); + nv_wo32(chan, 0x0680, 0x00040000); + nv_wo32(chan, 0x0684, 0x00010000); + for (i = 0x1b04; i <= 0x2374; i += 16) { + nv_wo32(chan, (i + 0), 0x10700ff9); + nv_wo32(chan, (i + 4), 0x0436086c); + nv_wo32(chan, (i + 8), 0x000c001b); + } + nv_wo32(chan, 0x2704, 0x3f800000); + nv_wo32(chan, 0x2718, 0x3f800000); + nv_wo32(chan, 0x2744, 0x40000000); + nv_wo32(chan, 0x2748, 0x3f800000); + nv_wo32(chan, 0x274c, 0x3f000000); + nv_wo32(chan, 0x2754, 0x40000000); + nv_wo32(chan, 0x2758, 0x3f800000); + nv_wo32(chan, 0x2760, 0xbf800000); + nv_wo32(chan, 0x2768, 0xbf800000); + nv_wo32(chan, 0x308c, 0x000fe000); + nv_wo32(chan, 0x3108, 0x000003f8); + nv_wo32(chan, 0x3468, 0x002fe000); + for (i = 0x3484; i <= 0x34a0; i += 4) + nv_wo32(chan, i, 0x001c527c); + return 0; +} + +static struct nouveau_oclass +nv25_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x25), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv25_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = nv20_graph_context_init, + .fini = nv20_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static int +nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_priv *priv; + int ret; + + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv20_graph_intr; + nv_engine(priv)->cclass = &nv25_graph_cclass; + nv_engine(priv)->sclass = nv25_graph_sclass; + nv_engine(priv)->tile_prog = nv20_graph_tile_prog; + return 0; +} + +struct nouveau_oclass +nv25_graph_oclass = { + .handle = NV_ENGINE(GR, 0x25), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv25_graph_ctor, + .dtor = nv20_graph_dtor, + .init = nv20_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c new file mode 100644 index 0000000..700462f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c @@ -0,0 +1,134 @@ +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/enum.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/graph.h> + +#include "nv20.h" +#include "regs.h" + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static int +nv2a_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_chan *chan; + int ret, i; + + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x36b0, + 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->chid = nouveau_fifo_chan(parent)->chid; + + nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24)); + nv_wo32(chan, 0x033c, 0xffff0000); + nv_wo32(chan, 0x03a0, 0x0fff0000); + nv_wo32(chan, 0x03a4, 0x0fff0000); + nv_wo32(chan, 0x047c, 0x00000101); + nv_wo32(chan, 0x0490, 0x00000111); + nv_wo32(chan, 0x04a8, 0x44400000); + for (i = 0x04d4; i <= 0x04e0; i += 4) + nv_wo32(chan, i, 0x00030303); + for (i = 0x04f4; i <= 0x0500; i += 4) + nv_wo32(chan, i, 0x00080000); + for (i = 0x050c; i <= 0x0518; i += 4) + nv_wo32(chan, i, 0x01012000); + for (i = 0x051c; i <= 0x0528; i += 4) + nv_wo32(chan, i, 0x000105b8); + for (i = 0x052c; i <= 0x0538; i += 4) + nv_wo32(chan, i, 0x00080008); + for (i = 0x055c; i <= 0x0598; i += 4) + nv_wo32(chan, i, 0x07ff0000); + nv_wo32(chan, 0x05a4, 0x4b7fffff); + nv_wo32(chan, 0x05fc, 0x00000001); + nv_wo32(chan, 0x0604, 0x00004000); + nv_wo32(chan, 0x0610, 0x00000001); + nv_wo32(chan, 0x0618, 0x00040000); + nv_wo32(chan, 0x061c, 0x00010000); + for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */ + nv_wo32(chan, (i + 0), 0x10700ff9); + nv_wo32(chan, (i + 4), 0x0436086c); + nv_wo32(chan, (i + 8), 0x000c001b); + } + nv_wo32(chan, 0x269c, 0x3f800000); + nv_wo32(chan, 0x26b0, 0x3f800000); + nv_wo32(chan, 0x26dc, 0x40000000); + nv_wo32(chan, 0x26e0, 0x3f800000); + nv_wo32(chan, 0x26e4, 0x3f000000); + nv_wo32(chan, 0x26ec, 0x40000000); + nv_wo32(chan, 0x26f0, 0x3f800000); + nv_wo32(chan, 0x26f8, 0xbf800000); + nv_wo32(chan, 0x2700, 0xbf800000); + nv_wo32(chan, 0x3024, 0x000fe000); + nv_wo32(chan, 0x30a0, 0x000003f8); + nv_wo32(chan, 0x33fc, 0x002fe000); + for (i = 0x341c; i <= 0x3438; i += 4) + nv_wo32(chan, i, 0x001c527c); + return 0; +} + +static struct nouveau_oclass +nv2a_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x2a), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv2a_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = nv20_graph_context_init, + .fini = nv20_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static int +nv2a_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_priv *priv; + int ret; + + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv20_graph_intr; + nv_engine(priv)->cclass = &nv2a_graph_cclass; + nv_engine(priv)->sclass = nv25_graph_sclass; + nv_engine(priv)->tile_prog = nv20_graph_tile_prog; + return 0; +} + +struct nouveau_oclass +nv2a_graph_oclass = { + .handle = NV_ENGINE(GR, 0x2a), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv2a_graph_ctor, + .dtor = nv20_graph_dtor, + .init = nv20_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c new file mode 100644 index 0000000..cedadaa --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c @@ -0,0 +1,238 @@ +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/enum.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/graph.h> + +#include "nv20.h" +#include "regs.h" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv30_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */ + { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */ + { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */ + { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */ + { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */ + { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */ + { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */ + { 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */ + { 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */ + { 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */ + { 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */ + { 0x0397, &nv04_graph_ofuncs, NULL }, /* rankine */ + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static int +nv30_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_chan *chan; + int ret, i; + + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x5f48, + 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->chid = nouveau_fifo_chan(parent)->chid; + + nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); + nv_wo32(chan, 0x0410, 0x00000101); + nv_wo32(chan, 0x0424, 0x00000111); + nv_wo32(chan, 0x0428, 0x00000060); + nv_wo32(chan, 0x0444, 0x00000080); + nv_wo32(chan, 0x0448, 0xffff0000); + nv_wo32(chan, 0x044c, 0x00000001); + nv_wo32(chan, 0x0460, 0x44400000); + nv_wo32(chan, 0x048c, 0xffff0000); + for (i = 0x04e0; i < 0x04e8; i += 4) + nv_wo32(chan, i, 0x0fff0000); + nv_wo32(chan, 0x04ec, 0x00011100); + for (i = 0x0508; i < 0x0548; i += 4) + nv_wo32(chan, i, 0x07ff0000); + nv_wo32(chan, 0x0550, 0x4b7fffff); + nv_wo32(chan, 0x058c, 0x00000080); + nv_wo32(chan, 0x0590, 0x30201000); + nv_wo32(chan, 0x0594, 0x70605040); + nv_wo32(chan, 0x0598, 0xb8a89888); + nv_wo32(chan, 0x059c, 0xf8e8d8c8); + nv_wo32(chan, 0x05b0, 0xb0000000); + for (i = 0x0600; i < 0x0640; i += 4) + nv_wo32(chan, i, 0x00010588); + for (i = 0x0640; i < 0x0680; i += 4) + nv_wo32(chan, i, 0x00030303); + for (i = 0x06c0; i < 0x0700; i += 4) + nv_wo32(chan, i, 0x0008aae4); + for (i = 0x0700; i < 0x0740; i += 4) + nv_wo32(chan, i, 0x01012000); + for (i = 0x0740; i < 0x0780; i += 4) + nv_wo32(chan, i, 0x00080008); + nv_wo32(chan, 0x085c, 0x00040000); + nv_wo32(chan, 0x0860, 0x00010000); + for (i = 0x0864; i < 0x0874; i += 4) + nv_wo32(chan, i, 0x00040004); + for (i = 0x1f18; i <= 0x3088 ; i += 16) { + nv_wo32(chan, i + 0, 0x10700ff9); + nv_wo32(chan, i + 1, 0x0436086c); + nv_wo32(chan, i + 2, 0x000c001b); + } + for (i = 0x30b8; i < 0x30c8; i += 4) + nv_wo32(chan, i, 0x0000ffff); + nv_wo32(chan, 0x344c, 0x3f800000); + nv_wo32(chan, 0x3808, 0x3f800000); + nv_wo32(chan, 0x381c, 0x3f800000); + nv_wo32(chan, 0x3848, 0x40000000); + nv_wo32(chan, 0x384c, 0x3f800000); + nv_wo32(chan, 0x3850, 0x3f000000); + nv_wo32(chan, 0x3858, 0x40000000); + nv_wo32(chan, 0x385c, 0x3f800000); + nv_wo32(chan, 0x3864, 0xbf800000); + nv_wo32(chan, 0x386c, 0xbf800000); + return 0; +} + +static struct nouveau_oclass +nv30_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x30), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv30_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = nv20_graph_context_init, + .fini = nv20_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static int +nv30_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_priv *priv; + int ret; + + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv20_graph_intr; + nv_engine(priv)->cclass = &nv30_graph_cclass; + nv_engine(priv)->sclass = nv30_graph_sclass; + nv_engine(priv)->tile_prog = nv20_graph_tile_prog; + return 0; +} + +int +nv30_graph_init(struct nouveau_object *object) +{ + struct nouveau_engine *engine = nv_engine(object); + struct nv20_graph_priv *priv = (void *)engine; + struct nouveau_fb *pfb = nouveau_fb(object); + int ret, i; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4); + + nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nv_wr32(priv, 0x400890, 0x01b463ff); + nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475); + nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000); + nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); + nv_wr32(priv, 0x400B80, 0x1003d888); + nv_wr32(priv, 0x400B84, 0x0c000000); + nv_wr32(priv, 0x400098, 0x00000000); + nv_wr32(priv, 0x40009C, 0x0005ad00); + nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ + nv_wr32(priv, 0x4000a0, 0x00000000); + nv_wr32(priv, 0x4000a4, 0x00000008); + nv_wr32(priv, 0x4008a8, 0xb784a400); + nv_wr32(priv, 0x400ba0, 0x002f8685); + nv_wr32(priv, 0x400ba4, 0x00231f3f); + nv_wr32(priv, 0x4008a4, 0x40000020); + + if (nv_device(priv)->chipset == 0x34) { + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032); + nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004); + nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002); + } + + nv_wr32(priv, 0x4000c0, 0x00000016); + + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->tile.regions; i++) + engine->tile_prog(engine, i); + + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(priv, 0x0040075c , 0x00000001); + + /* begin RAM config */ + /* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */ + nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); + if (nv_device(priv)->chipset != 0x34) { + nv_wr32(priv, 0x400750, 0x00EA0000); + nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x400750, 0x00EA0004); + nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204)); + } + return 0; +} + +struct nouveau_oclass +nv30_graph_oclass = { + .handle = NV_ENGINE(GR, 0x30), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv30_graph_ctor, + .dtor = nv20_graph_dtor, + .init = nv30_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c new file mode 100644 index 0000000..273f632 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c @@ -0,0 +1,168 @@ +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/enum.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/graph.h> + +#include "nv20.h" +#include "regs.h" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv34_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */ + { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */ + { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */ + { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */ + { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */ + { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */ + { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */ + { 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */ + { 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */ + { 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */ + { 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */ + { 0x0697, &nv04_graph_ofuncs, NULL }, /* rankine */ + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static int +nv34_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_chan *chan; + int ret, i; + + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x46dc, + 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->chid = nouveau_fifo_chan(parent)->chid; + + nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); + nv_wo32(chan, 0x040c, 0x01000101); + nv_wo32(chan, 0x0420, 0x00000111); + nv_wo32(chan, 0x0424, 0x00000060); + nv_wo32(chan, 0x0440, 0x00000080); + nv_wo32(chan, 0x0444, 0xffff0000); + nv_wo32(chan, 0x0448, 0x00000001); + nv_wo32(chan, 0x045c, 0x44400000); + nv_wo32(chan, 0x0480, 0xffff0000); + for (i = 0x04d4; i < 0x04dc; i += 4) + nv_wo32(chan, i, 0x0fff0000); + nv_wo32(chan, 0x04e0, 0x00011100); + for (i = 0x04fc; i < 0x053c; i += 4) + nv_wo32(chan, i, 0x07ff0000); + nv_wo32(chan, 0x0544, 0x4b7fffff); + nv_wo32(chan, 0x057c, 0x00000080); + nv_wo32(chan, 0x0580, 0x30201000); + nv_wo32(chan, 0x0584, 0x70605040); + nv_wo32(chan, 0x0588, 0xb8a89888); + nv_wo32(chan, 0x058c, 0xf8e8d8c8); + nv_wo32(chan, 0x05a0, 0xb0000000); + for (i = 0x05f0; i < 0x0630; i += 4) + nv_wo32(chan, i, 0x00010588); + for (i = 0x0630; i < 0x0670; i += 4) + nv_wo32(chan, i, 0x00030303); + for (i = 0x06b0; i < 0x06f0; i += 4) + nv_wo32(chan, i, 0x0008aae4); + for (i = 0x06f0; i < 0x0730; i += 4) + nv_wo32(chan, i, 0x01012000); + for (i = 0x0730; i < 0x0770; i += 4) + nv_wo32(chan, i, 0x00080008); + nv_wo32(chan, 0x0850, 0x00040000); + nv_wo32(chan, 0x0854, 0x00010000); + for (i = 0x0858; i < 0x0868; i += 4) + nv_wo32(chan, i, 0x00040004); + for (i = 0x15ac; i <= 0x271c ; i += 16) { + nv_wo32(chan, i + 0, 0x10700ff9); + nv_wo32(chan, i + 1, 0x0436086c); + nv_wo32(chan, i + 2, 0x000c001b); + } + for (i = 0x274c; i < 0x275c; i += 4) + nv_wo32(chan, i, 0x0000ffff); + nv_wo32(chan, 0x2ae0, 0x3f800000); + nv_wo32(chan, 0x2e9c, 0x3f800000); + nv_wo32(chan, 0x2eb0, 0x3f800000); + nv_wo32(chan, 0x2edc, 0x40000000); + nv_wo32(chan, 0x2ee0, 0x3f800000); + nv_wo32(chan, 0x2ee4, 0x3f000000); + nv_wo32(chan, 0x2eec, 0x40000000); + nv_wo32(chan, 0x2ef0, 0x3f800000); + nv_wo32(chan, 0x2ef8, 0xbf800000); + nv_wo32(chan, 0x2f00, 0xbf800000); + return 0; +} + +static struct nouveau_oclass +nv34_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x34), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv34_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = nv20_graph_context_init, + .fini = nv20_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static int +nv34_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_priv *priv; + int ret; + + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv20_graph_intr; + nv_engine(priv)->cclass = &nv34_graph_cclass; + nv_engine(priv)->sclass = nv34_graph_sclass; + nv_engine(priv)->tile_prog = nv20_graph_tile_prog; + return 0; +} + +struct nouveau_oclass +nv34_graph_oclass = { + .handle = NV_ENGINE(GR, 0x34), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv34_graph_ctor, + .dtor = nv20_graph_dtor, + .init = nv30_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c new file mode 100644 index 0000000..f40ee21 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c @@ -0,0 +1,166 @@ +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/enum.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include "nv20.h" +#include "regs.h" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv35_graph_sclass[] = { + { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */ + { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */ + { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */ + { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */ + { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */ + { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */ + { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */ + { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */ + { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */ + { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */ + { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */ + { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */ + { 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */ + { 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */ + { 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */ + { 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */ + { 0x0497, &nv04_graph_ofuncs, NULL }, /* rankine */ + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static int +nv35_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_chan *chan; + int ret, i; + + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x577c, + 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->chid = nouveau_fifo_chan(parent)->chid; + + nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); + nv_wo32(chan, 0x040c, 0x00000101); + nv_wo32(chan, 0x0420, 0x00000111); + nv_wo32(chan, 0x0424, 0x00000060); + nv_wo32(chan, 0x0440, 0x00000080); + nv_wo32(chan, 0x0444, 0xffff0000); + nv_wo32(chan, 0x0448, 0x00000001); + nv_wo32(chan, 0x045c, 0x44400000); + nv_wo32(chan, 0x0488, 0xffff0000); + for (i = 0x04dc; i < 0x04e4; i += 4) + nv_wo32(chan, i, 0x0fff0000); + nv_wo32(chan, 0x04e8, 0x00011100); + for (i = 0x0504; i < 0x0544; i += 4) + nv_wo32(chan, i, 0x07ff0000); + nv_wo32(chan, 0x054c, 0x4b7fffff); + nv_wo32(chan, 0x0588, 0x00000080); + nv_wo32(chan, 0x058c, 0x30201000); + nv_wo32(chan, 0x0590, 0x70605040); + nv_wo32(chan, 0x0594, 0xb8a89888); + nv_wo32(chan, 0x0598, 0xf8e8d8c8); + nv_wo32(chan, 0x05ac, 0xb0000000); + for (i = 0x0604; i < 0x0644; i += 4) + nv_wo32(chan, i, 0x00010588); + for (i = 0x0644; i < 0x0684; i += 4) + nv_wo32(chan, i, 0x00030303); + for (i = 0x06c4; i < 0x0704; i += 4) + nv_wo32(chan, i, 0x0008aae4); + for (i = 0x0704; i < 0x0744; i += 4) + nv_wo32(chan, i, 0x01012000); + for (i = 0x0744; i < 0x0784; i += 4) + nv_wo32(chan, i, 0x00080008); + nv_wo32(chan, 0x0860, 0x00040000); + nv_wo32(chan, 0x0864, 0x00010000); + for (i = 0x0868; i < 0x0878; i += 4) + nv_wo32(chan, i, 0x00040004); + for (i = 0x1f1c; i <= 0x308c ; i += 16) { + nv_wo32(chan, i + 0, 0x10700ff9); + nv_wo32(chan, i + 4, 0x0436086c); + nv_wo32(chan, i + 8, 0x000c001b); + } + for (i = 0x30bc; i < 0x30cc; i += 4) + nv_wo32(chan, i, 0x0000ffff); + nv_wo32(chan, 0x3450, 0x3f800000); + nv_wo32(chan, 0x380c, 0x3f800000); + nv_wo32(chan, 0x3820, 0x3f800000); + nv_wo32(chan, 0x384c, 0x40000000); + nv_wo32(chan, 0x3850, 0x3f800000); + nv_wo32(chan, 0x3854, 0x3f000000); + nv_wo32(chan, 0x385c, 0x40000000); + nv_wo32(chan, 0x3860, 0x3f800000); + nv_wo32(chan, 0x3868, 0xbf800000); + nv_wo32(chan, 0x3870, 0xbf800000); + return 0; +} + +static struct nouveau_oclass +nv35_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x35), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv35_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = nv20_graph_context_init, + .fini = nv20_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static int +nv35_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_graph_priv *priv; + int ret; + + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv20_graph_intr; + nv_engine(priv)->cclass = &nv35_graph_cclass; + nv_engine(priv)->sclass = nv35_graph_sclass; + nv_engine(priv)->tile_prog = nv20_graph_tile_prog; + return 0; +} + +struct nouveau_oclass +nv35_graph_oclass = { + .handle = NV_ENGINE(GR, 0x35), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv35_graph_ctor, + .dtor = nv20_graph_dtor, + .init = nv30_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 466d215..2f9f2c6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -1,151 +1,238 @@ /* - * Copyright (C) 2007 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" +#include <core/os.h> +#include <core/class.h> +#include <core/handle.h> +#include <core/engctx.h> + +#include <subdev/fb.h> +#include <subdev/timer.h> + +#include <engine/graph.h> #include <engine/fifo.h> -#include <core/ramht.h> -struct nv40_graph_engine { - struct nouveau_exec_engine base; - u32 grctx_size; +#include "nv40.h" +#include "regs.h" + +struct nv40_graph_priv { + struct nouveau_graph base; + u32 size; }; +struct nv40_graph_chan { + struct nouveau_graph_chan base; +}; + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + static int -nv40_graph_context_new(struct nouveau_channel *chan, int engine) +nv40_graph_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine); - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *grctx = NULL; - unsigned long flags; + struct nouveau_gpuobj *obj; int ret; - ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16, - NVOBJ_FLAG_ZERO_ALLOC, &grctx); + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent, + 20, 16, 0, &obj); + *pobject = nv_object(obj); if (ret) return ret; - /* Initialise default context values */ - nv40_grctx_fill(dev, grctx); - nv_wo32(grctx, 0, grctx->addr); - - /* init grctx pointer in ramfc, and on PFIFO if channel is - * already active there - */ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_wo32(chan->ramfc, 0x38, grctx->addr >> 4); - nv_mask(dev, 0x002500, 0x00000001, 0x00000000); - if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id) - nv_wr32(dev, 0x0032e0, grctx->addr >> 4); - nv_mask(dev, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - - chan->engctx[engine] = grctx; + nv_wo32(obj, 0x00, nv_mclass(obj)); + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); +#ifdef __BIG_ENDIAN + nv_mo32(obj, 0x08, 0x01000000, 0x01000000); +#endif + nv_wo32(obj, 0x0c, 0x00000000); + nv_wo32(obj, 0x10, 0x00000000); return 0; } -static void -nv40_graph_context_del(struct nouveau_channel *chan, int engine) -{ - struct nouveau_gpuobj *grctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 inst = 0x01000000 | (grctx->addr >> 4); - unsigned long flags; +struct nouveau_ofuncs +nv40_graph_ofuncs = { + .ctor = nv40_graph_object_ctor, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, +}; - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, 0x400720, 0x00000000, 0x00000001); - if (nv_rd32(dev, 0x40032c) == inst) - nv_mask(dev, 0x40032c, 0x01000000, 0x00000000); - if (nv_rd32(dev, 0x400330) == inst) - nv_mask(dev, 0x400330, 0x01000000, 0x00000000); - nv_mask(dev, 0x400720, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - - /* Free the context resources */ - nouveau_gpuobj_ref(NULL, &grctx); - chan->engctx[engine] = NULL; -} +static struct nouveau_oclass +nv40_graph_sclass[] = { + { 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */ + { 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */ + { 0x0030, &nv40_graph_ofuncs, NULL }, /* null */ + { 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */ + { 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */ + { 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */ + { 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */ + { 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */ + { 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */ + { 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */ + { 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */ + { 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */ + { 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */ + { 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */ + { 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */ + { 0x4097, &nv40_graph_ofuncs, NULL }, /* curie */ + {}, +}; + +static struct nouveau_oclass +nv44_graph_sclass[] = { + { 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */ + { 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */ + { 0x0030, &nv40_graph_ofuncs, NULL }, /* null */ + { 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */ + { 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */ + { 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */ + { 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */ + { 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */ + { 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */ + { 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */ + { 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */ + { 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */ + { 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */ + { 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */ + { 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */ + { 0x4497, &nv40_graph_ofuncs, NULL }, /* curie */ + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ -int -nv40_graph_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +static int +nv40_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *obj = NULL; + struct nv40_graph_priv *priv = (void *)engine; + struct nv40_graph_chan *chan; int ret; - ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj); + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, + priv->size, 16, + NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); if (ret) return ret; - obj->engine = 1; - obj->class = class; - nv_wo32(obj, 0x00, class); - nv_wo32(obj, 0x04, 0x00000000); -#ifndef __BIG_ENDIAN - nv_wo32(obj, 0x08, 0x00000000); -#else - nv_wo32(obj, 0x08, 0x01000000); -#endif - nv_wo32(obj, 0x0c, 0x00000000); - nv_wo32(obj, 0x10, 0x00000000); + nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan)); + nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4); + return 0; +} + +static int +nv40_graph_context_fini(struct nouveau_object *object, bool suspend) +{ + struct nv04_graph_priv *priv = (void *)object->engine; + struct nv04_graph_chan *chan = (void *)object; + u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4; + int ret = 0; + + nv_mask(priv, 0x400720, 0x00000001, 0x00000000); + + if (nv_rd32(priv, 0x40032c) == inst) { + if (suspend) { + nv_wr32(priv, 0x400720, 0x00000000); + nv_wr32(priv, 0x400784, inst); + nv_mask(priv, 0x400310, 0x00000020, 0x00000020); + nv_mask(priv, 0x400304, 0x00000001, 0x00000001); + if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) { + u32 insn = nv_rd32(priv, 0x400308); + nv_warn(priv, "ctxprog timeout 0x%08x\n", insn); + ret = -EBUSY; + } + } - ret = nouveau_ramht_insert(chan, handle, obj); - nouveau_gpuobj_ref(NULL, &obj); + nv_mask(priv, 0x40032c, 0x01000000, 0x00000000); + } + + if (nv_rd32(priv, 0x400330) == inst) + nv_mask(priv, 0x400330, 0x01000000, 0x00000000); + + nv_mask(priv, 0x400720, 0x00000001, 0x00000001); return ret; } +static struct nouveau_oclass +nv40_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = _nouveau_graph_context_init, + .fini = nv40_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + static void -nv40_graph_set_tile_region(struct drm_device *dev, int i) +nv40_graph_tile_prog(struct nouveau_engine *engine, int i) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_tile *tile = nvfb_tile(dev, i); + struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i]; + struct nouveau_fifo *pfifo = nouveau_fifo(engine); + struct nv40_graph_priv *priv = (void *)engine; + unsigned long flags; + + pfifo->pause(pfifo, &flags); + nv04_graph_idle(priv); - switch (dev_priv->chipset) { + switch (nv_device(priv)->chipset) { case 0x40: case 0x41: /* guess */ case 0x42: case 0x43: case 0x45: /* guess */ case 0x4e: - nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); + nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr); break; case 0x44: case 0x4a: - nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); break; case 0x46: case 0x47: @@ -154,149 +241,213 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i) case 0x4c: case 0x67: default: - nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); + nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr); + nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr); break; } + + pfifo->start(pfifo, &flags); } -/* - * G70 0x47 - * G71 0x49 - * NV45 0x48 - * G72[M] 0x46 - * G73 0x4b - * C51_G7X 0x4c - * C51 0x4e - */ -int -nv40_graph_init(struct drm_device *dev, int engine) +static void +nv40_graph_intr(struct nouveau_subdev *subdev) +{ + struct nv40_graph_priv *priv = (void *)subdev; + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_handle *handle = NULL; + u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); + u32 inst = (nv_rd32(priv, 0x40032c) & 0x000fffff) << 4; + u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff; + u32 show = stat; + + if (stat & NV_PGRAPH_INTR_ERROR) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + handle = nouveau_engctx_lookup_class(engine, inst, class); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; + nouveau_engctx_handle_put(handle); + } + + if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { + nv_mask(priv, 0x402000, 0, 0); + } + } + + nv_wr32(priv, NV03_PGRAPH_INTR, stat); + nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + + if (show) { + nv_info(priv, ""); + nouveau_bitfield_print(nv10_graph_intr_name, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv10_graph_nstatus, nstatus); + printk("\n"); + nv_error(priv, "ch 0x%08x subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + } +} + +static int +nv40_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv40_graph_engine *pgraph = nv_engine(dev, engine); - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t vramsz; - int i, j; + struct nv40_graph_priv *priv; + int ret; + + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & - ~NV_PMC_ENABLE_PGRAPH); - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | - NV_PMC_ENABLE_PGRAPH); + nv_subdev(priv)->unit = 0x00001000; + nv_subdev(priv)->intr = nv40_graph_intr; + nv_engine(priv)->cclass = &nv40_graph_cclass; + if (nv44_graph_class(priv)) + nv_engine(priv)->sclass = nv44_graph_sclass; + else + nv_engine(priv)->sclass = nv40_graph_sclass; + nv_engine(priv)->tile_prog = nv40_graph_tile_prog; + return 0; +} + +static int +nv40_graph_init(struct nouveau_object *object) +{ + struct nouveau_engine *engine = nv_engine(object); + struct nouveau_fb *pfb = nouveau_fb(object); + struct nv40_graph_priv *priv = (void *)engine; + int ret, i, j; + u32 vramsz; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; /* generate and upload context program */ - nv40_grctx_init(dev, &pgraph->grctx_size); + nv40_grctx_init(nv_device(priv), &priv->size); /* No context present currently */ - nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); + nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); - nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); + nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xe0de8055); - nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055); + nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000); + nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); - j = nv_rd32(dev, 0x1540) & 0xff; + j = nv_rd32(priv, 0x1540) & 0xff; if (j) { for (i = 0; !(j & 1); j >>= 1, i++) ; - nv_wr32(dev, 0x405000, i); + nv_wr32(priv, 0x405000, i); } - if (dev_priv->chipset == 0x40) { - nv_wr32(dev, 0x4009b0, 0x83280fff); - nv_wr32(dev, 0x4009b4, 0x000000a0); + if (nv_device(priv)->chipset == 0x40) { + nv_wr32(priv, 0x4009b0, 0x83280fff); + nv_wr32(priv, 0x4009b4, 0x000000a0); } else { - nv_wr32(dev, 0x400820, 0x83280eff); - nv_wr32(dev, 0x400824, 0x000000a0); + nv_wr32(priv, 0x400820, 0x83280eff); + nv_wr32(priv, 0x400824, 0x000000a0); } - switch (dev_priv->chipset) { + switch (nv_device(priv)->chipset) { case 0x40: case 0x45: - nv_wr32(dev, 0x4009b8, 0x0078e366); - nv_wr32(dev, 0x4009bc, 0x0000014c); + nv_wr32(priv, 0x4009b8, 0x0078e366); + nv_wr32(priv, 0x4009bc, 0x0000014c); break; case 0x41: case 0x42: /* pciid also 0x00Cx */ /* case 0x0120: XXX (pciid) */ - nv_wr32(dev, 0x400828, 0x007596ff); - nv_wr32(dev, 0x40082c, 0x00000108); + nv_wr32(priv, 0x400828, 0x007596ff); + nv_wr32(priv, 0x40082c, 0x00000108); break; case 0x43: - nv_wr32(dev, 0x400828, 0x0072cb77); - nv_wr32(dev, 0x40082c, 0x00000108); + nv_wr32(priv, 0x400828, 0x0072cb77); + nv_wr32(priv, 0x40082c, 0x00000108); break; case 0x44: case 0x46: /* G72 */ case 0x4a: case 0x4c: /* G7x-based C51 */ case 0x4e: - nv_wr32(dev, 0x400860, 0); - nv_wr32(dev, 0x400864, 0); + nv_wr32(priv, 0x400860, 0); + nv_wr32(priv, 0x400864, 0); break; case 0x47: /* G70 */ case 0x49: /* G71 */ case 0x4b: /* G73 */ - nv_wr32(dev, 0x400828, 0x07830610); - nv_wr32(dev, 0x40082c, 0x0000016A); + nv_wr32(priv, 0x400828, 0x07830610); + nv_wr32(priv, 0x40082c, 0x0000016A); break; default: break; } - nv_wr32(dev, 0x400b38, 0x2ffff800); - nv_wr32(dev, 0x400b3c, 0x00006000); + nv_wr32(priv, 0x400b38, 0x2ffff800); + nv_wr32(priv, 0x400b3c, 0x00006000); /* Tiling related stuff. */ - switch (dev_priv->chipset) { + switch (nv_device(priv)->chipset) { case 0x44: case 0x4a: - nv_wr32(dev, 0x400bc4, 0x1003d888); - nv_wr32(dev, 0x400bbc, 0xb7a7b500); + nv_wr32(priv, 0x400bc4, 0x1003d888); + nv_wr32(priv, 0x400bbc, 0xb7a7b500); break; case 0x46: - nv_wr32(dev, 0x400bc4, 0x0000e024); - nv_wr32(dev, 0x400bbc, 0xb7a7b520); + nv_wr32(priv, 0x400bc4, 0x0000e024); + nv_wr32(priv, 0x400bbc, 0xb7a7b520); break; case 0x4c: case 0x4e: case 0x67: - nv_wr32(dev, 0x400bc4, 0x1003d888); - nv_wr32(dev, 0x400bbc, 0xb7a7b540); + nv_wr32(priv, 0x400bc4, 0x1003d888); + nv_wr32(priv, 0x400bbc, 0xb7a7b540); break; default: break; } /* Turn all the tiling regions off. */ - for (i = 0; i < nvfb_tile_nr(dev); i++) - nv40_graph_set_tile_region(dev, i); + for (i = 0; i < pfb->tile.regions; i++) + engine->tile_prog(engine, i); /* begin RAM config */ - vramsz = pci_resource_len(dev->pdev, 0) - 1; - switch (dev_priv->chipset) { + vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1; + switch (nv_device(priv)->chipset) { case 0x40: - nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1)); - nv_wr32(dev, 0x4069A4, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x4069A8, nv_rd32(dev, NV04_PFB_CFG1)); - nv_wr32(dev, 0x400820, 0); - nv_wr32(dev, 0x400824, 0); - nv_wr32(dev, 0x400864, vramsz); - nv_wr32(dev, 0x400868, vramsz); + nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); + nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204)); + nv_wr32(priv, 0x400820, 0); + nv_wr32(priv, 0x400824, 0); + nv_wr32(priv, 0x400864, vramsz); + nv_wr32(priv, 0x400868, vramsz); break; default: - switch (dev_priv->chipset) { + switch (nv_device(priv)->chipset) { case 0x41: case 0x42: case 0x43: @@ -304,163 +455,33 @@ nv40_graph_init(struct drm_device *dev, int engine) case 0x4e: case 0x44: case 0x4a: - nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1)); + nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204)); break; default: - nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); + nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204)); break; } - nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1)); - nv_wr32(dev, 0x400840, 0); - nv_wr32(dev, 0x400844, 0); - nv_wr32(dev, 0x4008A0, vramsz); - nv_wr32(dev, 0x4008A4, vramsz); + nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204)); + nv_wr32(priv, 0x400840, 0); + nv_wr32(priv, 0x400844, 0); + nv_wr32(priv, 0x4008A0, vramsz); + nv_wr32(priv, 0x4008A4, vramsz); break; } return 0; } -static int -nv40_graph_fini(struct drm_device *dev, int engine, bool suspend) -{ - u32 inst = nv_rd32(dev, 0x40032c); - if (inst & 0x01000000) { - nv_wr32(dev, 0x400720, 0x00000000); - nv_wr32(dev, 0x400784, inst); - nv_mask(dev, 0x400310, 0x00000020, 0x00000020); - nv_mask(dev, 0x400304, 0x00000001, 0x00000001); - if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) { - u32 insn = nv_rd32(dev, 0x400308); - NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn); - } - nv_mask(dev, 0x40032c, 0x01000000, 0x00000000); - } - return 0; -} - -static int -nv40_graph_isr_chid(struct drm_device *dev, u32 inst) -{ - struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *grctx; - unsigned long flags; - int i; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (i = 0; i < pfifo->channels; i++) { - if (!dev_priv->channels.ptr[i]) - continue; - grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR]; - - if (grctx && grctx->addr == inst) - break; - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - return i; -} - -static void -nv40_graph_isr(struct drm_device *dev) -{ - u32 stat; - - while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { - u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); - u32 inst = (nv_rd32(dev, 0x40032c) & 0x000fffff) << 4; - u32 chid = nv40_graph_isr_chid(dev, inst); - u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); - u32 subc = (addr & 0x00070000) >> 16; - u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xffff; - u32 show = stat; - - if (stat & NV_PGRAPH_INTR_ERROR) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) - show &= ~NV_PGRAPH_INTR_ERROR; - } else - if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { - nv_mask(dev, 0x402000, 0, 0); - } - } - - nv_wr32(dev, NV03_PGRAPH_INTR, stat); - nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); - - if (show && nouveau_ratelimit()) { - NV_INFO(dev, "PGRAPH -"); - nouveau_bitfield_print(nv10_graph_intr, show); - printk(" nsource:"); - nouveau_bitfield_print(nv04_graph_nsource, nsource); - printk(" nstatus:"); - nouveau_bitfield_print(nv10_graph_nstatus, nstatus); - printk("\n"); - NV_INFO(dev, "PGRAPH - ch %d (0x%08x) subc %d " - "class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst, subc, class, mthd, data); - } - } -} - -static void -nv40_graph_destroy(struct drm_device *dev, int engine) -{ - struct nv40_graph_engine *pgraph = nv_engine(dev, engine); - - nouveau_irq_unregister(dev, 12); - - NVOBJ_ENGINE_DEL(dev, GR); - kfree(pgraph); -} - -int -nv40_graph_create(struct drm_device *dev) -{ - struct nv40_graph_engine *pgraph; - - pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); - if (!pgraph) - return -ENOMEM; - - pgraph->base.destroy = nv40_graph_destroy; - pgraph->base.init = nv40_graph_init; - pgraph->base.fini = nv40_graph_fini; - pgraph->base.context_new = nv40_graph_context_new; - pgraph->base.context_del = nv40_graph_context_del; - pgraph->base.object_new = nv40_graph_object_new; - pgraph->base.set_tile_region = nv40_graph_set_tile_region; - - NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); - nouveau_irq_register(dev, 12, nv40_graph_isr); - - NVOBJ_CLASS(dev, 0x0030, GR); /* null */ - NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ - NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ - NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ - NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ - NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ - NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */ - NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ - NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */ - NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ - NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ - NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ - NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ - NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ - NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */ - - /* curie */ - if (nv44_graph_class(dev)) - NVOBJ_CLASS(dev, 0x4497, GR); - else - NVOBJ_CLASS(dev, 0x4097, GR); - - return 0; -} +struct nouveau_oclass +nv40_graph_oclass = { + .handle = NV_ENGINE(GR, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_graph_ctor, + .dtor = _nouveau_graph_dtor, + .init = nv40_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h new file mode 100644 index 0000000..d2ac975 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h @@ -0,0 +1,21 @@ +#ifndef __NV40_GRAPH_H__ +#define __NV40_GRAPH_H__ + +/* returns 1 if device is one of the nv4x using the 0x4497 object class, + * helpful to determine a number of other hardware features + */ +static inline int +nv44_graph_class(void *priv) +{ + struct nouveau_device *device = nv_device(priv); + + if ((device->chipset & 0xf0) == 0x60) + return 1; + + return !(0x0baf & (1 << (device->chipset & 0x0f))); +} + +void nv40_grctx_init(struct nouveau_device *, u32 *size); +void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c index 28932c4..8955bdd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c @@ -1,266 +1,234 @@ /* - * Copyright (C) 2007 Ben Skeggs. - * All Rights Reserved. + * 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: + * 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 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 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. + * 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 "drm.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> -#include <core/ramht.h> -#include "nouveau_dma.h" -#include "nv50_evo.h" - -struct nv50_graph_engine { - struct nouveau_exec_engine base; - u32 ctxprog[512]; - u32 ctxprog_size; - u32 grctx_size; -}; - -static int -nv50_graph_init(struct drm_device *dev, int engine) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_graph_engine *pgraph = nv_engine(dev, engine); - u32 units = nv_rd32(dev, 0x001540); - int i; +#include <core/os.h> +#include <core/class.h> +#include <core/handle.h> +#include <core/engctx.h> +#include <core/enum.h> - NV_DEBUG(dev, "\n"); +#include <subdev/fb.h> +#include <subdev/vm.h> +#include <subdev/timer.h> - /* master reset */ - nv_mask(dev, 0x000200, 0x00201000, 0x00000000); - nv_mask(dev, 0x000200, 0x00201000, 0x00201000); - nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ - - /* reset/enable traps and interrupts */ - nv_wr32(dev, 0x400804, 0xc0000000); - nv_wr32(dev, 0x406800, 0xc0000000); - nv_wr32(dev, 0x400c04, 0xc0000000); - nv_wr32(dev, 0x401800, 0xc0000000); - nv_wr32(dev, 0x405018, 0xc0000000); - nv_wr32(dev, 0x402000, 0xc0000000); - for (i = 0; i < 16; i++) { - if (!(units & (1 << i))) - continue; +#include <engine/graph.h> - if (dev_priv->chipset < 0xa0) { - nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); - nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); - nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); - } else { - nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); - nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); - nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); - } - } +#include "nv50.h" - nv_wr32(dev, 0x400108, 0xffffffff); - nv_wr32(dev, 0x400138, 0xffffffff); - nv_wr32(dev, 0x400100, 0xffffffff); - nv_wr32(dev, 0x40013c, 0xffffffff); - nv_wr32(dev, 0x400500, 0x00010001); +struct nv50_graph_priv { + struct nouveau_graph base; + spinlock_t lock; + u32 size; +}; - /* upload context program, initialise ctxctl defaults */ - nv_wr32(dev, 0x400324, 0x00000000); - for (i = 0; i < pgraph->ctxprog_size; i++) - nv_wr32(dev, 0x400328, pgraph->ctxprog[i]); - nv_wr32(dev, 0x400824, 0x00000000); - nv_wr32(dev, 0x400828, 0x00000000); - nv_wr32(dev, 0x40082c, 0x00000000); - nv_wr32(dev, 0x400830, 0x00000000); - nv_wr32(dev, 0x400724, 0x00000000); - nv_wr32(dev, 0x40032c, 0x00000000); - nv_wr32(dev, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */ +struct nv50_graph_chan { + struct nouveau_graph_chan base; +}; - /* some unknown zcull magic */ - switch (dev_priv->chipset & 0xf0) { - case 0x50: - case 0x80: - case 0x90: - nv_wr32(dev, 0x402ca8, 0x00000800); - break; - case 0xa0: - default: - nv_wr32(dev, 0x402cc0, 0x00000000); - if (dev_priv->chipset == 0xa0 || - dev_priv->chipset == 0xaa || - dev_priv->chipset == 0xac) { - nv_wr32(dev, 0x402ca8, 0x00000802); - } else { - nv_wr32(dev, 0x402cc0, 0x00000000); - nv_wr32(dev, 0x402ca8, 0x00000002); - } +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ - break; - } +static int +nv50_graph_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_gpuobj *obj; + int ret; - /* zero out zcull regions */ - for (i = 0; i < 8; i++) { - nv_wr32(dev, 0x402c20 + (i * 8), 0x00000000); - nv_wr32(dev, 0x402c24 + (i * 8), 0x00000000); - nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000); - nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000); - } + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent, + 16, 16, 0, &obj); + *pobject = nv_object(obj); + if (ret) + return ret; + nv_wo32(obj, 0x00, nv_mclass(obj)); + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); + nv_wo32(obj, 0x0c, 0x00000000); return 0; } -static int -nv50_graph_fini(struct drm_device *dev, int engine, bool suspend) -{ - nv_wr32(dev, 0x40013c, 0x00000000); - return 0; -} +struct nouveau_ofuncs +nv50_graph_ofuncs = { + .ctor = nv50_graph_object_ctor, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, +}; -static int -nv50_graph_context_new(struct nouveau_channel *chan, int engine) -{ - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *ramin = chan->ramin; - struct nouveau_gpuobj *grctx = NULL; - struct nv50_graph_engine *pgraph = nv_engine(dev, engine); - int hdr, ret; - - NV_DEBUG(dev, "ch%d\n", chan->id); - - ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0, - NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &grctx); - if (ret) - return ret; +static struct nouveau_oclass +nv50_graph_sclass[] = { + { 0x0030, &nv50_graph_ofuncs }, + { 0x502d, &nv50_graph_ofuncs }, + { 0x5039, &nv50_graph_ofuncs }, + { 0x5097, &nv50_graph_ofuncs }, + { 0x50c0, &nv50_graph_ofuncs }, + {} +}; - hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; - nv_wo32(ramin, hdr + 0x00, 0x00190002); - nv_wo32(ramin, hdr + 0x04, grctx->addr + grctx->size - 1); - nv_wo32(ramin, hdr + 0x08, grctx->addr); - nv_wo32(ramin, hdr + 0x0c, 0); - nv_wo32(ramin, hdr + 0x10, 0); - nv_wo32(ramin, hdr + 0x14, 0x00010000); +static struct nouveau_oclass +nv84_graph_sclass[] = { + { 0x0030, &nv50_graph_ofuncs }, + { 0x502d, &nv50_graph_ofuncs }, + { 0x5039, &nv50_graph_ofuncs }, + { 0x50c0, &nv50_graph_ofuncs }, + { 0x8297, &nv50_graph_ofuncs }, + {} +}; - nv50_grctx_fill(dev, grctx); - nv_wo32(grctx, 0x00000, chan->ramin->addr >> 12); +static struct nouveau_oclass +nva0_graph_sclass[] = { + { 0x0030, &nv50_graph_ofuncs }, + { 0x502d, &nv50_graph_ofuncs }, + { 0x5039, &nv50_graph_ofuncs }, + { 0x50c0, &nv50_graph_ofuncs }, + { 0x8397, &nv50_graph_ofuncs }, + {} +}; - nvimem_flush(dev); +static struct nouveau_oclass +nva3_graph_sclass[] = { + { 0x0030, &nv50_graph_ofuncs }, + { 0x502d, &nv50_graph_ofuncs }, + { 0x5039, &nv50_graph_ofuncs }, + { 0x50c0, &nv50_graph_ofuncs }, + { 0x8597, &nv50_graph_ofuncs }, + { 0x85c0, &nv50_graph_ofuncs }, + {} +}; - nvvm_engref(chan->vm, engine, 1); - chan->engctx[NVOBJ_ENGINE_GR] = grctx; - return 0; -} +static struct nouveau_oclass +nvaf_graph_sclass[] = { + { 0x0030, &nv50_graph_ofuncs }, + { 0x502d, &nv50_graph_ofuncs }, + { 0x5039, &nv50_graph_ofuncs }, + { 0x50c0, &nv50_graph_ofuncs }, + { 0x85c0, &nv50_graph_ofuncs }, + { 0x8697, &nv50_graph_ofuncs }, + {} +}; -static void -nv50_graph_context_del(struct nouveau_channel *chan, int engine) -{ - struct nouveau_gpuobj *grctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; - - for (i = hdr; i < hdr + 24; i += 4) - nv_wo32(chan->ramin, i, 0); - nvimem_flush(dev); - - nvvm_engref(chan->vm, engine, -1); - nouveau_gpuobj_ref(NULL, &grctx); - chan->engctx[engine] = NULL; -} +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ static int -nv50_graph_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +nv50_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *obj = NULL; + struct nv50_graph_priv *priv = (void *)engine; + struct nv50_graph_chan *chan; int ret; - ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, + priv->size, 0, + NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); if (ret) return ret; - obj->engine = 1; - obj->class = class; - - nv_wo32(obj, 0x00, class); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); - nvimem_flush(dev); - ret = nouveau_ramht_insert(chan, handle, obj); - nouveau_gpuobj_ref(NULL, &obj); - return ret; + nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan)); + return 0; } -static void -nv50_graph_tlb_flush(struct drm_device *dev, int engine) +static struct nouveau_oclass +nv50_graph_cclass = { + .handle = NV_ENGCTX(GR, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_graph_context_ctor, + .dtor = _nouveau_graph_context_dtor, + .init = _nouveau_graph_context_init, + .fini = _nouveau_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static int +nv50_graph_tlb_flush(struct nouveau_engine *engine) { - nv50_vm_flush_engine(dev, 0); + nv50_vm_flush_engine(&engine->base, 0x00); + return 0; } -static void -nv84_graph_tlb_flush(struct drm_device *dev, int engine) +static int +nv84_graph_tlb_flush(struct nouveau_engine *engine) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer *ptimer = nouveau_timer(engine); + struct nv50_graph_priv *priv = (void *)engine; bool idle, timeout = false; unsigned long flags; u64 start; u32 tmp; - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, 0x400500, 0x00000001, 0x00000000); + spin_lock_irqsave(&priv->lock, flags); + nv_mask(priv, 0x400500, 0x00000001, 0x00000000); - start = nv_timer_read(dev); + start = ptimer->read(ptimer); do { idle = true; - for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) { + for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } - for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) { + for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } - for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) { + for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } - } while (!idle && !(timeout = nv_timer_read(dev) - start > 2000000000)); + } while (!idle && + !(timeout = ptimer->read(ptimer) - start > 2000000000)); if (timeout) { - NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: " + nv_error(priv, "PGRAPH TLB flush idle timeout fail: " "0x%08x 0x%08x 0x%08x 0x%08x\n", - nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380), - nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); + nv_rd32(priv, 0x400700), nv_rd32(priv, 0x400380), + nv_rd32(priv, 0x400384), nv_rd32(priv, 0x400388)); } - nv50_vm_flush_engine(dev, 0); + nv50_vm_flush_engine(&engine->base, 0x00); - nv_mask(dev, 0x400500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + nv_mask(priv, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&priv->lock, flags); + return timeout ? -EBUSY : 0; } static struct nouveau_enum nv50_mp_exec_error_names[] = { @@ -341,7 +309,7 @@ struct nouveau_enum nv50_data_error_names[] = { {} }; -static struct nouveau_bitfield nv50_graph_intr[] = { +static struct nouveau_bitfield nv50_graph_intr_name[] = { { 0x00000001, "NOTIFY" }, { 0x00000002, "COMPUTE_QUERY" }, { 0x00000010, "ILLEGAL_MTHD" }, @@ -356,95 +324,93 @@ static struct nouveau_bitfield nv50_graph_intr[] = { }; static void -nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) +nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t units = nv_rd32(dev, 0x1540); - uint32_t addr, mp10, status, pc, oplow, ophigh; + u32 units = nv_rd32(priv, 0x1540); + u32 addr, mp10, status, pc, oplow, ophigh; int i; int mps = 0; for (i = 0; i < 4; i++) { if (!(units & 1 << (i+24))) continue; - if (dev_priv->chipset < 0xa0) + if (nv_device(priv)->chipset < 0xa0) addr = 0x408200 + (tpid << 12) + (i << 7); else addr = 0x408100 + (tpid << 11) + (i << 7); - mp10 = nv_rd32(dev, addr + 0x10); - status = nv_rd32(dev, addr + 0x14); + mp10 = nv_rd32(priv, addr + 0x10); + status = nv_rd32(priv, addr + 0x14); if (!status) continue; if (display) { - nv_rd32(dev, addr + 0x20); - pc = nv_rd32(dev, addr + 0x24); - oplow = nv_rd32(dev, addr + 0x70); - ophigh = nv_rd32(dev, addr + 0x74); - NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " + nv_rd32(priv, addr + 0x20); + pc = nv_rd32(priv, addr + 0x24); + oplow = nv_rd32(priv, addr + 0x70); + ophigh = nv_rd32(priv, addr + 0x74); + nv_error(priv, "TRAP_MP_EXEC - " "TP %d MP %d: ", tpid, i); nouveau_enum_print(nv50_mp_exec_error_names, status); printk(" at %06x warp %d, opcode %08x %08x\n", pc&0xffffff, pc >> 24, oplow, ophigh); } - nv_wr32(dev, addr + 0x10, mp10); - nv_wr32(dev, addr + 0x14, 0); + nv_wr32(priv, addr + 0x10, mp10); + nv_wr32(priv, addr + 0x14, 0); mps++; } if (!mps && display) - NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " + nv_error(priv, "TRAP_MP_EXEC - TP %d: " "No MPs claiming errors?\n", tpid); } static void -nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, - uint32_t ustatus_new, int display, const char *name) +nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old, + u32 ustatus_new, int display, const char *name) { - struct drm_nouveau_private *dev_priv = dev->dev_private; int tps = 0; - uint32_t units = nv_rd32(dev, 0x1540); + u32 units = nv_rd32(priv, 0x1540); int i, r; - uint32_t ustatus_addr, ustatus; + u32 ustatus_addr, ustatus; for (i = 0; i < 16; i++) { if (!(units & (1 << i))) continue; - if (dev_priv->chipset < 0xa0) + if (nv_device(priv)->chipset < 0xa0) ustatus_addr = ustatus_old + (i << 12); else ustatus_addr = ustatus_new + (i << 11); - ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; + ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff; if (!ustatus) continue; tps++; switch (type) { case 6: /* texture error... unknown for now */ if (display) { - NV_ERROR(dev, "magic set %d:\n", i); + nv_error(priv, "magic set %d:\n", i); for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, - nv_rd32(dev, r)); + nv_error(priv, "\t0x%08x: 0x%08x\n", r, + nv_rd32(priv, r)); } break; case 7: /* MP error */ if (ustatus & 0x04030000) { - nv50_pgraph_mp_trap(dev, i, display); + nv50_priv_mp_trap(priv, i, display); ustatus &= ~0x04030000; } break; case 8: /* TPDMA error */ { - uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); - uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); - uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); - uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); - uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); - uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); - uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); + u32 e0c = nv_rd32(priv, ustatus_addr + 4); + u32 e10 = nv_rd32(priv, ustatus_addr + 8); + u32 e14 = nv_rd32(priv, ustatus_addr + 0xc); + u32 e18 = nv_rd32(priv, ustatus_addr + 0x10); + u32 e1c = nv_rd32(priv, ustatus_addr + 0x14); + u32 e20 = nv_rd32(priv, ustatus_addr + 0x18); + u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c); /* 2d engine destination */ if (ustatus & 0x00000010) { if (display) { - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", + nv_error(priv, "TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", i, e14, e10); - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + nv_error(priv, "TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", i, e0c, e18, e1c, e20, e24); } ustatus &= ~0x00000010; @@ -452,9 +418,9 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, /* Render target */ if (ustatus & 0x00000040) { if (display) { - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", + nv_error(priv, "TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", i, e14, e10); - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + nv_error(priv, "TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", i, e0c, e18, e1c, e20, e24); } ustatus &= ~0x00000040; @@ -464,19 +430,19 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, if (display) { if (e18 & 0x80000000) { /* g[] read fault? */ - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", + nv_error(priv, "TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", i, e14, e10 | ((e18 >> 24) & 0x1f)); e18 &= ~0x1f000000; } else if (e18 & 0xc) { /* g[] write fault? */ - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", + nv_error(priv, "TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", i, e14, e10 | ((e18 >> 7) & 0x1f)); e18 &= ~0x00000f80; } else { - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", + nv_error(priv, "TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", i, e14, e10); } - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + nv_error(priv, "TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", i, e0c, e18, e1c, e20, e24); } ustatus &= ~0x00000080; @@ -486,23 +452,23 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, } if (ustatus) { if (display) - NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); + nv_info(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); } - nv_wr32(dev, ustatus_addr, 0xc0000000); + nv_wr32(priv, ustatus_addr, 0xc0000000); } if (!tps && display) - NV_INFO(dev, "%s - No TPs claiming errors?\n", name); + nv_info(priv, "%s - No TPs claiming errors?\n", name); } static int -nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid) +nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, u64 inst) { - u32 status = nv_rd32(dev, 0x400108); + u32 status = nv_rd32(priv, 0x400108); u32 ustatus; if (!status && display) { - NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n"); + nv_error(priv, "TRAP: no units reporting traps?\n"); return 1; } @@ -510,72 +476,72 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid * COND, QUERY. If you get a trap from it, the command is still stuck * in DISPATCH and you need to do something about it. */ if (status & 0x001) { - ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; + ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff; if (!ustatus && display) { - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); + nv_error(priv, "TRAP_DISPATCH - no ustatus?\n"); } - nv_wr32(dev, 0x400500, 0x00000000); + nv_wr32(priv, 0x400500, 0x00000000); /* Known to be triggered by screwed up NOTIFY and COND... */ if (ustatus & 0x00000001) { - u32 addr = nv_rd32(dev, 0x400808); + u32 addr = nv_rd32(priv, 0x400808); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 datal = nv_rd32(dev, 0x40080c); - u32 datah = nv_rd32(dev, 0x400810); - u32 class = nv_rd32(dev, 0x400814); - u32 r848 = nv_rd32(dev, 0x400848); + u32 datal = nv_rd32(priv, 0x40080c); + u32 datah = nv_rd32(priv, 0x400810); + u32 class = nv_rd32(priv, 0x400814); + u32 r848 = nv_rd32(priv, 0x400848); - NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n"); + nv_error(priv, "TRAP DISPATCH_FAULT\n"); if (display && (addr & 0x80000000)) { - NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " + nv_error(priv, "ch 0x%010llx " "subc %d class 0x%04x mthd 0x%04x " "data 0x%08x%08x " "400808 0x%08x 400848 0x%08x\n", - chid, inst, subc, class, mthd, datah, + inst, subc, class, mthd, datah, datal, addr, r848); } else if (display) { - NV_INFO(dev, "PGRAPH - no stuck command?\n"); + nv_error(priv, "no stuck command?\n"); } - nv_wr32(dev, 0x400808, 0); - nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); - nv_wr32(dev, 0x400848, 0); + nv_wr32(priv, 0x400808, 0); + nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3); + nv_wr32(priv, 0x400848, 0); ustatus &= ~0x00000001; } if (ustatus & 0x00000002) { - u32 addr = nv_rd32(dev, 0x40084c); + u32 addr = nv_rd32(priv, 0x40084c); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(dev, 0x40085c); - u32 class = nv_rd32(dev, 0x400814); + u32 data = nv_rd32(priv, 0x40085c); + u32 class = nv_rd32(priv, 0x400814); - NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n"); + nv_error(priv, "TRAP DISPATCH_QUERY\n"); if (display && (addr & 0x80000000)) { - NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " + nv_error(priv, "ch 0x%010llx " "subc %d class 0x%04x mthd 0x%04x " "data 0x%08x 40084c 0x%08x\n", - chid, inst, subc, class, mthd, + inst, subc, class, mthd, data, addr); } else if (display) { - NV_INFO(dev, "PGRAPH - no stuck command?\n"); + nv_error(priv, "no stuck command?\n"); } - nv_wr32(dev, 0x40084c, 0); + nv_wr32(priv, 0x40084c, 0); ustatus &= ~0x00000002; } if (ustatus && display) { - NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown " + nv_error(priv, "TRAP_DISPATCH (unknown " "0x%08x)\n", ustatus); } - nv_wr32(dev, 0x400804, 0xc0000000); - nv_wr32(dev, 0x400108, 0x001); + nv_wr32(priv, 0x400804, 0xc0000000); + nv_wr32(priv, 0x400108, 0x001); status &= ~0x001; if (!status) return 0; @@ -583,81 +549,81 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid /* M2MF: Memory to memory copy engine. */ if (status & 0x002) { - u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; + u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff; if (display) { - NV_INFO(dev, "PGRAPH - TRAP_M2MF"); + nv_error(priv, "TRAP_M2MF"); nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); printk("\n"); - NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n", - nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808), - nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810)); + nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n", + nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808), + nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(dev, 0x400040, 2); - nv_wr32(dev, 0x400040, 0); - nv_wr32(dev, 0x406800, 0xc0000000); - nv_wr32(dev, 0x400108, 0x002); + nv_wr32(priv, 0x400040, 2); + nv_wr32(priv, 0x400040, 0); + nv_wr32(priv, 0x406800, 0xc0000000); + nv_wr32(priv, 0x400108, 0x002); status &= ~0x002; } /* VFETCH: Fetches data from vertex buffers. */ if (status & 0x004) { - u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; + u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff; if (display) { - NV_INFO(dev, "PGRAPH - TRAP_VFETCH"); + nv_error(priv, "TRAP_VFETCH"); nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); printk("\n"); - NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n", - nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08), - nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10)); + nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n", + nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08), + nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10)); } - nv_wr32(dev, 0x400c04, 0xc0000000); - nv_wr32(dev, 0x400108, 0x004); + nv_wr32(priv, 0x400c04, 0xc0000000); + nv_wr32(priv, 0x400108, 0x004); status &= ~0x004; } /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ if (status & 0x008) { - ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; + ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff; if (display) { - NV_INFO(dev, "PGRAPH - TRAP_STRMOUT"); + nv_error(priv, "TRAP_STRMOUT"); nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); printk("\n"); - NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n", - nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808), - nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810)); + nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n", + nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808), + nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(dev, 0x400040, 0x80); - nv_wr32(dev, 0x400040, 0); - nv_wr32(dev, 0x401800, 0xc0000000); - nv_wr32(dev, 0x400108, 0x008); + nv_wr32(priv, 0x400040, 0x80); + nv_wr32(priv, 0x400040, 0); + nv_wr32(priv, 0x401800, 0xc0000000); + nv_wr32(priv, 0x400108, 0x008); status &= ~0x008; } /* CCACHE: Handles code and c[] caches and fills them. */ if (status & 0x010) { - ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; + ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff; if (display) { - NV_INFO(dev, "PGRAPH - TRAP_CCACHE"); + nv_error(priv, "TRAP_CCACHE"); nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); printk("\n"); - NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" + nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x" " %08x %08x %08x\n", - nv_rd32(dev, 0x405000), nv_rd32(dev, 0x405004), - nv_rd32(dev, 0x405008), nv_rd32(dev, 0x40500c), - nv_rd32(dev, 0x405010), nv_rd32(dev, 0x405014), - nv_rd32(dev, 0x40501c)); + nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004), + nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c), + nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014), + nv_rd32(priv, 0x40501c)); } - nv_wr32(dev, 0x405018, 0xc0000000); - nv_wr32(dev, 0x400108, 0x010); + nv_wr32(priv, 0x405018, 0xc0000000); + nv_wr32(priv, 0x400108, 0x010); status &= ~0x010; } @@ -665,201 +631,248 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid * remaining, so try to handle it anyway. Perhaps related to that * unknown DMA slot on tesla? */ if (status & 0x20) { - ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; + ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff; if (display) - NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus); - nv_wr32(dev, 0x402000, 0xc0000000); + nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus); + nv_wr32(priv, 0x402000, 0xc0000000); /* no status modifiction on purpose */ } /* TEXTURE: CUDA texturing units */ if (status & 0x040) { - nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display, - "PGRAPH - TRAP_TEXTURE"); - nv_wr32(dev, 0x400108, 0x040); + nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display, + "TRAP_TEXTURE"); + nv_wr32(priv, 0x400108, 0x040); status &= ~0x040; } /* MP: CUDA execution engines. */ if (status & 0x080) { - nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display, - "PGRAPH - TRAP_MP"); - nv_wr32(dev, 0x400108, 0x080); + nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display, + "TRAP_MP"); + nv_wr32(priv, 0x400108, 0x080); status &= ~0x080; } /* TPDMA: Handles TP-initiated uncached memory accesses: * l[], g[], stack, 2d surfaces, render targets. */ if (status & 0x100) { - nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display, - "PGRAPH - TRAP_TPDMA"); - nv_wr32(dev, 0x400108, 0x100); + nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display, + "TRAP_TPDMA"); + nv_wr32(priv, 0x400108, 0x100); status &= ~0x100; } if (status) { if (display) - NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status); - nv_wr32(dev, 0x400108, status); + nv_error(priv, "TRAP: unknown 0x%08x\n", status); + nv_wr32(priv, 0x400108, status); } return 1; } -int -nv50_graph_isr_chid(struct drm_device *dev, u64 inst) +static void +nv50_graph_intr(struct nouveau_subdev *subdev) { - struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan; - unsigned long flags; - int i; + struct nv50_graph_priv *priv = (void *)subdev; + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_handle *handle = NULL; + u32 stat = nv_rd32(priv, 0x400100); + u64 inst = (u64)(nv_rd32(priv, 0x40032c) & 0x0fffffff) << 12; + u32 addr = nv_rd32(priv, 0x400704); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(priv, 0x400708); + u32 class = nv_rd32(priv, 0x400814); + u32 show = stat; + + if (stat & 0x00000010) { + handle = nouveau_engctx_lookup_class(engine, inst, class); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~0x00000010; + nouveau_engctx_handle_put(handle); + } - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (i = 0; i < pfifo->channels; i++) { - chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->ramin) - continue; + if (show & 0x00100000) { + u32 ecode = nv_rd32(priv, 0x400110); + nv_error(priv, "DATA_ERROR "); + nouveau_enum_print(nv50_data_error_names, ecode); + printk("\n"); + } - if (inst == chan->ramin->addr) - break; + if (stat & 0x00200000) { + if (!nv50_graph_trap_handler(priv, show, inst)) + show &= ~0x00200000; + } + + nv_wr32(priv, 0x400100, stat); + nv_wr32(priv, 0x400500, 0x00010001); + + if (show) { + nv_info(priv, ""); + nouveau_bitfield_print(nv50_graph_intr_name, show); + printk("\n"); + nv_error(priv, "ch 0x%010llx subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + nv50_fb_trap(nouveau_fb(priv), 1); } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - return i; + + if (nv_rd32(priv, 0x400824) & (1 << 31)) + nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31)); } -static void -nv50_graph_isr(struct drm_device *dev) +static int +nv50_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - u32 stat; - - while ((stat = nv_rd32(dev, 0x400100))) { - u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12; - u32 chid = nv50_graph_isr_chid(dev, inst); - u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); - u32 subc = (addr & 0x00070000) >> 16; - u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(dev, 0x400814); - u32 show = stat; - - if (stat & 0x00000010) { - if (!nouveau_gpuobj_mthd_call2(dev, chid, class, - mthd, data)) - show &= ~0x00000010; - } + struct nv50_graph_priv *priv; + int ret; - show = (show && nouveau_ratelimit()) ? show : 0; + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - if (show & 0x00100000) { - u32 ecode = nv_rd32(dev, 0x400110); - NV_INFO(dev, "PGRAPH - DATA_ERROR "); - nouveau_enum_print(nv50_data_error_names, ecode); - printk("\n"); - } + nv_subdev(priv)->unit = 0x00201000; + nv_subdev(priv)->intr = nv50_graph_intr; + nv_engine(priv)->cclass = &nv50_graph_cclass; - if (stat & 0x00200000) { - if (!nv50_pgraph_trap_handler(dev, show, inst, chid)) - show &= ~0x00200000; - } + switch (nv_device(priv)->chipset) { + case 0x50: + nv_engine(priv)->sclass = nv50_graph_sclass; + break; + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + nv_engine(priv)->sclass = nv84_graph_sclass; + break; + case 0xa0: + case 0xaa: + case 0xac: + nv_engine(priv)->sclass = nva0_graph_sclass; + break; + case 0xa3: + case 0xa5: + case 0xa8: + nv_engine(priv)->sclass = nva3_graph_sclass; + break; + case 0xaf: + nv_engine(priv)->sclass = nvaf_graph_sclass; + break; - nv_wr32(dev, 0x400100, stat); - nv_wr32(dev, 0x400500, 0x00010001); + }; - if (show) { - NV_INFO(dev, "PGRAPH -"); - nouveau_bitfield_print(nv50_graph_intr, show); - printk("\n"); - NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d " - "class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst, subc, class, mthd, data); - nv50_fb_vm_trap(dev, 1); - } - } + if (nv_device(priv)->chipset == 0x50 || + nv_device(priv)->chipset == 0xac) + nv_engine(priv)->tlb_flush = nv50_graph_tlb_flush; + else + nv_engine(priv)->tlb_flush = nv84_graph_tlb_flush; - if (nv_rd32(dev, 0x400824) & (1 << 31)) - nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); + spin_lock_init(&priv->lock); + return 0; } -static void -nv50_graph_destroy(struct drm_device *dev, int engine) +static int +nv50_graph_init(struct nouveau_object *object) { - struct nv50_graph_engine *pgraph = nv_engine(dev, engine); + struct nv50_graph_priv *priv = (void *)object; + int ret, units, i; - NVOBJ_ENGINE_DEL(dev, GR); + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; - nouveau_irq_unregister(dev, 12); - kfree(pgraph); -} + /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */ + nv_wr32(priv, 0x40008c, 0x00000004); -int -nv50_graph_create(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_graph_engine *pgraph; - int ret; + /* reset/enable traps and interrupts */ + nv_wr32(priv, 0x400804, 0xc0000000); + nv_wr32(priv, 0x406800, 0xc0000000); + nv_wr32(priv, 0x400c04, 0xc0000000); + nv_wr32(priv, 0x401800, 0xc0000000); + nv_wr32(priv, 0x405018, 0xc0000000); + nv_wr32(priv, 0x402000, 0xc0000000); + + units = nv_rd32(priv, 0x001540); + for (i = 0; i < 16; i++) { + if (!(units & (1 << i))) + continue; - pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL); - if (!pgraph) - return -ENOMEM; - - ret = nv50_grctx_init(dev, pgraph->ctxprog, ARRAY_SIZE(pgraph->ctxprog), - &pgraph->ctxprog_size, - &pgraph->grctx_size); - if (ret) { - NV_ERROR(dev, "PGRAPH: ctxprog build failed\n"); - kfree(pgraph); - return 0; + if (nv_device(priv)->chipset < 0xa0) { + nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000); + nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000); + nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000); + } else { + nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000); + nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000); + nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000); + } } - pgraph->base.destroy = nv50_graph_destroy; - pgraph->base.init = nv50_graph_init; - pgraph->base.fini = nv50_graph_fini; - pgraph->base.context_new = nv50_graph_context_new; - pgraph->base.context_del = nv50_graph_context_del; - pgraph->base.object_new = nv50_graph_object_new; - if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac) - pgraph->base.tlb_flush = nv50_graph_tlb_flush; - else - pgraph->base.tlb_flush = nv84_graph_tlb_flush; + nv_wr32(priv, 0x400108, 0xffffffff); + nv_wr32(priv, 0x400138, 0xffffffff); + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); + nv_wr32(priv, 0x400500, 0x00010001); - nouveau_irq_register(dev, 12, nv50_graph_isr); + /* upload context program, initialise ctxctl defaults */ + ret = nv50_grctx_init(nv_device(priv), &priv->size); + if (ret) + return ret; - NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); - NVOBJ_CLASS(dev, 0x0030, GR); /* null */ - NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ - NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */ + nv_wr32(priv, 0x400824, 0x00000000); + nv_wr32(priv, 0x400828, 0x00000000); + nv_wr32(priv, 0x40082c, 0x00000000); + nv_wr32(priv, 0x400830, 0x00000000); + nv_wr32(priv, 0x400724, 0x00000000); + nv_wr32(priv, 0x40032c, 0x00000000); + nv_wr32(priv, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */ - /* tesla */ - if (dev_priv->chipset == 0x50) - NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */ - else - if (dev_priv->chipset < 0xa0) - NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */ - else { - switch (dev_priv->chipset) { - case 0xa0: - case 0xaa: - case 0xac: - NVOBJ_CLASS(dev, 0x8397, GR); - break; - case 0xa3: - case 0xa5: - case 0xa8: - NVOBJ_CLASS(dev, 0x8597, GR); - break; - case 0xaf: - NVOBJ_CLASS(dev, 0x8697, GR); - break; + /* some unknown zcull magic */ + switch (nv_device(priv)->chipset & 0xf0) { + case 0x50: + case 0x80: + case 0x90: + nv_wr32(priv, 0x402ca8, 0x00000800); + break; + case 0xa0: + default: + nv_wr32(priv, 0x402cc0, 0x00000000); + if (nv_device(priv)->chipset == 0xa0 || + nv_device(priv)->chipset == 0xaa || + nv_device(priv)->chipset == 0xac) { + nv_wr32(priv, 0x402ca8, 0x00000802); + } else { + nv_wr32(priv, 0x402cc0, 0x00000000); + nv_wr32(priv, 0x402ca8, 0x00000002); } - } - /* compute */ - NVOBJ_CLASS(dev, 0x50c0, GR); - if (dev_priv->chipset > 0xa0 && - dev_priv->chipset != 0xaa && - dev_priv->chipset != 0xac) - NVOBJ_CLASS(dev, 0x85c0, GR); + break; + } + /* zero out zcull regions */ + for (i = 0; i < 8; i++) { + nv_wr32(priv, 0x402c20 + (i * 8), 0x00000000); + nv_wr32(priv, 0x402c24 + (i * 8), 0x00000000); + nv_wr32(priv, 0x402c28 + (i * 8), 0x00000000); + nv_wr32(priv, 0x402c2c + (i * 8), 0x00000000); + } return 0; } + +struct nouveau_oclass +nv50_graph_oclass = { + .handle = NV_ENGINE(GR, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_graph_ctor, + .dtor = _nouveau_graph_dtor, + .init = nv50_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h new file mode 100644 index 0000000..0505fb4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h @@ -0,0 +1,7 @@ +#ifndef __NV50_GRAPH_H__ +#define __NV50_GRAPH_H__ + +int nv50_grctx_init(struct nouveau_device *, u32 *size); +void nv50_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index f994d2f..db8aefc 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -1,5 +1,5 @@ /* - * Copyright 2010 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,94 +22,92 @@ * Authors: Ben Skeggs */ -#include <linux/firmware.h> -#include <linux/module.h> - -#include "drmP.h" - -#include "nouveau_drv.h" -#include <core/mm.h> -#include <engine/fifo.h> - #include "nvc0.h" #include "fuc/hubnvc0.fuc.h" #include "fuc/gpcnvc0.fuc.h" -static void -nvc0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base) -{ - NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base, - nv_rd32(dev, base + 0x400)); - NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804), - nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c)); - NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814), - nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c)); -} - -void -nvc0_graph_ctxctl_debug(struct drm_device *dev) -{ - u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff; - u32 gpc; - - nvc0_graph_ctxctl_debug_unit(dev, 0x409000); - for (gpc = 0; gpc < gpcnr; gpc++) - nvc0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000)); -} +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +nvc0_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0x9039, &nouveau_object_ofuncs }, + { 0x9097, &nouveau_object_ofuncs }, + { 0x90c0, &nouveau_object_ofuncs }, + {} +}; + +static struct nouveau_oclass +nvc1_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0x9039, &nouveau_object_ofuncs }, + { 0x9097, &nouveau_object_ofuncs }, + { 0x90c0, &nouveau_object_ofuncs }, + { 0x9197, &nouveau_object_ofuncs }, + {} +}; + +static struct nouveau_oclass +nvc8_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0x9039, &nouveau_object_ofuncs }, + { 0x9097, &nouveau_object_ofuncs }, + { 0x90c0, &nouveau_object_ofuncs }, + { 0x9197, &nouveau_object_ofuncs }, + { 0x9297, &nouveau_object_ofuncs }, + {} +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ int -nvc0_graph_context_new(struct nouveau_channel *chan, int engine) +nvc0_graph_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *args, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nvc0_graph_priv *priv = nv_engine(dev, engine); + struct nouveau_vm *vm = nouveau_client(parent)->vm; + struct nvc0_graph_priv *priv = (void *)engine; struct nvc0_graph_data *data = priv->mmio_data; struct nvc0_graph_mmio *mmio = priv->mmio_list; - struct nvc0_graph_chan *grch; - struct nouveau_gpuobj *grctx; + struct nvc0_graph_chan *chan; int ret, i; - grch = kzalloc(sizeof(*grch), GFP_KERNEL); - if (!grch) - return -ENOMEM; - chan->engctx[NVOBJ_ENGINE_GR] = grch; - - ret = nouveau_gpuobj_new(dev, NULL, priv->size, 256, 0, &grch->grctx); - if (ret) - goto error; - - ret = nouveau_gpuobj_map_vm(grch->grctx, chan->vm, NV_MEM_ACCESS_RW | - NV_MEM_ACCESS_SYS, &grch->grctx_vma); + /* allocate memory for context, and fill with default values */ + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, + priv->size, 0x100, + NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); if (ret) return ret; - grctx = grch->grctx; - /* allocate memory for a "mmio list" buffer that's used by the HUB * fuc to modify some per-context register settings on first load * of the context. */ - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x100, 0, &grch->mmio); + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x100, 0, &chan->mmio); if (ret) return ret; - ret = nouveau_gpuobj_map_vm(grch->mmio, chan->vm, + ret = nouveau_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, - &grch->mmio_vma); + &chan->mmio_vma); if (ret) return ret; /* allocate buffers referenced by mmio list */ for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) { - ret = nouveau_gpuobj_new(dev, NULL, data->size, data->align, - 0, &grch->data[i].mem); + ret = nouveau_gpuobj_new(parent, NULL, data->size, data->align, + 0, &chan->data[i].mem); if (ret) return ret; - ret = nouveau_gpuobj_map_vm(grch->data[i].mem, chan->vm, - data->access, - &grch->data[i].vma); + ret = nouveau_gpuobj_map_vm(chan->data[i].mem, vm, data->access, + &chan->data[i].vma); if (ret) return ret; @@ -122,117 +120,378 @@ nvc0_graph_context_new(struct nouveau_channel *chan, int engine) u32 data = mmio->data; if (mmio->shift) { - u64 info = grch->data[mmio->buffer].vma.offset; + u64 info = chan->data[mmio->buffer].vma.offset; data |= info >> mmio->shift; } - nv_wo32(grch->mmio, grch->mmio_nr++ * 4, addr); - nv_wo32(grch->mmio, grch->mmio_nr++ * 4, data); + nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); + nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data); mmio++; } for (i = 0; i < priv->size; i += 4) - nv_wo32(grch->grctx, i, priv->data[i / 4]); - - nv_wo32(chan->ramin, 0x0210, lower_32_bits(grch->grctx_vma.offset) | 4); - nv_wo32(chan->ramin, 0x0214, upper_32_bits(grch->grctx_vma.offset)); - nvimem_flush(dev); + nv_wo32(chan, i, priv->data[i / 4]); if (!priv->firmware) { - nv_wo32(grctx, 0x00, grch->mmio_nr / 2); - nv_wo32(grctx, 0x04, grch->mmio_vma.offset >> 8); + nv_wo32(chan, 0x00, chan->mmio_nr / 2); + nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8); } else { - nv_wo32(grctx, 0xf4, 0); - nv_wo32(grctx, 0xf8, 0); - nv_wo32(grctx, 0x10, grch->mmio_nr / 2); - nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio_vma.offset)); - nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio_vma.offset)); - nv_wo32(grctx, 0x1c, 1); - nv_wo32(grctx, 0x20, 0); - nv_wo32(grctx, 0x28, 0); - nv_wo32(grctx, 0x2c, 0); + nv_wo32(chan, 0xf4, 0); + nv_wo32(chan, 0xf8, 0); + nv_wo32(chan, 0x10, chan->mmio_nr / 2); + nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset)); + nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset)); + nv_wo32(chan, 0x1c, 1); + nv_wo32(chan, 0x20, 0); + nv_wo32(chan, 0x28, 0); + nv_wo32(chan, 0x2c, 0); } - nvimem_flush(dev); - return 0; -error: - priv->base.context_del(chan, engine); - return ret; + return 0; } void -nvc0_graph_context_del(struct nouveau_channel *chan, int engine) +nvc0_graph_context_dtor(struct nouveau_object *object) { - struct nvc0_graph_chan *grch = chan->engctx[engine]; + struct nvc0_graph_chan *chan = (void *)object; int i; - for (i = 0; i < ARRAY_SIZE(grch->data); i++) { - nouveau_gpuobj_unmap(&grch->data[i].vma); - nouveau_gpuobj_ref(NULL, &grch->data[i].mem); + for (i = 0; i < ARRAY_SIZE(chan->data); i++) { + nouveau_gpuobj_unmap(&chan->data[i].vma); + nouveau_gpuobj_ref(NULL, &chan->data[i].mem); } - nouveau_gpuobj_unmap(&grch->mmio_vma); - nouveau_gpuobj_ref(NULL, &grch->mmio); + nouveau_gpuobj_unmap(&chan->mmio_vma); + nouveau_gpuobj_ref(NULL, &chan->mmio); - nouveau_gpuobj_unmap(&grch->grctx_vma); - nouveau_gpuobj_ref(NULL, &grch->grctx); - chan->engctx[engine] = NULL; + nouveau_graph_context_destroy(&chan->base); } -static int -nvc0_graph_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +static struct nouveau_oclass +nvc0_graph_cclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_context_ctor, + .dtor = nvc0_graph_context_dtor, + .init = _nouveau_graph_context_init, + .fini = _nouveau_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static void +nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base) { - return 0; + nv_error(priv, "%06x - done 0x%08x\n", base, + nv_rd32(priv, base + 0x400)); + nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, + nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804), + nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c)); + nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, + nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814), + nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c)); +} + +void +nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv) +{ + u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff; + u32 gpc; + + nvc0_graph_ctxctl_debug_unit(priv, 0x409000); + for (gpc = 0; gpc < gpcnr; gpc++) + nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000)); +} + +static void +nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv) +{ + u32 ustat = nv_rd32(priv, 0x409c18); + + if (ustat & 0x00000001) + nv_error(priv, "CTXCTRL ucode error\n"); + if (ustat & 0x00080000) + nv_error(priv, "CTXCTRL watchdog timeout\n"); + if (ustat & ~0x00080001) + nv_error(priv, "CTXCTRL 0x%08x\n", ustat); + + nvc0_graph_ctxctl_debug(priv); + nv_wr32(priv, 0x409c20, ustat); +} + +static void +nvc0_graph_intr(struct nouveau_subdev *subdev) +{ + struct nvc0_graph_priv *priv = (void *)subdev; + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_handle *handle = NULL; + u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12; + u32 stat = nv_rd32(priv, 0x400100); + u32 addr = nv_rd32(priv, 0x400704); + u32 mthd = (addr & 0x00003ffc); + u32 subc = (addr & 0x00070000) >> 16; + u32 data = nv_rd32(priv, 0x400708); + u32 code = nv_rd32(priv, 0x400110); + u32 class = nv_rd32(priv, 0x404200 + (subc * 4)); + + if (stat & 0x00000010) { + handle = nouveau_engctx_lookup_class(engine, inst, class); + if (!handle || nv_call(handle->object, mthd, data)) { + nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx " + "subc %d class 0x%04x mthd 0x%04x " + "data 0x%08x\n", + inst, subc, class, mthd, data); + } + nouveau_engctx_handle_put(handle); + nv_wr32(priv, 0x400100, 0x00000010); + stat &= ~0x00000010; + } + + if (stat & 0x00000020) { + nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + nv_wr32(priv, 0x400100, 0x00000020); + stat &= ~0x00000020; + } + + if (stat & 0x00100000) { + nv_error(priv, "DATA_ERROR ["); + nouveau_enum_print(nv50_data_error_names, code); + printk("] ch 0x%010llx subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + nv_wr32(priv, 0x400100, 0x00100000); + stat &= ~0x00100000; + } + + if (stat & 0x00200000) { + u32 trap = nv_rd32(priv, 0x400108); + nv_error(priv, "TRAP ch 0x%010llx status 0x%08x\n", inst, trap); + nv_wr32(priv, 0x400108, trap); + nv_wr32(priv, 0x400100, 0x00200000); + stat &= ~0x00200000; + } + + if (stat & 0x00080000) { + nvc0_graph_ctxctl_isr(priv); + nv_wr32(priv, 0x400100, 0x00080000); + stat &= ~0x00080000; + } + + if (stat) { + nv_error(priv, "unknown stat 0x%08x\n", stat); + nv_wr32(priv, 0x400100, stat); + } + + nv_wr32(priv, 0x400500, 0x00010001); +} + +int +nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname, + struct nvc0_graph_fuc *fuc) +{ + struct nouveau_device *device = nv_device(priv); + const struct firmware *fw; + char f[32]; + int ret; + + snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname); + ret = request_firmware(&fw, f, &device->pdev->dev); + if (ret) { + snprintf(f, sizeof(f), "nouveau/%s", fwname); + ret = request_firmware(&fw, f, &device->pdev->dev); + if (ret) { + nv_error(priv, "failed to load %s\n", fwname); + return ret; + } + } + + fuc->size = fw->size; + fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); + release_firmware(fw); + return (fuc->data != NULL) ? 0 : -ENOMEM; } static int -nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend) +nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { + struct nouveau_device *device = nv_device(parent); + struct nvc0_graph_priv *priv; + bool enable = true; + int ret, i; + + switch (device->chipset) { + case 0xd9: /* known broken without binary driver firmware */ + enable = false; + break; + default: + break; + } + + ret = nouveau_graph_create(parent, engine, oclass, enable, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x18001000; + nv_subdev(priv)->intr = nvc0_graph_intr; + nv_engine(priv)->cclass = &nvc0_graph_cclass; + + if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) { + nv_info(priv, "using external firmware\n"); + if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) || + nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) || + nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) || + nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad)) + return -EINVAL; + priv->firmware = true; + } + + switch (nvc0_graph_class(priv)) { + case 0x9097: + nv_engine(priv)->sclass = nvc0_graph_sclass; + break; + case 0x9197: + nv_engine(priv)->sclass = nvc1_graph_sclass; + break; + case 0x9297: + nv_engine(priv)->sclass = nvc8_graph_sclass; + break; + } + + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8); + if (ret) + return ret; + + for (i = 0; i < 0x1000; i += 4) { + nv_wo32(priv->unk4188b4, i, 0x00000010); + nv_wo32(priv->unk4188b8, i, 0x00000010); + } + + priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16; + priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f; + for (i = 0; i < priv->gpc_nr; i++) { + priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608)); + priv->tpc_total += priv->tpc_nr[i]; + } + + /*XXX: these need figuring out... though it might not even matter */ + switch (nv_device(priv)->chipset) { + case 0xc0: + if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ + priv->magic_not_rop_nr = 0x07; + } else + if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ + priv->magic_not_rop_nr = 0x05; + } else + if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ + priv->magic_not_rop_nr = 0x06; + } + break; + case 0xc3: /* 450, 4/0/0/0, 2 */ + priv->magic_not_rop_nr = 0x03; + break; + case 0xc4: /* 460, 3/4/0/0, 4 */ + priv->magic_not_rop_nr = 0x01; + break; + case 0xc1: /* 2/0/0/0, 1 */ + priv->magic_not_rop_nr = 0x01; + break; + case 0xc8: /* 4/4/3/4, 5 */ + priv->magic_not_rop_nr = 0x06; + break; + case 0xce: /* 4/4/0/0, 4 */ + priv->magic_not_rop_nr = 0x03; + break; + case 0xcf: /* 4/0/0/0, 3 */ + priv->magic_not_rop_nr = 0x03; + break; + case 0xd9: /* 1/0/0/0, 1 */ + priv->magic_not_rop_nr = 0x01; + break; + } + return 0; } static void -nvc0_graph_init_obj418880(struct drm_device *dev) +nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc) +{ + if (fuc->data) { + kfree(fuc->data); + fuc->data = NULL; + } +} + +void +nvc0_graph_dtor(struct nouveau_object *object) +{ + struct nvc0_graph_priv *priv = (void *)object; + + if (priv->data) + kfree(priv->data); + + nvc0_graph_dtor_fw(&priv->fuc409c); + nvc0_graph_dtor_fw(&priv->fuc409d); + nvc0_graph_dtor_fw(&priv->fuc41ac); + nvc0_graph_dtor_fw(&priv->fuc41ad); + + nouveau_gpuobj_ref(NULL, &priv->unk4188b8); + nouveau_gpuobj_ref(NULL, &priv->unk4188b4); + + nouveau_graph_destroy(&priv->base); +} + +static void +nvc0_graph_init_obj418880(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); int i; - nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); for (i = 0; i < 4; i++) - nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000); - nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); + nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); } static void -nvc0_graph_init_regs(struct drm_device *dev) +nvc0_graph_init_regs(struct nvc0_graph_priv *priv) { - nv_wr32(dev, 0x400080, 0x003083c2); - nv_wr32(dev, 0x400088, 0x00006fe7); - nv_wr32(dev, 0x40008c, 0x00000000); - nv_wr32(dev, 0x400090, 0x00000030); - nv_wr32(dev, 0x40013c, 0x013901f7); - nv_wr32(dev, 0x400140, 0x00000100); - nv_wr32(dev, 0x400144, 0x00000000); - nv_wr32(dev, 0x400148, 0x00000110); - nv_wr32(dev, 0x400138, 0x00000000); - nv_wr32(dev, 0x400130, 0x00000000); - nv_wr32(dev, 0x400134, 0x00000000); - nv_wr32(dev, 0x400124, 0x00000002); + nv_wr32(priv, 0x400080, 0x003083c2); + nv_wr32(priv, 0x400088, 0x00006fe7); + nv_wr32(priv, 0x40008c, 0x00000000); + nv_wr32(priv, 0x400090, 0x00000030); + nv_wr32(priv, 0x40013c, 0x013901f7); + nv_wr32(priv, 0x400140, 0x00000100); + nv_wr32(priv, 0x400144, 0x00000000); + nv_wr32(priv, 0x400148, 0x00000110); + nv_wr32(priv, 0x400138, 0x00000000); + nv_wr32(priv, 0x400130, 0x00000000); + nv_wr32(priv, 0x400134, 0x00000000); + nv_wr32(priv, 0x400124, 0x00000002); } static void -nvc0_graph_init_gpc_0(struct drm_device *dev) +nvc0_graph_init_gpc_0(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); u32 data[TPC_MAX / 8]; - u8 tpnr[GPC_MAX]; + u8 tpcnr[GPC_MAX]; int i, gpc, tpc; - nv_wr32(dev, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */ + nv_wr32(priv, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */ /* * TP ROP UNKVAL(magic_not_rop_nr) @@ -244,205 +503,208 @@ nvc0_graph_init_gpc_0(struct drm_device *dev) */ memset(data, 0x00, sizeof(data)); - memcpy(tpnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); for (i = 0, gpc = -1; i < priv->tpc_total; i++) { do { gpc = (gpc + 1) % priv->gpc_nr; - } while (!tpnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpnr[gpc]--; + } while (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(dev, GPC_BCAST(0x0980), data[0]); - nv_wr32(dev, GPC_BCAST(0x0984), data[1]); - nv_wr32(dev, GPC_BCAST(0x0988), data[2]); - nv_wr32(dev, GPC_BCAST(0x098c), data[3]); + nv_wr32(priv, GPC_BCAST(0x0980), data[0]); + nv_wr32(priv, GPC_BCAST(0x0984), data[1]); + nv_wr32(priv, GPC_BCAST(0x0988), data[2]); + nv_wr32(priv, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | + nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); - nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918); + nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918); - nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800)); + nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918); + nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); } static void -nvc0_graph_init_units(struct drm_device *dev) +nvc0_graph_init_units(struct nvc0_graph_priv *priv) { - nv_wr32(dev, 0x409c24, 0x000f0000); - nv_wr32(dev, 0x404000, 0xc0000000); /* DISPATCH */ - nv_wr32(dev, 0x404600, 0xc0000000); /* M2MF */ - nv_wr32(dev, 0x408030, 0xc0000000); - nv_wr32(dev, 0x40601c, 0xc0000000); - nv_wr32(dev, 0x404490, 0xc0000000); /* MACRO */ - nv_wr32(dev, 0x406018, 0xc0000000); - nv_wr32(dev, 0x405840, 0xc0000000); - nv_wr32(dev, 0x405844, 0x00ffffff); - nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000); + nv_wr32(priv, 0x409c24, 0x000f0000); + nv_wr32(priv, 0x404000, 0xc0000000); /* DISPATCH */ + nv_wr32(priv, 0x404600, 0xc0000000); /* M2MF */ + nv_wr32(priv, 0x408030, 0xc0000000); + nv_wr32(priv, 0x40601c, 0xc0000000); + nv_wr32(priv, 0x404490, 0xc0000000); /* MACRO */ + nv_wr32(priv, 0x406018, 0xc0000000); + nv_wr32(priv, 0x405840, 0xc0000000); + nv_wr32(priv, 0x405844, 0x00ffffff); + nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); + nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000); } static void -nvc0_graph_init_gpc_1(struct drm_device *dev) +nvc0_graph_init_gpc_1(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); - int gpc, tp; + int gpc, tpc; for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tp = 0; tp < priv->tpc_nr[gpc]; tp++) { - nv_wr32(dev, TPC_UNIT(gpc, tp, 0x508), 0xffffffff); - nv_wr32(dev, TPC_UNIT(gpc, tp, 0x50c), 0xffffffff); - nv_wr32(dev, TPC_UNIT(gpc, tp, 0x224), 0xc0000000); - nv_wr32(dev, TPC_UNIT(gpc, tp, 0x48c), 0xc0000000); - nv_wr32(dev, TPC_UNIT(gpc, tp, 0x084), 0xc0000000); - nv_wr32(dev, TPC_UNIT(gpc, tp, 0x644), 0x001ffffe); - nv_wr32(dev, TPC_UNIT(gpc, tp, 0x64c), 0x0000000f); + nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } - nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } } static void -nvc0_graph_init_rop(struct drm_device *dev) +nvc0_graph_init_rop(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); int rop; for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff); + nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); + nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); + nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); } } -static void -nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base, - struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data) +void +nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base, + struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data) { int i; - nv_wr32(dev, fuc_base + 0x01c0, 0x01000000); + nv_wr32(priv, fuc_base + 0x01c0, 0x01000000); for (i = 0; i < data->size / 4; i++) - nv_wr32(dev, fuc_base + 0x01c4, data->data[i]); + nv_wr32(priv, fuc_base + 0x01c4, data->data[i]); - nv_wr32(dev, fuc_base + 0x0180, 0x01000000); + nv_wr32(priv, fuc_base + 0x0180, 0x01000000); for (i = 0; i < code->size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(dev, fuc_base + 0x0188, i >> 6); - nv_wr32(dev, fuc_base + 0x0184, code->data[i]); + nv_wr32(priv, fuc_base + 0x0188, i >> 6); + nv_wr32(priv, fuc_base + 0x0184, code->data[i]); } } static int -nvc0_graph_init_ctxctl(struct drm_device *dev) +nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); u32 r000260; int i; if (priv->firmware) { /* load fuc microcode */ - r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); - nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, + r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d); - nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, + nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad); - nv_wr32(dev, 0x000260, r000260); + nv_wr32(priv, 0x000260, r000260); /* start both of them running */ - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x41a10c, 0x00000000); - nv_wr32(dev, 0x40910c, 0x00000000); - nv_wr32(dev, 0x41a100, 0x00000002); - nv_wr32(dev, 0x409100, 0x00000002); - if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001)) - NV_INFO(dev, "0x409800 wait failed\n"); - - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x7fffffff); - nv_wr32(dev, 0x409504, 0x00000021); - - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x00000000); - nv_wr32(dev, 0x409504, 0x00000010); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x10 timeout\n"); + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x41a10c, 0x00000000); + nv_wr32(priv, 0x40910c, 0x00000000); + nv_wr32(priv, 0x41a100, 0x00000002); + nv_wr32(priv, 0x409100, 0x00000002); + if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001)) + nv_info(priv, "0x409800 wait failed\n"); + + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x7fffffff); + nv_wr32(priv, 0x409504, 0x00000021); + + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x00000000); + nv_wr32(priv, 0x409504, 0x00000010); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x10 timeout\n"); return -EBUSY; } - priv->size = nv_rd32(dev, 0x409800); + priv->size = nv_rd32(priv, 0x409800); - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x00000000); - nv_wr32(dev, 0x409504, 0x00000016); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x16 timeout\n"); + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x00000000); + nv_wr32(priv, 0x409504, 0x00000016); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x16 timeout\n"); return -EBUSY; } - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x00000000); - nv_wr32(dev, 0x409504, 0x00000025); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x25 timeout\n"); + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x00000000); + nv_wr32(priv, 0x409504, 0x00000025); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x25 timeout\n"); return -EBUSY; } - goto done; + if (priv->data == NULL) { + int ret = nvc0_grctx_generate(priv); + if (ret) { + nv_error(priv, "failed to construct context\n"); + return ret; + } + } + + return 0; } /* load HUB microcode */ - r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); - nv_wr32(dev, 0x4091c0, 0x01000000); + r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nv_wr32(priv, 0x4091c0, 0x01000000); for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++) - nv_wr32(dev, 0x4091c4, nvc0_grhub_data[i]); + nv_wr32(priv, 0x4091c4, nvc0_grhub_data[i]); - nv_wr32(dev, 0x409180, 0x01000000); + nv_wr32(priv, 0x409180, 0x01000000); for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(dev, 0x409188, i >> 6); - nv_wr32(dev, 0x409184, nvc0_grhub_code[i]); + nv_wr32(priv, 0x409188, i >> 6); + nv_wr32(priv, 0x409184, nvc0_grhub_code[i]); } /* load GPC microcode */ - nv_wr32(dev, 0x41a1c0, 0x01000000); + nv_wr32(priv, 0x41a1c0, 0x01000000); for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++) - nv_wr32(dev, 0x41a1c4, nvc0_grgpc_data[i]); + nv_wr32(priv, 0x41a1c4, nvc0_grgpc_data[i]); - nv_wr32(dev, 0x41a180, 0x01000000); + nv_wr32(priv, 0x41a180, 0x01000000); for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(dev, 0x41a188, i >> 6); - nv_wr32(dev, 0x41a184, nvc0_grgpc_code[i]); + nv_wr32(priv, 0x41a188, i >> 6); + nv_wr32(priv, 0x41a184, nvc0_grgpc_code[i]); } - nv_wr32(dev, 0x000260, r000260); + nv_wr32(priv, 0x000260, r000260); /* start HUB ucode running, it'll init the GPCs */ - nv_wr32(dev, 0x409800, dev_priv->chipset); - nv_wr32(dev, 0x40910c, 0x00000000); - nv_wr32(dev, 0x409100, 0x00000002); - if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) { - NV_ERROR(dev, "PGRAPH: HUB_INIT timed out\n"); - nvc0_graph_ctxctl_debug(dev); + nv_wr32(priv, 0x409800, nv_device(priv)->chipset); + nv_wr32(priv, 0x40910c, 0x00000000); + nv_wr32(priv, 0x409100, 0x00000002); + if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) { + nv_error(priv, "HUB_INIT timed out\n"); + nvc0_graph_ctxctl_debug(priv); return -EBUSY; } - priv->size = nv_rd32(dev, 0x409804); -done: + priv->size = nv_rd32(priv, 0x409804); if (priv->data == NULL) { - int ret = nvc0_grctx_generate(dev); + int ret = nvc0_grctx_generate(priv); if (ret) { - NV_ERROR(dev, "PGRAPH: failed to construct context\n"); + nv_error(priv, "failed to construct context\n"); return ret; } @@ -453,37 +715,39 @@ done: } static int -nvc0_graph_init(struct drm_device *dev, int engine) +nvc0_graph_init(struct nouveau_object *object) { + struct nvc0_graph_priv *priv = (void *)object; int ret; reset: - nv_mask(dev, 0x000200, 0x18001000, 0x00000000); - nv_mask(dev, 0x000200, 0x18001000, 0x18001000); - - nvc0_graph_init_obj418880(dev); - nvc0_graph_init_regs(dev); - /*nvc0_graph_init_unitplemented_magics(dev);*/ - nvc0_graph_init_gpc_0(dev); - /*nvc0_graph_init_unitplemented_c242(dev);*/ - - nv_wr32(dev, 0x400500, 0x00010001); - nv_wr32(dev, 0x400100, 0xffffffff); - nv_wr32(dev, 0x40013c, 0xffffffff); - - nvc0_graph_init_units(dev); - nvc0_graph_init_gpc_1(dev); - nvc0_graph_init_rop(dev); - - nv_wr32(dev, 0x400108, 0xffffffff); - nv_wr32(dev, 0x400138, 0xffffffff); - nv_wr32(dev, 0x400118, 0xffffffff); - nv_wr32(dev, 0x400130, 0xffffffff); - nv_wr32(dev, 0x40011c, 0xffffffff); - nv_wr32(dev, 0x400134, 0xffffffff); - nv_wr32(dev, 0x400054, 0x34ce3464); - - ret = nvc0_graph_init_ctxctl(dev); + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + nvc0_graph_init_obj418880(priv); + nvc0_graph_init_regs(priv); + /*nvc0_graph_init_unitplemented_magics(priv);*/ + nvc0_graph_init_gpc_0(priv); + /*nvc0_graph_init_unitplemented_c242(priv);*/ + + nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); + + nvc0_graph_init_units(priv); + nvc0_graph_init_gpc_1(priv); + nvc0_graph_init_rop(priv); + + nv_wr32(priv, 0x400108, 0xffffffff); + nv_wr32(priv, 0x400138, 0xffffffff); + nv_wr32(priv, 0x400118, 0xffffffff); + nv_wr32(priv, 0x400130, 0xffffffff); + nv_wr32(priv, 0x40011c, 0xffffffff); + nv_wr32(priv, 0x400134, 0xffffffff); + nv_wr32(priv, 0x400054, 0x34ce3464); + + ret = nvc0_graph_init_ctxctl(priv); if (ret) { if (ret == 1) goto reset; @@ -493,279 +757,13 @@ reset: return 0; } -int -nvc0_graph_isr_chid(struct drm_device *dev, u64 inst) -{ - struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan; - unsigned long flags; - int i; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (i = 0; i < pfifo->channels; i++) { - chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->ramin) - continue; - - if (inst == chan->ramin->addr) - break; - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - return i; -} - -static void -nvc0_graph_ctxctl_isr(struct drm_device *dev) -{ - u32 ustat = nv_rd32(dev, 0x409c18); - - if (ustat & 0x00000001) - NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n"); - if (ustat & 0x00080000) - NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n"); - if (ustat & ~0x00080001) - NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat); - - nvc0_graph_ctxctl_debug(dev); - nv_wr32(dev, 0x409c20, ustat); -} - -static void -nvc0_graph_isr(struct drm_device *dev) -{ - u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; - u32 chid = nvc0_graph_isr_chid(dev, inst); - u32 stat = nv_rd32(dev, 0x400100); - u32 addr = nv_rd32(dev, 0x400704); - u32 mthd = (addr & 0x00003ffc); - u32 subc = (addr & 0x00070000) >> 16; - u32 data = nv_rd32(dev, 0x400708); - u32 code = nv_rd32(dev, 0x400110); - u32 class = nv_rd32(dev, 0x404200 + (subc * 4)); - - if (stat & 0x00000010) { - if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) { - NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] " - "subc %d class 0x%04x mthd 0x%04x " - "data 0x%08x\n", - chid, inst, subc, class, mthd, data); - } - nv_wr32(dev, 0x400100, 0x00000010); - stat &= ~0x00000010; - } - - if (stat & 0x00000020) { - NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d " - "class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst, subc, class, mthd, data); - nv_wr32(dev, 0x400100, 0x00000020); - stat &= ~0x00000020; - } - - if (stat & 0x00100000) { - NV_INFO(dev, "PGRAPH: DATA_ERROR ["); - nouveau_enum_print(nv50_data_error_names, code); - printk("] ch %d [0x%010llx] subc %d class 0x%04x " - "mthd 0x%04x data 0x%08x\n", - chid, inst, subc, class, mthd, data); - nv_wr32(dev, 0x400100, 0x00100000); - stat &= ~0x00100000; - } - - if (stat & 0x00200000) { - u32 trap = nv_rd32(dev, 0x400108); - NV_INFO(dev, "PGRAPH: TRAP ch %d status 0x%08x\n", chid, trap); - nv_wr32(dev, 0x400108, trap); - nv_wr32(dev, 0x400100, 0x00200000); - stat &= ~0x00200000; - } - - if (stat & 0x00080000) { - nvc0_graph_ctxctl_isr(dev); - nv_wr32(dev, 0x400100, 0x00080000); - stat &= ~0x00080000; - } - - if (stat) { - NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat); - nv_wr32(dev, 0x400100, stat); - } - - nv_wr32(dev, 0x400500, 0x00010001); -} - -static int -nvc0_graph_create_fw(struct drm_device *dev, const char *fwname, - struct nvc0_graph_fuc *fuc) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - const struct firmware *fw; - char f[32]; - int ret; - - snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname); - ret = request_firmware(&fw, f, &dev->pdev->dev); - if (ret) { - snprintf(f, sizeof(f), "nouveau/%s", fwname); - ret = request_firmware(&fw, f, &dev->pdev->dev); - if (ret) { - NV_ERROR(dev, "failed to load %s\n", fwname); - return ret; - } - } - - fuc->size = fw->size; - fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); - release_firmware(fw); - return (fuc->data != NULL) ? 0 : -ENOMEM; -} - -static void -nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc) -{ - if (fuc->data) { - kfree(fuc->data); - fuc->data = NULL; - } -} - -static void -nvc0_graph_destroy(struct drm_device *dev, int engine) -{ - struct nvc0_graph_priv *priv = nv_engine(dev, engine); - - nvc0_graph_destroy_fw(&priv->fuc409c); - nvc0_graph_destroy_fw(&priv->fuc409d); - nvc0_graph_destroy_fw(&priv->fuc41ac); - nvc0_graph_destroy_fw(&priv->fuc41ad); - - nouveau_irq_unregister(dev, 12); - - nouveau_gpuobj_ref(NULL, &priv->unk4188b8); - nouveau_gpuobj_ref(NULL, &priv->unk4188b4); - - if (priv->data) - kfree(priv->data); - - NVOBJ_ENGINE_DEL(dev, GR); - kfree(priv); -} - -int -nvc0_graph_create(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvc0_graph_priv *priv; - int ret, gpc, i; - u32 fermi; - - fermi = nvc0_graph_class(dev); - if (!fermi) { - NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n"); - return 0; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->base.destroy = nvc0_graph_destroy; - priv->base.init = nvc0_graph_init; - priv->base.fini = nvc0_graph_fini; - priv->base.context_new = nvc0_graph_context_new; - priv->base.context_del = nvc0_graph_context_del; - priv->base.object_new = nvc0_graph_object_new; - - NVOBJ_ENGINE_ADD(dev, GR, &priv->base); - nouveau_irq_register(dev, 12, nvc0_graph_isr); - - if (nouveau_ctxfw) { - NV_INFO(dev, "PGRAPH: using external firmware\n"); - if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) || - nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) || - nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) || - nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) { - ret = 0; - goto error; - } - priv->firmware = true; - } - - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); - if (ret) - goto error; - - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8); - if (ret) - goto error; - - for (i = 0; i < 0x1000; i += 4) { - nv_wo32(priv->unk4188b4, i, 0x00000010); - nv_wo32(priv->unk4188b8, i, 0x00000010); - } - - priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f; - priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16; - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608)); - priv->tpc_total += priv->tpc_nr[gpc]; - } - - /*XXX: these need figuring out... */ - switch (dev_priv->chipset) { - case 0xc0: - if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ - priv->magic_not_rop_nr = 0x07; - } else - if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ - priv->magic_not_rop_nr = 0x05; - } else - if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ - priv->magic_not_rop_nr = 0x06; - } - break; - case 0xc3: /* 450, 4/0/0/0, 2 */ - priv->magic_not_rop_nr = 0x03; - break; - case 0xc4: /* 460, 3/4/0/0, 4 */ - priv->magic_not_rop_nr = 0x01; - break; - case 0xc1: /* 2/0/0/0, 1 */ - priv->magic_not_rop_nr = 0x01; - break; - case 0xc8: /* 4/4/3/4, 5 */ - priv->magic_not_rop_nr = 0x06; - break; - case 0xce: /* 4/4/0/0, 4 */ - priv->magic_not_rop_nr = 0x03; - break; - case 0xcf: /* 4/0/0/0, 3 */ - priv->magic_not_rop_nr = 0x03; - break; - case 0xd9: /* 1/0/0/0, 1 */ - priv->magic_not_rop_nr = 0x01; - break; - } - - if (!priv->magic_not_rop_nr) { - NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n", - priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2], - priv->tpc_nr[3], priv->rop_nr); - priv->magic_not_rop_nr = 0x00; - } - - NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ - NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ - NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ - if (fermi >= 0x9197) - NVOBJ_CLASS(dev, 0x9197, GR); /* 3D (NVC1-) */ - if (fermi >= 0x9297) - NVOBJ_CLASS(dev, 0x9297, GR); /* 3D (NVC8-) */ - NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */ - return 0; - -error: - nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR); - return ret; -} +struct nouveau_oclass +nvc0_graph_oclass = { + .handle = NV_ENGINE(GR, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_ctor, + .dtor = nvc0_graph_dtor, + .init = nvc0_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h index 30ea3ab..26f8268 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h @@ -25,6 +25,18 @@ #ifndef __NVC0_GRAPH_H__ #define __NVC0_GRAPH_H__ +#include <core/client.h> +#include <core/handle.h> +#include <core/gpuobj.h> +#include <core/option.h> + +#include <subdev/fb.h> +#include <subdev/vm.h> +#include <subdev/bar.h> +#include <subdev/timer.h> + +#include <engine/graph.h> + #define GPC_MAX 4 #define TPC_MAX 32 @@ -53,7 +65,7 @@ struct nvc0_graph_fuc { }; struct nvc0_graph_priv { - struct nouveau_exec_engine base; + struct nouveau_graph base; struct nvc0_graph_fuc fuc409c; struct nvc0_graph_fuc fuc409d; @@ -78,11 +90,10 @@ struct nvc0_graph_priv { }; struct nvc0_graph_chan { - struct nouveau_gpuobj *grctx; - struct nouveau_vma grctx_vma; + struct nouveau_graph_chan base; struct nouveau_gpuobj *mmio; - struct nouveau_vma mmio_vma; + struct nouveau_vma mmio_vma; int mmio_nr; struct { struct nouveau_gpuobj *mem; @@ -91,11 +102,11 @@ struct nvc0_graph_chan { }; static inline u32 -nvc0_graph_class(struct drm_device *priv) +nvc0_graph_class(void *obj) { - struct drm_nouveau_private *dev_priv = priv->dev_private; + struct nouveau_device *device = nv_device(obj); - switch (dev_priv->chipset) { + switch (device->chipset) { case 0xc0: case 0xc3: case 0xc4: @@ -115,17 +126,16 @@ nvc0_graph_class(struct drm_device *priv) } } -void nv_icmd(struct drm_device *priv, u32 icmd, u32 data); +void nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data); static inline void -nv_mthd(struct drm_device *priv, u32 class, u32 mthd, u32 data) +nv_mthd(struct nvc0_graph_priv *priv, u32 class, u32 mthd, u32 data) { nv_wr32(priv, 0x40448c, data); nv_wr32(priv, 0x404488, 0x80000000 | (mthd << 14) | class); } struct nvc0_grctx { - struct drm_device *dev; struct nvc0_graph_priv *priv; struct nvc0_graph_data *data; struct nvc0_graph_mmio *mmio; @@ -135,18 +145,18 @@ struct nvc0_grctx { u64 addr; }; -int nvc0_grctx_generate(struct drm_device *); -int nvc0_grctx_init(struct drm_device *, struct nvc0_graph_priv *, - struct nvc0_grctx *); +int nvc0_grctx_generate(struct nvc0_graph_priv *); +int nvc0_grctx_init(struct nvc0_graph_priv *, struct nvc0_grctx *); void nvc0_grctx_data(struct nvc0_grctx *, u32, u32, u32); void nvc0_grctx_mmio(struct nvc0_grctx *, u32, u32, u32, u32); int nvc0_grctx_fini(struct nvc0_grctx *); -int nve0_grctx_generate(struct drm_device *); +int nve0_grctx_generate(struct nvc0_graph_priv *); #define mmio_data(s,a,p) nvc0_grctx_data(&info, (s), (a), (p)) #define mmio_list(r,d,s,b) nvc0_grctx_mmio(&info, (r), (d), (s), (b)) +void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *); int nvc0_graph_ctor_fw(struct nvc0_graph_priv *, const char *, struct nvc0_graph_fuc *); void nvc0_graph_dtor(struct nouveau_object *); @@ -157,9 +167,4 @@ int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *, struct nouveau_object **); void nvc0_graph_context_dtor(struct nouveau_object *); -void nvc0_graph_ctxctl_debug(struct drm_device *); - -int nvc0_graph_context_new(struct nouveau_channel *, int); -void nvc0_graph_context_del(struct nouveau_channel *, int); - #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c index a3a4ee7..c79748a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c @@ -1,5 +1,5 @@ /* - * Copyright 2010 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,116 +22,290 @@ * Authors: Ben Skeggs */ -#include <linux/firmware.h> -#include <linux/module.h> - -#include "drmP.h" - -#include "nouveau_drv.h" -#include <core/mm.h> -#include <engine/fifo.h> - #include "nvc0.h" +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +nve0_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0xa040, &nouveau_object_ofuncs }, + { 0xa097, &nouveau_object_ofuncs }, + { 0xa0c0, &nouveau_object_ofuncs }, + { 0xa0b5, &nouveau_object_ofuncs }, + {} +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static struct nouveau_oclass +nve0_graph_cclass = { + .handle = NV_ENGCTX(GR, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_context_ctor, + .dtor = nvc0_graph_context_dtor, + .init = _nouveau_graph_context_init, + .fini = _nouveau_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + static void -nve0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base) +nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv) { - NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base, - nv_rd32(dev, base + 0x400)); - NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804), - nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c)); - NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814), - nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c)); + u32 ustat = nv_rd32(priv, 0x409c18); + + if (ustat & 0x00000001) + nv_error(priv, "CTXCTRL ucode error\n"); + if (ustat & 0x00080000) + nv_error(priv, "CTXCTRL watchdog timeout\n"); + if (ustat & ~0x00080001) + nv_error(priv, "CTXCTRL 0x%08x\n", ustat); + + nvc0_graph_ctxctl_debug(priv); + nv_wr32(priv, 0x409c20, ustat); } static void -nve0_graph_ctxctl_debug(struct drm_device *dev) +nve0_graph_trap_isr(struct nvc0_graph_priv *priv, u64 inst) { - u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff; - u32 gpc; + u32 trap = nv_rd32(priv, 0x400108); + int rop; + + if (trap & 0x00000001) { + u32 stat = nv_rd32(priv, 0x404000); + nv_error(priv, "DISPATCH ch 0x%010llx 0x%08x\n", inst, stat); + nv_wr32(priv, 0x404000, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000001); + trap &= ~0x00000001; + } - nve0_graph_ctxctl_debug_unit(dev, 0x409000); - for (gpc = 0; gpc < gpcnr; gpc++) - nve0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000)); + if (trap & 0x00000010) { + u32 stat = nv_rd32(priv, 0x405840); + nv_error(priv, "SHADER ch 0x%010llx 0x%08x\n", inst, stat); + nv_wr32(priv, 0x405840, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000010); + trap &= ~0x00000010; + } + + if (trap & 0x02000000) { + for (rop = 0; rop < priv->rop_nr; rop++) { + u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070)); + u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144)); + nv_error(priv, "ROP%d ch 0x%010llx 0x%08x 0x%08x\n", + rop, inst, statz, statc); + nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); + nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); + } + nv_wr32(priv, 0x400108, 0x02000000); + trap &= ~0x02000000; + } + + if (trap) { + nv_error(priv, "TRAP ch 0x%010llx 0x%08x\n", inst, trap); + nv_wr32(priv, 0x400108, trap); + } } -static int -nve0_graph_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +static void +nve0_graph_intr(struct nouveau_subdev *subdev) { - return 0; + struct nvc0_graph_priv *priv = (void *)subdev; + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_handle *handle = NULL; + u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12; + u32 stat = nv_rd32(priv, 0x400100); + u32 addr = nv_rd32(priv, 0x400704); + u32 mthd = (addr & 0x00003ffc); + u32 subc = (addr & 0x00070000) >> 16; + u32 data = nv_rd32(priv, 0x400708); + u32 code = nv_rd32(priv, 0x400110); + u32 class = nv_rd32(priv, 0x404200 + (subc * 4)); + + if (stat & 0x00000010) { + handle = nouveau_engctx_lookup_class(engine, inst, class); + if (!handle || nv_call(handle->object, mthd, data)) { + nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx " + "subc %d class 0x%04x mthd 0x%04x " + "data 0x%08x\n", + inst, subc, class, mthd, data); + } + nouveau_engctx_handle_put(handle); + nv_wr32(priv, 0x400100, 0x00000010); + stat &= ~0x00000010; + } + + if (stat & 0x00000020) { + nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + nv_wr32(priv, 0x400100, 0x00000020); + stat &= ~0x00000020; + } + + if (stat & 0x00100000) { + nv_error(priv, "DATA_ERROR ["); + nouveau_enum_print(nv50_data_error_names, code); + printk("] ch 0x%010llx subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + nv_wr32(priv, 0x400100, 0x00100000); + stat &= ~0x00100000; + } + + if (stat & 0x00200000) { + nve0_graph_trap_isr(priv, inst); + nv_wr32(priv, 0x400100, 0x00200000); + stat &= ~0x00200000; + } + + if (stat & 0x00080000) { + nve0_graph_ctxctl_isr(priv); + nv_wr32(priv, 0x400100, 0x00080000); + stat &= ~0x00080000; + } + + if (stat) { + nv_error(priv, "unknown stat 0x%08x\n", stat); + nv_wr32(priv, 0x400100, stat); + } + + nv_wr32(priv, 0x400500, 0x00010001); } static int -nve0_graph_fini(struct drm_device *dev, int engine, bool suspend) +nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { + struct nvc0_graph_priv *priv; + int ret, i; + + ret = nouveau_graph_create(parent, engine, oclass, false, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x18001000; + nv_subdev(priv)->intr = nve0_graph_intr; + nv_engine(priv)->cclass = &nve0_graph_cclass; + nv_engine(priv)->sclass = nve0_graph_sclass; + + nv_info(priv, "using external firmware\n"); + if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) || + nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) || + nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) || + nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad)) + return -EINVAL; + priv->firmware = true; + + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8); + if (ret) + return ret; + + for (i = 0; i < 0x1000; i += 4) { + nv_wo32(priv->unk4188b4, i, 0x00000010); + nv_wo32(priv->unk4188b8, i, 0x00000010); + } + + priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f; + priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16; + for (i = 0; i < priv->gpc_nr; i++) { + priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608)); + priv->tpc_total += priv->tpc_nr[i]; + } + + switch (nv_device(priv)->chipset) { + case 0xe4: + if (priv->tpc_total == 8) + priv->magic_not_rop_nr = 3; + else + if (priv->tpc_total == 7) + priv->magic_not_rop_nr = 1; + break; + case 0xe7: + priv->magic_not_rop_nr = 1; + break; + default: + break; + } + return 0; } static void -nve0_graph_init_obj418880(struct drm_device *dev) +nve0_graph_init_obj418880(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); int i; - nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); for (i = 0; i < 4; i++) - nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000); - nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); + nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); } static void -nve0_graph_init_regs(struct drm_device *dev) +nve0_graph_init_regs(struct nvc0_graph_priv *priv) { - nv_wr32(dev, 0x400080, 0x003083c2); - nv_wr32(dev, 0x400088, 0x0001ffe7); - nv_wr32(dev, 0x40008c, 0x00000000); - nv_wr32(dev, 0x400090, 0x00000030); - nv_wr32(dev, 0x40013c, 0x003901f7); - nv_wr32(dev, 0x400140, 0x00000100); - nv_wr32(dev, 0x400144, 0x00000000); - nv_wr32(dev, 0x400148, 0x00000110); - nv_wr32(dev, 0x400138, 0x00000000); - nv_wr32(dev, 0x400130, 0x00000000); - nv_wr32(dev, 0x400134, 0x00000000); - nv_wr32(dev, 0x400124, 0x00000002); + nv_wr32(priv, 0x400080, 0x003083c2); + nv_wr32(priv, 0x400088, 0x0001ffe7); + nv_wr32(priv, 0x40008c, 0x00000000); + nv_wr32(priv, 0x400090, 0x00000030); + nv_wr32(priv, 0x40013c, 0x003901f7); + nv_wr32(priv, 0x400140, 0x00000100); + nv_wr32(priv, 0x400144, 0x00000000); + nv_wr32(priv, 0x400148, 0x00000110); + nv_wr32(priv, 0x400138, 0x00000000); + nv_wr32(priv, 0x400130, 0x00000000); + nv_wr32(priv, 0x400134, 0x00000000); + nv_wr32(priv, 0x400124, 0x00000002); } static void -nve0_graph_init_units(struct drm_device *dev) +nve0_graph_init_units(struct nvc0_graph_priv *priv) { - nv_wr32(dev, 0x409ffc, 0x00000000); - nv_wr32(dev, 0x409c14, 0x00003e3e); - nv_wr32(dev, 0x409c24, 0x000f0000); - - nv_wr32(dev, 0x404000, 0xc0000000); - nv_wr32(dev, 0x404600, 0xc0000000); - nv_wr32(dev, 0x408030, 0xc0000000); - nv_wr32(dev, 0x404490, 0xc0000000); - nv_wr32(dev, 0x406018, 0xc0000000); - nv_wr32(dev, 0x407020, 0xc0000000); - nv_wr32(dev, 0x405840, 0xc0000000); - nv_wr32(dev, 0x405844, 0x00ffffff); - - nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000); + nv_wr32(priv, 0x409ffc, 0x00000000); + nv_wr32(priv, 0x409c14, 0x00003e3e); + nv_wr32(priv, 0x409c24, 0x000f0000); + + nv_wr32(priv, 0x404000, 0xc0000000); + nv_wr32(priv, 0x404600, 0xc0000000); + nv_wr32(priv, 0x408030, 0xc0000000); + nv_wr32(priv, 0x404490, 0xc0000000); + nv_wr32(priv, 0x406018, 0xc0000000); + nv_wr32(priv, 0x407020, 0xc0000000); + nv_wr32(priv, 0x405840, 0xc0000000); + nv_wr32(priv, 0x405844, 0x00ffffff); + + nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); + nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000); } static void -nve0_graph_init_gpc_0(struct drm_device *dev) +nve0_graph_init_gpc_0(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); u32 data[TPC_MAX / 8]; u8 tpcnr[GPC_MAX]; int i, gpc, tpc; - nv_wr32(dev, GPC_UNIT(0, 0x3018), 0x00000001); + nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); @@ -144,164 +318,143 @@ nve0_graph_init_gpc_0(struct drm_device *dev) data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(dev, GPC_BCAST(0x0980), data[0]); - nv_wr32(dev, GPC_BCAST(0x0984), data[1]); - nv_wr32(dev, GPC_BCAST(0x0988), data[2]); - nv_wr32(dev, GPC_BCAST(0x098c), data[3]); + nv_wr32(priv, GPC_BCAST(0x0980), data[0]); + nv_wr32(priv, GPC_BCAST(0x0984), data[1]); + nv_wr32(priv, GPC_BCAST(0x0988), data[2]); + nv_wr32(priv, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | + nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); - nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918); + nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918); - nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800)); + nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918); + nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); } static void -nve0_graph_init_gpc_1(struct drm_device *dev) +nve0_graph_init_gpc_1(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); int gpc, tpc; for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(dev, GPC_UNIT(gpc, 0x3038), 0xc0000000); - nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); - nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } - nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } } static void -nve0_graph_init_rop(struct drm_device *dev) +nve0_graph_init_rop(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); int rop; for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff); - } -} - -static void -nve0_graph_init_fuc(struct drm_device *dev, u32 fuc_base, - struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data) -{ - int i; - - nv_wr32(dev, fuc_base + 0x01c0, 0x01000000); - for (i = 0; i < data->size / 4; i++) - nv_wr32(dev, fuc_base + 0x01c4, data->data[i]); - - nv_wr32(dev, fuc_base + 0x0180, 0x01000000); - for (i = 0; i < code->size / 4; i++) { - if ((i & 0x3f) == 0) - nv_wr32(dev, fuc_base + 0x0188, i >> 6); - nv_wr32(dev, fuc_base + 0x0184, code->data[i]); + nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); + nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); + nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); } } static int -nve0_graph_init_ctxctl(struct drm_device *dev) +nve0_graph_init_ctxctl(struct nvc0_graph_priv *priv) { - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); u32 r000260; /* load fuc microcode */ - r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); - nve0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d); - nve0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad); - nv_wr32(dev, 0x000260, r000260); + r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d); + nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad); + nv_wr32(priv, 0x000260, r000260); /* start both of them running */ - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x41a10c, 0x00000000); - nv_wr32(dev, 0x40910c, 0x00000000); - nv_wr32(dev, 0x41a100, 0x00000002); - nv_wr32(dev, 0x409100, 0x00000002); - if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001)) - NV_INFO(dev, "0x409800 wait failed\n"); - - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x7fffffff); - nv_wr32(dev, 0x409504, 0x00000021); - - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x00000000); - nv_wr32(dev, 0x409504, 0x00000010); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x10 timeout\n"); + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x41a10c, 0x00000000); + nv_wr32(priv, 0x40910c, 0x00000000); + nv_wr32(priv, 0x41a100, 0x00000002); + nv_wr32(priv, 0x409100, 0x00000002); + if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001)) + nv_error(priv, "0x409800 wait failed\n"); + + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x7fffffff); + nv_wr32(priv, 0x409504, 0x00000021); + + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x00000000); + nv_wr32(priv, 0x409504, 0x00000010); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x10 timeout\n"); return -EBUSY; } - priv->size = nv_rd32(dev, 0x409800); + priv->size = nv_rd32(priv, 0x409800); - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x00000000); - nv_wr32(dev, 0x409504, 0x00000016); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x16 timeout\n"); + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x00000000); + nv_wr32(priv, 0x409504, 0x00000016); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x16 timeout\n"); return -EBUSY; } - nv_wr32(dev, 0x409840, 0xffffffff); - nv_wr32(dev, 0x409500, 0x00000000); - nv_wr32(dev, 0x409504, 0x00000025); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x25 timeout\n"); + nv_wr32(priv, 0x409840, 0xffffffff); + nv_wr32(priv, 0x409500, 0x00000000); + nv_wr32(priv, 0x409504, 0x00000025); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x25 timeout\n"); return -EBUSY; } - nv_wr32(dev, 0x409800, 0x00000000); - nv_wr32(dev, 0x409500, 0x00000001); - nv_wr32(dev, 0x409504, 0x00000030); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x30 timeout\n"); + nv_wr32(priv, 0x409800, 0x00000000); + nv_wr32(priv, 0x409500, 0x00000001); + nv_wr32(priv, 0x409504, 0x00000030); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x30 timeout\n"); return -EBUSY; } - nv_wr32(dev, 0x409810, 0xb00095c8); - nv_wr32(dev, 0x409800, 0x00000000); - nv_wr32(dev, 0x409500, 0x00000001); - nv_wr32(dev, 0x409504, 0x00000031); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x31 timeout\n"); + nv_wr32(priv, 0x409810, 0xb00095c8); + nv_wr32(priv, 0x409800, 0x00000000); + nv_wr32(priv, 0x409500, 0x00000001); + nv_wr32(priv, 0x409504, 0x00000031); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x31 timeout\n"); return -EBUSY; } - nv_wr32(dev, 0x409810, 0x00080420); - nv_wr32(dev, 0x409800, 0x00000000); - nv_wr32(dev, 0x409500, 0x00000001); - nv_wr32(dev, 0x409504, 0x00000032); - if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { - NV_ERROR(dev, "fuc09 req 0x32 timeout\n"); + nv_wr32(priv, 0x409810, 0x00080420); + nv_wr32(priv, 0x409800, 0x00000000); + nv_wr32(priv, 0x409500, 0x00000001); + nv_wr32(priv, 0x409504, 0x00000032); + if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(priv, "fuc09 req 0x32 timeout\n"); return -EBUSY; } - nv_wr32(dev, 0x409614, 0x00000070); - nv_wr32(dev, 0x409614, 0x00000770); - nv_wr32(dev, 0x40802c, 0x00000001); + nv_wr32(priv, 0x409614, 0x00000070); + nv_wr32(priv, 0x409614, 0x00000770); + nv_wr32(priv, 0x40802c, 0x00000001); if (priv->data == NULL) { - int ret = nve0_grctx_generate(dev); + int ret = nve0_grctx_generate(priv); if (ret) { - NV_ERROR(dev, "PGRAPH: failed to construct context\n"); + nv_error(priv, "failed to construct context\n"); return ret; } @@ -312,325 +465,53 @@ nve0_graph_init_ctxctl(struct drm_device *dev) } static int -nve0_graph_init(struct drm_device *dev, int engine) +nve0_graph_init(struct nouveau_object *object) { + struct nvc0_graph_priv *priv = (void *)object; int ret; reset: - nv_mask(dev, 0x000200, 0x18001000, 0x00000000); - nv_mask(dev, 0x000200, 0x18001000, 0x18001000); - - nve0_graph_init_obj418880(dev); - nve0_graph_init_regs(dev); - nve0_graph_init_gpc_0(dev); - - nv_wr32(dev, 0x400500, 0x00010001); - nv_wr32(dev, 0x400100, 0xffffffff); - nv_wr32(dev, 0x40013c, 0xffffffff); - - nve0_graph_init_units(dev); - nve0_graph_init_gpc_1(dev); - nve0_graph_init_rop(dev); - - nv_wr32(dev, 0x400108, 0xffffffff); - nv_wr32(dev, 0x400138, 0xffffffff); - nv_wr32(dev, 0x400118, 0xffffffff); - nv_wr32(dev, 0x400130, 0xffffffff); - nv_wr32(dev, 0x40011c, 0xffffffff); - nv_wr32(dev, 0x400134, 0xffffffff); - nv_wr32(dev, 0x400054, 0x34ce3464); - - ret = nve0_graph_init_ctxctl(dev); - if (ret) { - if (ret == 1) - goto reset; - return ret; - } - - return 0; -} - -int -nve0_graph_isr_chid(struct drm_device *dev, u64 inst) -{ - struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan; - unsigned long flags; - int i; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (i = 0; i < pfifo->channels; i++) { - chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->ramin) - continue; - - if (inst == chan->ramin->addr) - break; - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - return i; -} - -static void -nve0_graph_ctxctl_isr(struct drm_device *dev) -{ - u32 ustat = nv_rd32(dev, 0x409c18); - - if (ustat & 0x00000001) - NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n"); - if (ustat & 0x00080000) - NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n"); - if (ustat & ~0x00080001) - NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat); - - nve0_graph_ctxctl_debug(dev); - nv_wr32(dev, 0x409c20, ustat); -} - -static void -nve0_graph_trap_isr(struct drm_device *dev, int chid) -{ - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); - u32 trap = nv_rd32(dev, 0x400108); - int rop; - - if (trap & 0x00000001) { - u32 stat = nv_rd32(dev, 0x404000); - NV_INFO(dev, "PGRAPH: DISPATCH ch %d 0x%08x\n", chid, stat); - nv_wr32(dev, 0x404000, 0xc0000000); - nv_wr32(dev, 0x400108, 0x00000001); - trap &= ~0x00000001; - } - - if (trap & 0x00000010) { - u32 stat = nv_rd32(dev, 0x405840); - NV_INFO(dev, "PGRAPH: SHADER ch %d 0x%08x\n", chid, stat); - nv_wr32(dev, 0x405840, 0xc0000000); - nv_wr32(dev, 0x400108, 0x00000010); - trap &= ~0x00000010; - } - - if (trap & 0x02000000) { - for (rop = 0; rop < priv->rop_nr; rop++) { - u32 statz = nv_rd32(dev, ROP_UNIT(rop, 0x070)); - u32 statc = nv_rd32(dev, ROP_UNIT(rop, 0x144)); - NV_INFO(dev, "PGRAPH: ROP%d ch %d 0x%08x 0x%08x\n", - rop, chid, statz, statc); - nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000); - } - nv_wr32(dev, 0x400108, 0x02000000); - trap &= ~0x02000000; - } - - if (trap) { - NV_INFO(dev, "PGRAPH: TRAP ch %d 0x%08x\n", chid, trap); - nv_wr32(dev, 0x400108, trap); - } -} - -static void -nve0_graph_isr(struct drm_device *dev) -{ - u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; - u32 chid = nve0_graph_isr_chid(dev, inst); - u32 stat = nv_rd32(dev, 0x400100); - u32 addr = nv_rd32(dev, 0x400704); - u32 mthd = (addr & 0x00003ffc); - u32 subc = (addr & 0x00070000) >> 16; - u32 data = nv_rd32(dev, 0x400708); - u32 code = nv_rd32(dev, 0x400110); - u32 class = nv_rd32(dev, 0x404200 + (subc * 4)); - - if (stat & 0x00000010) { - if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) { - NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] " - "subc %d class 0x%04x mthd 0x%04x " - "data 0x%08x\n", - chid, inst, subc, class, mthd, data); - } - nv_wr32(dev, 0x400100, 0x00000010); - stat &= ~0x00000010; - } - - if (stat & 0x00000020) { - NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d " - "class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst, subc, class, mthd, data); - nv_wr32(dev, 0x400100, 0x00000020); - stat &= ~0x00000020; - } - - if (stat & 0x00100000) { - NV_INFO(dev, "PGRAPH: DATA_ERROR ["); - nouveau_enum_print(nv50_data_error_names, code); - printk("] ch %d [0x%010llx] subc %d class 0x%04x " - "mthd 0x%04x data 0x%08x\n", - chid, inst, subc, class, mthd, data); - nv_wr32(dev, 0x400100, 0x00100000); - stat &= ~0x00100000; - } - - if (stat & 0x00200000) { - nve0_graph_trap_isr(dev, chid); - nv_wr32(dev, 0x400100, 0x00200000); - stat &= ~0x00200000; - } - - if (stat & 0x00080000) { - nve0_graph_ctxctl_isr(dev); - nv_wr32(dev, 0x400100, 0x00080000); - stat &= ~0x00080000; - } - - if (stat) { - NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat); - nv_wr32(dev, 0x400100, stat); - } - - nv_wr32(dev, 0x400500, 0x00010001); -} - -static int -nve0_graph_create_fw(struct drm_device *dev, const char *fwname, - struct nvc0_graph_fuc *fuc) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - const struct firmware *fw; - char f[32]; - int ret; - - snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname); - ret = request_firmware(&fw, f, &dev->pdev->dev); + ret = nouveau_graph_init(&priv->base); if (ret) return ret; - fuc->size = fw->size; - fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); - release_firmware(fw); - return (fuc->data != NULL) ? 0 : -ENOMEM; -} - -static void -nve0_graph_destroy_fw(struct nvc0_graph_fuc *fuc) -{ - if (fuc->data) { - kfree(fuc->data); - fuc->data = NULL; - } -} - -static void -nve0_graph_destroy(struct drm_device *dev, int engine) -{ - struct nvc0_graph_priv *priv = nv_engine(dev, engine); - - nve0_graph_destroy_fw(&priv->fuc409c); - nve0_graph_destroy_fw(&priv->fuc409d); - nve0_graph_destroy_fw(&priv->fuc41ac); - nve0_graph_destroy_fw(&priv->fuc41ad); - - nouveau_irq_unregister(dev, 12); - - nouveau_gpuobj_ref(NULL, &priv->unk4188b8); - nouveau_gpuobj_ref(NULL, &priv->unk4188b4); - - if (priv->data) - kfree(priv->data); - - NVOBJ_ENGINE_DEL(dev, GR); - kfree(priv); -} - -int -nve0_graph_create(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvc0_graph_priv *priv; - int ret, gpc, i; - u32 kepler; - - kepler = nvc0_graph_class(dev); - if (!kepler) { - NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n"); - return 0; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->base.destroy = nve0_graph_destroy; - priv->base.init = nve0_graph_init; - priv->base.fini = nve0_graph_fini; - priv->base.context_new = nvc0_graph_context_new; - priv->base.context_del = nvc0_graph_context_del; - priv->base.object_new = nve0_graph_object_new; - - NVOBJ_ENGINE_ADD(dev, GR, &priv->base); - nouveau_irq_register(dev, 12, nve0_graph_isr); - - NV_INFO(dev, "PGRAPH: using external firmware\n"); - if (nve0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) || - nve0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) || - nve0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) || - nve0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) { - ret = 0; - goto error; - } - priv->firmware = true; - - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); - if (ret) - goto error; + nve0_graph_init_obj418880(priv); + nve0_graph_init_regs(priv); + nve0_graph_init_gpc_0(priv); - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8); - if (ret) - goto error; + nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); - for (i = 0; i < 0x1000; i += 4) { - nv_wo32(priv->unk4188b4, i, 0x00000010); - nv_wo32(priv->unk4188b8, i, 0x00000010); - } + nve0_graph_init_units(priv); + nve0_graph_init_gpc_1(priv); + nve0_graph_init_rop(priv); - priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f; - priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16; - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608)); - priv->tpc_total += priv->tpc_nr[gpc]; - } - - switch (dev_priv->chipset) { - case 0xe4: - if (priv->tpc_total == 8) - priv->magic_not_rop_nr = 3; - else - if (priv->tpc_total == 7) - priv->magic_not_rop_nr = 1; - break; - case 0xe7: - priv->magic_not_rop_nr = 1; - break; - default: - break; - } + nv_wr32(priv, 0x400108, 0xffffffff); + nv_wr32(priv, 0x400138, 0xffffffff); + nv_wr32(priv, 0x400118, 0xffffffff); + nv_wr32(priv, 0x400130, 0xffffffff); + nv_wr32(priv, 0x40011c, 0xffffffff); + nv_wr32(priv, 0x400134, 0xffffffff); + nv_wr32(priv, 0x400054, 0x34ce3464); - if (!priv->magic_not_rop_nr) { - NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n", - priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2], - priv->tpc_nr[3], priv->rop_nr); - priv->magic_not_rop_nr = 0x00; + ret = nve0_graph_init_ctxctl(priv); + if (ret) { + if (ret == 1) + goto reset; + return ret; } - NVOBJ_CLASS(dev, 0xa097, GR); /* subc 0: 3D */ - NVOBJ_CLASS(dev, 0xa0c0, GR); /* subc 1: COMPUTE */ - NVOBJ_CLASS(dev, 0xa040, GR); /* subc 2: P2MF */ - NVOBJ_CLASS(dev, 0x902d, GR); /* subc 3: 2D */ - NVOBJ_CLASS(dev, 0xa0b5, GR); /* subc 4: COPY */ return 0; - -error: - nve0_graph_destroy(dev, NVOBJ_ENGINE_GR); - return ret; } + +struct nouveau_oclass +nve0_graph_oclass = { + .handle = NV_ENGINE(GR, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_graph_ctor, + .dtor = nvc0_graph_dtor, + .init = nve0_graph_init, + .fini = _nouveau_graph_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/regs.h b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h new file mode 100644 index 0000000..9c715a2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h @@ -0,0 +1,269 @@ +#ifndef __NOUVEAU_GRAPH_REGS_H__ +#define __NOUVEAU_GRAPH_REGS_H__ + +#define NV04_PGRAPH_DEBUG_0 0x00400080 +#define NV04_PGRAPH_DEBUG_1 0x00400084 +#define NV04_PGRAPH_DEBUG_2 0x00400088 +#define NV04_PGRAPH_DEBUG_3 0x0040008c +#define NV10_PGRAPH_DEBUG_4 0x00400090 +#define NV03_PGRAPH_INTR 0x00400100 +#define NV03_PGRAPH_NSTATUS 0x00400104 +# define NV04_PGRAPH_NSTATUS_STATE_IN_USE (1<<11) +# define NV04_PGRAPH_NSTATUS_INVALID_STATE (1<<12) +# define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<13) +# define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<14) +# define NV10_PGRAPH_NSTATUS_STATE_IN_USE (1<<23) +# define NV10_PGRAPH_NSTATUS_INVALID_STATE (1<<24) +# define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<25) +# define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<26) +#define NV03_PGRAPH_NSOURCE 0x00400108 +# define NV03_PGRAPH_NSOURCE_NOTIFICATION (1<<0) +# define NV03_PGRAPH_NSOURCE_DATA_ERROR (1<<1) +# define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR (1<<2) +# define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION (1<<3) +# define NV03_PGRAPH_NSOURCE_LIMIT_COLOR (1<<4) +# define NV03_PGRAPH_NSOURCE_LIMIT_ZETA (1<<5) +# define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD (1<<6) +# define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION (1<<7) +# define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION (1<<8) +# define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION (1<<9) +# define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION (1<<10) +# define NV03_PGRAPH_NSOURCE_STATE_INVALID (1<<11) +# define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY (1<<12) +# define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE (1<<13) +# define NV03_PGRAPH_NSOURCE_METHOD_CNT (1<<14) +# define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION (1<<15) +# define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION (1<<16) +# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A (1<<17) +# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B (1<<18) +#define NV03_PGRAPH_INTR_EN 0x00400140 +#define NV40_PGRAPH_INTR_EN 0x0040013C +# define NV_PGRAPH_INTR_NOTIFY (1<<0) +# define NV_PGRAPH_INTR_MISSING_HW (1<<4) +# define NV_PGRAPH_INTR_CONTEXT_SWITCH (1<<12) +# define NV_PGRAPH_INTR_BUFFER_NOTIFY (1<<16) +# define NV_PGRAPH_INTR_ERROR (1<<20) +#define NV10_PGRAPH_CTX_CONTROL 0x00400144 +#define NV10_PGRAPH_CTX_USER 0x00400148 +#define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i)) +#define NV04_PGRAPH_CTX_SWITCH1 0x00400160 +#define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \ + + 0x4*(i) + 0x20*(j)) +#define NV04_PGRAPH_CTX_SWITCH2 0x00400164 +#define NV04_PGRAPH_CTX_SWITCH3 0x00400168 +#define NV04_PGRAPH_CTX_SWITCH4 0x0040016C +#define NV04_PGRAPH_CTX_CONTROL 0x00400170 +#define NV04_PGRAPH_CTX_USER 0x00400174 +#define NV04_PGRAPH_CTX_CACHE1 0x00400180 +#define NV03_PGRAPH_CTX_CONTROL 0x00400190 +#define NV03_PGRAPH_CTX_USER 0x00400194 +#define NV04_PGRAPH_CTX_CACHE2 0x004001A0 +#define NV04_PGRAPH_CTX_CACHE3 0x004001C0 +#define NV04_PGRAPH_CTX_CACHE4 0x004001E0 +#define NV40_PGRAPH_CTXCTL_0304 0x00400304 +#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001 +#define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308 +#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK 0xff000000 +#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT 24 +#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK 0x00ffffff +#define NV40_PGRAPH_CTXCTL_0310 0x00400310 +#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE 0x00000020 +#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD 0x00000040 +#define NV40_PGRAPH_CTXCTL_030C 0x0040030c +#define NV40_PGRAPH_CTXCTL_UCODE_INDEX 0x00400324 +#define NV40_PGRAPH_CTXCTL_UCODE_DATA 0x00400328 +#define NV40_PGRAPH_CTXCTL_CUR 0x0040032c +#define NV40_PGRAPH_CTXCTL_CUR_LOADED 0x01000000 +#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE 0x000FFFFF +#define NV40_PGRAPH_CTXCTL_NEXT 0x00400330 +#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE 0x000fffff +#define NV50_PGRAPH_CTXCTL_CUR 0x0040032c +#define NV50_PGRAPH_CTXCTL_CUR_LOADED 0x80000000 +#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE 0x00ffffff +#define NV50_PGRAPH_CTXCTL_NEXT 0x00400330 +#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE 0x00ffffff +#define NV03_PGRAPH_ABS_X_RAM 0x00400400 +#define NV03_PGRAPH_ABS_Y_RAM 0x00400480 +#define NV03_PGRAPH_X_MISC 0x00400500 +#define NV03_PGRAPH_Y_MISC 0x00400504 +#define NV04_PGRAPH_VALID1 0x00400508 +#define NV04_PGRAPH_SOURCE_COLOR 0x0040050C +#define NV04_PGRAPH_MISC24_0 0x00400510 +#define NV03_PGRAPH_XY_LOGIC_MISC0 0x00400514 +#define NV03_PGRAPH_XY_LOGIC_MISC1 0x00400518 +#define NV03_PGRAPH_XY_LOGIC_MISC2 0x0040051C +#define NV03_PGRAPH_XY_LOGIC_MISC3 0x00400520 +#define NV03_PGRAPH_CLIPX_0 0x00400524 +#define NV03_PGRAPH_CLIPX_1 0x00400528 +#define NV03_PGRAPH_CLIPY_0 0x0040052C +#define NV03_PGRAPH_CLIPY_1 0x00400530 +#define NV03_PGRAPH_ABS_ICLIP_XMAX 0x00400534 +#define NV03_PGRAPH_ABS_ICLIP_YMAX 0x00400538 +#define NV03_PGRAPH_ABS_UCLIP_XMIN 0x0040053C +#define NV03_PGRAPH_ABS_UCLIP_YMIN 0x00400540 +#define NV03_PGRAPH_ABS_UCLIP_XMAX 0x00400544 +#define NV03_PGRAPH_ABS_UCLIP_YMAX 0x00400548 +#define NV03_PGRAPH_ABS_UCLIPA_XMIN 0x00400560 +#define NV03_PGRAPH_ABS_UCLIPA_YMIN 0x00400564 +#define NV03_PGRAPH_ABS_UCLIPA_XMAX 0x00400568 +#define NV03_PGRAPH_ABS_UCLIPA_YMAX 0x0040056C +#define NV04_PGRAPH_MISC24_1 0x00400570 +#define NV04_PGRAPH_MISC24_2 0x00400574 +#define NV04_PGRAPH_VALID2 0x00400578 +#define NV04_PGRAPH_PASSTHRU_0 0x0040057C +#define NV04_PGRAPH_PASSTHRU_1 0x00400580 +#define NV04_PGRAPH_PASSTHRU_2 0x00400584 +#define NV10_PGRAPH_DIMX_TEXTURE 0x00400588 +#define NV10_PGRAPH_WDIMX_TEXTURE 0x0040058C +#define NV04_PGRAPH_COMBINE_0_ALPHA 0x00400590 +#define NV04_PGRAPH_COMBINE_0_COLOR 0x00400594 +#define NV04_PGRAPH_COMBINE_1_ALPHA 0x00400598 +#define NV04_PGRAPH_COMBINE_1_COLOR 0x0040059C +#define NV04_PGRAPH_FORMAT_0 0x004005A8 +#define NV04_PGRAPH_FORMAT_1 0x004005AC +#define NV04_PGRAPH_FILTER_0 0x004005B0 +#define NV04_PGRAPH_FILTER_1 0x004005B4 +#define NV03_PGRAPH_MONO_COLOR0 0x00400600 +#define NV04_PGRAPH_ROP3 0x00400604 +#define NV04_PGRAPH_BETA_AND 0x00400608 +#define NV04_PGRAPH_BETA_PREMULT 0x0040060C +#define NV04_PGRAPH_LIMIT_VIOL_PIX 0x00400610 +#define NV04_PGRAPH_FORMATS 0x00400618 +#define NV10_PGRAPH_DEBUG_2 0x00400620 +#define NV04_PGRAPH_BOFFSET0 0x00400640 +#define NV04_PGRAPH_BOFFSET1 0x00400644 +#define NV04_PGRAPH_BOFFSET2 0x00400648 +#define NV04_PGRAPH_BOFFSET3 0x0040064C +#define NV04_PGRAPH_BOFFSET4 0x00400650 +#define NV04_PGRAPH_BOFFSET5 0x00400654 +#define NV04_PGRAPH_BBASE0 0x00400658 +#define NV04_PGRAPH_BBASE1 0x0040065C +#define NV04_PGRAPH_BBASE2 0x00400660 +#define NV04_PGRAPH_BBASE3 0x00400664 +#define NV04_PGRAPH_BBASE4 0x00400668 +#define NV04_PGRAPH_BBASE5 0x0040066C +#define NV04_PGRAPH_BPITCH0 0x00400670 +#define NV04_PGRAPH_BPITCH1 0x00400674 +#define NV04_PGRAPH_BPITCH2 0x00400678 +#define NV04_PGRAPH_BPITCH3 0x0040067C +#define NV04_PGRAPH_BPITCH4 0x00400680 +#define NV04_PGRAPH_BLIMIT0 0x00400684 +#define NV04_PGRAPH_BLIMIT1 0x00400688 +#define NV04_PGRAPH_BLIMIT2 0x0040068C +#define NV04_PGRAPH_BLIMIT3 0x00400690 +#define NV04_PGRAPH_BLIMIT4 0x00400694 +#define NV04_PGRAPH_BLIMIT5 0x00400698 +#define NV04_PGRAPH_BSWIZZLE2 0x0040069C +#define NV04_PGRAPH_BSWIZZLE5 0x004006A0 +#define NV03_PGRAPH_STATUS 0x004006B0 +#define NV04_PGRAPH_STATUS 0x00400700 +# define NV40_PGRAPH_STATUS_SYNC_STALL 0x00004000 +#define NV04_PGRAPH_TRAPPED_ADDR 0x00400704 +#define NV04_PGRAPH_TRAPPED_DATA 0x00400708 +#define NV04_PGRAPH_SURFACE 0x0040070C +#define NV10_PGRAPH_TRAPPED_DATA_HIGH 0x0040070C +#define NV04_PGRAPH_STATE 0x00400710 +#define NV10_PGRAPH_SURFACE 0x00400710 +#define NV04_PGRAPH_NOTIFY 0x00400714 +#define NV10_PGRAPH_STATE 0x00400714 +#define NV10_PGRAPH_NOTIFY 0x00400718 + +#define NV04_PGRAPH_FIFO 0x00400720 + +#define NV04_PGRAPH_BPIXEL 0x00400724 +#define NV10_PGRAPH_RDI_INDEX 0x00400750 +#define NV04_PGRAPH_FFINTFC_ST2 0x00400754 +#define NV10_PGRAPH_RDI_DATA 0x00400754 +#define NV04_PGRAPH_DMA_PITCH 0x00400760 +#define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760 +#define NV04_PGRAPH_DVD_COLORFMT 0x00400764 +#define NV10_PGRAPH_FFINTFC_ST2 0x00400764 +#define NV04_PGRAPH_SCALED_FORMAT 0x00400768 +#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768 +#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c +#define NV10_PGRAPH_DMA_PITCH 0x00400770 +#define NV10_PGRAPH_DVD_COLORFMT 0x00400774 +#define NV10_PGRAPH_SCALED_FORMAT 0x00400778 +#define NV20_PGRAPH_CHANNEL_CTX_TABLE 0x00400780 +#define NV20_PGRAPH_CHANNEL_CTX_POINTER 0x00400784 +#define NV20_PGRAPH_CHANNEL_CTX_XFER 0x00400788 +#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD 0x00000001 +#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE 0x00000002 +#define NV04_PGRAPH_PATT_COLOR0 0x00400800 +#define NV04_PGRAPH_PATT_COLOR1 0x00400804 +#define NV04_PGRAPH_PATTERN 0x00400808 +#define NV04_PGRAPH_PATTERN_SHAPE 0x00400810 +#define NV04_PGRAPH_CHROMA 0x00400814 +#define NV04_PGRAPH_CONTROL0 0x00400818 +#define NV04_PGRAPH_CONTROL1 0x0040081C +#define NV04_PGRAPH_CONTROL2 0x00400820 +#define NV04_PGRAPH_BLEND 0x00400824 +#define NV04_PGRAPH_STORED_FMT 0x00400830 +#define NV04_PGRAPH_PATT_COLORRAM 0x00400900 +#define NV20_PGRAPH_TILE(i) (0x00400900 + (i*16)) +#define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16)) +#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16)) +#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16)) +#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i)) +#define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16)) +#define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16)) +#define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16)) +#define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16)) +#define NV04_PGRAPH_U_RAM 0x00400D00 +#define NV47_PGRAPH_TILE(i) (0x00400D00 + (i*16)) +#define NV47_PGRAPH_TLIMIT(i) (0x00400D04 + (i*16)) +#define NV47_PGRAPH_TSIZE(i) (0x00400D08 + (i*16)) +#define NV47_PGRAPH_TSTATUS(i) (0x00400D0C + (i*16)) +#define NV04_PGRAPH_V_RAM 0x00400D40 +#define NV04_PGRAPH_W_RAM 0x00400D80 +#define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40 +#define NV10_PGRAPH_COMBINER1_IN_ALPHA 0x00400E44 +#define NV10_PGRAPH_COMBINER0_IN_RGB 0x00400E48 +#define NV10_PGRAPH_COMBINER1_IN_RGB 0x00400E4C +#define NV10_PGRAPH_COMBINER_COLOR0 0x00400E50 +#define NV10_PGRAPH_COMBINER_COLOR1 0x00400E54 +#define NV10_PGRAPH_COMBINER0_OUT_ALPHA 0x00400E58 +#define NV10_PGRAPH_COMBINER1_OUT_ALPHA 0x00400E5C +#define NV10_PGRAPH_COMBINER0_OUT_RGB 0x00400E60 +#define NV10_PGRAPH_COMBINER1_OUT_RGB 0x00400E64 +#define NV10_PGRAPH_COMBINER_FINAL0 0x00400E68 +#define NV10_PGRAPH_COMBINER_FINAL1 0x00400E6C +#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL 0x00400F00 +#define NV10_PGRAPH_WINDOWCLIP_VERTICAL 0x00400F20 +#define NV10_PGRAPH_XFMODE0 0x00400F40 +#define NV10_PGRAPH_XFMODE1 0x00400F44 +#define NV10_PGRAPH_GLOBALSTATE0 0x00400F48 +#define NV10_PGRAPH_GLOBALSTATE1 0x00400F4C +#define NV10_PGRAPH_PIPE_ADDRESS 0x00400F50 +#define NV10_PGRAPH_PIPE_DATA 0x00400F54 +#define NV04_PGRAPH_DMA_START_0 0x00401000 +#define NV04_PGRAPH_DMA_START_1 0x00401004 +#define NV04_PGRAPH_DMA_LENGTH 0x00401008 +#define NV04_PGRAPH_DMA_MISC 0x0040100C +#define NV04_PGRAPH_DMA_DATA_0 0x00401020 +#define NV04_PGRAPH_DMA_DATA_1 0x00401024 +#define NV04_PGRAPH_DMA_RM 0x00401030 +#define NV04_PGRAPH_DMA_A_XLATE_INST 0x00401040 +#define NV04_PGRAPH_DMA_A_CONTROL 0x00401044 +#define NV04_PGRAPH_DMA_A_LIMIT 0x00401048 +#define NV04_PGRAPH_DMA_A_TLB_PTE 0x0040104C +#define NV04_PGRAPH_DMA_A_TLB_TAG 0x00401050 +#define NV04_PGRAPH_DMA_A_ADJ_OFFSET 0x00401054 +#define NV04_PGRAPH_DMA_A_OFFSET 0x00401058 +#define NV04_PGRAPH_DMA_A_SIZE 0x0040105C +#define NV04_PGRAPH_DMA_A_Y_SIZE 0x00401060 +#define NV04_PGRAPH_DMA_B_XLATE_INST 0x00401080 +#define NV04_PGRAPH_DMA_B_CONTROL 0x00401084 +#define NV04_PGRAPH_DMA_B_LIMIT 0x00401088 +#define NV04_PGRAPH_DMA_B_TLB_PTE 0x0040108C +#define NV04_PGRAPH_DMA_B_TLB_TAG 0x00401090 +#define NV04_PGRAPH_DMA_B_ADJ_OFFSET 0x00401094 +#define NV04_PGRAPH_DMA_B_OFFSET 0x00401098 +#define NV04_PGRAPH_DMA_B_SIZE 0x0040109C +#define NV04_PGRAPH_DMA_B_Y_SIZE 0x004010A0 +#define NV40_PGRAPH_TILE1(i) (0x00406900 + (i*16)) +#define NV40_PGRAPH_TLIMIT1(i) (0x00406904 + (i*16)) +#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16)) +#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16)) + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c index a0258c7..7a1bc76 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.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,159 +22,62 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include <engine/fifo.h> -#include <core/ramht.h> +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/handle.h> +#include <core/engine/graph/nv40.h> -struct nv31_mpeg_engine { - struct nouveau_exec_engine base; - atomic_t refcount; -}; - - -static int -nv31_mpeg_context_new(struct nouveau_channel *chan, int engine) -{ - struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); - - if (!atomic_add_unless(&pmpeg->refcount, 1, 1)) - return -EBUSY; - - chan->engctx[engine] = (void *)0xdeadcafe; - return 0; -} - -static void -nv31_mpeg_context_del(struct nouveau_channel *chan, int engine) -{ - struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); - atomic_dec(&pmpeg->refcount); - chan->engctx[engine] = NULL; -} +#include <subdev/fb.h> +#include <subdev/timer.h> +#include <subdev/instmem.h> -static int -nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) -{ - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *ctx = NULL; - unsigned long flags; - int ret; - - NV_DEBUG(dev, "ch%d\n", chan->id); +#include <engine/mpeg.h> - ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &ctx); - if (ret) - return ret; - - nv_wo32(ctx, 0x78, 0x02001ec1); - - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, 0x002500, 0x00000001, 0x00000000); - if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) - nv_wr32(dev, 0x00330c, ctx->addr >> 4); - nv_wo32(chan->ramfc, 0x54, ctx->addr >> 4); - nv_mask(dev, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +struct nv31_mpeg_priv { + struct nouveau_mpeg base; + atomic_t refcount; +}; - chan->engctx[engine] = ctx; - return 0; -} +struct nv31_mpeg_chan { + struct nouveau_object base; +}; -static void -nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) -{ - struct drm_nouveau_private *dev_priv = chan->dev->dev_private; - struct nouveau_gpuobj *ctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - unsigned long flags; - u32 inst = 0x80000000 | (ctx->addr >> 4); - - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); - if (nv_rd32(dev, 0x00b318) == inst) - nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); - nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - - nouveau_gpuobj_ref(NULL, &ctx); - chan->engctx[engine] = NULL; -} +/******************************************************************************* + * MPEG object classes + ******************************************************************************/ static int -nv31_mpeg_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +nv31_mpeg_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *obj = NULL; + struct nouveau_gpuobj *obj; int ret; - ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &obj); + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent, + 20, 16, 0, &obj); + *pobject = nv_object(obj); if (ret) return ret; - obj->engine = 2; - obj->class = class; - - nv_wo32(obj, 0x00, class); - - ret = nouveau_ramht_insert(chan, handle, obj); - nouveau_gpuobj_ref(NULL, &obj); - return ret; -} - -static int -nv31_mpeg_init(struct drm_device *dev, int engine) -{ - struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); - int i; - - /* VPE init */ - nv_mask(dev, 0x000200, 0x00000002, 0x00000000); - nv_mask(dev, 0x000200, 0x00000002, 0x00000002); - nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - for (i = 0; i < nvfb_tile_nr(dev); i++) - pmpeg->base.set_tile_region(dev, i); - - /* PMPEG init */ - nv_wr32(dev, 0x00b32c, 0x00000000); - nv_wr32(dev, 0x00b314, 0x00000100); - nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031); - nv_wr32(dev, 0x00b300, 0x02001ec1); - nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); - - nv_wr32(dev, 0x00b100, 0xffffffff); - nv_wr32(dev, 0x00b140, 0xffffffff); - - if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); - return -EBUSY; - } - - return 0; -} - -static int -nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend) -{ - /*XXX: context save? */ - nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); - nv_wr32(dev, 0x00b140, 0x00000000); + nv_wo32(obj, 0x00, nv_mclass(obj)); + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); + nv_wo32(obj, 0x0c, 0x00000000); return 0; } static int -nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) +nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len) { - struct drm_device *dev = chan->dev; - u32 inst = data << 4; - u32 dma0 = nv_ri32(dev, inst + 0); - u32 dma1 = nv_ri32(dev, inst + 4); - u32 dma2 = nv_ri32(dev, inst + 8); + struct nouveau_instmem *imem = nouveau_instmem(object); + struct nv31_mpeg_priv *priv = (void *)object->engine; + u32 inst = *(u32 *)arg << 4; + u32 dma0 = nv_ro32(imem, inst + 0); + u32 dma1 = nv_ro32(imem, inst + 4); + u32 dma2 = nv_ro32(imem, inst + 8); u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); u32 size = dma1 + 1; @@ -184,160 +87,215 @@ nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); - nv_wr32(dev, 0x00b334, base); - nv_wr32(dev, 0x00b324, size); + nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000)); + nv_wr32(priv, 0x00b334, base); + nv_wr32(priv, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); - nv_wr32(dev, 0x00b360, base); - nv_wr32(dev, 0x00b364, size); + nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); + nv_wr32(priv, 0x00b360, base); + nv_wr32(priv, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x000c0000) return -EINVAL; - nv_wr32(dev, 0x00b370, base); - nv_wr32(dev, 0x00b374, size); + nv_wr32(priv, 0x00b370, base); + nv_wr32(priv, 0x00b374, size); } return 0; } +struct nouveau_ofuncs +nv31_mpeg_ofuncs = { + .ctor = nv31_mpeg_object_ctor, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, +}; + +struct nouveau_omthds +nv31_mpeg_omthds[] = { + { 0x0190, nv31_mpeg_mthd_dma }, + { 0x01a0, nv31_mpeg_mthd_dma }, + { 0x01b0, nv31_mpeg_mthd_dma }, + {} +}; + +struct nouveau_oclass +nv31_mpeg_sclass[] = { + { 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds }, + {} +}; + +/******************************************************************************* + * PMPEG context + ******************************************************************************/ + static int -nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) +nv31_mpeg_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *ctx; - unsigned long flags; - int i; - - /* hardcode drm channel id on nv3x, so swmthd lookup works */ - if (dev_priv->card_type < NV_40) - return 0; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (i = 0; i < pfifo->channels; i++) { - if (!dev_priv->channels.ptr[i]) - continue; - - ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; - if (ctx && ctx->addr == inst) - break; - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - return i; + struct nv31_mpeg_priv *priv = (void *)engine; + struct nv31_mpeg_chan *chan; + int ret; + + if (!atomic_add_unless(&priv->refcount, 1, 1)) + return -EBUSY; + + ret = nouveau_object_create(parent, engine, oclass, 0, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + return 0; } static void -nv31_vpe_set_tile_region(struct drm_device *dev, int i) +nv31_mpeg_context_dtor(struct nouveau_object *object) { - 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); + struct nv31_mpeg_priv *priv = (void *)object->engine; + struct nv31_mpeg_chan *chan = (void *)object; + atomic_dec(&priv->refcount); + nouveau_object_destroy(&chan->base); } -static void -nv31_mpeg_isr(struct drm_device *dev) +static struct nouveau_oclass +nv31_mpeg_cclass = { + .handle = NV_ENGCTX(MPEG, 0x31), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv31_mpeg_context_ctor, + .dtor = nv31_mpeg_context_dtor, + .init = nouveau_object_init, + .fini = nouveau_object_fini, + }, +}; + +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ + +void +nv31_mpeg_tile_prog(struct nouveau_engine *engine, int i) { - u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; - u32 chid = nv31_mpeg_isr_chid(dev, inst); - u32 stat = nv_rd32(dev, 0x00b100); - u32 type = nv_rd32(dev, 0x00b230); - u32 mthd = nv_rd32(dev, 0x00b234); - u32 data = nv_rd32(dev, 0x00b238); + struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i]; + struct nv31_mpeg_priv *priv = (void *)engine; + + nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch); + nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit); + nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr); +} + +void +nv31_mpeg_intr(struct nouveau_subdev *subdev) +{ + struct nv31_mpeg_priv *priv = (void *)subdev; + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_handle *handle = NULL; + u32 inst = (nv_rd32(priv, 0x00b318) & 0x000fffff) << 4; + u32 stat = nv_rd32(priv, 0x00b100); + u32 type = nv_rd32(priv, 0x00b230); + u32 mthd = nv_rd32(priv, 0x00b234); + u32 data = nv_rd32(priv, 0x00b238); u32 show = stat; if (stat & 0x01000000) { /* happens on initial binding of the object */ - if (type == 0x00000020 && mthd == 0x0000) { - nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); + if (handle && type == 0x00000020 && mthd == 0x0000) { + nv_mask(priv, 0x00b308, 0x00000000, 0x00000000); show &= ~0x01000000; } - if (type == 0x00000010) { - if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) + if (handle && type == 0x00000010) { + handle = nouveau_engctx_lookup_class(engine, inst, 0x3174); + + if (handle && !nv_call(handle->object, mthd, data)) { + nouveau_engctx_handle_put(handle); show &= ~0x01000000; + } } } - nv_wr32(dev, 0x00b100, stat); - nv_wr32(dev, 0x00b230, 0x00000001); + nv_wr32(priv, 0x00b100, stat); + nv_wr32(priv, 0x00b230, 0x00000001); - if (show && nouveau_ratelimit()) { - NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", - chid, inst, stat, type, mthd, data); + if (show) { + nv_error(priv, "ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", + inst, stat, type, mthd, data); } } -static void -nv31_vpe_isr(struct drm_device *dev) +static int +nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - if (nv_rd32(dev, 0x00b100)) - nv31_mpeg_isr(dev); + struct nv31_mpeg_priv *priv; + int ret; - if (nv_rd32(dev, 0x00b800)) { - u32 stat = nv_rd32(dev, 0x00b800); - NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); - nv_wr32(dev, 0xb800, stat); - } + ret = nouveau_mpeg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000002; + nv_subdev(priv)->intr = nv31_mpeg_intr; + nv_engine(priv)->cclass = &nv31_mpeg_cclass; + nv_engine(priv)->sclass = nv31_mpeg_sclass; + nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; + return 0; } -static void -nv31_mpeg_destroy(struct drm_device *dev, int engine) +int +nv31_mpeg_init(struct nouveau_object *object) { - struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); + struct nouveau_engine *engine = nv_engine(object->engine); + struct nv31_mpeg_priv *priv = (void *)engine; + struct nouveau_fb *pfb = nouveau_fb(object); + int ret, i; - nouveau_irq_unregister(dev, 0); + ret = nouveau_mpeg_init(&priv->base); + if (ret) + return ret; - NVOBJ_ENGINE_DEL(dev, MPEG); - kfree(pmpeg); -} + /* VPE init */ + nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ -int -nv31_mpeg_create(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv31_mpeg_engine *pmpeg; - - pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); - if (!pmpeg) - return -ENOMEM; - atomic_set(&pmpeg->refcount, 0); - - pmpeg->base.destroy = nv31_mpeg_destroy; - pmpeg->base.init = nv31_mpeg_init; - pmpeg->base.fini = nv31_mpeg_fini; - if (dev_priv->card_type < NV_40) { - pmpeg->base.context_new = nv31_mpeg_context_new; - pmpeg->base.context_del = nv31_mpeg_context_del; - } else { - pmpeg->base.context_new = nv40_mpeg_context_new; - pmpeg->base.context_del = nv40_mpeg_context_del; + for (i = 0; i < pfb->tile.regions; i++) + engine->tile_prog(engine, i); + + /* PMPEG init */ + nv_wr32(priv, 0x00b32c, 0x00000000); + nv_wr32(priv, 0x00b314, 0x00000100); + nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031); + nv_wr32(priv, 0x00b300, 0x02001ec1); + nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + + nv_wr32(priv, 0x00b100, 0xffffffff); + nv_wr32(priv, 0x00b140, 0xffffffff); + + if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) { + nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200)); + return -EBUSY; } - pmpeg->base.object_new = nv31_mpeg_object_new; - - /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between - * all VPE engines, for this driver's purposes the PMPEG engine - * will be treated as the "master" and handle the global VPE - * bits too - */ - pmpeg->base.set_tile_region = nv31_vpe_set_tile_region; - nouveau_irq_register(dev, 0, nv31_vpe_isr); - - NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); - NVOBJ_CLASS(dev, 0x3174, MPEG); - NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma); - NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma); - NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma); - -#if 0 - NVOBJ_ENGINE_ADD(dev, ME, &pme->base); - NVOBJ_CLASS(dev, 0x4075, ME); -#endif - return 0; + return 0; } + +struct nouveau_oclass +nv31_mpeg_oclass = { + .handle = NV_ENGINE(MPEG, 0x31), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv31_mpeg_ctor, + .dtor = _nouveau_mpeg_dtor, + .init = nv31_mpeg_init, + .fini = _nouveau_mpeg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c new file mode 100644 index 0000000..1241857 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c @@ -0,0 +1,144 @@ +/* + * 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 <core/os.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <subdev/fb.h> +#include <subdev/timer.h> +#include <subdev/instmem.h> + +#include <engine/mpeg.h> +#include <engine/graph/nv40.h> + +struct nv40_mpeg_priv { + struct nouveau_mpeg base; +}; + +struct nv40_mpeg_chan { + struct nouveau_mpeg base; +}; + +/******************************************************************************* + * PMPEG context + ******************************************************************************/ + +static int +nv40_mpeg_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv40_mpeg_chan *chan; + int ret; + + ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, + 264 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + return 0; +} + +static int +nv40_mpeg_context_fini(struct nouveau_object *object, bool suspend) +{ + + struct nv40_mpeg_priv *priv = (void *)object->engine; + struct nv40_mpeg_chan *chan = (void *)object; + u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4; + + nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000); + if (nv_rd32(priv, 0x00b318) == inst) + nv_mask(priv, 0x00b318, 0x80000000, 0x00000000); + nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + return 0; +} + +static struct nouveau_oclass +nv40_mpeg_cclass = { + .handle = NV_ENGCTX(MPEG, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_mpeg_context_ctor, + .dtor = _nouveau_mpeg_context_dtor, + .init = _nouveau_mpeg_context_init, + .fini = nv40_mpeg_context_fini, + .rd32 = _nouveau_mpeg_context_rd32, + .wr32 = _nouveau_mpeg_context_wr32, + }, +}; + +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ + +static void +nv40_mpeg_intr(struct nouveau_subdev *subdev) +{ + struct nv40_mpeg_priv *priv = (void *)subdev; + u32 stat; + + if ((stat = nv_rd32(priv, 0x00b100))) + nv31_mpeg_intr(subdev); + + if ((stat = nv_rd32(priv, 0x00b800))) { + nv_error(priv, "PMSRCH 0x%08x\n", stat); + nv_wr32(priv, 0x00b800, stat); + } +} + +static int +nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv40_mpeg_priv *priv; + int ret; + + ret = nouveau_mpeg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000002; + nv_subdev(priv)->intr = nv40_mpeg_intr; + nv_engine(priv)->cclass = &nv40_mpeg_cclass; + nv_engine(priv)->sclass = nv31_mpeg_sclass; + nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; + return 0; +} + +struct nouveau_oclass +nv40_mpeg_oclass = { + .handle = NV_ENGINE(MPEG, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_mpeg_ctor, + .dtor = _nouveau_mpeg_dtor, + .init = nv31_mpeg_init, + .fini = _nouveau_mpeg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c index 4e3292e..8678a99 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.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,218 +22,219 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include <core/ramht.h> +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> -struct nv50_mpeg_engine { - struct nouveau_exec_engine base; -}; +#include <subdev/vm.h> +#include <subdev/bar.h> +#include <subdev/timer.h> -static inline u32 -CTX_PTR(struct drm_device *dev, u32 offset) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; +#include <engine/mpeg.h> - if (dev_priv->chipset == 0x50) - offset += 0x0260; - else - offset += 0x0060; +struct nv50_mpeg_priv { + struct nouveau_mpeg base; +}; - return offset; -} +struct nv50_mpeg_chan { + struct nouveau_mpeg_chan base; +}; + +/******************************************************************************* + * MPEG object classes + ******************************************************************************/ static int -nv50_mpeg_context_new(struct nouveau_channel *chan, int engine) +nv50_mpeg_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *ramin = chan->ramin; - struct nouveau_gpuobj *ctx = NULL; + struct nouveau_gpuobj *obj; int ret; - NV_DEBUG(dev, "ch%d\n", chan->id); - - ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &ctx); + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent, + 16, 16, 0, &obj); + *pobject = nv_object(obj); if (ret) return ret; - nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002); - nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->addr + ctx->size - 1); - nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->addr); - nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0); - nv_wo32(ramin, CTX_PTR(dev, 0x10), 0); - nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000); - - nv_wo32(ctx, 0x70, 0x00801ec1); - nv_wo32(ctx, 0x7c, 0x0000037c); - nvimem_flush(dev); - - chan->engctx[engine] = ctx; + nv_wo32(obj, 0x00, nv_mclass(obj)); + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); + nv_wo32(obj, 0x0c, 0x00000000); return 0; } -static void -nv50_mpeg_context_del(struct nouveau_channel *chan, int engine) -{ - struct nouveau_gpuobj *ctx = chan->engctx[engine]; - struct drm_device *dev = chan->dev; - int i; +struct nouveau_ofuncs +nv50_mpeg_ofuncs = { + .ctor = nv50_mpeg_object_ctor, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, +}; - for (i = 0x00; i <= 0x14; i += 4) - nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000); +static struct nouveau_oclass +nv50_mpeg_sclass[] = { + { 0x3174, &nv50_mpeg_ofuncs }, + {} +}; - nouveau_gpuobj_ref(NULL, &ctx); - chan->engctx[engine] = NULL; -} +/******************************************************************************* + * PMPEG context + ******************************************************************************/ -static int -nv50_mpeg_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +int +nv50_mpeg_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *obj = NULL; + struct nouveau_bar *bar = nouveau_bar(parent); + struct nv50_mpeg_chan *chan; int ret; - ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); + ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4, + 0, NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); if (ret) return ret; - obj->engine = 2; - obj->class = class; - - nv_wo32(obj, 0x00, class); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); - nvimem_flush(dev); - - ret = nouveau_ramht_insert(chan, handle, obj); - nouveau_gpuobj_ref(NULL, &obj); - return ret; -} -static void -nv50_mpeg_tlb_flush(struct drm_device *dev, int engine) -{ - nv50_vm_flush_engine(dev, 0x08); + nv_wo32(chan, 0x0070, 0x00801ec1); + nv_wo32(chan, 0x007c, 0x0000037c); + bar->flush(bar); + return 0; } -static int -nv50_mpeg_init(struct drm_device *dev, int engine) -{ - nv_wr32(dev, 0x00b32c, 0x00000000); - nv_wr32(dev, 0x00b314, 0x00000100); - nv_wr32(dev, 0x00b0e0, 0x0000001a); - - nv_wr32(dev, 0x00b220, 0x00000044); - nv_wr32(dev, 0x00b300, 0x00801ec1); - nv_wr32(dev, 0x00b390, 0x00000000); - nv_wr32(dev, 0x00b394, 0x00000000); - nv_wr32(dev, 0x00b398, 0x00000000); - nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); - - nv_wr32(dev, 0x00b100, 0xffffffff); - nv_wr32(dev, 0x00b140, 0xffffffff); - - if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); - return -EBUSY; - } +static struct nouveau_oclass +nv50_mpeg_cclass = { + .handle = NV_ENGCTX(MPEG, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_mpeg_context_ctor, + .dtor = _nouveau_mpeg_context_dtor, + .init = _nouveau_mpeg_context_init, + .fini = _nouveau_mpeg_context_fini, + .rd32 = _nouveau_mpeg_context_rd32, + .wr32 = _nouveau_mpeg_context_wr32, + }, +}; - return 0; -} +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ -static int -nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend) +int +nv50_mpeg_tlb_flush(struct nouveau_engine *engine) { - nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); - nv_wr32(dev, 0x00b140, 0x00000000); + nv50_vm_flush_engine(&engine->base, 0x08); return 0; } -static void -nv50_mpeg_isr(struct drm_device *dev) +void +nv50_mpeg_intr(struct nouveau_subdev *subdev) { - u32 stat = nv_rd32(dev, 0x00b100); - u32 type = nv_rd32(dev, 0x00b230); - u32 mthd = nv_rd32(dev, 0x00b234); - u32 data = nv_rd32(dev, 0x00b238); + struct nv50_mpeg_priv *priv = (void *)subdev; + u32 stat = nv_rd32(priv, 0x00b100); + u32 type = nv_rd32(priv, 0x00b230); + u32 mthd = nv_rd32(priv, 0x00b234); + u32 data = nv_rd32(priv, 0x00b238); u32 show = stat; if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_wr32(dev, 0x00b308, 0x00000100); + nv_wr32(priv, 0x00b308, 0x00000100); show &= ~0x01000000; } } - if (show && nouveau_ratelimit()) { - NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n", + if (show) { + nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n", stat, type, mthd, data); } - nv_wr32(dev, 0x00b100, stat); - nv_wr32(dev, 0x00b230, 0x00000001); - nv50_fb_vm_trap(dev, 1); + nv_wr32(priv, 0x00b100, stat); + nv_wr32(priv, 0x00b230, 0x00000001); + nv50_fb_trap(nouveau_fb(priv), 1); } static void -nv50_vpe_isr(struct drm_device *dev) +nv50_vpe_intr(struct nouveau_subdev *subdev) { - if (nv_rd32(dev, 0x00b100)) - nv50_mpeg_isr(dev); + struct nv50_mpeg_priv *priv = (void *)subdev; - if (nv_rd32(dev, 0x00b800)) { - u32 stat = nv_rd32(dev, 0x00b800); - NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); - nv_wr32(dev, 0xb800, stat); + if (nv_rd32(priv, 0x00b100)) + nv50_mpeg_intr(subdev); + + if (nv_rd32(priv, 0x00b800)) { + u32 stat = nv_rd32(priv, 0x00b800); + nv_info(priv, "PMSRCH: 0x%08x\n", stat); + nv_wr32(priv, 0xb800, stat); } } -static void -nv50_mpeg_destroy(struct drm_device *dev, int engine) +static int +nv50_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine); + struct nv50_mpeg_priv *priv; + int ret; - nouveau_irq_unregister(dev, 0); + ret = nouveau_mpeg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - NVOBJ_ENGINE_DEL(dev, MPEG); - kfree(pmpeg); + nv_subdev(priv)->unit = 0x00400002; + nv_subdev(priv)->intr = nv50_vpe_intr; + nv_engine(priv)->cclass = &nv50_mpeg_cclass; + nv_engine(priv)->sclass = nv50_mpeg_sclass; + nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush; + return 0; } int -nv50_mpeg_create(struct drm_device *dev) +nv50_mpeg_init(struct nouveau_object *object) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_mpeg_engine *pmpeg; - - pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); - if (!pmpeg) - return -ENOMEM; - - pmpeg->base.destroy = nv50_mpeg_destroy; - pmpeg->base.init = nv50_mpeg_init; - pmpeg->base.fini = nv50_mpeg_fini; - pmpeg->base.context_new = nv50_mpeg_context_new; - pmpeg->base.context_del = nv50_mpeg_context_del; - pmpeg->base.object_new = nv50_mpeg_object_new; - pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush; - - if (dev_priv->chipset == 0x50) { - nouveau_irq_register(dev, 0, nv50_vpe_isr); - NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); - NVOBJ_CLASS(dev, 0x3174, MPEG); -#if 0 - NVOBJ_ENGINE_ADD(dev, ME, &pme->base); - NVOBJ_CLASS(dev, 0x4075, ME); -#endif - } else { - nouveau_irq_register(dev, 0, nv50_mpeg_isr); - NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); - NVOBJ_CLASS(dev, 0x8274, MPEG); + struct nv50_mpeg_priv *priv = (void *)object; + int ret; + + ret = nouveau_mpeg_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, 0x00b32c, 0x00000000); + nv_wr32(priv, 0x00b314, 0x00000100); + nv_wr32(priv, 0x00b0e0, 0x0000001a); + + nv_wr32(priv, 0x00b220, 0x00000044); + nv_wr32(priv, 0x00b300, 0x00801ec1); + nv_wr32(priv, 0x00b390, 0x00000000); + nv_wr32(priv, 0x00b394, 0x00000000); + nv_wr32(priv, 0x00b398, 0x00000000); + nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + + nv_wr32(priv, 0x00b100, 0xffffffff); + nv_wr32(priv, 0x00b140, 0xffffffff); + + if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) { + nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200)); + return -EBUSY; } return 0; - } + +struct nouveau_oclass +nv50_mpeg_oclass = { + .handle = NV_ENGINE(MPEG, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_mpeg_ctor, + .dtor = _nouveau_mpeg_dtor, + .init = nv50_mpeg_init, + .fini = _nouveau_mpeg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c new file mode 100644 index 0000000..8f805b4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c @@ -0,0 +1,104 @@ +/* + * 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 <core/os.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <subdev/vm.h> +#include <subdev/bar.h> +#include <subdev/timer.h> + +#include <engine/mpeg.h> + +struct nv84_mpeg_priv { + struct nouveau_mpeg base; +}; + +struct nv84_mpeg_chan { + struct nouveau_mpeg_chan base; +}; + +/******************************************************************************* + * MPEG object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv84_mpeg_sclass[] = { + { 0x8274, &nv50_mpeg_ofuncs }, + {} +}; + +/******************************************************************************* + * PMPEG context + ******************************************************************************/ + +static struct nouveau_oclass +nv84_mpeg_cclass = { + .handle = NV_ENGCTX(MPEG, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_mpeg_context_ctor, + .dtor = _nouveau_mpeg_context_dtor, + .init = _nouveau_mpeg_context_init, + .fini = _nouveau_mpeg_context_fini, + .rd32 = _nouveau_mpeg_context_rd32, + .wr32 = _nouveau_mpeg_context_wr32, + }, +}; + +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ + +static int +nv84_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv84_mpeg_priv *priv; + int ret; + + ret = nouveau_mpeg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000002; + nv_subdev(priv)->intr = nv50_mpeg_intr; + nv_engine(priv)->cclass = &nv84_mpeg_cclass; + nv_engine(priv)->sclass = nv84_mpeg_sclass; + nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush; + return 0; +} + +struct nouveau_oclass +nv84_mpeg_oclass = { + .handle = NV_ENGINE(MPEG, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_mpeg_ctor, + .dtor = _nouveau_mpeg_dtor, + .init = nv50_mpeg_init, + .fini = _nouveau_mpeg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c index 384de6d..50e7e0d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c +++ b/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.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,56 +22,154 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include "nouveau_util.h" -#include <core/ramht.h> +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> -struct nv98_ppp_engine { - struct nouveau_exec_engine base; +#include <engine/ppp.h> + +struct nv98_ppp_priv { + struct nouveau_ppp base; +}; + +struct nv98_ppp_chan { + struct nouveau_ppp_chan base; }; +/******************************************************************************* + * PPP object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv98_ppp_sclass[] = { + {}, +}; + +/******************************************************************************* + * PPPP context + ******************************************************************************/ + static int -nv98_ppp_fini(struct drm_device *dev, int engine, bool suspend) +nv98_ppp_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - if (!(nv_rd32(dev, 0x000200) & 0x00000002)) - return 0; + struct nv98_ppp_chan *priv; + int ret; + + ret = nouveau_ppp_context_create(parent, engine, oclass, NULL, + 0, 0, 0, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_mask(dev, 0x000200, 0x00000002, 0x00000000); return 0; } +static void +nv98_ppp_context_dtor(struct nouveau_object *object) +{ + struct nv98_ppp_chan *priv = (void *)object; + nouveau_ppp_context_destroy(&priv->base); +} + static int -nv98_ppp_init(struct drm_device *dev, int engine) +nv98_ppp_context_init(struct nouveau_object *object) { - nv_mask(dev, 0x000200, 0x00000002, 0x00000000); - nv_mask(dev, 0x000200, 0x00000002, 0x00000002); + struct nv98_ppp_chan *priv = (void *)object; + int ret; + + ret = nouveau_ppp_context_init(&priv->base); + if (ret) + return ret; + return 0; } +static int +nv98_ppp_context_fini(struct nouveau_object *object, bool suspend) +{ + struct nv98_ppp_chan *priv = (void *)object; + return nouveau_ppp_context_fini(&priv->base, suspend); +} + +static struct nouveau_oclass +nv98_ppp_cclass = { + .handle = NV_ENGCTX(PPP, 0x98), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv98_ppp_context_ctor, + .dtor = nv98_ppp_context_dtor, + .init = nv98_ppp_context_init, + .fini = nv98_ppp_context_fini, + .rd32 = _nouveau_ppp_context_rd32, + .wr32 = _nouveau_ppp_context_wr32, + }, +}; + +/******************************************************************************* + * PPPP engine/subdev functions + ******************************************************************************/ + static void -nv98_ppp_destroy(struct drm_device *dev, int engine) +nv98_ppp_intr(struct nouveau_subdev *subdev) { - struct nv98_ppp_engine *pppp = nv_engine(dev, engine); +} - NVOBJ_ENGINE_DEL(dev, PPP); +static int +nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv98_ppp_priv *priv; + int ret; + + ret = nouveau_ppp_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - kfree(pppp); + nv_subdev(priv)->unit = 0x00400002; + nv_subdev(priv)->intr = nv98_ppp_intr; + nv_engine(priv)->cclass = &nv98_ppp_cclass; + nv_engine(priv)->sclass = nv98_ppp_sclass; + return 0; } -int -nv98_ppp_create(struct drm_device *dev) +static void +nv98_ppp_dtor(struct nouveau_object *object) { - struct nv98_ppp_engine *pppp; + struct nv98_ppp_priv *priv = (void *)object; + nouveau_ppp_destroy(&priv->base); +} - pppp = kzalloc(sizeof(*pppp), GFP_KERNEL); - if (!pppp) - return -ENOMEM; +static int +nv98_ppp_init(struct nouveau_object *object) +{ + struct nv98_ppp_priv *priv = (void *)object; + int ret; - pppp->base.destroy = nv98_ppp_destroy; - pppp->base.init = nv98_ppp_init; - pppp->base.fini = nv98_ppp_fini; + ret = nouveau_ppp_init(&priv->base); + if (ret) + return ret; - NVOBJ_ENGINE_ADD(dev, PPP, &pppp->base); return 0; } + +static int +nv98_ppp_fini(struct nouveau_object *object, bool suspend) +{ + struct nv98_ppp_priv *priv = (void *)object; + return nouveau_ppp_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv98_ppp_oclass = { + .handle = NV_ENGINE(PPP, 0x98), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv98_ppp_ctor, + .dtor = nv98_ppp_dtor, + .init = nv98_ppp_init, + .fini = nv98_ppp_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c new file mode 100644 index 0000000..f48da75 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c @@ -0,0 +1,140 @@ +/* + * 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 <core/os.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <engine/software.h> +#include <engine/fifo.h> + +struct nv04_software_priv { + struct nouveau_software base; +}; + +struct nv04_software_chan { + struct nouveau_software_chan base; +}; + +/******************************************************************************* + * software object classes + ******************************************************************************/ + +static int +nv04_software_set_ref(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + struct nouveau_object *channel = (void *)nv_engctx(object->parent); + struct nouveau_fifo_chan *fifo = (void *)channel->parent; + atomic_set(&fifo->refcnt, *(u32*)data); + return 0; +} + +static int +nv04_software_flip(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv04_software_chan *chan = (void *)nv_engctx(object->parent); + if (chan->base.flip) + return chan->base.flip(chan->base.flip_data); + return -EINVAL; +} + +static struct nouveau_omthds +nv04_software_omthds[] = { + { 0x0150, nv04_software_set_ref }, + { 0x0500, nv04_software_flip }, + {} +}; + +static struct nouveau_oclass +nv04_software_sclass[] = { + { 0x006e, &nouveau_object_ofuncs, nv04_software_omthds }, + {} +}; + +/******************************************************************************* + * software context + ******************************************************************************/ + +static int +nv04_software_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_software_chan *chan; + int ret; + + ret = nouveau_software_context_create(parent, engine, oclass, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + return 0; +} + +static struct nouveau_oclass +nv04_software_cclass = { + .handle = NV_ENGCTX(SW, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_software_context_ctor, + .dtor = _nouveau_software_context_dtor, + .init = _nouveau_software_context_init, + .fini = _nouveau_software_context_fini, + }, +}; + +/******************************************************************************* + * software engine/subdev functions + ******************************************************************************/ + +static int +nv04_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_software_priv *priv; + int ret; + + ret = nouveau_software_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nv04_software_cclass; + nv_engine(priv)->sclass = nv04_software_sclass; + return 0; +} + +struct nouveau_oclass +nv04_software_oclass = { + .handle = NV_ENGINE(SW, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_software_ctor, + .dtor = _nouveau_software_dtor, + .init = _nouveau_software_init, + .fini = _nouveau_software_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c new file mode 100644 index 0000000..46dada5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c @@ -0,0 +1,128 @@ +/* + * 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 <core/os.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <engine/software.h> + +struct nv10_software_priv { + struct nouveau_software base; +}; + +struct nv10_software_chan { + struct nouveau_software_chan base; +}; + +/******************************************************************************* + * software object classes + ******************************************************************************/ + +static int +nv10_software_flip(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv10_software_chan *chan = (void *)nv_engctx(object->parent); + if (chan->base.flip) + return chan->base.flip(chan->base.flip_data); + return -EINVAL; +} + +static struct nouveau_omthds +nv10_software_omthds[] = { + { 0x0500, nv10_software_flip }, + {} +}; + +static struct nouveau_oclass +nv10_software_sclass[] = { + { 0x016e, &nouveau_object_ofuncs, nv10_software_omthds }, + {} +}; + +/******************************************************************************* + * software context + ******************************************************************************/ + +static int +nv10_software_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv10_software_chan *chan; + int ret; + + ret = nouveau_software_context_create(parent, engine, oclass, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + return 0; +} + +static struct nouveau_oclass +nv10_software_cclass = { + .handle = NV_ENGCTX(SW, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_software_context_ctor, + .dtor = _nouveau_software_context_dtor, + .init = _nouveau_software_context_init, + .fini = _nouveau_software_context_fini, + }, +}; + +/******************************************************************************* + * software engine/subdev functions + ******************************************************************************/ + +static int +nv10_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv10_software_priv *priv; + int ret; + + ret = nouveau_software_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nv10_software_cclass; + nv_engine(priv)->sclass = nv10_software_sclass; + return 0; +} + +struct nouveau_oclass +nv10_software_oclass = { + .handle = NV_ENGINE(SW, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_software_ctor, + .dtor = _nouveau_software_dtor, + .init = _nouveau_software_init, + .fini = _nouveau_software_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c new file mode 100644 index 0000000..6b88971 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c @@ -0,0 +1,198 @@ +/* + * 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 <core/os.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/namedb.h> +#include <core/handle.h> +#include <core/gpuobj.h> + +#include <engine/software.h> +#include <engine/disp.h> + +struct nv50_software_priv { + struct nouveau_software base; +}; + +struct nv50_software_chan { + struct nouveau_software_chan base; +}; + +/******************************************************************************* + * software object classes + ******************************************************************************/ + +static int +nv50_software_mthd_dma_vblsem(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); + struct nouveau_fifo_chan *fifo = (void *)nv_object(chan)->parent; + struct nouveau_handle *handle; + int ret = -EINVAL; + + handle = nouveau_namedb_get(nv_namedb(fifo), *(u32 *)args); + if (!handle) + return -ENOENT; + + if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { + struct nouveau_gpuobj *gpuobj = nv_gpuobj(handle->object); + chan->base.vblank.ctxdma = gpuobj->node->offset >> 4; + ret = 0; + } + nouveau_namedb_put(handle); + return ret; +} + +static int +nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); + chan->base.vblank.offset = *(u32 *)args; + return 0; +} + +static int +nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); + chan->base.vblank.value = *(u32 *)args; + return 0; +} + +static int +nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); + struct nouveau_disp *disp = nouveau_disp(object); + unsigned long flags; + u32 crtc = *(u32 *)args; + + if (crtc > 1) + return -EINVAL; + + disp->vblank.get(disp->vblank.data, crtc); + + spin_lock_irqsave(&disp->vblank.lock, flags); + list_add(&chan->base.vblank.head, &disp->vblank.list); + chan->base.vblank.crtc = crtc; + spin_unlock_irqrestore(&disp->vblank.lock, flags); + return 0; +} + +static int +nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); + if (chan->base.flip) + return chan->base.flip(chan->base.flip_data); + return -EINVAL; +} + +static struct nouveau_omthds +nv50_software_omthds[] = { + { 0x018c, nv50_software_mthd_dma_vblsem }, + { 0x0400, nv50_software_mthd_vblsem_offset }, + { 0x0404, nv50_software_mthd_vblsem_value }, + { 0x0408, nv50_software_mthd_vblsem_release }, + { 0x0500, nv50_software_mthd_flip }, + {} +}; + +static struct nouveau_oclass +nv50_software_sclass[] = { + { 0x506e, &nouveau_object_ofuncs, nv50_software_omthds }, + {} +}; + +/******************************************************************************* + * software context + ******************************************************************************/ + +static int +nv50_software_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_software_chan *chan; + int ret; + + ret = nouveau_software_context_create(parent, engine, oclass, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; + return 0; +} + +static struct nouveau_oclass +nv50_software_cclass = { + .handle = NV_ENGCTX(SW, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_software_context_ctor, + .dtor = _nouveau_software_context_dtor, + .init = _nouveau_software_context_init, + .fini = _nouveau_software_context_fini, + }, +}; + +/******************************************************************************* + * software engine/subdev functions + ******************************************************************************/ + +static int +nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_software_priv *priv; + int ret; + + ret = nouveau_software_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nv50_software_cclass; + nv_engine(priv)->sclass = nv50_software_sclass; + return 0; +} + +struct nouveau_oclass +nv50_software_oclass = { + .handle = NV_ENGINE(SW, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_software_ctor, + .dtor = _nouveau_software_dtor, + .init = _nouveau_software_init, + .fini = _nouveau_software_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c new file mode 100644 index 0000000..e3be78f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c @@ -0,0 +1,180 @@ +/* + * 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 <core/os.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <engine/software.h> +#include <engine/disp.h> + +struct nvc0_software_priv { + struct nouveau_software base; +}; + +struct nvc0_software_chan { + struct nouveau_software_chan base; +}; + +/******************************************************************************* + * software object classes + ******************************************************************************/ + +static int +nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); + u64 data = *(u32 *)args; + if (mthd == 0x0400) { + chan->base.vblank.offset &= 0x00ffffffffULL; + chan->base.vblank.offset |= data << 32; + } else { + chan->base.vblank.offset &= 0xff00000000ULL; + chan->base.vblank.offset |= data; + } + return 0; +} + +static int +nvc0_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); + chan->base.vblank.value = *(u32 *)args; + return 0; +} + +static int +nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); + struct nouveau_disp *disp = nouveau_disp(object); + unsigned long flags; + u32 crtc = *(u32 *)args; + + if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3) + return -EINVAL; + + disp->vblank.get(disp->vblank.data, crtc); + + spin_lock_irqsave(&disp->vblank.lock, flags); + list_add(&chan->base.vblank.head, &disp->vblank.list); + chan->base.vblank.crtc = crtc; + spin_unlock_irqrestore(&disp->vblank.lock, flags); + return 0; +} + +static int +nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); + if (chan->base.flip) + return chan->base.flip(chan->base.flip_data); + return -EINVAL; +} + +static struct nouveau_omthds +nvc0_software_omthds[] = { + { 0x0400, nvc0_software_mthd_vblsem_offset }, + { 0x0404, nvc0_software_mthd_vblsem_offset }, + { 0x0408, nvc0_software_mthd_vblsem_value }, + { 0x040c, nvc0_software_mthd_vblsem_release }, + { 0x0500, nvc0_software_mthd_flip }, + {} +}; + +static struct nouveau_oclass +nvc0_software_sclass[] = { + { 0x906e, &nouveau_object_ofuncs, nvc0_software_omthds }, + {} +}; + +/******************************************************************************* + * software context + ******************************************************************************/ + +static int +nvc0_software_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_software_chan *chan; + int ret; + + ret = nouveau_software_context_create(parent, engine, oclass, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; + return 0; +} + +static struct nouveau_oclass +nvc0_software_cclass = { + .handle = NV_ENGCTX(SW, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_software_context_ctor, + .dtor = _nouveau_software_context_dtor, + .init = _nouveau_software_context_init, + .fini = _nouveau_software_context_fini, + }, +}; + +/******************************************************************************* + * software engine/subdev functions + ******************************************************************************/ + +static int +nvc0_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_software_priv *priv; + int ret; + + ret = nouveau_software_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nvc0_software_cclass; + nv_engine(priv)->sclass = nvc0_software_sclass; + return 0; +} + +struct nouveau_oclass +nvc0_software_oclass = { + .handle = NV_ENGINE(SW, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_software_ctor, + .dtor = _nouveau_software_dtor, + .init = _nouveau_software_init, + .fini = _nouveau_software_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c index 5e164a6..dd23c80 100644 --- a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.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,61 +22,154 @@ * Authors: Ben Skeggs */ -#include "drmP.h" -#include "nouveau_drv.h" -#include "nouveau_util.h" -#include <core/ramht.h> +#include <core/os.h> +#include <core/class.h> +#include <core/engctx.h> -/*XXX: This stub is currently used on NV98+ also, as soon as this becomes - * more than just an enable/disable stub this needs to be split out to - * nv98_vp.c... - */ +#include <engine/vp.h> + +struct nv84_vp_priv { + struct nouveau_vp base; +}; -struct nv84_vp_engine { - struct nouveau_exec_engine base; +struct nv84_vp_chan { + struct nouveau_vp_chan base; }; +/******************************************************************************* + * VP object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv84_vp_sclass[] = { + {}, +}; + +/******************************************************************************* + * PVP context + ******************************************************************************/ + static int -nv84_vp_fini(struct drm_device *dev, int engine, bool suspend) +nv84_vp_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - if (!(nv_rd32(dev, 0x000200) & 0x00020000)) - return 0; + struct nv84_vp_chan *priv; + int ret; + + ret = nouveau_vp_context_create(parent, engine, oclass, NULL, + 0, 0, 0, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - nv_mask(dev, 0x000200, 0x00020000, 0x00000000); return 0; } +static void +nv84_vp_context_dtor(struct nouveau_object *object) +{ + struct nv84_vp_chan *priv = (void *)object; + nouveau_vp_context_destroy(&priv->base); +} + static int -nv84_vp_init(struct drm_device *dev, int engine) +nv84_vp_context_init(struct nouveau_object *object) { - nv_mask(dev, 0x000200, 0x00020000, 0x00000000); - nv_mask(dev, 0x000200, 0x00020000, 0x00020000); + struct nv84_vp_chan *priv = (void *)object; + int ret; + + ret = nouveau_vp_context_init(&priv->base); + if (ret) + return ret; + return 0; } +static int +nv84_vp_context_fini(struct nouveau_object *object, bool suspend) +{ + struct nv84_vp_chan *priv = (void *)object; + return nouveau_vp_context_fini(&priv->base, suspend); +} + +static struct nouveau_oclass +nv84_vp_cclass = { + .handle = NV_ENGCTX(VP, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_vp_context_ctor, + .dtor = nv84_vp_context_dtor, + .init = nv84_vp_context_init, + .fini = nv84_vp_context_fini, + .rd32 = _nouveau_vp_context_rd32, + .wr32 = _nouveau_vp_context_wr32, + }, +}; + +/******************************************************************************* + * PVP engine/subdev functions + ******************************************************************************/ + static void -nv84_vp_destroy(struct drm_device *dev, int engine) +nv84_vp_intr(struct nouveau_subdev *subdev) { - struct nv84_vp_engine *pvp = nv_engine(dev, engine); +} - NVOBJ_ENGINE_DEL(dev, VP); +static int +nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv84_vp_priv *priv; + int ret; + + ret = nouveau_vp_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; - kfree(pvp); + nv_subdev(priv)->unit = 0x01020000; + nv_subdev(priv)->intr = nv84_vp_intr; + nv_engine(priv)->cclass = &nv84_vp_cclass; + nv_engine(priv)->sclass = nv84_vp_sclass; + return 0; } -int -nv84_vp_create(struct drm_device *dev) +static void +nv84_vp_dtor(struct nouveau_object *object) { - struct nv84_vp_engine *pvp; + struct nv84_vp_priv *priv = (void *)object; + nouveau_vp_destroy(&priv->base); +} - pvp = kzalloc(sizeof(*pvp), GFP_KERNEL); - if (!pvp) - return -ENOMEM; +static int +nv84_vp_init(struct nouveau_object *object) +{ + struct nv84_vp_priv *priv = (void *)object; + int ret; - pvp->base.destroy = nv84_vp_destroy; - pvp->base.init = nv84_vp_init; - pvp->base.fini = nv84_vp_fini; + ret = nouveau_vp_init(&priv->base); + if (ret) + return ret; - NVOBJ_ENGINE_ADD(dev, VP, &pvp->base); return 0; } + +static int +nv84_vp_fini(struct nouveau_object *object, bool suspend) +{ + struct nv84_vp_priv *priv = (void *)object; + return nouveau_vp_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv84_vp_oclass = { + .handle = NV_ENGINE(VP, 0x84), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv84_vp_ctor, + .dtor = nv84_vp_dtor, + .init = nv84_vp_init, + .fini = nv84_vp_fini, + }, +}; |