diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/core')
236 files changed, 57786 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c new file mode 100644 index 00000000000..c617f048007 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/client.c @@ -0,0 +1,103 @@ +/* + * 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/client.h> +#include <core/handle.h> +#include <core/option.h> + +#include <subdev/device.h> + +static void +nouveau_client_dtor(struct nouveau_object *object) +{ + struct nouveau_client *client = (void *)object; + nouveau_object_ref(NULL, &client->device); + nouveau_handle_destroy(client->root); + nouveau_namedb_destroy(&client->base); +} + +static struct nouveau_oclass +nouveau_client_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .dtor = nouveau_client_dtor, + }, +}; + +int +nouveau_client_create_(const char *name, u64 devname, const char *cfg, + const char *dbg, int length, void **pobject) +{ + struct nouveau_object *device; + struct nouveau_client *client; + int ret; + + device = (void *)nouveau_device_find(devname); + if (!device) + return -ENODEV; + + ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass, + NV_CLIENT_CLASS, nouveau_device_sclass, + 0, length, pobject); + client = *pobject; + if (ret) + return ret; + + ret = nouveau_handle_create(nv_object(client), ~0, ~0, + nv_object(client), &client->root); + if (ret) { + nouveau_namedb_destroy(&client->base); + return ret; + } + + /* prevent init/fini being called, os in in charge of this */ + atomic_set(&nv_object(client)->usecount, 2); + + nouveau_object_ref(device, &client->device); + snprintf(client->name, sizeof(client->name), "%s", name); + client->debug = nouveau_dbgopt(dbg, "CLIENT"); + return 0; +} + +int +nouveau_client_init(struct nouveau_client *client) +{ + int ret; + nv_debug(client, "init running\n"); + ret = nouveau_handle_init(client->root); + nv_debug(client, "init completed with %d\n", ret); + return ret; +} + +int +nouveau_client_fini(struct nouveau_client *client, bool suspend) +{ + const char *name[2] = { "fini", "suspend" }; + int ret; + + nv_debug(client, "%s running\n", name[suspend]); + ret = nouveau_handle_fini(client->root, suspend); + nv_debug(client, "%s completed with %d\n", name[suspend], ret); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/core/engctx.c b/drivers/gpu/drm/nouveau/core/core/engctx.c new file mode 100644 index 00000000000..e41b10d5eb5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/engctx.c @@ -0,0 +1,236 @@ +/* + * 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/namedb.h> +#include <core/handle.h> +#include <core/client.h> +#include <core/engctx.h> + +#include <subdev/vm.h> + +static inline int +nouveau_engctx_exists(struct nouveau_object *parent, + struct nouveau_engine *engine, void **pobject) +{ + struct nouveau_engctx *engctx; + struct nouveau_object *parctx; + + list_for_each_entry(engctx, &engine->contexts, head) { + parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS); + if (parctx == parent) { + atomic_inc(&nv_object(engctx)->refcount); + *pobject = engctx; + return 1; + } + } + + return 0; +} + +int +nouveau_engctx_create_(struct nouveau_object *parent, + struct nouveau_object *engobj, + struct nouveau_oclass *oclass, + struct nouveau_object *pargpu, + u32 size, u32 align, u32 flags, + int length, void **pobject) +{ + struct nouveau_client *client = nouveau_client(parent); + struct nouveau_engine *engine = nv_engine(engobj); + struct nouveau_object *engctx; + unsigned long save; + int ret; + + /* check if this engine already has a context for the parent object, + * and reference it instead of creating a new one + */ + spin_lock_irqsave(&engine->lock, save); + ret = nouveau_engctx_exists(parent, engine, pobject); + spin_unlock_irqrestore(&engine->lock, save); + if (ret) + return ret; + + /* create the new context, supports creating both raw objects and + * objects backed by instance memory + */ + if (size) { + ret = nouveau_gpuobj_create_(parent, engobj, oclass, + NV_ENGCTX_CLASS, + pargpu, size, align, flags, + length, pobject); + } else { + ret = nouveau_object_create_(parent, engobj, oclass, + NV_ENGCTX_CLASS, length, pobject); + } + + engctx = *pobject; + if (ret) + return ret; + + /* must take the lock again and re-check a context doesn't already + * exist (in case of a race) - the lock had to be dropped before as + * it's not possible to allocate the object with it held. + */ + spin_lock_irqsave(&engine->lock, save); + ret = nouveau_engctx_exists(parent, engine, pobject); + if (ret) { + spin_unlock_irqrestore(&engine->lock, save); + nouveau_object_ref(NULL, &engctx); + return ret; + } + + if (client->vm) + atomic_inc(&client->vm->engref[nv_engidx(engobj)]); + list_add(&nv_engctx(engctx)->head, &engine->contexts); + nv_engctx(engctx)->addr = ~0ULL; + spin_unlock_irqrestore(&engine->lock, save); + return 0; +} + +void +nouveau_engctx_destroy(struct nouveau_engctx *engctx) +{ + struct nouveau_object *engobj = nv_object(engctx)->engine; + struct nouveau_engine *engine = nv_engine(engobj); + struct nouveau_client *client = nouveau_client(engctx); + unsigned long save; + + nouveau_gpuobj_unmap(&engctx->vma); + spin_lock_irqsave(&engine->lock, save); + list_del(&engctx->head); + spin_unlock_irqrestore(&engine->lock, save); + + if (client->vm) + atomic_dec(&client->vm->engref[nv_engidx(engobj)]); + + if (engctx->base.size) + nouveau_gpuobj_destroy(&engctx->base); + else + nouveau_object_destroy(&engctx->base.base); +} + +int +nouveau_engctx_init(struct nouveau_engctx *engctx) +{ + struct nouveau_object *object = nv_object(engctx); + struct nouveau_subdev *subdev = nv_subdev(object->engine); + struct nouveau_object *parent; + struct nouveau_subdev *pardev; + int ret; + + ret = nouveau_gpuobj_init(&engctx->base); + if (ret) + return ret; + + parent = nv_pclass(object->parent, NV_PARENT_CLASS); + pardev = nv_subdev(parent->engine); + if (nv_parent(parent)->context_attach) { + mutex_lock(&pardev->mutex); + ret = nv_parent(parent)->context_attach(parent, object); + mutex_unlock(&pardev->mutex); + } + + if (ret) { + nv_error(parent, "failed to attach %s context, %d\n", + subdev->name, ret); + return ret; + } + + nv_debug(parent, "attached %s context\n", subdev->name); + return 0; +} + +int +nouveau_engctx_fini(struct nouveau_engctx *engctx, bool suspend) +{ + struct nouveau_object *object = nv_object(engctx); + struct nouveau_subdev *subdev = nv_subdev(object->engine); + struct nouveau_object *parent; + struct nouveau_subdev *pardev; + int ret = 0; + + parent = nv_pclass(object->parent, NV_PARENT_CLASS); + pardev = nv_subdev(parent->engine); + if (nv_parent(parent)->context_detach) { + mutex_lock(&pardev->mutex); + ret = nv_parent(parent)->context_detach(parent, suspend, object); + mutex_unlock(&pardev->mutex); + } + + if (ret) { + nv_error(parent, "failed to detach %s context, %d\n", + subdev->name, ret); + return ret; + } + + nv_debug(parent, "detached %s context\n", subdev->name); + return nouveau_gpuobj_fini(&engctx->base, suspend); +} + +void +_nouveau_engctx_dtor(struct nouveau_object *object) +{ + nouveau_engctx_destroy(nv_engctx(object)); +} + +int +_nouveau_engctx_init(struct nouveau_object *object) +{ + return nouveau_engctx_init(nv_engctx(object)); +} + + +int +_nouveau_engctx_fini(struct nouveau_object *object, bool suspend) +{ + return nouveau_engctx_fini(nv_engctx(object), suspend); +} + +struct nouveau_object * +nouveau_engctx_get(struct nouveau_engine *engine, u64 addr) +{ + struct nouveau_engctx *engctx; + unsigned long flags; + + spin_lock_irqsave(&engine->lock, flags); + list_for_each_entry(engctx, &engine->contexts, head) { + if (engctx->addr == addr) { + engctx->save = flags; + return nv_object(engctx); + } + } + spin_unlock_irqrestore(&engine->lock, flags); + return NULL; +} + +void +nouveau_engctx_put(struct nouveau_object *object) +{ + if (object) { + struct nouveau_engine *engine = nv_engine(object->engine); + struct nouveau_engctx *engctx = nv_engctx(object); + spin_unlock_irqrestore(&engine->lock, engctx->save); + } +} diff --git a/drivers/gpu/drm/nouveau/core/core/engine.c b/drivers/gpu/drm/nouveau/core/core/engine.c new file mode 100644 index 00000000000..09b3bd502fd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/engine.c @@ -0,0 +1,55 @@ +/* + * 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/device.h> +#include <core/engine.h> +#include <core/option.h> + +int +nouveau_engine_create_(struct nouveau_object *parent, + struct nouveau_object *engobj, + struct nouveau_oclass *oclass, bool enable, + const char *iname, const char *fname, + int length, void **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_engine *engine; + int ret; + + ret = nouveau_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS, + iname, fname, length, pobject); + engine = *pobject; + if (ret) + return ret; + + if (!nouveau_boolopt(device->cfgopt, iname, enable)) { + if (!enable) + nv_warn(engine, "disabled, %s=1 to enable\n", iname); + return -ENODEV; + } + + INIT_LIST_HEAD(&engine->contexts); + spin_lock_init(&engine->lock); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/core/enum.c b/drivers/gpu/drm/nouveau/core/core/enum.c new file mode 100644 index 00000000000..7cc7133d82d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/enum.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 Nouveau Project + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <core/os.h> +#include <core/enum.h> + +const struct nouveau_enum * +nouveau_enum_find(const struct nouveau_enum *en, u32 value) +{ + while (en->name) { + if (en->value == value) + return en; + en++; + } + + return NULL; +} + +void +nouveau_enum_print(const struct nouveau_enum *en, u32 value) +{ + en = nouveau_enum_find(en, value); + if (en) + printk("%s", en->name); + else + printk("(unknown enum 0x%08x)", value); +} + +void +nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value) +{ + while (bf->name) { + if (value & bf->mask) { + printk(" %s", bf->name); + value &= ~bf->mask; + } + + bf++; + } + + if (value) + printk(" (unknown bits 0x%08x)", value); +} diff --git a/drivers/gpu/drm/nouveau/core/core/gpuobj.c b/drivers/gpu/drm/nouveau/core/core/gpuobj.c new file mode 100644 index 00000000000..1f34549aff1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/gpuobj.c @@ -0,0 +1,318 @@ +/* + * 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/gpuobj.h> + +#include <subdev/instmem.h> +#include <subdev/bar.h> +#include <subdev/vm.h> + +void +nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj) +{ + int i; + + if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) { + for (i = 0; i < gpuobj->size; i += 4) + nv_wo32(gpuobj, i, 0x00000000); + } + + if (gpuobj->heap.block_size) + nouveau_mm_fini(&gpuobj->heap); + + nouveau_object_destroy(&gpuobj->base); +} + +int +nouveau_gpuobj_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, u32 pclass, + struct nouveau_object *pargpu, + u32 size, u32 align, u32 flags, + int length, void **pobject) +{ + struct nouveau_instmem *imem = nouveau_instmem(parent); + struct nouveau_bar *bar = nouveau_bar(parent); + struct nouveau_gpuobj *gpuobj; + struct nouveau_mm *heap = NULL; + int ret, i; + u64 addr; + + *pobject = NULL; + + if (pargpu) { + while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) { + if (nv_gpuobj(pargpu)->heap.block_size) + break; + pargpu = pargpu->parent; + } + + if (unlikely(pargpu == NULL)) { + nv_error(parent, "no gpuobj heap\n"); + return -EINVAL; + } + + addr = nv_gpuobj(pargpu)->addr; + heap = &nv_gpuobj(pargpu)->heap; + atomic_inc(&parent->refcount); + } else { + ret = imem->alloc(imem, parent, size, align, &parent); + pargpu = parent; + if (ret) + return ret; + + addr = nv_memobj(pargpu)->addr; + size = nv_memobj(pargpu)->size; + + if (bar && bar->alloc) { + struct nouveau_instobj *iobj = (void *)parent; + struct nouveau_mem **mem = (void *)(iobj + 1); + struct nouveau_mem *node = *mem; + if (!bar->alloc(bar, parent, node, &pargpu)) { + nouveau_object_ref(NULL, &parent); + parent = pargpu; + } + } + } + + ret = nouveau_object_create_(parent, engine, oclass, pclass | + NV_GPUOBJ_CLASS, length, pobject); + nouveau_object_ref(NULL, &parent); + gpuobj = *pobject; + if (ret) + return ret; + + gpuobj->parent = pargpu; + gpuobj->flags = flags; + gpuobj->addr = addr; + gpuobj->size = size; + + if (heap) { + ret = nouveau_mm_head(heap, 1, size, size, + max(align, (u32)1), &gpuobj->node); + if (ret) + return ret; + + gpuobj->addr += gpuobj->node->offset; + } + + if (gpuobj->flags & NVOBJ_FLAG_HEAP) { + ret = nouveau_mm_init(&gpuobj->heap, 0, gpuobj->size, 1); + if (ret) + return ret; + } + + if (flags & NVOBJ_FLAG_ZERO_ALLOC) { + for (i = 0; i < gpuobj->size; i += 4) + nv_wo32(gpuobj, i, 0x00000000); + } + + return ret; +} + +struct nouveau_gpuobj_class { + struct nouveau_object *pargpu; + u64 size; + u32 align; + u32 flags; +}; + +static int +_nouveau_gpuobj_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_gpuobj_class *args = data; + struct nouveau_gpuobj *object; + int ret; + + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, args->pargpu, + args->size, args->align, args->flags, + &object); + *pobject = nv_object(object); + if (ret) + return ret; + + return 0; +} + +void +_nouveau_gpuobj_dtor(struct nouveau_object *object) +{ + nouveau_gpuobj_destroy(nv_gpuobj(object)); +} + +int +_nouveau_gpuobj_init(struct nouveau_object *object) +{ + return nouveau_gpuobj_init(nv_gpuobj(object)); +} + +int +_nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend) +{ + return nouveau_gpuobj_fini(nv_gpuobj(object), suspend); +} + +u32 +_nouveau_gpuobj_rd32(struct nouveau_object *object, u32 addr) +{ + struct nouveau_gpuobj *gpuobj = nv_gpuobj(object); + struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent); + if (gpuobj->node) + addr += gpuobj->node->offset; + return pfuncs->rd32(gpuobj->parent, addr); +} + +void +_nouveau_gpuobj_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + struct nouveau_gpuobj *gpuobj = nv_gpuobj(object); + struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent); + if (gpuobj->node) + addr += gpuobj->node->offset; + pfuncs->wr32(gpuobj->parent, addr, data); +} + +static struct nouveau_oclass +_nouveau_gpuobj_oclass = { + .handle = 0x00000000, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpuobj_ctor, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, + }, +}; + +int +nouveau_gpuobj_new(struct nouveau_object *parent, struct nouveau_object *pargpu, + u32 size, u32 align, u32 flags, + struct nouveau_gpuobj **pgpuobj) +{ + struct nouveau_object *engine = parent; + struct nouveau_gpuobj_class args = { + .pargpu = pargpu, + .size = size, + .align = align, + .flags = flags, + }; + + if (!nv_iclass(engine, NV_SUBDEV_CLASS)) + engine = engine->engine; + BUG_ON(engine == NULL); + + return nouveau_object_ctor(parent, engine, &_nouveau_gpuobj_oclass, + &args, sizeof(args), + (struct nouveau_object **)pgpuobj); +} + +int +nouveau_gpuobj_map(struct nouveau_gpuobj *gpuobj, u32 access, + struct nouveau_vma *vma) +{ + struct nouveau_bar *bar = nouveau_bar(gpuobj); + int ret = -EINVAL; + + if (bar && bar->umap) { + struct nouveau_instobj *iobj = (void *) + nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS); + struct nouveau_mem **mem = (void *)(iobj + 1); + ret = bar->umap(bar, *mem, access, vma); + } + + return ret; +} + +int +nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm, + u32 access, struct nouveau_vma *vma) +{ + struct nouveau_instobj *iobj = (void *) + nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS); + struct nouveau_mem **mem = (void *)(iobj + 1); + int ret; + + ret = nouveau_vm_get(vm, gpuobj->size, 12, access, vma); + if (ret) + return ret; + + nouveau_vm_map(vma, *mem); + return 0; +} + +void +nouveau_gpuobj_unmap(struct nouveau_vma *vma) +{ + if (vma->node) { + nouveau_vm_unmap(vma); + nouveau_vm_put(vma); + } +} + +/* the below is basically only here to support sharing the paged dma object + * for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work + * anywhere else. + */ + +static void +nouveau_gpudup_dtor(struct nouveau_object *object) +{ + struct nouveau_gpuobj *gpuobj = (void *)object; + nouveau_object_ref(NULL, &gpuobj->parent); + nouveau_object_destroy(&gpuobj->base); +} + +static struct nouveau_oclass +nouveau_gpudup_oclass = { + .handle = NV_GPUOBJ_CLASS, + .ofuncs = &(struct nouveau_ofuncs) { + .dtor = nouveau_gpudup_dtor, + .init = nouveau_object_init, + .fini = nouveau_object_fini, + }, +}; + +int +nouveau_gpuobj_dup(struct nouveau_object *parent, struct nouveau_gpuobj *base, + struct nouveau_gpuobj **pgpuobj) +{ + struct nouveau_gpuobj *gpuobj; + int ret; + + ret = nouveau_object_create(parent, parent->engine, + &nouveau_gpudup_oclass, 0, &gpuobj); + *pgpuobj = gpuobj; + if (ret) + return ret; + + nouveau_object_ref(nv_object(base), &gpuobj->parent); + gpuobj->addr = base->addr; + gpuobj->size = base->size; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/core/handle.c b/drivers/gpu/drm/nouveau/core/core/handle.c new file mode 100644 index 00000000000..b8d2cbf8a7a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/handle.c @@ -0,0 +1,223 @@ +/* + * 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 <core/client.h> + +#define hprintk(h,l,f,a...) do { \ + struct nouveau_client *c = nouveau_client((h)->object); \ + struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \ + nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \ +} while(0) + +int +nouveau_handle_init(struct nouveau_handle *handle) +{ + struct nouveau_handle *item; + int ret; + + hprintk(handle, TRACE, "init running\n"); + ret = nouveau_object_inc(handle->object); + if (ret) + return ret; + + hprintk(handle, TRACE, "init children\n"); + list_for_each_entry(item, &handle->tree, head) { + ret = nouveau_handle_init(item); + if (ret) + goto fail; + } + + hprintk(handle, TRACE, "init completed\n"); + return 0; +fail: + hprintk(handle, ERROR, "init failed with %d\n", ret); + list_for_each_entry_continue_reverse(item, &handle->tree, head) { + nouveau_handle_fini(item, false); + } + + nouveau_object_dec(handle->object, false); + return ret; +} + +int +nouveau_handle_fini(struct nouveau_handle *handle, bool suspend) +{ + static char *name[2] = { "fini", "suspend" }; + struct nouveau_handle *item; + int ret; + + hprintk(handle, TRACE, "%s children\n", name[suspend]); + list_for_each_entry(item, &handle->tree, head) { + ret = nouveau_handle_fini(item, suspend); + if (ret && suspend) + goto fail; + } + + hprintk(handle, TRACE, "%s running\n", name[suspend]); + if (handle->object) { + ret = nouveau_object_dec(handle->object, suspend); + if (ret && suspend) + goto fail; + } + + hprintk(handle, TRACE, "%s completed\n", name[suspend]); + return 0; +fail: + hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret); + list_for_each_entry_continue_reverse(item, &handle->tree, head) { + int rret = nouveau_handle_init(item); + if (rret) + hprintk(handle, FATAL, "failed to restart, %d\n", rret); + } + + return ret; +} + +int +nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, + struct nouveau_object *object, + struct nouveau_handle **phandle) +{ + struct nouveau_object *namedb; + struct nouveau_handle *handle; + int ret; + + namedb = parent; + while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) + namedb = namedb->parent; + + handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + INIT_LIST_HEAD(&handle->head); + INIT_LIST_HEAD(&handle->tree); + handle->name = _handle; + handle->priv = ~0; + + ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle); + if (ret) { + kfree(handle); + return ret; + } + + if (nv_parent(parent)->object_attach) { + ret = nv_parent(parent)->object_attach(parent, object, _handle); + if (ret < 0) { + nouveau_handle_destroy(handle); + return ret; + } + + handle->priv = ret; + } + + if (object != namedb) { + while (!nv_iclass(namedb, NV_CLIENT_CLASS)) + namedb = namedb->parent; + + handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent); + if (handle->parent) { + list_add(&handle->head, &handle->parent->tree); + nouveau_namedb_put(handle->parent); + } + } + + hprintk(handle, TRACE, "created\n"); + return 0; +} + +void +nouveau_handle_destroy(struct nouveau_handle *handle) +{ + struct nouveau_handle *item, *temp; + + hprintk(handle, TRACE, "destroy running\n"); + list_for_each_entry_safe(item, temp, &handle->tree, head) { + nouveau_handle_destroy(item); + } + list_del(&handle->head); + + if (handle->priv != ~0) { + struct nouveau_object *parent = handle->parent->object; + nv_parent(parent)->object_detach(parent, handle->priv); + } + + hprintk(handle, TRACE, "destroy completed\n"); + nouveau_namedb_remove(handle); + kfree(handle); +} + +struct nouveau_object * +nouveau_handle_ref(struct nouveau_object *parent, u32 name) +{ + struct nouveau_object *object = NULL; + struct nouveau_handle *handle; + + while (!nv_iclass(parent, NV_NAMEDB_CLASS)) + parent = parent->parent; + + handle = nouveau_namedb_get(nv_namedb(parent), name); + if (handle) { + nouveau_object_ref(handle->object, &object); + nouveau_namedb_put(handle); + } + + return object; +} + +struct nouveau_handle * +nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass) +{ + struct nouveau_namedb *namedb; + if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS))) + return nouveau_namedb_get_class(namedb, oclass); + return NULL; +} + +struct nouveau_handle * +nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst) +{ + struct nouveau_namedb *namedb; + if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS))) + return nouveau_namedb_get_vinst(namedb, vinst); + return NULL; +} + +struct nouveau_handle * +nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst) +{ + struct nouveau_namedb *namedb; + if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS))) + return nouveau_namedb_get_cinst(namedb, cinst); + return NULL; +} + +void +nouveau_handle_put(struct nouveau_handle *handle) +{ + if (handle) + nouveau_namedb_put(handle); +} diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c new file mode 100644 index 00000000000..bfddf87926d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/mm.c @@ -0,0 +1,245 @@ +/* + * 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/mm.h" + +#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \ + list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) + +void +nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis) +{ + struct nouveau_mm_node *this = *pthis; + + if (this) { + struct nouveau_mm_node *prev = node(this, prev); + struct nouveau_mm_node *next = node(this, next); + + if (prev && prev->type == 0) { + prev->length += this->length; + list_del(&this->nl_entry); + kfree(this); this = prev; + } + + if (next && next->type == 0) { + next->offset = this->offset; + next->length += this->length; + if (this->type == 0) + list_del(&this->fl_entry); + list_del(&this->nl_entry); + kfree(this); this = NULL; + } + + if (this && this->type != 0) { + list_for_each_entry(prev, &mm->free, fl_entry) { + if (this->offset < prev->offset) + break; + } + + list_add_tail(&this->fl_entry, &prev->fl_entry); + this->type = 0; + } + } + + *pthis = NULL; +} + +static struct nouveau_mm_node * +region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) +{ + struct nouveau_mm_node *b; + + if (a->length == size) + return a; + + b = kmalloc(sizeof(*b), GFP_KERNEL); + if (unlikely(b == NULL)) + return NULL; + + b->offset = a->offset; + b->length = size; + b->type = a->type; + a->offset += size; + a->length -= size; + list_add_tail(&b->nl_entry, &a->nl_entry); + if (b->type == 0) + list_add_tail(&b->fl_entry, &a->fl_entry); + return b; +} + +int +nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, + u32 align, struct nouveau_mm_node **pnode) +{ + struct nouveau_mm_node *prev, *this, *next; + u32 mask = align - 1; + u32 splitoff; + u32 s, e; + + list_for_each_entry(this, &mm->free, fl_entry) { + e = this->offset + this->length; + s = this->offset; + + prev = node(this, prev); + if (prev && prev->type != type) + s = roundup(s, mm->block_size); + + next = node(this, next); + if (next && next->type != type) + e = rounddown(e, mm->block_size); + + s = (s + mask) & ~mask; + e &= ~mask; + if (s > e || e - s < size_min) + continue; + + splitoff = s - this->offset; + if (splitoff && !region_head(mm, this, splitoff)) + return -ENOMEM; + + this = region_head(mm, this, min(size_max, e - s)); + if (!this) + return -ENOMEM; + + this->type = type; + list_del(&this->fl_entry); + *pnode = this; + return 0; + } + + return -ENOSPC; +} + +static struct nouveau_mm_node * +region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) +{ + struct nouveau_mm_node *b; + + if (a->length == size) + return a; + + b = kmalloc(sizeof(*b), GFP_KERNEL); + if (unlikely(b == NULL)) + return NULL; + + a->length -= size; + b->offset = a->offset + a->length; + b->length = size; + b->type = a->type; + + list_add(&b->nl_entry, &a->nl_entry); + if (b->type == 0) + list_add(&b->fl_entry, &a->fl_entry); + return b; +} + +int +nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, + u32 align, struct nouveau_mm_node **pnode) +{ + struct nouveau_mm_node *prev, *this, *next; + u32 mask = align - 1; + + list_for_each_entry_reverse(this, &mm->free, fl_entry) { + u32 e = this->offset + this->length; + u32 s = this->offset; + u32 c = 0, a; + + prev = node(this, prev); + if (prev && prev->type != type) + s = roundup(s, mm->block_size); + + next = node(this, next); + if (next && next->type != type) { + e = rounddown(e, mm->block_size); + c = next->offset - e; + } + + s = (s + mask) & ~mask; + a = e - s; + if (s > e || a < size_min) + continue; + + a = min(a, size_max); + s = (e - a) & ~mask; + c += (e - s) - a; + + if (c && !region_tail(mm, this, c)) + return -ENOMEM; + + this = region_tail(mm, this, a); + if (!this) + return -ENOMEM; + + this->type = type; + list_del(&this->fl_entry); + *pnode = this; + return 0; + } + + return -ENOSPC; +} + +int +nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) +{ + struct nouveau_mm_node *node; + + if (block) { + mutex_init(&mm->mutex); + INIT_LIST_HEAD(&mm->nodes); + INIT_LIST_HEAD(&mm->free); + mm->block_size = block; + mm->heap_nodes = 0; + } + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + node->offset = roundup(offset, mm->block_size); + node->length = rounddown(offset + length, mm->block_size) - node->offset; + + list_add_tail(&node->nl_entry, &mm->nodes); + list_add_tail(&node->fl_entry, &mm->free); + mm->heap_nodes++; + mm->heap_size += length; + return 0; +} + +int +nouveau_mm_fini(struct nouveau_mm *mm) +{ + struct nouveau_mm_node *node, *heap = + list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry); + int nodes = 0; + + list_for_each_entry(node, &mm->nodes, nl_entry) { + if (nodes++ == mm->heap_nodes) + return -EBUSY; + } + + kfree(heap); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/core/namedb.c b/drivers/gpu/drm/nouveau/core/core/namedb.c new file mode 100644 index 00000000000..1ce95a8709d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/namedb.c @@ -0,0 +1,203 @@ +/* + * 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/namedb.h> +#include <core/handle.h> +#include <core/gpuobj.h> + +static struct nouveau_handle * +nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name) +{ + struct nouveau_handle *handle; + + list_for_each_entry(handle, &namedb->list, node) { + if (handle->name == name) + return handle; + } + + return NULL; +} + +static struct nouveau_handle * +nouveau_namedb_lookup_class(struct nouveau_namedb *namedb, u16 oclass) +{ + struct nouveau_handle *handle; + + list_for_each_entry(handle, &namedb->list, node) { + if (nv_mclass(handle->object) == oclass) + return handle; + } + + return NULL; +} + +static struct nouveau_handle * +nouveau_namedb_lookup_vinst(struct nouveau_namedb *namedb, u64 vinst) +{ + struct nouveau_handle *handle; + + list_for_each_entry(handle, &namedb->list, node) { + if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { + if (nv_gpuobj(handle->object)->addr == vinst) + return handle; + } + } + + return NULL; +} + +static struct nouveau_handle * +nouveau_namedb_lookup_cinst(struct nouveau_namedb *namedb, u32 cinst) +{ + struct nouveau_handle *handle; + + list_for_each_entry(handle, &namedb->list, node) { + if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { + if (nv_gpuobj(handle->object)->node && + nv_gpuobj(handle->object)->node->offset == cinst) + return handle; + } + } + + return NULL; +} + +int +nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name, + struct nouveau_object *object, + struct nouveau_handle *handle) +{ + int ret = -EEXIST; + write_lock_irq(&namedb->lock); + if (!nouveau_namedb_lookup(namedb, name)) { + nouveau_object_ref(object, &handle->object); + handle->namedb = namedb; + list_add(&handle->node, &namedb->list); + ret = 0; + } + write_unlock_irq(&namedb->lock); + return ret; +} + +void +nouveau_namedb_remove(struct nouveau_handle *handle) +{ + struct nouveau_namedb *namedb = handle->namedb; + struct nouveau_object *object = handle->object; + write_lock_irq(&namedb->lock); + list_del(&handle->node); + write_unlock_irq(&namedb->lock); + nouveau_object_ref(NULL, &object); +} + +struct nouveau_handle * +nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name) +{ + struct nouveau_handle *handle; + read_lock(&namedb->lock); + handle = nouveau_namedb_lookup(namedb, name); + if (handle == NULL) + read_unlock(&namedb->lock); + return handle; +} + +struct nouveau_handle * +nouveau_namedb_get_class(struct nouveau_namedb *namedb, u16 oclass) +{ + struct nouveau_handle *handle; + read_lock(&namedb->lock); + handle = nouveau_namedb_lookup_class(namedb, oclass); + if (handle == NULL) + read_unlock(&namedb->lock); + return handle; +} + +struct nouveau_handle * +nouveau_namedb_get_vinst(struct nouveau_namedb *namedb, u64 vinst) +{ + struct nouveau_handle *handle; + read_lock(&namedb->lock); + handle = nouveau_namedb_lookup_vinst(namedb, vinst); + if (handle == NULL) + read_unlock(&namedb->lock); + return handle; +} + +struct nouveau_handle * +nouveau_namedb_get_cinst(struct nouveau_namedb *namedb, u32 cinst) +{ + struct nouveau_handle *handle; + read_lock(&namedb->lock); + handle = nouveau_namedb_lookup_cinst(namedb, cinst); + if (handle == NULL) + read_unlock(&namedb->lock); + return handle; +} + +void +nouveau_namedb_put(struct nouveau_handle *handle) +{ + if (handle) + read_unlock(&handle->namedb->lock); +} + +int +nouveau_namedb_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, u32 pclass, + struct nouveau_oclass *sclass, u32 engcls, + int length, void **pobject) +{ + struct nouveau_namedb *namedb; + int ret; + + ret = nouveau_parent_create_(parent, engine, oclass, pclass | + NV_NAMEDB_CLASS, sclass, engcls, + length, pobject); + namedb = *pobject; + if (ret) + return ret; + + rwlock_init(&namedb->lock); + INIT_LIST_HEAD(&namedb->list); + return 0; +} + +int +_nouveau_namedb_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_namedb *object; + int ret; + + ret = nouveau_namedb_create(parent, engine, oclass, 0, NULL, 0, &object); + *pobject = nv_object(object); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/core/object.c b/drivers/gpu/drm/nouveau/core/core/object.c new file mode 100644 index 00000000000..0daab62ea14 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/object.c @@ -0,0 +1,468 @@ +/* + * 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/parent.h> +#include <core/namedb.h> +#include <core/handle.h> +#include <core/engine.h> + +#ifdef NOUVEAU_OBJECT_MAGIC +static struct list_head _objlist = LIST_HEAD_INIT(_objlist); +static DEFINE_SPINLOCK(_objlist_lock); +#endif + +int +nouveau_object_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, u32 pclass, + int size, void **pobject) +{ + struct nouveau_object *object; + + object = *pobject = kzalloc(size, GFP_KERNEL); + if (!object) + return -ENOMEM; + + nouveau_object_ref(parent, &object->parent); + nouveau_object_ref(engine, &object->engine); + object->oclass = oclass; + object->oclass->handle |= pclass; + atomic_set(&object->refcount, 1); + atomic_set(&object->usecount, 0); + +#ifdef NOUVEAU_OBJECT_MAGIC + object->_magic = NOUVEAU_OBJECT_MAGIC; + spin_lock(&_objlist_lock); + list_add(&object->list, &_objlist); + spin_unlock(&_objlist_lock); +#endif + return 0; +} + +static int +_nouveau_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_object *object; + int ret; + + ret = nouveau_object_create(parent, engine, oclass, 0, &object); + *pobject = nv_object(object); + if (ret) + return ret; + + return 0; +} + +void +nouveau_object_destroy(struct nouveau_object *object) +{ +#ifdef NOUVEAU_OBJECT_MAGIC + spin_lock(&_objlist_lock); + list_del(&object->list); + spin_unlock(&_objlist_lock); +#endif + nouveau_object_ref(NULL, &object->engine); + nouveau_object_ref(NULL, &object->parent); + kfree(object); +} + +static void +_nouveau_object_dtor(struct nouveau_object *object) +{ + nouveau_object_destroy(object); +} + +int +nouveau_object_init(struct nouveau_object *object) +{ + return 0; +} + +static int +_nouveau_object_init(struct nouveau_object *object) +{ + return nouveau_object_init(object); +} + +int +nouveau_object_fini(struct nouveau_object *object, bool suspend) +{ + return 0; +} + +static int +_nouveau_object_fini(struct nouveau_object *object, bool suspend) +{ + return nouveau_object_fini(object, suspend); +} + +struct nouveau_ofuncs +nouveau_object_ofuncs = { + .ctor = _nouveau_object_ctor, + .dtor = _nouveau_object_dtor, + .init = _nouveau_object_init, + .fini = _nouveau_object_fini, +}; + +int +nouveau_object_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_ofuncs *ofuncs = oclass->ofuncs; + int ret; + + *pobject = NULL; + + ret = ofuncs->ctor(parent, engine, oclass, data, size, pobject); + if (ret < 0) { + if (ret != -ENODEV) { + nv_error(parent, "failed to create 0x%08x, %d\n", + oclass->handle, ret); + } + + if (*pobject) { + ofuncs->dtor(*pobject); + *pobject = NULL; + } + + return ret; + } + + nv_debug(*pobject, "created\n"); + return 0; +} + +static void +nouveau_object_dtor(struct nouveau_object *object) +{ + nv_debug(object, "destroying\n"); + nv_ofuncs(object)->dtor(object); +} + +void +nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref) +{ + if (obj) { + atomic_inc(&obj->refcount); + nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount)); + } + + if (*ref) { + int dead = atomic_dec_and_test(&(*ref)->refcount); + nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount)); + if (dead) + nouveau_object_dtor(*ref); + } + + *ref = obj; +} + +int +nouveau_object_new(struct nouveau_object *client, u32 _parent, u32 _handle, + u16 _oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_object *parent = NULL; + struct nouveau_object *engctx = NULL; + struct nouveau_object *object = NULL; + struct nouveau_object *engine; + struct nouveau_oclass *oclass; + struct nouveau_handle *handle; + int ret; + + /* lookup parent object and ensure it *is* a parent */ + parent = nouveau_handle_ref(client, _parent); + if (!parent) { + nv_error(client, "parent 0x%08x not found\n", _parent); + return -ENOENT; + } + + if (!nv_iclass(parent, NV_PARENT_CLASS)) { + nv_error(parent, "cannot have children\n"); + ret = -EINVAL; + goto fail_class; + } + + /* check that parent supports the requested subclass */ + ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass); + if (ret) { + nv_debug(parent, "illegal class 0x%04x\n", _oclass); + goto fail_class; + } + + /* make sure engine init has been completed *before* any objects + * it controls are created - the constructors may depend on + * state calculated at init (ie. default context construction) + */ + if (engine) { + ret = nouveau_object_inc(engine); + if (ret) + goto fail_class; + } + + /* if engine requires it, create a context object to insert + * between the parent and its children (eg. PGRAPH context) + */ + if (engine && nv_engine(engine)->cclass) { + ret = nouveau_object_ctor(parent, engine, + nv_engine(engine)->cclass, + data, size, &engctx); + if (ret) + goto fail_engctx; + } else { + nouveau_object_ref(parent, &engctx); + } + + /* finally, create new object and bind it to its handle */ + ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object); + *pobject = object; + if (ret) + goto fail_ctor; + + ret = nouveau_object_inc(object); + if (ret) + goto fail_init; + + ret = nouveau_handle_create(parent, _parent, _handle, object, &handle); + if (ret) + goto fail_handle; + + ret = nouveau_handle_init(handle); + if (ret) + nouveau_handle_destroy(handle); + +fail_handle: + nouveau_object_dec(object, false); +fail_init: + nouveau_object_ref(NULL, &object); +fail_ctor: + nouveau_object_ref(NULL, &engctx); +fail_engctx: + if (engine) + nouveau_object_dec(engine, false); +fail_class: + nouveau_object_ref(NULL, &parent); + return ret; +} + +int +nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle) +{ + struct nouveau_object *parent = NULL; + struct nouveau_object *namedb = NULL; + struct nouveau_handle *handle = NULL; + int ret = -EINVAL; + + parent = nouveau_handle_ref(client, _parent); + if (!parent) + return -ENOENT; + + namedb = nv_pclass(parent, NV_NAMEDB_CLASS); + if (namedb) { + handle = nouveau_namedb_get(nv_namedb(namedb), _handle); + if (handle) { + nouveau_namedb_put(handle); + nouveau_handle_fini(handle, false); + nouveau_handle_destroy(handle); + } + } + + nouveau_object_ref(NULL, &parent); + return ret; +} + +int +nouveau_object_inc(struct nouveau_object *object) +{ + int ref = atomic_add_return(1, &object->usecount); + int ret; + + nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount)); + if (ref != 1) + return 0; + + nv_trace(object, "initialising...\n"); + if (object->parent) { + ret = nouveau_object_inc(object->parent); + if (ret) { + nv_error(object, "parent failed, %d\n", ret); + goto fail_parent; + } + } + + if (object->engine) { + mutex_lock(&nv_subdev(object->engine)->mutex); + ret = nouveau_object_inc(object->engine); + mutex_unlock(&nv_subdev(object->engine)->mutex); + if (ret) { + nv_error(object, "engine failed, %d\n", ret); + goto fail_engine; + } + } + + ret = nv_ofuncs(object)->init(object); + if (ret) { + nv_error(object, "init failed, %d\n", ret); + goto fail_self; + } + + nv_debug(object, "initialised\n"); + return 0; + +fail_self: + if (object->engine) { + mutex_lock(&nv_subdev(object->engine)->mutex); + nouveau_object_dec(object->engine, false); + mutex_unlock(&nv_subdev(object->engine)->mutex); + } +fail_engine: + if (object->parent) + nouveau_object_dec(object->parent, false); +fail_parent: + atomic_dec(&object->usecount); + return ret; +} + +static int +nouveau_object_decf(struct nouveau_object *object) +{ + int ret; + + nv_trace(object, "stopping...\n"); + + ret = nv_ofuncs(object)->fini(object, false); + if (ret) + nv_warn(object, "failed fini, %d\n", ret); + + if (object->engine) { + mutex_lock(&nv_subdev(object->engine)->mutex); + nouveau_object_dec(object->engine, false); + mutex_unlock(&nv_subdev(object->engine)->mutex); + } + + if (object->parent) + nouveau_object_dec(object->parent, false); + + nv_debug(object, "stopped\n"); + return 0; +} + +static int +nouveau_object_decs(struct nouveau_object *object) +{ + int ret, rret; + + nv_trace(object, "suspending...\n"); + + ret = nv_ofuncs(object)->fini(object, true); + if (ret) { + nv_error(object, "failed suspend, %d\n", ret); + return ret; + } + + if (object->engine) { + mutex_lock(&nv_subdev(object->engine)->mutex); + ret = nouveau_object_dec(object->engine, true); + mutex_unlock(&nv_subdev(object->engine)->mutex); + if (ret) { + nv_warn(object, "engine failed suspend, %d\n", ret); + goto fail_engine; + } + } + + if (object->parent) { + ret = nouveau_object_dec(object->parent, true); + if (ret) { + nv_warn(object, "parent failed suspend, %d\n", ret); + goto fail_parent; + } + } + + nv_debug(object, "suspended\n"); + return 0; + +fail_parent: + if (object->engine) { + mutex_lock(&nv_subdev(object->engine)->mutex); + rret = nouveau_object_inc(object->engine); + mutex_unlock(&nv_subdev(object->engine)->mutex); + if (rret) + nv_fatal(object, "engine failed to reinit, %d\n", rret); + } + +fail_engine: + rret = nv_ofuncs(object)->init(object); + if (rret) + nv_fatal(object, "failed to reinit, %d\n", rret); + + return ret; +} + +int +nouveau_object_dec(struct nouveau_object *object, bool suspend) +{ + int ref = atomic_add_return(-1, &object->usecount); + int ret; + + nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount)); + + if (ref == 0) { + if (suspend) + ret = nouveau_object_decs(object); + else + ret = nouveau_object_decf(object); + + if (ret) { + atomic_inc(&object->usecount); + return ret; + } + } + + return 0; +} + +void +nouveau_object_debug(void) +{ +#ifdef NOUVEAU_OBJECT_MAGIC + struct nouveau_object *object; + if (!list_empty(&_objlist)) { + nv_fatal(NULL, "*******************************************\n"); + nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n"); + nv_fatal(NULL, "*******************************************\n"); + list_for_each_entry(object, &_objlist, list) { + nv_fatal(object, "%p/%p/%d/%d\n", + object->parent, object->engine, + atomic_read(&object->refcount), + atomic_read(&object->usecount)); + } + } +#endif +} diff --git a/drivers/gpu/drm/nouveau/core/core/option.c b/drivers/gpu/drm/nouveau/core/core/option.c new file mode 100644 index 00000000000..62a432ea39e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/option.c @@ -0,0 +1,131 @@ +/* + * 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/option.h> +#include <core/debug.h> + +/* compares unterminated string 'str' with zero-terminated string 'cmp' */ +static inline int +strncasecmpz(const char *str, const char *cmp, size_t len) +{ + if (strlen(cmp) != len) + return len; + return strncasecmp(str, cmp, len); +} + +const char * +nouveau_stropt(const char *optstr, const char *opt, int *arglen) +{ + while (optstr && *optstr != '\0') { + int len = strcspn(optstr, ",="); + switch (optstr[len]) { + case '=': + if (!strncasecmpz(optstr, opt, len)) { + optstr += len + 1; + *arglen = strcspn(optstr, ",="); + return *arglen ? optstr : NULL; + } + optstr++; + break; + case ',': + optstr++; + break; + default: + break; + } + optstr += len; + } + + return NULL; +} + +bool +nouveau_boolopt(const char *optstr, const char *opt, bool value) +{ + int arglen; + + optstr = nouveau_stropt(optstr, opt, &arglen); + if (optstr) { + if (!strncasecmpz(optstr, "0", arglen) || + !strncasecmpz(optstr, "no", arglen) || + !strncasecmpz(optstr, "off", arglen) || + !strncasecmpz(optstr, "false", arglen)) + value = false; + else + if (!strncasecmpz(optstr, "1", arglen) || + !strncasecmpz(optstr, "yes", arglen) || + !strncasecmpz(optstr, "on", arglen) || + !strncasecmpz(optstr, "true", arglen)) + value = true; + } + + return value; +} + +int +nouveau_dbgopt(const char *optstr, const char *sub) +{ + int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT; + + while (optstr) { + int len = strcspn(optstr, ",="); + switch (optstr[len]) { + case '=': + if (strncasecmpz(optstr, sub, len)) + mode = 0; + optstr++; + break; + default: + if (mode) { + if (!strncasecmpz(optstr, "fatal", len)) + level = NV_DBG_FATAL; + else if (!strncasecmpz(optstr, "error", len)) + level = NV_DBG_ERROR; + else if (!strncasecmpz(optstr, "warn", len)) + level = NV_DBG_WARN; + else if (!strncasecmpz(optstr, "info", len)) + level = NV_DBG_INFO; + else if (!strncasecmpz(optstr, "debug", len)) + level = NV_DBG_DEBUG; + else if (!strncasecmpz(optstr, "trace", len)) + level = NV_DBG_TRACE; + else if (!strncasecmpz(optstr, "paranoia", len)) + level = NV_DBG_PARANOIA; + else if (!strncasecmpz(optstr, "spam", len)) + level = NV_DBG_SPAM; + } + + if (optstr[len] != '\0') { + optstr++; + mode = 1; + break; + } + + return level; + } + optstr += len; + } + + return level; +} diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c new file mode 100644 index 00000000000..a1ea034611d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/parent.c @@ -0,0 +1,139 @@ +/* + * 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/parent.h> + +int +nouveau_parent_sclass(struct nouveau_object *parent, u16 handle, + struct nouveau_object **pengine, + struct nouveau_oclass **poclass) +{ + struct nouveau_sclass *sclass; + struct nouveau_engine *engine; + struct nouveau_oclass *oclass; + u64 mask; + + sclass = nv_parent(parent)->sclass; + while (sclass) { + if ((sclass->oclass->handle & 0xffff) == handle) { + *pengine = parent->engine; + *poclass = sclass->oclass; + return 0; + } + + sclass = sclass->sclass; + } + + mask = nv_parent(parent)->engine; + while (mask) { + int i = ffsll(mask) - 1; + + if ((engine = nouveau_engine(parent, i))) { + oclass = engine->sclass; + while (oclass->ofuncs) { + if ((oclass->handle & 0xffff) == handle) { + *pengine = nv_object(engine); + *poclass = oclass; + return 0; + } + oclass++; + } + } + + mask &= ~(1ULL << i); + } + + return -EINVAL; +} + +int +nouveau_parent_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, u32 pclass, + struct nouveau_oclass *sclass, u64 engcls, + int size, void **pobject) +{ + struct nouveau_parent *object; + struct nouveau_sclass *nclass; + int ret; + + ret = nouveau_object_create_(parent, engine, oclass, pclass | + NV_PARENT_CLASS, size, pobject); + object = *pobject; + if (ret) + return ret; + + while (sclass && sclass->ofuncs) { + nclass = kzalloc(sizeof(*nclass), GFP_KERNEL); + if (!nclass) + return -ENOMEM; + + nclass->sclass = object->sclass; + object->sclass = nclass; + nclass->engine = engine ? nv_engine(engine) : NULL; + nclass->oclass = sclass; + sclass++; + } + + object->engine = engcls; + return 0; +} + +int +_nouveau_parent_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_parent *object; + int ret; + + ret = nouveau_parent_create(parent, engine, oclass, 0, NULL, 0, &object); + *pobject = nv_object(object); + if (ret) + return ret; + + return 0; +} + +void +nouveau_parent_destroy(struct nouveau_parent *parent) +{ + struct nouveau_sclass *sclass; + + while ((sclass = parent->sclass)) { + parent->sclass = sclass->sclass; + kfree(sclass); + } + + nouveau_object_destroy(&parent->base); +} + + +void +_nouveau_parent_dtor(struct nouveau_object *object) +{ + nouveau_parent_destroy(nv_parent(object)); +} diff --git a/drivers/gpu/drm/nouveau/core/core/printk.c b/drivers/gpu/drm/nouveau/core/core/printk.c new file mode 100644 index 00000000000..6161eaf5447 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/printk.c @@ -0,0 +1,74 @@ +/* + * 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/client.h> +#include <core/subdev.h> +#include <core/printk.h> + +void +nv_printk_(struct nouveau_object *object, const char *pfx, int level, + const char *fmt, ...) +{ + static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' }; + char mfmt[256]; + va_list args; + + if (object && !nv_iclass(object, NV_CLIENT_CLASS)) { + struct nouveau_object *device = object; + struct nouveau_object *subdev = object; + char obuf[64], *ofmt = ""; + + if (object->engine) { + snprintf(obuf, sizeof(obuf), "[0x%08x][%p]", + nv_hclass(object), object); + ofmt = obuf; + subdev = object->engine; + device = object->engine; + } + + if (subdev->parent) + device = subdev->parent; + + if (level > nv_subdev(subdev)->debug) + return; + + snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx, + name[level], nv_subdev(subdev)->name, + nv_device(device)->name, ofmt, fmt); + } else + if (object && nv_iclass(object, NV_CLIENT_CLASS)) { + if (level > nv_client(object)->debug) + return; + + snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx, + name[level], nv_client(object)->name, fmt); + } else { + snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt); + } + + va_start(args, fmt); + vprintk(mfmt, args); + va_end(args); +} diff --git a/drivers/gpu/drm/nouveau/core/core/ramht.c b/drivers/gpu/drm/nouveau/core/core/ramht.c new file mode 100644 index 00000000000..86a64045dd6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/ramht.c @@ -0,0 +1,109 @@ +/* + * 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. + */ + +#include <core/object.h> +#include <core/ramht.h> +#include <core/math.h> + +#include <subdev/bar.h> + +static u32 +nouveau_ramht_hash(struct nouveau_ramht *ramht, int chid, u32 handle) +{ + u32 hash = 0; + + while (handle) { + hash ^= (handle & ((1 << ramht->bits) - 1)); + handle >>= ramht->bits; + } + + hash ^= chid << (ramht->bits - 4); + hash = hash << 3; + return hash; +} + +int +nouveau_ramht_insert(struct nouveau_ramht *ramht, int chid, + u32 handle, u32 context) +{ + struct nouveau_bar *bar = nouveau_bar(ramht); + u32 co, ho; + + co = ho = nouveau_ramht_hash(ramht, chid, handle); + do { + if (!nv_ro32(ramht, co + 4)) { + nv_wo32(ramht, co + 0, handle); + nv_wo32(ramht, co + 4, context); + if (bar) + bar->flush(bar); + return co; + } + + co += 8; + if (co >= nv_gpuobj(ramht)->size) + co = 0; + } while (co != ho); + + return -ENOMEM; +} + +void +nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie) +{ + struct nouveau_bar *bar = nouveau_bar(ramht); + nv_wo32(ramht, cookie + 0, 0x00000000); + nv_wo32(ramht, cookie + 4, 0x00000000); + if (bar) + bar->flush(bar); +} + +static struct nouveau_oclass +nouveau_ramht_oclass = { + .handle = 0x0000abcd, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = NULL, + .dtor = _nouveau_gpuobj_dtor, + .init = _nouveau_gpuobj_init, + .fini = _nouveau_gpuobj_fini, + .rd32 = _nouveau_gpuobj_rd32, + .wr32 = _nouveau_gpuobj_wr32, + }, +}; + +int +nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu, + u32 size, u32 align, struct nouveau_ramht **pramht) +{ + struct nouveau_ramht *ramht; + int ret; + + ret = nouveau_gpuobj_create(parent, parent->engine ? + parent->engine : parent, /* <nv50 ramht */ + &nouveau_ramht_oclass, 0, pargpu, size, + align, NVOBJ_FLAG_ZERO_ALLOC, &ramht); + *pramht = ramht; + if (ret) + return ret; + + ramht->bits = log2i(nv_gpuobj(ramht)->size >> 3); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c new file mode 100644 index 00000000000..f74c30aa33a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/subdev.c @@ -0,0 +1,115 @@ +/* + * 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/subdev.h> +#include <core/device.h> +#include <core/option.h> + +void +nouveau_subdev_reset(struct nouveau_object *subdev) +{ + nv_trace(subdev, "resetting...\n"); + nv_ofuncs(subdev)->fini(subdev, false); + nv_debug(subdev, "reset\n"); +} + +int +nouveau_subdev_init(struct nouveau_subdev *subdev) +{ + int ret = nouveau_object_init(&subdev->base); + if (ret) + return ret; + + nouveau_subdev_reset(&subdev->base); + return 0; +} + +int +_nouveau_subdev_init(struct nouveau_object *object) +{ + return nouveau_subdev_init(nv_subdev(object)); +} + +int +nouveau_subdev_fini(struct nouveau_subdev *subdev, bool suspend) +{ + if (subdev->unit) { + nv_mask(subdev, 0x000200, subdev->unit, 0x00000000); + nv_mask(subdev, 0x000200, subdev->unit, subdev->unit); + } + + return nouveau_object_fini(&subdev->base, suspend); +} + +int +_nouveau_subdev_fini(struct nouveau_object *object, bool suspend) +{ + return nouveau_subdev_fini(nv_subdev(object), suspend); +} + +void +nouveau_subdev_destroy(struct nouveau_subdev *subdev) +{ + int subidx = nv_hclass(subdev) & 0xff; + nv_device(subdev)->subdev[subidx] = NULL; + nouveau_object_destroy(&subdev->base); +} + +void +_nouveau_subdev_dtor(struct nouveau_object *object) +{ + nouveau_subdev_destroy(nv_subdev(object)); +} + +int +nouveau_subdev_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, u32 pclass, + const char *subname, const char *sysname, + int size, void **pobject) +{ + struct nouveau_subdev *subdev; + int ret; + + ret = nouveau_object_create_(parent, engine, oclass, pclass | + NV_SUBDEV_CLASS, size, pobject); + subdev = *pobject; + if (ret) + return ret; + + mutex_init(&subdev->mutex); + subdev->name = subname; + + if (parent) { + struct nouveau_device *device = nv_device(parent); + int subidx = nv_hclass(subdev) & 0xff; + + subdev->debug = nouveau_dbgopt(device->dbgopt, subname); + subdev->mmio = nv_subdev(device)->mmio; + device->subdev[subidx] = *pobject; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c new file mode 100644 index 00000000000..66f7dfd907e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c @@ -0,0 +1,175 @@ +/* + * 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/bsp.h> + +struct nv84_bsp_priv { + struct nouveau_bsp 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_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + 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; + + 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_context_init(struct nouveau_object *object) +{ + 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_intr(struct nouveau_subdev *subdev) +{ +} + +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; + + 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; +} + +static void +nv84_bsp_dtor(struct nouveau_object *object) +{ + struct nv84_bsp_priv *priv = (void *)object; + nouveau_bsp_destroy(&priv->base); +} + +static int +nv84_bsp_init(struct nouveau_object *object) +{ + struct nv84_bsp_priv *priv = (void *)object; + int ret; + + ret = nouveau_bsp_init(&priv->base); + if (ret) + return ret; + + 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/fuc/nva3.fuc b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc new file mode 100644 index 00000000000..219850d5328 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc @@ -0,0 +1,872 @@ +/* fuc microcode for copy engine on nva3- chipsets + * + * Copyright 2011 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 + */ + +/* To build for nva3:nvc0 + * m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h + * + * To build for nvc0- + * m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h + */ + +ifdef(`NVA3', +.section #nva3_pcopy_data +, +.section #nvc0_pcopy_data +) + +ctx_object: .b32 0 +ifdef(`NVA3', +ctx_dma: +ctx_dma_query: .b32 0 +ctx_dma_src: .b32 0 +ctx_dma_dst: .b32 0 +,) +.equ #ctx_dma_count 3 +ctx_query_address_high: .b32 0 +ctx_query_address_low: .b32 0 +ctx_query_counter: .b32 0 +ctx_src_address_high: .b32 0 +ctx_src_address_low: .b32 0 +ctx_src_pitch: .b32 0 +ctx_src_tile_mode: .b32 0 +ctx_src_xsize: .b32 0 +ctx_src_ysize: .b32 0 +ctx_src_zsize: .b32 0 +ctx_src_zoff: .b32 0 +ctx_src_xoff: .b32 0 +ctx_src_yoff: .b32 0 +ctx_src_cpp: .b32 0 +ctx_dst_address_high: .b32 0 +ctx_dst_address_low: .b32 0 +ctx_dst_pitch: .b32 0 +ctx_dst_tile_mode: .b32 0 +ctx_dst_xsize: .b32 0 +ctx_dst_ysize: .b32 0 +ctx_dst_zsize: .b32 0 +ctx_dst_zoff: .b32 0 +ctx_dst_xoff: .b32 0 +ctx_dst_yoff: .b32 0 +ctx_dst_cpp: .b32 0 +ctx_format: .b32 0 +ctx_swz_const0: .b32 0 +ctx_swz_const1: .b32 0 +ctx_xcnt: .b32 0 +ctx_ycnt: .b32 0 +.align 256 + +dispatch_table: +// mthd 0x0000, NAME +.b16 0x000 1 +.b32 #ctx_object ~0xffffffff +// mthd 0x0100, NOP +.b16 0x040 1 +.b32 0x00010000 + #cmd_nop ~0xffffffff +// mthd 0x0140, PM_TRIGGER +.b16 0x050 1 +.b32 0x00010000 + #cmd_pm_trigger ~0xffffffff +ifdef(`NVA3', ` +// mthd 0x0180-0x018c, DMA_ +.b16 0x060 #ctx_dma_count +dispatch_dma: +.b32 0x00010000 + #cmd_dma ~0xffffffff +.b32 0x00010000 + #cmd_dma ~0xffffffff +.b32 0x00010000 + #cmd_dma ~0xffffffff +',) +// mthd 0x0200-0x0218, SRC_TILE +.b16 0x80 7 +.b32 #ctx_src_tile_mode ~0x00000fff +.b32 #ctx_src_xsize ~0x0007ffff +.b32 #ctx_src_ysize ~0x00001fff +.b32 #ctx_src_zsize ~0x000007ff +.b32 #ctx_src_zoff ~0x00000fff +.b32 #ctx_src_xoff ~0x0007ffff +.b32 #ctx_src_yoff ~0x00001fff +// mthd 0x0220-0x0238, DST_TILE +.b16 0x88 7 +.b32 #ctx_dst_tile_mode ~0x00000fff +.b32 #ctx_dst_xsize ~0x0007ffff +.b32 #ctx_dst_ysize ~0x00001fff +.b32 #ctx_dst_zsize ~0x000007ff +.b32 #ctx_dst_zoff ~0x00000fff +.b32 #ctx_dst_xoff ~0x0007ffff +.b32 #ctx_dst_yoff ~0x00001fff +// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH +.b16 0xc0 2 +.b32 0x00010000 + #cmd_exec ~0xffffffff +.b32 0x00010000 + #cmd_wrcache_flush ~0xffffffff +// mthd 0x030c-0x0340, various stuff +.b16 0xc3 14 +.b32 #ctx_src_address_high ~0x000000ff +.b32 #ctx_src_address_low ~0xffffffff +.b32 #ctx_dst_address_high ~0x000000ff +.b32 #ctx_dst_address_low ~0xffffffff +.b32 #ctx_src_pitch ~0x0007ffff +.b32 #ctx_dst_pitch ~0x0007ffff +.b32 #ctx_xcnt ~0x0000ffff +.b32 #ctx_ycnt ~0x00001fff +.b32 #ctx_format ~0x0333ffff +.b32 #ctx_swz_const0 ~0xffffffff +.b32 #ctx_swz_const1 ~0xffffffff +.b32 #ctx_query_address_high ~0x000000ff +.b32 #ctx_query_address_low ~0xffffffff +.b32 #ctx_query_counter ~0xffffffff +.b16 0x800 0 + +ifdef(`NVA3', +.section #nva3_pcopy_code +, +.section #nvc0_pcopy_code +) + +main: + clear b32 $r0 + mov $sp $r0 + + // setup i0 handler and route fifo and ctxswitch to it + mov $r1 #ih + mov $iv0 $r1 + mov $r1 0x400 + movw $r2 0xfff3 + sethi $r2 0 + iowr I[$r1 + 0x300] $r2 + + // enable interrupts + or $r2 0xc + iowr I[$r1] $r2 + bset $flags ie0 + + // enable fifo access and context switching + mov $r1 0x1200 + mov $r2 3 + iowr I[$r1] $r2 + + // sleep forever, waking for interrupts + bset $flags $p0 + spin: + sleep $p0 + bra #spin + +// i0 handler +ih: + iord $r1 I[$r0 + 0x200] + + and $r2 $r1 0x00000008 + bra e #ih_no_chsw + call #chsw + ih_no_chsw: + and $r2 $r1 0x00000004 + bra e #ih_no_cmd + call #dispatch + + ih_no_cmd: + and $r1 $r1 0x0000000c + iowr I[$r0 + 0x100] $r1 + iret + +// $p1 direction (0 = unload, 1 = load) +// $r3 channel +swctx: + mov $r4 0x7700 + mov $xtargets $r4 +ifdef(`NVA3', ` + // target 7 hardcoded to ctx dma object + mov $xdbase $r0 +', ` // NVC0 + // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1 + mov $r4 0x2100 + iord $r4 I[$r4 + 0] + and $r4 1 + shl b32 $r4 4 + add b32 $r4 0x30 + + // channel is in vram + mov $r15 0x61c + shl b32 $r15 6 + mov $r5 0x114 + iowrs I[$r15] $r5 + + // read 16-byte PCOPYn info, containing context pointer, from channel + shl b32 $r5 $r3 4 + add b32 $r5 2 + mov $xdbase $r5 + mov $r5 $sp + // get a chunk of stack space, aligned to 256 byte boundary + sub b32 $r5 0x100 + mov $r6 0xff + not b32 $r6 + and $r5 $r6 + sethi $r5 0x00020000 + xdld $r4 $r5 + xdwait + sethi $r5 0 + + // set context pointer, from within channel VM + mov $r14 0 + iowrs I[$r15] $r14 + ld b32 $r4 D[$r5 + 0] + shr b32 $r4 8 + ld b32 $r6 D[$r5 + 4] + shl b32 $r6 24 + or $r4 $r6 + mov $xdbase $r4 +') + // 256-byte context, at start of data segment + mov b32 $r4 $r0 + sethi $r4 0x60000 + + // swap! + bra $p1 #swctx_load + xdst $r0 $r4 + bra #swctx_done + swctx_load: + xdld $r0 $r4 + swctx_done: + xdwait + ret + +chsw: + // read current channel + mov $r2 0x1400 + iord $r3 I[$r2] + + // if it's active, unload it and return + xbit $r15 $r3 0x1e + bra e #chsw_no_unload + bclr $flags $p1 + call #swctx + bclr $r3 0x1e + iowr I[$r2] $r3 + mov $r4 1 + iowr I[$r2 + 0x200] $r4 + ret + + // read next channel + chsw_no_unload: + iord $r3 I[$r2 + 0x100] + + // is there a channel waiting to be loaded? + xbit $r13 $r3 0x1e + bra e #chsw_finish_load + bset $flags $p1 + call #swctx +ifdef(`NVA3', + // load dma objects back into TARGET regs + mov $r5 #ctx_dma + mov $r6 #ctx_dma_count + chsw_load_ctx_dma: + ld b32 $r7 D[$r5 + $r6 * 4] + add b32 $r8 $r6 0x180 + shl b32 $r8 8 + iowr I[$r8] $r7 + sub b32 $r6 1 + bra nc #chsw_load_ctx_dma +,) + + chsw_finish_load: + mov $r3 2 + iowr I[$r2 + 0x200] $r3 + ret + +dispatch: + // read incoming fifo command + mov $r3 0x1900 + iord $r2 I[$r3 + 0x100] + iord $r3 I[$r3 + 0x000] + and $r4 $r2 0x7ff + // $r2 will be used to store exception data + shl b32 $r2 0x10 + + // lookup method in the dispatch table, ILLEGAL_MTHD if not found + mov $r5 #dispatch_table + clear b32 $r6 + clear b32 $r7 + dispatch_loop: + ld b16 $r6 D[$r5 + 0] + ld b16 $r7 D[$r5 + 2] + add b32 $r5 4 + cmpu b32 $r4 $r6 + bra c #dispatch_illegal_mthd + add b32 $r7 $r6 + cmpu b32 $r4 $r7 + bra c #dispatch_valid_mthd + sub b32 $r7 $r6 + shl b32 $r7 3 + add b32 $r5 $r7 + bra #dispatch_loop + + // ensure no bits set in reserved fields, INVALID_BITFIELD + dispatch_valid_mthd: + sub b32 $r4 $r6 + shl b32 $r4 3 + add b32 $r4 $r5 + ld b32 $r5 D[$r4 + 4] + and $r5 $r3 + cmpu b32 $r5 0 + bra ne #dispatch_invalid_bitfield + + // depending on dispatch flags: execute method, or save data as state + ld b16 $r5 D[$r4 + 0] + ld b16 $r6 D[$r4 + 2] + cmpu b32 $r6 0 + bra ne #dispatch_cmd + st b32 D[$r5] $r3 + bra #dispatch_done + dispatch_cmd: + bclr $flags $p1 + call $r5 + bra $p1 #dispatch_error + bra #dispatch_done + + dispatch_invalid_bitfield: + or $r2 2 + dispatch_illegal_mthd: + or $r2 1 + + // store exception data in SCRATCH0/SCRATCH1, signal hostirq + dispatch_error: + mov $r4 0x1000 + iowr I[$r4 + 0x000] $r2 + iowr I[$r4 + 0x100] $r3 + mov $r2 0x40 + iowr I[$r0] $r2 + hostirq_wait: + iord $r2 I[$r0 + 0x200] + and $r2 0x40 + cmpu b32 $r2 0 + bra ne #hostirq_wait + + dispatch_done: + mov $r2 0x1d00 + mov $r3 1 + iowr I[$r2] $r3 + ret + +// No-operation +// +// Inputs: +// $r1: irqh state +// $r2: hostirq state +// $r3: data +// $r4: dispatch table entry +// Outputs: +// $r1: irqh state +// $p1: set on error +// $r2: hostirq state +// $r3: data +cmd_nop: + ret + +// PM_TRIGGER +// +// Inputs: +// $r1: irqh state +// $r2: hostirq state +// $r3: data +// $r4: dispatch table entry +// Outputs: +// $r1: irqh state +// $p1: set on error +// $r2: hostirq state +// $r3: data +cmd_pm_trigger: + mov $r2 0x2200 + clear b32 $r3 + sethi $r3 0x20000 + iowr I[$r2] $r3 + ret + +ifdef(`NVA3', +// SET_DMA_* method handler +// +// Inputs: +// $r1: irqh state +// $r2: hostirq state +// $r3: data +// $r4: dispatch table entry +// Outputs: +// $r1: irqh state +// $p1: set on error +// $r2: hostirq state +// $r3: data +cmd_dma: + sub b32 $r4 #dispatch_dma + shr b32 $r4 1 + bset $r3 0x1e + st b32 D[$r4 + #ctx_dma] $r3 + add b32 $r4 0x600 + shl b32 $r4 6 + iowr I[$r4] $r3 + ret +,) + +// Calculates the hw swizzle mask and adjusts the surface's xcnt to match +// +cmd_exec_set_format: + // zero out a chunk of the stack to store the swizzle into + add $sp -0x10 + st b32 D[$sp + 0x00] $r0 + st b32 D[$sp + 0x04] $r0 + st b32 D[$sp + 0x08] $r0 + st b32 D[$sp + 0x0c] $r0 + + // extract cpp, src_ncomp and dst_ncomp from FORMAT + ld b32 $r4 D[$r0 + #ctx_format] + extr $r5 $r4 16:17 + add b32 $r5 1 + extr $r6 $r4 20:21 + add b32 $r6 1 + extr $r7 $r4 24:25 + add b32 $r7 1 + + // convert FORMAT swizzle mask to hw swizzle mask + bclr $flags $p2 + clear b32 $r8 + clear b32 $r9 + ncomp_loop: + and $r10 $r4 0xf + shr b32 $r4 4 + clear b32 $r11 + bpc_loop: + cmpu b8 $r10 4 + bra nc #cmp_c0 + mulu $r12 $r10 $r5 + add b32 $r12 $r11 + bset $flags $p2 + bra #bpc_next + cmp_c0: + bra ne #cmp_c1 + mov $r12 0x10 + add b32 $r12 $r11 + bra #bpc_next + cmp_c1: + cmpu b8 $r10 6 + bra nc #cmp_zero + mov $r12 0x14 + add b32 $r12 $r11 + bra #bpc_next + cmp_zero: + mov $r12 0x80 + bpc_next: + st b8 D[$sp + $r8] $r12 + add b32 $r8 1 + add b32 $r11 1 + cmpu b32 $r11 $r5 + bra c #bpc_loop + add b32 $r9 1 + cmpu b32 $r9 $r7 + bra c #ncomp_loop + + // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang) + mulu $r6 $r5 + st b32 D[$r0 + #ctx_src_cpp] $r6 + ld b32 $r8 D[$r0 + #ctx_xcnt] + mulu $r6 $r8 + bra $p2 #dst_xcnt + clear b32 $r6 + + dst_xcnt: + mulu $r7 $r5 + st b32 D[$r0 + #ctx_dst_cpp] $r7 + mulu $r7 $r8 + + mov $r5 0x810 + shl b32 $r5 6 + iowr I[$r5 + 0x000] $r6 + iowr I[$r5 + 0x100] $r7 + add b32 $r5 0x800 + ld b32 $r6 D[$r0 + #ctx_dst_cpp] + sub b32 $r6 1 + shl b32 $r6 8 + ld b32 $r7 D[$r0 + #ctx_src_cpp] + sub b32 $r7 1 + or $r6 $r7 + iowr I[$r5 + 0x000] $r6 + add b32 $r5 0x100 + ld b32 $r6 D[$sp + 0x00] + iowr I[$r5 + 0x000] $r6 + ld b32 $r6 D[$sp + 0x04] + iowr I[$r5 + 0x100] $r6 + ld b32 $r6 D[$sp + 0x08] + iowr I[$r5 + 0x200] $r6 + ld b32 $r6 D[$sp + 0x0c] + iowr I[$r5 + 0x300] $r6 + add b32 $r5 0x400 + ld b32 $r6 D[$r0 + #ctx_swz_const0] + iowr I[$r5 + 0x000] $r6 + ld b32 $r6 D[$r0 + #ctx_swz_const1] + iowr I[$r5 + 0x100] $r6 + add $sp 0x10 + ret + +// Setup to handle a tiled surface +// +// Calculates a number of parameters the hardware requires in order +// to correctly handle tiling. +// +// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE): +// nTx = round_up(w * cpp, 1 << Tp) >> Tp +// nTy = round_up(h, 1 << Th) >> Th +// Txo = (x * cpp) & ((1 << Tp) - 1) +// Tx = (x * cpp) >> Tp +// Tyo = y & ((1 << Th) - 1) +// Ty = y >> Th +// Tzo = z & ((1 << Td) - 1) +// Tz = z >> Td +// +// off = (Tzo << Tp << Th) + (Tyo << Tp) + Txo +// off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp; +// +// Inputs: +// $r4: hw command (0x104800) +// $r5: ctx offset adjustment for src/dst selection +// $p2: set if dst surface +// +cmd_exec_set_surface_tiled: + // translate TILE_MODE into Tp, Th, Td shift values + ld b32 $r7 D[$r5 + #ctx_src_tile_mode] + extr $r9 $r7 8:11 + extr $r8 $r7 4:7 +ifdef(`NVA3', + add b32 $r8 2 +, + add b32 $r8 3 +) + extr $r7 $r7 0:3 + cmp b32 $r7 0xe + bra ne #xtile64 + mov $r7 4 + bra #xtileok + xtile64: + xbit $r7 $flags $p2 + add b32 $r7 17 + bset $r4 $r7 + mov $r7 6 + xtileok: + + // Op = (x * cpp) & ((1 << Tp) - 1) + // Tx = (x * cpp) >> Tp + ld b32 $r10 D[$r5 + #ctx_src_xoff] + ld b32 $r11 D[$r5 + #ctx_src_cpp] + mulu $r10 $r11 + mov $r11 1 + shl b32 $r11 $r7 + sub b32 $r11 1 + and $r12 $r10 $r11 + shr b32 $r10 $r7 + + // Tyo = y & ((1 << Th) - 1) + // Ty = y >> Th + ld b32 $r13 D[$r5 + #ctx_src_yoff] + mov $r14 1 + shl b32 $r14 $r8 + sub b32 $r14 1 + and $r11 $r13 $r14 + shr b32 $r13 $r8 + + // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo) + add b32 $r14 1 + shl b32 $r15 $r14 12 + sub b32 $r14 $r11 + or $r15 $r14 + xbit $r6 $flags $p2 + add b32 $r6 0x208 + shl b32 $r6 8 + iowr I[$r6 + 0x000] $r15 + + // Op += Tyo << Tp + shl b32 $r11 $r7 + add b32 $r12 $r11 + + // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp) + ld b32 $r15 D[$r5 + #ctx_src_xsize] + ld b32 $r11 D[$r5 + #ctx_src_cpp] + mulu $r15 $r11 + mov $r11 1 + shl b32 $r11 $r7 + sub b32 $r11 1 + add b32 $r15 $r11 + shr b32 $r15 $r7 + push $r15 + + // nTy = (h + ((1 << Th) - 1)) >> Th + ld b32 $r15 D[$r5 + #ctx_src_ysize] + mov $r11 1 + shl b32 $r11 $r8 + sub b32 $r11 1 + add b32 $r15 $r11 + shr b32 $r15 $r8 + push $r15 + + // Tys = Tp + Th + // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td + add b32 $r7 $r8 + sub b32 $r8 2 + mov $r11 1 + shl b32 $r11 $r8 + shl b32 $r11 $r9 + + // Tzo = z & ((1 << Td) - 1) + // Tz = z >> Td + // Op += Tzo << Tys + // Ts = Tys + Td + ld b32 $r8 D[$r5 + #ctx_src_zoff] + mov $r14 1 + shl b32 $r14 $r9 + sub b32 $r14 1 + and $r15 $r8 $r14 + shl b32 $r15 $r7 + add b32 $r12 $r15 + add b32 $r7 $r9 + shr b32 $r8 $r9 + + // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts + pop $r15 + pop $r9 + mulu $r13 $r9 + add b32 $r10 $r13 + mulu $r8 $r9 + mulu $r8 $r15 + add b32 $r10 $r8 + shl b32 $r10 $r7 + + // PITCH = (nTx - 1) << Ts + sub b32 $r9 1 + shl b32 $r9 $r7 + iowr I[$r6 + 0x200] $r9 + + // SRC_ADDRESS_LOW = (Ot + Op) & 0xffffffff + // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16 + ld b32 $r7 D[$r5 + #ctx_src_address_low] + ld b32 $r8 D[$r5 + #ctx_src_address_high] + add b32 $r10 $r12 + add b32 $r7 $r10 + adc b32 $r8 0 + shl b32 $r8 16 + or $r8 $r11 + sub b32 $r6 0x600 + iowr I[$r6 + 0x000] $r7 + add b32 $r6 0x400 + iowr I[$r6 + 0x000] $r8 + ret + +// Setup to handle a linear surface +// +// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting +// +cmd_exec_set_surface_linear: + xbit $r6 $flags $p2 + add b32 $r6 0x202 + shl b32 $r6 8 + ld b32 $r7 D[$r5 + #ctx_src_address_low] + iowr I[$r6 + 0x000] $r7 + add b32 $r6 0x400 + ld b32 $r7 D[$r5 + #ctx_src_address_high] + shl b32 $r7 16 + iowr I[$r6 + 0x000] $r7 + add b32 $r6 0x400 + ld b32 $r7 D[$r5 + #ctx_src_pitch] + iowr I[$r6 + 0x000] $r7 + ret + +// wait for regs to be available for use +cmd_exec_wait: + push $r0 + push $r1 + mov $r0 0x800 + shl b32 $r0 6 + loop: + iord $r1 I[$r0] + and $r1 1 + bra ne #loop + pop $r1 + pop $r0 + ret + +cmd_exec_query: + // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI } + xbit $r4 $r3 13 + bra ne #query_counter + call #cmd_exec_wait + mov $r4 0x80c + shl b32 $r4 6 + ld b32 $r5 D[$r0 + #ctx_query_address_low] + add b32 $r5 4 + iowr I[$r4 + 0x000] $r5 + iowr I[$r4 + 0x100] $r0 + mov $r5 0xc + iowr I[$r4 + 0x200] $r5 + add b32 $r4 0x400 + ld b32 $r5 D[$r0 + #ctx_query_address_high] + shl b32 $r5 16 + iowr I[$r4 + 0x000] $r5 + add b32 $r4 0x500 + mov $r5 0x00000b00 + sethi $r5 0x00010000 + iowr I[$r4 + 0x000] $r5 + mov $r5 0x00004040 + shl b32 $r5 1 + sethi $r5 0x80800000 + iowr I[$r4 + 0x100] $r5 + mov $r5 0x00001110 + sethi $r5 0x13120000 + iowr I[$r4 + 0x200] $r5 + mov $r5 0x00001514 + sethi $r5 0x17160000 + iowr I[$r4 + 0x300] $r5 + mov $r5 0x00002601 + sethi $r5 0x00010000 + mov $r4 0x800 + shl b32 $r4 6 + iowr I[$r4 + 0x000] $r5 + + // write COUNTER + query_counter: + call #cmd_exec_wait + mov $r4 0x80c + shl b32 $r4 6 + ld b32 $r5 D[$r0 + #ctx_query_address_low] + iowr I[$r4 + 0x000] $r5 + iowr I[$r4 + 0x100] $r0 + mov $r5 0x4 + iowr I[$r4 + 0x200] $r5 + add b32 $r4 0x400 + ld b32 $r5 D[$r0 + #ctx_query_address_high] + shl b32 $r5 16 + iowr I[$r4 + 0x000] $r5 + add b32 $r4 0x500 + mov $r5 0x00000300 + iowr I[$r4 + 0x000] $r5 + mov $r5 0x00001110 + sethi $r5 0x13120000 + iowr I[$r4 + 0x100] $r5 + ld b32 $r5 D[$r0 + #ctx_query_counter] + add b32 $r4 0x500 + iowr I[$r4 + 0x000] $r5 + mov $r5 0x00002601 + sethi $r5 0x00010000 + mov $r4 0x800 + shl b32 $r4 6 + iowr I[$r4 + 0x000] $r5 + ret + +// Execute a copy operation +// +// Inputs: +// $r1: irqh state +// $r2: hostirq state +// $r3: data +// 000002000 QUERY_SHORT +// 000001000 QUERY +// 000000100 DST_LINEAR +// 000000010 SRC_LINEAR +// 000000001 FORMAT +// $r4: dispatch table entry +// Outputs: +// $r1: irqh state +// $p1: set on error +// $r2: hostirq state +// $r3: data +cmd_exec: + call #cmd_exec_wait + + // if format requested, call function to calculate it, otherwise + // fill in cpp/xcnt for both surfaces as if (cpp == 1) + xbit $r15 $r3 0 + bra e #cmd_exec_no_format + call #cmd_exec_set_format + mov $r4 0x200 + bra #cmd_exec_init_src_surface + cmd_exec_no_format: + mov $r6 0x810 + shl b32 $r6 6 + mov $r7 1 + st b32 D[$r0 + #ctx_src_cpp] $r7 + st b32 D[$r0 + #ctx_dst_cpp] $r7 + ld b32 $r7 D[$r0 + #ctx_xcnt] + iowr I[$r6 + 0x000] $r7 + iowr I[$r6 + 0x100] $r7 + clear b32 $r4 + + cmd_exec_init_src_surface: + bclr $flags $p2 + clear b32 $r5 + xbit $r15 $r3 4 + bra e #src_tiled + call #cmd_exec_set_surface_linear + bra #cmd_exec_init_dst_surface + src_tiled: + call #cmd_exec_set_surface_tiled + bset $r4 7 + + cmd_exec_init_dst_surface: + bset $flags $p2 + mov $r5 #ctx_dst_address_high - #ctx_src_address_high + xbit $r15 $r3 8 + bra e #dst_tiled + call #cmd_exec_set_surface_linear + bra #cmd_exec_kick + dst_tiled: + call #cmd_exec_set_surface_tiled + bset $r4 8 + + cmd_exec_kick: + mov $r5 0x800 + shl b32 $r5 6 + ld b32 $r6 D[$r0 + #ctx_ycnt] + iowr I[$r5 + 0x100] $r6 + mov $r6 0x0041 + // SRC_TARGET = 1, DST_TARGET = 2 + sethi $r6 0x44000000 + or $r4 $r6 + iowr I[$r5] $r4 + + // if requested, queue up a QUERY write after the copy has completed + xbit $r15 $r3 12 + bra e #cmd_exec_done + call #cmd_exec_query + + cmd_exec_done: + ret + +// Flush write cache +// +// Inputs: +// $r1: irqh state +// $r2: hostirq state +// $r3: data +// $r4: dispatch table entry +// Outputs: +// $r1: irqh state +// $p1: set on error +// $r2: hostirq state +// $r3: data +cmd_wrcache_flush: + mov $r2 0x2200 + clear b32 $r3 + sethi $r3 0x10000 + iowr I[$r2] $r3 + ret + +.align 0x100 diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h new file mode 100644 index 00000000000..c92520f3ed4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h @@ -0,0 +1,620 @@ +static u32 nva3_pcopy_data[] = { +/* 0x0000: ctx_object */ + 0x00000000, +/* 0x0004: ctx_dma */ +/* 0x0004: ctx_dma_query */ + 0x00000000, +/* 0x0008: ctx_dma_src */ + 0x00000000, +/* 0x000c: ctx_dma_dst */ + 0x00000000, +/* 0x0010: ctx_query_address_high */ + 0x00000000, +/* 0x0014: ctx_query_address_low */ + 0x00000000, +/* 0x0018: ctx_query_counter */ + 0x00000000, +/* 0x001c: ctx_src_address_high */ + 0x00000000, +/* 0x0020: ctx_src_address_low */ + 0x00000000, +/* 0x0024: ctx_src_pitch */ + 0x00000000, +/* 0x0028: ctx_src_tile_mode */ + 0x00000000, +/* 0x002c: ctx_src_xsize */ + 0x00000000, +/* 0x0030: ctx_src_ysize */ + 0x00000000, +/* 0x0034: ctx_src_zsize */ + 0x00000000, +/* 0x0038: ctx_src_zoff */ + 0x00000000, +/* 0x003c: ctx_src_xoff */ + 0x00000000, +/* 0x0040: ctx_src_yoff */ + 0x00000000, +/* 0x0044: ctx_src_cpp */ + 0x00000000, +/* 0x0048: ctx_dst_address_high */ + 0x00000000, +/* 0x004c: ctx_dst_address_low */ + 0x00000000, +/* 0x0050: ctx_dst_pitch */ + 0x00000000, +/* 0x0054: ctx_dst_tile_mode */ + 0x00000000, +/* 0x0058: ctx_dst_xsize */ + 0x00000000, +/* 0x005c: ctx_dst_ysize */ + 0x00000000, +/* 0x0060: ctx_dst_zsize */ + 0x00000000, +/* 0x0064: ctx_dst_zoff */ + 0x00000000, +/* 0x0068: ctx_dst_xoff */ + 0x00000000, +/* 0x006c: ctx_dst_yoff */ + 0x00000000, +/* 0x0070: ctx_dst_cpp */ + 0x00000000, +/* 0x0074: ctx_format */ + 0x00000000, +/* 0x0078: ctx_swz_const0 */ + 0x00000000, +/* 0x007c: ctx_swz_const1 */ + 0x00000000, +/* 0x0080: ctx_xcnt */ + 0x00000000, +/* 0x0084: ctx_ycnt */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0100: dispatch_table */ + 0x00010000, + 0x00000000, + 0x00000000, + 0x00010040, + 0x00010160, + 0x00000000, + 0x00010050, + 0x00010162, + 0x00000000, + 0x00030060, +/* 0x0128: dispatch_dma */ + 0x00010170, + 0x00000000, + 0x00010170, + 0x00000000, + 0x00010170, + 0x00000000, + 0x00070080, + 0x00000028, + 0xfffff000, + 0x0000002c, + 0xfff80000, + 0x00000030, + 0xffffe000, + 0x00000034, + 0xfffff800, + 0x00000038, + 0xfffff000, + 0x0000003c, + 0xfff80000, + 0x00000040, + 0xffffe000, + 0x00070088, + 0x00000054, + 0xfffff000, + 0x00000058, + 0xfff80000, + 0x0000005c, + 0xffffe000, + 0x00000060, + 0xfffff800, + 0x00000064, + 0xfffff000, + 0x00000068, + 0xfff80000, + 0x0000006c, + 0xffffe000, + 0x000200c0, + 0x00010492, + 0x00000000, + 0x0001051b, + 0x00000000, + 0x000e00c3, + 0x0000001c, + 0xffffff00, + 0x00000020, + 0x00000000, + 0x00000048, + 0xffffff00, + 0x0000004c, + 0x00000000, + 0x00000024, + 0xfff80000, + 0x00000050, + 0xfff80000, + 0x00000080, + 0xffff0000, + 0x00000084, + 0xffffe000, + 0x00000074, + 0xfccc0000, + 0x00000078, + 0x00000000, + 0x0000007c, + 0x00000000, + 0x00000010, + 0xffffff00, + 0x00000014, + 0x00000000, + 0x00000018, + 0x00000000, + 0x00000800, +}; + +static u32 nva3_pcopy_code[] = { +/* 0x0000: main */ + 0x04fe04bd, + 0x3517f000, + 0xf10010fe, + 0xf1040017, + 0xf0fff327, + 0x12d00023, + 0x0c25f0c0, + 0xf40012d0, + 0x17f11031, + 0x27f01200, + 0x0012d003, +/* 0x002f: spin */ + 0xf40031f4, + 0x0ef40028, +/* 0x0035: ih */ + 0x8001cffd, + 0xf40812c4, + 0x21f4060b, +/* 0x0041: ih_no_chsw */ + 0x0412c472, + 0xf4060bf4, +/* 0x004a: ih_no_cmd */ + 0x11c4c321, + 0x4001d00c, +/* 0x0052: swctx */ + 0x47f101f8, + 0x4bfe7700, + 0x0007fe00, + 0xf00204b9, + 0x01f40643, + 0x0604fa09, +/* 0x006b: swctx_load */ + 0xfa060ef4, +/* 0x006e: swctx_done */ + 0x03f80504, +/* 0x0072: chsw */ + 0x27f100f8, + 0x23cf1400, + 0x1e3fc800, + 0xf4170bf4, + 0x21f40132, + 0x1e3af052, + 0xf00023d0, + 0x24d00147, +/* 0x0093: chsw_no_unload */ + 0xcf00f880, + 0x3dc84023, + 0x220bf41e, + 0xf40131f4, + 0x57f05221, + 0x0367f004, +/* 0x00a8: chsw_load_ctx_dma */ + 0xa07856bc, + 0xb6018068, + 0x87d00884, + 0x0162b600, +/* 0x00bb: chsw_finish_load */ + 0xf0f018f4, + 0x23d00237, +/* 0x00c3: dispatch */ + 0xf100f880, + 0xcf190037, + 0x33cf4032, + 0xff24e400, + 0x1024b607, + 0x010057f1, + 0x74bd64bd, +/* 0x00dc: dispatch_loop */ + 0x58005658, + 0x50b60157, + 0x0446b804, + 0xbb4d08f4, + 0x47b80076, + 0x0f08f404, + 0xb60276bb, + 0x57bb0374, + 0xdf0ef400, +/* 0x0100: dispatch_valid_mthd */ + 0xb60246bb, + 0x45bb0344, + 0x01459800, + 0xb00453fd, + 0x1bf40054, + 0x00455820, + 0xb0014658, + 0x1bf40064, + 0x00538009, +/* 0x0127: dispatch_cmd */ + 0xf4300ef4, + 0x55f90132, + 0xf40c01f4, +/* 0x0132: dispatch_invalid_bitfield */ + 0x25f0250e, +/* 0x0135: dispatch_illegal_mthd */ + 0x0125f002, +/* 0x0138: dispatch_error */ + 0x100047f1, + 0xd00042d0, + 0x27f04043, + 0x0002d040, +/* 0x0148: hostirq_wait */ + 0xf08002cf, + 0x24b04024, + 0xf71bf400, +/* 0x0154: dispatch_done */ + 0x1d0027f1, + 0xd00137f0, + 0x00f80023, +/* 0x0160: cmd_nop */ +/* 0x0162: cmd_pm_trigger */ + 0x27f100f8, + 0x34bd2200, + 0xd00233f0, + 0x00f80023, +/* 0x0170: cmd_dma */ + 0x012842b7, + 0xf00145b6, + 0x43801e39, + 0x0040b701, + 0x0644b606, + 0xf80043d0, +/* 0x0189: cmd_exec_set_format */ + 0xf030f400, + 0xb00001b0, + 0x01b00101, + 0x0301b002, + 0xc71d0498, + 0x50b63045, + 0x3446c701, + 0xc70160b6, + 0x70b63847, + 0x0232f401, + 0x94bd84bd, +/* 0x01b4: ncomp_loop */ + 0xb60f4ac4, + 0xb4bd0445, +/* 0x01bc: bpc_loop */ + 0xf404a430, + 0xa5ff0f18, + 0x00cbbbc0, + 0xf40231f4, +/* 0x01ce: cmp_c0 */ + 0x1bf4220e, + 0x10c7f00c, + 0xf400cbbb, +/* 0x01da: cmp_c1 */ + 0xa430160e, + 0x0c18f406, + 0xbb14c7f0, + 0x0ef400cb, +/* 0x01e9: cmp_zero */ + 0x80c7f107, +/* 0x01ed: bpc_next */ + 0x01c83800, + 0xb60180b6, + 0xb5b801b0, + 0xc308f404, + 0xb80190b6, + 0x08f40497, + 0x0065fdb2, + 0x98110680, + 0x68fd2008, + 0x0502f400, +/* 0x0216: dst_xcnt */ + 0x75fd64bd, + 0x1c078000, + 0xf10078fd, + 0xb6081057, + 0x56d00654, + 0x4057d000, + 0x080050b7, + 0xb61c0698, + 0x64b60162, + 0x11079808, + 0xfd0172b6, + 0x56d00567, + 0x0050b700, + 0x0060b401, + 0xb40056d0, + 0x56d00160, + 0x0260b440, + 0xb48056d0, + 0x56d00360, + 0x0050b7c0, + 0x1e069804, + 0x980056d0, + 0x56d01f06, + 0x1030f440, +/* 0x0276: cmd_exec_set_surface_tiled */ + 0x579800f8, + 0x6879c70a, + 0xb66478c7, + 0x77c70280, + 0x0e76b060, + 0xf0091bf4, + 0x0ef40477, +/* 0x0291: xtile64 */ + 0x027cf00f, + 0xfd1170b6, + 0x77f00947, +/* 0x029d: xtileok */ + 0x0f5a9806, + 0xfd115b98, + 0xb7f000ab, + 0x04b7bb01, + 0xff01b2b6, + 0xa7bbc4ab, + 0x105d9805, + 0xbb01e7f0, + 0xe2b604e8, + 0xb4deff01, + 0xb605d8bb, + 0xef9401e0, + 0x02ebbb0c, + 0xf005fefd, + 0x60b7026c, + 0x64b60208, + 0x006fd008, + 0xbb04b7bb, + 0x5f9800cb, + 0x115b980b, + 0xf000fbfd, + 0xb7bb01b7, + 0x01b2b604, + 0xbb00fbbb, + 0xf0f905f7, + 0xf00c5f98, + 0xb8bb01b7, + 0x01b2b604, + 0xbb00fbbb, + 0xf0f905f8, + 0xb60078bb, + 0xb7f00282, + 0x04b8bb01, + 0x9804b9bb, + 0xe7f00e58, + 0x04e9bb01, + 0xff01e2b6, + 0xf7bbf48e, + 0x00cfbb04, + 0xbb0079bb, + 0xf0fc0589, + 0xd9fd90fc, + 0x00adbb00, + 0xfd0089fd, + 0xa8bb008f, + 0x04a7bb00, + 0xbb0192b6, + 0x69d00497, + 0x08579880, + 0xbb075898, + 0x7abb00ac, + 0x0081b600, + 0xfd1084b6, + 0x62b7058b, + 0x67d00600, + 0x0060b700, + 0x0068d004, +/* 0x0382: cmd_exec_set_surface_linear */ + 0x6cf000f8, + 0x0260b702, + 0x0864b602, + 0xd0085798, + 0x60b70067, + 0x57980400, + 0x1074b607, + 0xb70067d0, + 0x98040060, + 0x67d00957, +/* 0x03ab: cmd_exec_wait */ + 0xf900f800, + 0xf110f900, + 0xb6080007, +/* 0x03b6: loop */ + 0x01cf0604, + 0x0114f000, + 0xfcfa1bf4, + 0xf800fc10, +/* 0x03c5: cmd_exec_query */ + 0x0d34c800, + 0xf5701bf4, + 0xf103ab21, + 0xb6080c47, + 0x05980644, + 0x0450b605, + 0xd00045d0, + 0x57f04040, + 0x8045d00c, + 0x040040b7, + 0xb6040598, + 0x45d01054, + 0x0040b700, + 0x0057f105, + 0x0153f00b, + 0xf10045d0, + 0xb6404057, + 0x53f10154, + 0x45d08080, + 0x1057f140, + 0x1253f111, + 0x8045d013, + 0x151457f1, + 0x171653f1, + 0xf1c045d0, + 0xf0260157, + 0x47f10153, + 0x44b60800, + 0x0045d006, +/* 0x0438: query_counter */ + 0x03ab21f5, + 0x080c47f1, + 0x980644b6, + 0x45d00505, + 0x4040d000, + 0xd00457f0, + 0x40b78045, + 0x05980400, + 0x1054b604, + 0xb70045d0, + 0xf1050040, + 0xd0030057, + 0x57f10045, + 0x53f11110, + 0x45d01312, + 0x06059840, + 0x050040b7, + 0xf10045d0, + 0xf0260157, + 0x47f10153, + 0x44b60800, + 0x0045d006, +/* 0x0492: cmd_exec */ + 0x21f500f8, + 0x3fc803ab, + 0x0e0bf400, + 0x018921f5, + 0x020047f1, +/* 0x04a7: cmd_exec_no_format */ + 0xf11e0ef4, + 0xb6081067, + 0x77f00664, + 0x11078001, + 0x981c0780, + 0x67d02007, + 0x4067d000, +/* 0x04c2: cmd_exec_init_src_surface */ + 0x32f444bd, + 0xc854bd02, + 0x0bf4043f, + 0x8221f50a, + 0x0a0ef403, +/* 0x04d4: src_tiled */ + 0x027621f5, +/* 0x04db: cmd_exec_init_dst_surface */ + 0xf40749f0, + 0x57f00231, + 0x083fc82c, + 0xf50a0bf4, + 0xf4038221, +/* 0x04ee: dst_tiled */ + 0x21f50a0e, + 0x49f00276, +/* 0x04f5: cmd_exec_kick */ + 0x0057f108, + 0x0654b608, + 0xd0210698, + 0x67f04056, + 0x0063f141, + 0x0546fd44, + 0xc80054d0, + 0x0bf40c3f, + 0xc521f507, +/* 0x0519: cmd_exec_done */ +/* 0x051b: cmd_wrcache_flush */ + 0xf100f803, + 0xbd220027, + 0x0133f034, + 0xf80023d0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h new file mode 100644 index 00000000000..0d98c6c0958 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h @@ -0,0 +1,606 @@ +static u32 nvc0_pcopy_data[] = { +/* 0x0000: ctx_object */ + 0x00000000, +/* 0x0004: ctx_query_address_high */ + 0x00000000, +/* 0x0008: ctx_query_address_low */ + 0x00000000, +/* 0x000c: ctx_query_counter */ + 0x00000000, +/* 0x0010: ctx_src_address_high */ + 0x00000000, +/* 0x0014: ctx_src_address_low */ + 0x00000000, +/* 0x0018: ctx_src_pitch */ + 0x00000000, +/* 0x001c: ctx_src_tile_mode */ + 0x00000000, +/* 0x0020: ctx_src_xsize */ + 0x00000000, +/* 0x0024: ctx_src_ysize */ + 0x00000000, +/* 0x0028: ctx_src_zsize */ + 0x00000000, +/* 0x002c: ctx_src_zoff */ + 0x00000000, +/* 0x0030: ctx_src_xoff */ + 0x00000000, +/* 0x0034: ctx_src_yoff */ + 0x00000000, +/* 0x0038: ctx_src_cpp */ + 0x00000000, +/* 0x003c: ctx_dst_address_high */ + 0x00000000, +/* 0x0040: ctx_dst_address_low */ + 0x00000000, +/* 0x0044: ctx_dst_pitch */ + 0x00000000, +/* 0x0048: ctx_dst_tile_mode */ + 0x00000000, +/* 0x004c: ctx_dst_xsize */ + 0x00000000, +/* 0x0050: ctx_dst_ysize */ + 0x00000000, +/* 0x0054: ctx_dst_zsize */ + 0x00000000, +/* 0x0058: ctx_dst_zoff */ + 0x00000000, +/* 0x005c: ctx_dst_xoff */ + 0x00000000, +/* 0x0060: ctx_dst_yoff */ + 0x00000000, +/* 0x0064: ctx_dst_cpp */ + 0x00000000, +/* 0x0068: ctx_format */ + 0x00000000, +/* 0x006c: ctx_swz_const0 */ + 0x00000000, +/* 0x0070: ctx_swz_const1 */ + 0x00000000, +/* 0x0074: ctx_xcnt */ + 0x00000000, +/* 0x0078: ctx_ycnt */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0100: dispatch_table */ + 0x00010000, + 0x00000000, + 0x00000000, + 0x00010040, + 0x0001019f, + 0x00000000, + 0x00010050, + 0x000101a1, + 0x00000000, + 0x00070080, + 0x0000001c, + 0xfffff000, + 0x00000020, + 0xfff80000, + 0x00000024, + 0xffffe000, + 0x00000028, + 0xfffff800, + 0x0000002c, + 0xfffff000, + 0x00000030, + 0xfff80000, + 0x00000034, + 0xffffe000, + 0x00070088, + 0x00000048, + 0xfffff000, + 0x0000004c, + 0xfff80000, + 0x00000050, + 0xffffe000, + 0x00000054, + 0xfffff800, + 0x00000058, + 0xfffff000, + 0x0000005c, + 0xfff80000, + 0x00000060, + 0xffffe000, + 0x000200c0, + 0x000104b8, + 0x00000000, + 0x00010541, + 0x00000000, + 0x000e00c3, + 0x00000010, + 0xffffff00, + 0x00000014, + 0x00000000, + 0x0000003c, + 0xffffff00, + 0x00000040, + 0x00000000, + 0x00000018, + 0xfff80000, + 0x00000044, + 0xfff80000, + 0x00000074, + 0xffff0000, + 0x00000078, + 0xffffe000, + 0x00000068, + 0xfccc0000, + 0x0000006c, + 0x00000000, + 0x00000070, + 0x00000000, + 0x00000004, + 0xffffff00, + 0x00000008, + 0x00000000, + 0x0000000c, + 0x00000000, + 0x00000800, +}; + +static u32 nvc0_pcopy_code[] = { +/* 0x0000: main */ + 0x04fe04bd, + 0x3517f000, + 0xf10010fe, + 0xf1040017, + 0xf0fff327, + 0x12d00023, + 0x0c25f0c0, + 0xf40012d0, + 0x17f11031, + 0x27f01200, + 0x0012d003, +/* 0x002f: spin */ + 0xf40031f4, + 0x0ef40028, +/* 0x0035: ih */ + 0x8001cffd, + 0xf40812c4, + 0x21f4060b, +/* 0x0041: ih_no_chsw */ + 0x0412c4ca, + 0xf5070bf4, +/* 0x004b: ih_no_cmd */ + 0xc4010221, + 0x01d00c11, +/* 0x0053: swctx */ + 0xf101f840, + 0xfe770047, + 0x47f1004b, + 0x44cf2100, + 0x0144f000, + 0xb60444b6, + 0xf7f13040, + 0xf4b6061c, + 0x1457f106, + 0x00f5d101, + 0xb6043594, + 0x57fe0250, + 0x0145fe00, + 0x010052b7, + 0x00ff67f1, + 0x56fd60bd, + 0x0253f004, + 0xf80545fa, + 0x0053f003, + 0xd100e7f0, + 0x549800fe, + 0x0845b600, + 0xb6015698, + 0x46fd1864, + 0x0047fe05, + 0xf00204b9, + 0x01f40643, + 0x0604fa09, +/* 0x00c3: swctx_load */ + 0xfa060ef4, +/* 0x00c6: swctx_done */ + 0x03f80504, +/* 0x00ca: chsw */ + 0x27f100f8, + 0x23cf1400, + 0x1e3fc800, + 0xf4170bf4, + 0x21f40132, + 0x1e3af053, + 0xf00023d0, + 0x24d00147, +/* 0x00eb: chsw_no_unload */ + 0xcf00f880, + 0x3dc84023, + 0x090bf41e, + 0xf40131f4, +/* 0x00fa: chsw_finish_load */ + 0x37f05321, + 0x8023d002, +/* 0x0102: dispatch */ + 0x37f100f8, + 0x32cf1900, + 0x0033cf40, + 0x07ff24e4, + 0xf11024b6, + 0xbd010057, +/* 0x011b: dispatch_loop */ + 0x5874bd64, + 0x57580056, + 0x0450b601, + 0xf40446b8, + 0x76bb4d08, + 0x0447b800, + 0xbb0f08f4, + 0x74b60276, + 0x0057bb03, +/* 0x013f: dispatch_valid_mthd */ + 0xbbdf0ef4, + 0x44b60246, + 0x0045bb03, + 0xfd014598, + 0x54b00453, + 0x201bf400, + 0x58004558, + 0x64b00146, + 0x091bf400, + 0xf4005380, +/* 0x0166: dispatch_cmd */ + 0x32f4300e, + 0xf455f901, + 0x0ef40c01, +/* 0x0171: dispatch_invalid_bitfield */ + 0x0225f025, +/* 0x0174: dispatch_illegal_mthd */ +/* 0x0177: dispatch_error */ + 0xf10125f0, + 0xd0100047, + 0x43d00042, + 0x4027f040, +/* 0x0187: hostirq_wait */ + 0xcf0002d0, + 0x24f08002, + 0x0024b040, +/* 0x0193: dispatch_done */ + 0xf1f71bf4, + 0xf01d0027, + 0x23d00137, +/* 0x019f: cmd_nop */ + 0xf800f800, +/* 0x01a1: cmd_pm_trigger */ + 0x0027f100, + 0xf034bd22, + 0x23d00233, +/* 0x01af: cmd_exec_set_format */ + 0xf400f800, + 0x01b0f030, + 0x0101b000, + 0xb00201b0, + 0x04980301, + 0x3045c71a, + 0xc70150b6, + 0x60b63446, + 0x3847c701, + 0xf40170b6, + 0x84bd0232, +/* 0x01da: ncomp_loop */ + 0x4ac494bd, + 0x0445b60f, +/* 0x01e2: bpc_loop */ + 0xa430b4bd, + 0x0f18f404, + 0xbbc0a5ff, + 0x31f400cb, + 0x220ef402, +/* 0x01f4: cmp_c0 */ + 0xf00c1bf4, + 0xcbbb10c7, + 0x160ef400, +/* 0x0200: cmp_c1 */ + 0xf406a430, + 0xc7f00c18, + 0x00cbbb14, +/* 0x020f: cmp_zero */ + 0xf1070ef4, +/* 0x0213: bpc_next */ + 0x380080c7, + 0x80b601c8, + 0x01b0b601, + 0xf404b5b8, + 0x90b6c308, + 0x0497b801, + 0xfdb208f4, + 0x06800065, + 0x1d08980e, + 0xf40068fd, + 0x64bd0502, +/* 0x023c: dst_xcnt */ + 0x800075fd, + 0x78fd1907, + 0x1057f100, + 0x0654b608, + 0xd00056d0, + 0x50b74057, + 0x06980800, + 0x0162b619, + 0x980864b6, + 0x72b60e07, + 0x0567fd01, + 0xb70056d0, + 0xb4010050, + 0x56d00060, + 0x0160b400, + 0xb44056d0, + 0x56d00260, + 0x0360b480, + 0xb7c056d0, + 0x98040050, + 0x56d01b06, + 0x1c069800, + 0xf44056d0, + 0x00f81030, +/* 0x029c: cmd_exec_set_surface_tiled */ + 0xc7075798, + 0x78c76879, + 0x0380b664, + 0xb06077c7, + 0x1bf40e76, + 0x0477f009, +/* 0x02b7: xtile64 */ + 0xf00f0ef4, + 0x70b6027c, + 0x0947fd11, +/* 0x02c3: xtileok */ + 0x980677f0, + 0x5b980c5a, + 0x00abfd0e, + 0xbb01b7f0, + 0xb2b604b7, + 0xc4abff01, + 0x9805a7bb, + 0xe7f00d5d, + 0x04e8bb01, + 0xff01e2b6, + 0xd8bbb4de, + 0x01e0b605, + 0xbb0cef94, + 0xfefd02eb, + 0x026cf005, + 0x020860b7, + 0xd00864b6, + 0xb7bb006f, + 0x00cbbb04, + 0x98085f98, + 0xfbfd0e5b, + 0x01b7f000, + 0xb604b7bb, + 0xfbbb01b2, + 0x05f7bb00, + 0x5f98f0f9, + 0x01b7f009, + 0xb604b8bb, + 0xfbbb01b2, + 0x05f8bb00, + 0x78bbf0f9, + 0x0282b600, + 0xbb01b7f0, + 0xb9bb04b8, + 0x0b589804, + 0xbb01e7f0, + 0xe2b604e9, + 0xf48eff01, + 0xbb04f7bb, + 0x79bb00cf, + 0x0589bb00, + 0x90fcf0fc, + 0xbb00d9fd, + 0x89fd00ad, + 0x008ffd00, + 0xbb00a8bb, + 0x92b604a7, + 0x0497bb01, + 0x988069d0, + 0x58980557, + 0x00acbb04, + 0xb6007abb, + 0x84b60081, + 0x058bfd10, + 0x060062b7, + 0xb70067d0, + 0xd0040060, + 0x00f80068, +/* 0x03a8: cmd_exec_set_surface_linear */ + 0xb7026cf0, + 0xb6020260, + 0x57980864, + 0x0067d005, + 0x040060b7, + 0xb6045798, + 0x67d01074, + 0x0060b700, + 0x06579804, + 0xf80067d0, +/* 0x03d1: cmd_exec_wait */ + 0xf900f900, + 0x0007f110, + 0x0604b608, +/* 0x03dc: loop */ + 0xf00001cf, + 0x1bf40114, + 0xfc10fcfa, +/* 0x03eb: cmd_exec_query */ + 0xc800f800, + 0x1bf40d34, + 0xd121f570, + 0x0c47f103, + 0x0644b608, + 0xb6020598, + 0x45d00450, + 0x4040d000, + 0xd00c57f0, + 0x40b78045, + 0x05980400, + 0x1054b601, + 0xb70045d0, + 0xf1050040, + 0xf00b0057, + 0x45d00153, + 0x4057f100, + 0x0154b640, + 0x808053f1, + 0xf14045d0, + 0xf1111057, + 0xd0131253, + 0x57f18045, + 0x53f11514, + 0x45d01716, + 0x0157f1c0, + 0x0153f026, + 0x080047f1, + 0xd00644b6, +/* 0x045e: query_counter */ + 0x21f50045, + 0x47f103d1, + 0x44b6080c, + 0x02059806, + 0xd00045d0, + 0x57f04040, + 0x8045d004, + 0x040040b7, + 0xb6010598, + 0x45d01054, + 0x0040b700, + 0x0057f105, + 0x0045d003, + 0x111057f1, + 0x131253f1, + 0x984045d0, + 0x40b70305, + 0x45d00500, + 0x0157f100, + 0x0153f026, + 0x080047f1, + 0xd00644b6, + 0x00f80045, +/* 0x04b8: cmd_exec */ + 0x03d121f5, + 0xf4003fc8, + 0x21f50e0b, + 0x47f101af, + 0x0ef40200, +/* 0x04cd: cmd_exec_no_format */ + 0x1067f11e, + 0x0664b608, + 0x800177f0, + 0x07800e07, + 0x1d079819, + 0xd00067d0, + 0x44bd4067, +/* 0x04e8: cmd_exec_init_src_surface */ + 0xbd0232f4, + 0x043fc854, + 0xf50a0bf4, + 0xf403a821, +/* 0x04fa: src_tiled */ + 0x21f50a0e, + 0x49f0029c, +/* 0x0501: cmd_exec_init_dst_surface */ + 0x0231f407, + 0xc82c57f0, + 0x0bf4083f, + 0xa821f50a, + 0x0a0ef403, +/* 0x0514: dst_tiled */ + 0x029c21f5, +/* 0x051b: cmd_exec_kick */ + 0xf10849f0, + 0xb6080057, + 0x06980654, + 0x4056d01e, + 0xf14167f0, + 0xfd440063, + 0x54d00546, + 0x0c3fc800, + 0xf5070bf4, +/* 0x053f: cmd_exec_done */ + 0xf803eb21, +/* 0x0541: cmd_wrcache_flush */ + 0x0027f100, + 0xf034bd22, + 0x23d00133, + 0x0000f800, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c new file mode 100644 index 00000000000..4df6da0af74 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c @@ -0,0 +1,222 @@ +/* + * 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/enum.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <subdev/fb.h> +#include <subdev/vm.h> + +#include <engine/fifo.h> +#include <engine/copy.h> + +#include "fuc/nva3.fuc.h" + +struct nva3_copy_priv { + struct nouveau_copy base; +}; + +struct nva3_copy_chan { + struct nouveau_copy_chan base; +}; + +/******************************************************************************* + * Copy object classes + ******************************************************************************/ + +static struct nouveau_oclass +nva3_copy_sclass[] = { + { 0x85b5, &nouveau_object_ofuncs }, + {} +}; + +/******************************************************************************* + * PCOPY context + ******************************************************************************/ + +static int +nva3_copy_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nva3_copy_chan *priv; + int ret; + + ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, 0, + NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + 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 const struct nouveau_enum nva3_copy_isr_error_name[] = { + { 0x0001, "ILLEGAL_MTHD" }, + { 0x0002, "INVALID_ENUM" }, + { 0x0003, "INVALID_BITFIELD" }, + {} +}; + +static void +nva3_copy_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nva3_copy_priv *priv = (void *)subdev; + u32 dispatch = nv_rd32(priv, 0x10401c); + u32 stat = nv_rd32(priv, 0x104008) & dispatch & ~(dispatch >> 16); + u64 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(priv, 0x104044); + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x00000040) { + nv_error(priv, "DISPATCH_ERROR ["); + nouveau_enum_print(nva3_copy_isr_error_name, ssta); + printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n", + chid, inst << 12, subc, mthd, data); + nv_wr32(priv, 0x104004, 0x00000040); + stat &= ~0x00000040; + } + + if (stat) { + nv_error(priv, "unhandled intr 0x%08x\n", stat); + nv_wr32(priv, 0x104004, stat); + } + + nv50_fb_trap(nouveau_fb(priv), 1); + nouveau_engctx_put(engctx); +} + +static int +nva3_copy_tlb_flush(struct nouveau_engine *engine) +{ + nv50_vm_flush_engine(&engine->base, 0x0d); + return 0; +} + +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; + + 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; +} + +static int +nva3_copy_init(struct nouveau_object *object) +{ + struct nva3_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, 0xffffffff); + + /* 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]); + } + + /* 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 new file mode 100644 index 00000000000..06d4a879105 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c @@ -0,0 +1,265 @@ +/* + * 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/enum.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <engine/fifo.h> +#include <engine/copy.h> + +#include "fuc/nvc0.fuc.h" + +struct nvc0_copy_priv { + struct nouveau_copy base; +}; + +struct nvc0_copy_chan { + struct nouveau_copy_chan base; +}; + +/******************************************************************************* + * Copy object classes + ******************************************************************************/ + +static struct nouveau_oclass +nvc0_copy0_sclass[] = { + { 0x90b5, &nouveau_object_ofuncs }, + {}, +}; + +static struct nouveau_oclass +nvc0_copy1_sclass[] = { + { 0x90b8, &nouveau_object_ofuncs }, + {}, +}; + +/******************************************************************************* + * PCOPY context + ******************************************************************************/ + +static int +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_chan *priv; + int ret; + + ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, + 256, NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +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, +}; + +static struct nouveau_oclass +nvc0_copy0_cclass = { + .handle = NV_ENGCTX(COPY0, 0xc0), + .ofuncs = &nvc0_copy_context_ofuncs, +}; + +static struct nouveau_oclass +nvc0_copy1_cclass = { + .handle = NV_ENGCTX(COPY1, 0xc0), + .ofuncs = &nvc0_copy_context_ofuncs, +}; + +/******************************************************************************* + * PCOPY engine/subdev functions + ******************************************************************************/ + +static const struct nouveau_enum nvc0_copy_isr_error_name[] = { + { 0x0001, "ILLEGAL_MTHD" }, + { 0x0002, "INVALID_ENUM" }, + { 0x0003, "INVALID_BITFIELD" }, + {} +}; + +static void +nvc0_copy_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + 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(priv, 0x104044 + (idx * 0x1000)); + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x00000040) { + 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, (u64)inst << 12, subc, mthd, data); + nv_wr32(priv, 0x104004 + (idx * 0x1000), 0x00000040); + stat &= ~0x00000040; + } + + if (stat) { + nv_error(priv, "unhandled intr 0x%08x\n", stat); + nv_wr32(priv, 0x104004 + (idx * 0x1000), stat); + } + + nouveau_engctx_put(engctx); +} + +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) +{ + struct nvc0_copy_priv *priv; + int ret; + + 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 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_priv *priv; + int ret; + + if (nv_rd32(parent, 0x022500) & 0x00000200) + return -ENODEV; + + 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; +} + +static int +nvc0_copy_init(struct nouveau_object *object) +{ + 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/copy/nve0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c new file mode 100644 index 00000000000..2017c1579ac --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c @@ -0,0 +1,156 @@ +/* + * 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/enum.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <engine/copy.h> + +struct nve0_copy_priv { + struct nouveau_copy base; +}; + +struct nve0_copy_chan { + struct nouveau_copy_chan base; +}; + +/******************************************************************************* + * Copy object classes + ******************************************************************************/ + +static struct nouveau_oclass +nve0_copy_sclass[] = { + { 0xa0b5, &nouveau_object_ofuncs }, + {}, +}; + +/******************************************************************************* + * PCOPY context + ******************************************************************************/ + +static int +nve0_copy_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nve0_copy_chan *priv; + int ret; + + ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, + 256, NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +static struct nouveau_ofuncs +nve0_copy_context_ofuncs = { + .ctor = nve0_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, +}; + +static struct nouveau_oclass +nve0_copy_cclass = { + .handle = NV_ENGCTX(COPY0, 0xc0), + .ofuncs = &nve0_copy_context_ofuncs, +}; + +/******************************************************************************* + * PCOPY engine/subdev functions + ******************************************************************************/ + +static int +nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nve0_copy_priv *priv; + int ret; + + 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_engine(priv)->cclass = &nve0_copy_cclass; + nv_engine(priv)->sclass = nve0_copy_sclass; + return 0; +} + +static int +nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nve0_copy_priv *priv; + int ret; + + if (nv_rd32(parent, 0x022500) & 0x00000200) + return -ENODEV; + + ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000080; + nv_engine(priv)->cclass = &nve0_copy_cclass; + nv_engine(priv)->sclass = nve0_copy_sclass; + return 0; +} + +struct nouveau_oclass +nve0_copy0_oclass = { + .handle = NV_ENGINE(COPY0, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_copy0_ctor, + .dtor = _nouveau_copy_dtor, + .init = _nouveau_copy_init, + .fini = _nouveau_copy_fini, + }, +}; + +struct nouveau_oclass +nve0_copy1_oclass = { + .handle = NV_ENGINE(COPY1, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_copy1_ctor, + .dtor = _nouveau_copy_dtor, + .init = _nouveau_copy_init, + .fini = _nouveau_copy_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc new file mode 100644 index 00000000000..629da02dc35 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc @@ -0,0 +1,698 @@ +/* + * fuc microcode for nv98 pcrypt engine + * Copyright (C) 2010 Marcin Kościelnicki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +.section #nv98_pcrypt_data + +ctx_dma: +ctx_dma_query: .b32 0 +ctx_dma_src: .b32 0 +ctx_dma_dst: .b32 0 +.equ #dma_count 3 +ctx_query_address_high: .b32 0 +ctx_query_address_low: .b32 0 +ctx_query_counter: .b32 0 +ctx_cond_address_high: .b32 0 +ctx_cond_address_low: .b32 0 +ctx_cond_off: .b32 0 +ctx_src_address_high: .b32 0 +ctx_src_address_low: .b32 0 +ctx_dst_address_high: .b32 0 +ctx_dst_address_low: .b32 0 +ctx_mode: .b32 0 +.align 16 +ctx_key: .skip 16 +ctx_iv: .skip 16 + +.align 0x80 +swap: +.skip 32 + +.align 8 +common_cmd_dtable: +.b32 #ctx_query_address_high + 0x20000 ~0xff +.b32 #ctx_query_address_low + 0x20000 ~0xfffffff0 +.b32 #ctx_query_counter + 0x20000 ~0xffffffff +.b32 #cmd_query_get + 0x00000 ~1 +.b32 #ctx_cond_address_high + 0x20000 ~0xff +.b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0 +.b32 #cmd_cond_mode + 0x00000 ~7 +.b32 #cmd_wrcache_flush + 0x00000 ~0 +.equ #common_cmd_max 0x88 + + +.align 8 +engine_cmd_dtable: +.b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff +.b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff +.b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff +.b32 #ctx_key + 0xc + 0x20000 ~0xffffffff +.b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff +.b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff +.b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff +.b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff +.b32 #ctx_src_address_high + 0x20000 ~0xff +.b32 #ctx_src_address_low + 0x20000 ~0xfffffff0 +.b32 #ctx_dst_address_high + 0x20000 ~0xff +.b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0 +.b32 #crypt_cmd_mode + 0x00000 ~0xf +.b32 #crypt_cmd_length + 0x10000 ~0x0ffffff0 +.equ #engine_cmd_max 0xce + +.align 4 +crypt_dtable: +.b16 #crypt_copy_prep #crypt_do_inout +.b16 #crypt_store_prep #crypt_do_out +.b16 #crypt_ecb_e_prep #crypt_do_inout +.b16 #crypt_ecb_d_prep #crypt_do_inout +.b16 #crypt_cbc_e_prep #crypt_do_inout +.b16 #crypt_cbc_d_prep #crypt_do_inout +.b16 #crypt_pcbc_e_prep #crypt_do_inout +.b16 #crypt_pcbc_d_prep #crypt_do_inout +.b16 #crypt_cfb_e_prep #crypt_do_inout +.b16 #crypt_cfb_d_prep #crypt_do_inout +.b16 #crypt_ofb_prep #crypt_do_inout +.b16 #crypt_ctr_prep #crypt_do_inout +.b16 #crypt_cbc_mac_prep #crypt_do_in +.b16 #crypt_cmac_finish_complete_prep #crypt_do_in +.b16 #crypt_cmac_finish_partial_prep #crypt_do_in + +.align 0x100 + +.section #nv98_pcrypt_code + + // $r0 is always set to 0 in our code - this allows some space savings. + clear b32 $r0 + + // set up the interrupt handler + mov $r1 #ih + mov $iv0 $r1 + + // init stack pointer + mov $sp $r0 + + // set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host + movw $r1 0xfff0 + sethi $r1 0 + mov $r2 0x400 + iowr I[$r2 + 0x300] $r1 + + // enable the interrupts + or $r1 0xc + iowr I[$r2] $r1 + + // enable fifo access and context switching + mov $r1 3 + mov $r2 0x1200 + iowr I[$r2] $r1 + + // enable i0 delivery + bset $flags ie0 + + // sleep forver, waking only for interrupts. + bset $flags $p0 + spin: + sleep $p0 + bra #spin + +// i0 handler +ih: + // see which interrupts we got + iord $r1 I[$r0 + 0x200] + + and $r2 $r1 0x8 + cmpu b32 $r2 0 + bra e #noctx + + // context switch... prepare the regs for xfer + mov $r2 0x7700 + mov $xtargets $r2 + mov $xdbase $r0 + // 128-byte context. + mov $r2 0 + sethi $r2 0x50000 + + // read current channel + mov $r3 0x1400 + iord $r4 I[$r3] + // if bit 30 set, it's active, so we have to unload it first. + shl b32 $r5 $r4 1 + cmps b32 $r5 0 + bra nc #ctxload + + // unload the current channel - save the context + xdst $r0 $r2 + xdwait + // and clear bit 30, then write back + bclr $r4 0x1e + iowr I[$r3] $r4 + // tell PFIFO we unloaded + mov $r4 1 + iowr I[$r3 + 0x200] $r4 + + bra #noctx + + ctxload: + // no channel loaded - perhaps we're requested to load one + iord $r4 I[$r3 + 0x100] + shl b32 $r15 $r4 1 + cmps b32 $r15 0 + // if bit 30 of next channel not set, probably PFIFO is just + // killing a context. do a faux load, without the active bit. + bra nc #dummyload + + // ok, do a real context load. + xdld $r0 $r2 + xdwait + mov $r5 #ctx_dma + mov $r6 #dma_count - 1 + ctxload_dma_loop: + ld b32 $r7 D[$r5 + $r6 * 4] + add b32 $r8 $r6 0x180 + shl b32 $r8 8 + iowr I[$r8] $r7 + sub b32 $r6 1 + bra nc #ctxload_dma_loop + + dummyload: + // tell PFIFO we're done + mov $r5 2 + iowr I[$r3 + 0x200] $r5 + + noctx: + and $r2 $r1 0x4 + cmpu b32 $r2 0 + bra e #nocmd + + // incoming fifo command. + mov $r3 0x1900 + iord $r2 I[$r3 + 0x100] + iord $r3 I[$r3] + // extract the method + and $r4 $r2 0x7ff + // shift the addr to proper position if we need to interrupt later + shl b32 $r2 0x10 + + // mthd 0 and 0x100 [NAME, NOP]: ignore + and $r5 $r4 0x7bf + cmpu b32 $r5 0 + bra e #cmddone + + mov $r5 #engine_cmd_dtable - 0xc0 * 8 + mov $r6 #engine_cmd_max + cmpu b32 $r4 0xc0 + bra nc #dtable_cmd + mov $r5 #common_cmd_dtable - 0x80 * 8 + mov $r6 #common_cmd_max + cmpu b32 $r4 0x80 + bra nc #dtable_cmd + cmpu b32 $r4 0x60 + bra nc #dma_cmd + cmpu b32 $r4 0x50 + bra ne #illegal_mthd + + // mthd 0x140: PM_TRIGGER + mov $r2 0x2200 + clear b32 $r3 + sethi $r3 0x20000 + iowr I[$r2] $r3 + bra #cmddone + + dma_cmd: + // mthd 0x180...: DMA_* + cmpu b32 $r4 0x60+#dma_count + bra nc #illegal_mthd + shl b32 $r5 $r4 2 + add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff) + bset $r3 0x1e + st b32 D[$r5] $r3 + add b32 $r4 0x180 - 0x60 + shl b32 $r4 8 + iowr I[$r4] $r3 + bra #cmddone + + dtable_cmd: + cmpu b32 $r4 $r6 + bra nc #illegal_mthd + shl b32 $r4 3 + add b32 $r4 $r5 + ld b32 $r5 D[$r4 + 4] + and $r5 $r3 + cmpu b32 $r5 0 + bra ne #invalid_bitfield + ld b16 $r5 D[$r4] + ld b16 $r6 D[$r4 + 2] + cmpu b32 $r6 2 + bra e #cmd_setctx + ld b32 $r7 D[$r0 + #ctx_cond_off] + and $r6 $r7 + cmpu b32 $r6 1 + bra e #cmddone + call $r5 + bra $p1 #dispatch_error + bra #cmddone + + cmd_setctx: + st b32 D[$r5] $r3 + bra #cmddone + + + invalid_bitfield: + or $r2 1 + dispatch_error: + illegal_mthd: + mov $r4 0x1000 + iowr I[$r4] $r2 + iowr I[$r4 + 0x100] $r3 + mov $r4 0x40 + iowr I[$r0] $r4 + + im_loop: + iord $r4 I[$r0 + 0x200] + and $r4 0x40 + cmpu b32 $r4 0 + bra ne #im_loop + + cmddone: + // remove the command from FIFO + mov $r3 0x1d00 + mov $r4 1 + iowr I[$r3] $r4 + + nocmd: + // ack the processed interrupts + and $r1 $r1 0xc + iowr I[$r0 + 0x100] $r1 +iret + +cmd_query_get: + // if bit 0 of param set, trigger interrupt afterwards. + setp $p1 $r3 + or $r2 3 + + // read PTIMER, beware of races... + mov $r4 0xb00 + ptimer_retry: + iord $r6 I[$r4 + 0x100] + iord $r5 I[$r4] + iord $r7 I[$r4 + 0x100] + cmpu b32 $r6 $r7 + bra ne #ptimer_retry + + // prepare the query structure + ld b32 $r4 D[$r0 + #ctx_query_counter] + st b32 D[$r0 + #swap + 0x0] $r4 + st b32 D[$r0 + #swap + 0x4] $r0 + st b32 D[$r0 + #swap + 0x8] $r5 + st b32 D[$r0 + #swap + 0xc] $r6 + + // will use target 0, DMA_QUERY. + mov $xtargets $r0 + + ld b32 $r4 D[$r0 + #ctx_query_address_high] + shl b32 $r4 0x18 + mov $xdbase $r4 + + ld b32 $r4 D[$r0 + #ctx_query_address_low] + mov $r5 #swap + sethi $r5 0x20000 + xdst $r4 $r5 + xdwait + + ret + +cmd_cond_mode: + // if >= 5, INVALID_ENUM + bset $flags $p1 + or $r2 2 + cmpu b32 $r3 5 + bra nc #return + + // otherwise, no error. + bclr $flags $p1 + + // if < 2, no QUERY object is involved + cmpu b32 $r3 2 + bra nc #cmd_cond_mode_queryful + + xor $r3 1 + st b32 D[$r0 + #ctx_cond_off] $r3 + return: + ret + + cmd_cond_mode_queryful: + // ok, will need to pull a QUERY object, prepare offsets + ld b32 $r4 D[$r0 + #ctx_cond_address_high] + ld b32 $r5 D[$r0 + #ctx_cond_address_low] + and $r6 $r5 0xff + shr b32 $r5 8 + shl b32 $r4 0x18 + or $r4 $r5 + mov $xdbase $r4 + mov $xtargets $r0 + + // pull the first one + mov $r5 #swap + sethi $r5 0x20000 + xdld $r6 $r5 + + // if == 2, only a single QUERY is involved... + cmpu b32 $r3 2 + bra ne #cmd_cond_mode_double + + xdwait + ld b32 $r4 D[$r0 + #swap + 4] + cmpu b32 $r4 0 + xbit $r4 $flags z + st b32 D[$r0 + #ctx_cond_off] $r4 + ret + + // ok, we'll need to pull second one too + cmd_cond_mode_double: + add b32 $r6 0x10 + add b32 $r5 0x10 + xdld $r6 $r5 + xdwait + + // compare COUNTERs + ld b32 $r5 D[$r0 + #swap + 0x00] + ld b32 $r6 D[$r0 + #swap + 0x10] + cmpu b32 $r5 $r6 + xbit $r4 $flags z + + // compare RESen + ld b32 $r5 D[$r0 + #swap + 0x04] + ld b32 $r6 D[$r0 + #swap + 0x14] + cmpu b32 $r5 $r6 + xbit $r5 $flags z + and $r4 $r5 + + // and negate or not, depending on mode + cmpu b32 $r3 3 + xbit $r5 $flags z + xor $r4 $r5 + st b32 D[$r0 + #ctx_cond_off] $r4 + ret + +cmd_wrcache_flush: + bclr $flags $p1 + mov $r2 0x2200 + clear b32 $r3 + sethi $r3 0x10000 + iowr I[$r2] $r3 + ret + +crypt_cmd_mode: + // if >= 0xf, INVALID_ENUM + bset $flags $p1 + or $r2 2 + cmpu b32 $r3 0xf + bra nc #crypt_cmd_mode_return + + bclr $flags $p1 + st b32 D[$r0 + #ctx_mode] $r3 + + crypt_cmd_mode_return: + ret + +crypt_cmd_length: + // nop if length == 0 + cmpu b32 $r3 0 + bra e #crypt_cmd_mode_return + + // init key, IV + cxset 3 + mov $r4 #ctx_key + sethi $r4 0x70000 + xdst $r0 $r4 + mov $r4 #ctx_iv + sethi $r4 0x60000 + xdst $r0 $r4 + xdwait + ckeyreg $c7 + + // prepare the targets + mov $r4 0x2100 + mov $xtargets $r4 + + // prepare src address + ld b32 $r4 D[$r0 + #ctx_src_address_high] + ld b32 $r5 D[$r0 + #ctx_src_address_low] + shr b32 $r8 $r5 8 + shl b32 $r4 0x18 + or $r4 $r8 + and $r5 $r5 0xff + + // prepare dst address + ld b32 $r6 D[$r0 + #ctx_dst_address_high] + ld b32 $r7 D[$r0 + #ctx_dst_address_low] + shr b32 $r8 $r7 8 + shl b32 $r6 0x18 + or $r6 $r8 + and $r7 $r7 0xff + + // find the proper prep & do functions + ld b32 $r8 D[$r0 + #ctx_mode] + shl b32 $r8 2 + + // run prep + ld b16 $r9 D[$r8 + #crypt_dtable] + call $r9 + + // do it + ld b16 $r9 D[$r8 + #crypt_dtable + 2] + call $r9 + cxset 1 + xdwait + cxset 0x61 + xdwait + xdwait + + // update src address + shr b32 $r8 $r4 0x18 + shl b32 $r9 $r4 8 + add b32 $r9 $r5 + adc b32 $r8 0 + st b32 D[$r0 + #ctx_src_address_high] $r8 + st b32 D[$r0 + #ctx_src_address_low] $r9 + + // update dst address + shr b32 $r8 $r6 0x18 + shl b32 $r9 $r6 8 + add b32 $r9 $r7 + adc b32 $r8 0 + st b32 D[$r0 + #ctx_dst_address_high] $r8 + st b32 D[$r0 + #ctx_dst_address_low] $r9 + + // pull updated IV + cxset 2 + mov $r4 #ctx_iv + sethi $r4 0x60000 + xdld $r0 $r4 + xdwait + + ret + + +crypt_copy_prep: + cs0begin 2 + cxsin $c0 + cxsout $c0 + ret + +crypt_store_prep: + cs0begin 1 + cxsout $c6 + ret + +crypt_ecb_e_prep: + cs0begin 3 + cxsin $c0 + cenc $c0 $c0 + cxsout $c0 + ret + +crypt_ecb_d_prep: + ckexp $c7 $c7 + cs0begin 3 + cxsin $c0 + cdec $c0 $c0 + cxsout $c0 + ret + +crypt_cbc_e_prep: + cs0begin 4 + cxsin $c0 + cxor $c6 $c0 + cenc $c6 $c6 + cxsout $c6 + ret + +crypt_cbc_d_prep: + ckexp $c7 $c7 + cs0begin 5 + cmov $c2 $c6 + cxsin $c6 + cdec $c0 $c6 + cxor $c0 $c2 + cxsout $c0 + ret + +crypt_pcbc_e_prep: + cs0begin 5 + cxsin $c0 + cxor $c6 $c0 + cenc $c6 $c6 + cxsout $c6 + cxor $c6 $c0 + ret + +crypt_pcbc_d_prep: + ckexp $c7 $c7 + cs0begin 5 + cxsin $c0 + cdec $c1 $c0 + cxor $c6 $c1 + cxsout $c6 + cxor $c6 $c0 + ret + +crypt_cfb_e_prep: + cs0begin 4 + cenc $c6 $c6 + cxsin $c0 + cxor $c6 $c0 + cxsout $c6 + ret + +crypt_cfb_d_prep: + cs0begin 4 + cenc $c0 $c6 + cxsin $c6 + cxor $c0 $c6 + cxsout $c0 + ret + +crypt_ofb_prep: + cs0begin 4 + cenc $c6 $c6 + cxsin $c0 + cxor $c0 $c6 + cxsout $c0 + ret + +crypt_ctr_prep: + cs0begin 5 + cenc $c1 $c6 + cadd $c6 1 + cxsin $c0 + cxor $c0 $c1 + cxsout $c0 + ret + +crypt_cbc_mac_prep: + cs0begin 3 + cxsin $c0 + cxor $c6 $c0 + cenc $c6 $c6 + ret + +crypt_cmac_finish_complete_prep: + cs0begin 7 + cxsin $c0 + cxor $c6 $c0 + cxor $c0 $c0 + cenc $c0 $c0 + cprecmac $c0 $c0 + cxor $c6 $c0 + cenc $c6 $c6 + ret + +crypt_cmac_finish_partial_prep: + cs0begin 8 + cxsin $c0 + cxor $c6 $c0 + cxor $c0 $c0 + cenc $c0 $c0 + cprecmac $c0 $c0 + cprecmac $c0 $c0 + cxor $c6 $c0 + cenc $c6 $c6 + ret + +// TODO +crypt_do_in: + add b32 $r3 $r5 + mov $xdbase $r4 + mov $r9 #swap + sethi $r9 0x20000 + crypt_do_in_loop: + xdld $r5 $r9 + xdwait + cxset 0x22 + xdst $r0 $r9 + cs0exec 1 + xdwait + add b32 $r5 0x10 + cmpu b32 $r5 $r3 + bra ne #crypt_do_in_loop + cxset 1 + xdwait + ret + +crypt_do_out: + add b32 $r3 $r7 + mov $xdbase $r6 + mov $r9 #swap + sethi $r9 0x20000 + crypt_do_out_loop: + cs0exec 1 + cxset 0x61 + xdld $r7 $r9 + xdst $r7 $r9 + cxset 1 + xdwait + add b32 $r7 0x10 + cmpu b32 $r7 $r3 + bra ne #crypt_do_out_loop + ret + +crypt_do_inout: + add b32 $r3 $r5 + mov $r9 #swap + sethi $r9 0x20000 + crypt_do_inout_loop: + mov $xdbase $r4 + xdld $r5 $r9 + xdwait + cxset 0x21 + xdst $r0 $r9 + cs0exec 1 + cxset 0x61 + mov $xdbase $r6 + xdld $r7 $r9 + xdst $r7 $r9 + cxset 1 + xdwait + add b32 $r5 0x10 + add b32 $r7 0x10 + cmpu b32 $r5 $r3 + bra ne #crypt_do_inout_loop + ret + +.align 0x100 diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h new file mode 100644 index 00000000000..09962e4210e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h @@ -0,0 +1,584 @@ +static uint32_t nv98_pcrypt_data[] = { +/* 0x0000: ctx_dma */ +/* 0x0000: ctx_dma_query */ + 0x00000000, +/* 0x0004: ctx_dma_src */ + 0x00000000, +/* 0x0008: ctx_dma_dst */ + 0x00000000, +/* 0x000c: ctx_query_address_high */ + 0x00000000, +/* 0x0010: ctx_query_address_low */ + 0x00000000, +/* 0x0014: ctx_query_counter */ + 0x00000000, +/* 0x0018: ctx_cond_address_high */ + 0x00000000, +/* 0x001c: ctx_cond_address_low */ + 0x00000000, +/* 0x0020: ctx_cond_off */ + 0x00000000, +/* 0x0024: ctx_src_address_high */ + 0x00000000, +/* 0x0028: ctx_src_address_low */ + 0x00000000, +/* 0x002c: ctx_dst_address_high */ + 0x00000000, +/* 0x0030: ctx_dst_address_low */ + 0x00000000, +/* 0x0034: ctx_mode */ + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0040: ctx_key */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0050: ctx_iv */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0080: swap */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x00a0: common_cmd_dtable */ + 0x0002000c, + 0xffffff00, + 0x00020010, + 0x0000000f, + 0x00020014, + 0x00000000, + 0x00000192, + 0xfffffffe, + 0x00020018, + 0xffffff00, + 0x0002001c, + 0x0000000f, + 0x000001d7, + 0xfffffff8, + 0x00000260, + 0xffffffff, +/* 0x00e0: engine_cmd_dtable */ + 0x00020040, + 0x00000000, + 0x00020044, + 0x00000000, + 0x00020048, + 0x00000000, + 0x0002004c, + 0x00000000, + 0x00020050, + 0x00000000, + 0x00020054, + 0x00000000, + 0x00020058, + 0x00000000, + 0x0002005c, + 0x00000000, + 0x00020024, + 0xffffff00, + 0x00020028, + 0x0000000f, + 0x0002002c, + 0xffffff00, + 0x00020030, + 0x0000000f, + 0x00000271, + 0xfffffff0, + 0x00010285, + 0xf000000f, +/* 0x0150: crypt_dtable */ + 0x04db0321, + 0x04b1032f, + 0x04db0339, + 0x04db034b, + 0x04db0361, + 0x04db0377, + 0x04db0395, + 0x04db03af, + 0x04db03cd, + 0x04db03e3, + 0x04db03f9, + 0x04db040f, + 0x04830429, + 0x0483043b, + 0x0483045d, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static uint32_t nv98_pcrypt_code[] = { + 0x17f004bd, + 0x0010fe35, + 0xf10004fe, + 0xf0fff017, + 0x27f10013, + 0x21d00400, + 0x0c15f0c0, + 0xf00021d0, + 0x27f10317, + 0x21d01200, + 0x1031f400, +/* 0x002f: spin */ + 0xf40031f4, + 0x0ef40028, +/* 0x0035: ih */ + 0x8001cffd, + 0xb00812c4, + 0x0bf40024, + 0x0027f167, + 0x002bfe77, + 0xf00007fe, + 0x23f00027, + 0x0037f105, + 0x0034cf14, + 0xb0014594, + 0x18f40055, + 0x0602fa17, + 0x4af003f8, + 0x0034d01e, + 0xd00147f0, + 0x0ef48034, +/* 0x0075: ctxload */ + 0x4034cf33, + 0xb0014f94, + 0x18f400f5, + 0x0502fa21, + 0x57f003f8, + 0x0267f000, +/* 0x008c: ctxload_dma_loop */ + 0xa07856bc, + 0xb6018068, + 0x87d00884, + 0x0162b600, +/* 0x009f: dummyload */ + 0xf0f018f4, + 0x35d00257, +/* 0x00a5: noctx */ + 0x0412c480, + 0xf50024b0, + 0xf100df0b, + 0xcf190037, + 0x33cf4032, + 0xff24e400, + 0x1024b607, + 0x07bf45e4, + 0xf50054b0, + 0xf100b90b, + 0xf1fae057, + 0xb000ce67, + 0x18f4c044, + 0xa057f14d, + 0x8867f1fc, + 0x8044b000, + 0xb03f18f4, + 0x18f46044, + 0x5044b019, + 0xf1741bf4, + 0xbd220027, + 0x0233f034, + 0xf50023d0, +/* 0x0103: dma_cmd */ + 0xb000810e, + 0x18f46344, + 0x0245945e, + 0xfe8050b7, + 0x801e39f0, + 0x40b70053, + 0x44b60120, + 0x0043d008, +/* 0x0123: dtable_cmd */ + 0xb8600ef4, + 0x18f40446, + 0x0344b63e, + 0x980045bb, + 0x53fd0145, + 0x0054b004, + 0x58291bf4, + 0x46580045, + 0x0264b001, + 0x98170bf4, + 0x67fd0807, + 0x0164b004, + 0xf9300bf4, + 0x0f01f455, +/* 0x015b: cmd_setctx */ + 0x80280ef4, + 0x0ef40053, +/* 0x0161: invalid_bitfield */ + 0x0125f022, +/* 0x0164: dispatch_error */ +/* 0x0164: illegal_mthd */ + 0x100047f1, + 0xd00042d0, + 0x47f04043, + 0x0004d040, +/* 0x0174: im_loop */ + 0xf08004cf, + 0x44b04044, + 0xf71bf400, +/* 0x0180: cmddone */ + 0x1d0037f1, + 0xd00147f0, +/* 0x018a: nocmd */ + 0x11c40034, + 0x4001d00c, +/* 0x0192: cmd_query_get */ + 0x38f201f8, + 0x0325f001, + 0x0b0047f1, +/* 0x019c: ptimer_retry */ + 0xcf4046cf, + 0x47cf0045, + 0x0467b840, + 0x98f41bf4, + 0x04800504, + 0x21008020, + 0x80220580, + 0x0bfe2306, + 0x03049800, + 0xfe1844b6, + 0x04980047, + 0x8057f104, + 0x0253f000, + 0xf80645fa, +/* 0x01d7: cmd_cond_mode */ + 0xf400f803, + 0x25f00131, + 0x0534b002, + 0xf41218f4, + 0x34b00132, + 0x0b18f402, + 0x800136f0, +/* 0x01f2: return */ + 0x00f80803, +/* 0x01f4: cmd_cond_mode_queryful */ + 0x98060498, + 0x56c40705, + 0x0855b6ff, + 0xfd1844b6, + 0x47fe0545, + 0x000bfe00, + 0x008057f1, + 0xfa0253f0, + 0x34b00565, + 0x131bf402, + 0x049803f8, + 0x0044b021, + 0x800b4cf0, + 0x00f80804, +/* 0x022c: cmd_cond_mode_double */ + 0xb61060b6, + 0x65fa1050, + 0x9803f805, + 0x06982005, + 0x0456b824, + 0x980b4cf0, + 0x06982105, + 0x0456b825, + 0xfd0b5cf0, + 0x34b00445, + 0x0b5cf003, + 0x800645fd, + 0x00f80804, +/* 0x0260: cmd_wrcache_flush */ + 0xf10132f4, + 0xbd220027, + 0x0133f034, + 0xf80023d0, +/* 0x0271: crypt_cmd_mode */ + 0x0131f400, + 0xb00225f0, + 0x18f40f34, + 0x0132f409, +/* 0x0283: crypt_cmd_mode_return */ + 0xf80d0380, +/* 0x0285: crypt_cmd_length */ + 0x0034b000, + 0xf4fb0bf4, + 0x47f0033c, + 0x0743f040, + 0xf00604fa, + 0x43f05047, + 0x0604fa06, + 0x3cf503f8, + 0x47f1c407, + 0x4bfe2100, + 0x09049800, + 0x950a0598, + 0x44b60858, + 0x0548fd18, + 0x98ff55c4, + 0x07980b06, + 0x0878950c, + 0xfd1864b6, + 0x77c40568, + 0x0d0898ff, + 0x580284b6, + 0x95f9a889, + 0xf9a98958, + 0x013cf495, + 0x3cf403f8, + 0xf803f861, + 0x18489503, + 0xbb084994, + 0x81b60095, + 0x09088000, + 0x950a0980, + 0x69941868, + 0x0097bb08, + 0x800081b6, + 0x09800b08, + 0x023cf40c, + 0xf05047f0, + 0x04fa0643, + 0xf803f805, +/* 0x0321: crypt_copy_prep */ + 0x203cf500, + 0x003cf594, + 0x003cf588, +/* 0x032f: crypt_store_prep */ + 0xf500f88c, + 0xf594103c, + 0xf88c063c, +/* 0x0339: crypt_ecb_e_prep */ + 0x303cf500, + 0x003cf594, + 0x003cf588, + 0x003cf5d0, +/* 0x034b: crypt_ecb_d_prep */ + 0xf500f88c, + 0xf5c8773c, + 0xf594303c, + 0xf588003c, + 0xf5d4003c, + 0xf88c003c, +/* 0x0361: crypt_cbc_e_prep */ + 0x403cf500, + 0x003cf594, + 0x063cf588, + 0x663cf5ac, + 0x063cf5d0, +/* 0x0377: crypt_cbc_d_prep */ + 0xf500f88c, + 0xf5c8773c, + 0xf594503c, + 0xf584623c, + 0xf588063c, + 0xf5d4603c, + 0xf5ac203c, + 0xf88c003c, +/* 0x0395: crypt_pcbc_e_prep */ + 0x503cf500, + 0x003cf594, + 0x063cf588, + 0x663cf5ac, + 0x063cf5d0, + 0x063cf58c, +/* 0x03af: crypt_pcbc_d_prep */ + 0xf500f8ac, + 0xf5c8773c, + 0xf594503c, + 0xf588003c, + 0xf5d4013c, + 0xf5ac163c, + 0xf58c063c, + 0xf8ac063c, +/* 0x03cd: crypt_cfb_e_prep */ + 0x403cf500, + 0x663cf594, + 0x003cf5d0, + 0x063cf588, + 0x063cf5ac, +/* 0x03e3: crypt_cfb_d_prep */ + 0xf500f88c, + 0xf594403c, + 0xf5d0603c, + 0xf588063c, + 0xf5ac603c, + 0xf88c003c, +/* 0x03f9: crypt_ofb_prep */ + 0x403cf500, + 0x663cf594, + 0x003cf5d0, + 0x603cf588, + 0x003cf5ac, +/* 0x040f: crypt_ctr_prep */ + 0xf500f88c, + 0xf594503c, + 0xf5d0613c, + 0xf5b0163c, + 0xf588003c, + 0xf5ac103c, + 0xf88c003c, +/* 0x0429: crypt_cbc_mac_prep */ + 0x303cf500, + 0x003cf594, + 0x063cf588, + 0x663cf5ac, +/* 0x043b: crypt_cmac_finish_complete_prep */ + 0xf500f8d0, + 0xf594703c, + 0xf588003c, + 0xf5ac063c, + 0xf5ac003c, + 0xf5d0003c, + 0xf5bc003c, + 0xf5ac063c, + 0xf8d0663c, +/* 0x045d: crypt_cmac_finish_partial_prep */ + 0x803cf500, + 0x003cf594, + 0x063cf588, + 0x003cf5ac, + 0x003cf5ac, + 0x003cf5d0, + 0x003cf5bc, + 0x063cf5bc, + 0x663cf5ac, +/* 0x0483: crypt_do_in */ + 0xbb00f8d0, + 0x47fe0035, + 0x8097f100, + 0x0293f000, +/* 0x0490: crypt_do_in_loop */ + 0xf80559fa, + 0x223cf403, + 0xf50609fa, + 0xf898103c, + 0x1050b603, + 0xf40453b8, + 0x3cf4e91b, + 0xf803f801, +/* 0x04b1: crypt_do_out */ + 0x0037bb00, + 0xf10067fe, + 0xf0008097, +/* 0x04be: crypt_do_out_loop */ + 0x3cf50293, + 0x3cf49810, + 0x0579fa61, + 0xf40679fa, + 0x03f8013c, + 0xb81070b6, + 0x1bf40473, +/* 0x04db: crypt_do_inout */ + 0xbb00f8e8, + 0x97f10035, + 0x93f00080, +/* 0x04e5: crypt_do_inout_loop */ + 0x0047fe02, + 0xf80559fa, + 0x213cf403, + 0xf50609fa, + 0xf498103c, + 0x67fe613c, + 0x0579fa00, + 0xf40679fa, + 0x03f8013c, + 0xb61050b6, + 0x53b81070, + 0xd41bf404, + 0x000000f8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c new file mode 100644 index 00000000000..1d85e5b66ca --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c @@ -0,0 +1,217 @@ +/* + * 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/enum.h> +#include <core/class.h> +#include <core/engctx.h> +#include <core/gpuobj.h> + +#include <subdev/fb.h> + +#include <engine/fifo.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_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)); + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); + nv_wo32(obj, 0x0c, 0x00000000); + return 0; +} + +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_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv84_crypt_chan *priv; + int ret; + + ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256, + 0, NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +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 const struct nouveau_bitfield nv84_crypt_intr_mask[] = { + { 0x00000001, "INVALID_STATE" }, + { 0x00000002, "ILLEGAL_MTHD" }, + { 0x00000004, "ILLEGAL_CLASS" }, + { 0x00000080, "QUERY" }, + { 0x00000100, "FAULT" }, + {} +}; + +static void +nv84_crypt_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + 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; + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat) { + nv_error(priv, ""); + nouveau_bitfield_print(nv84_crypt_intr_mask, stat); + printk(" ch %d [0x%010llx] mthd 0x%04x data 0x%08x\n", + chid, (u64)inst << 12, mthd, data); + } + + nv_wr32(priv, 0x102130, stat); + nv_wr32(priv, 0x10200c, 0x10); + + nv50_fb_trap(nouveau_fb(priv), 1); + nouveau_engctx_put(engctx); +} + +static int +nv84_crypt_tlb_flush(struct nouveau_engine *engine) +{ + nv50_vm_flush_engine(&engine->base, 0x0a); + return 0; +} + +static int +nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv84_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 = 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 int +nv84_crypt_init(struct nouveau_object *object) +{ + struct nv84_crypt_priv *priv = (void *)object; + int ret; + + ret = nouveau_crypt_init(&priv->base); + if (ret) + return ret; + + 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 new file mode 100644 index 00000000000..9e3876c89b9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c @@ -0,0 +1,208 @@ +/* + * 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/enum.h> +#include <core/class.h> +#include <core/engctx.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> + +#include <engine/fifo.h> +#include <engine/crypt.h> + +#include "fuc/nv98.fuc.h" + +struct nv98_crypt_priv { + struct nouveau_crypt base; +}; + +struct nv98_crypt_chan { + struct nouveau_crypt_chan base; +}; + +/******************************************************************************* + * Crypt object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv98_crypt_sclass[] = { + { 0x88b4, &nouveau_object_ofuncs }, + {}, +}; + +/******************************************************************************* + * PCRYPT context + ******************************************************************************/ + +static int +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 *priv; + int ret; + + ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256, + 256, NVOBJ_FLAG_ZERO_ALLOC, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +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, + }, +}; + +/******************************************************************************* + * PCRYPT engine/subdev functions + ******************************************************************************/ + +static const struct nouveau_enum nv98_crypt_isr_error_name[] = { + { 0x0000, "ILLEGAL_MTHD" }, + { 0x0001, "INVALID_BITFIELD" }, + { 0x0002, "INVALID_ENUM" }, + { 0x0003, "QUERY" }, + {} +}; + +static void +nv98_crypt_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + 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(priv, 0x087044); + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x00000040) { + nv_error(priv, "DISPATCH_ERROR ["); + nouveau_enum_print(nv98_crypt_isr_error_name, ssta); + printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n", + chid, (u64)inst << 12, subc, mthd, data); + nv_wr32(priv, 0x087004, 0x00000040); + stat &= ~0x00000040; + } + + if (stat) { + nv_error(priv, "unhandled intr 0x%08x\n", stat); + nv_wr32(priv, 0x087004, stat); + } + + nv50_fb_trap(nouveau_fb(priv), 1); + nouveau_engctx_put(engctx); +} + +static int +nv98_crypt_tlb_flush(struct nouveau_engine *engine) +{ + nv50_vm_flush_engine(&engine->base, 0x0a); + return 0; +} + +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; + + /* wait for exit interrupt to signal */ + nv_wait(priv, 0x087008, 0x00000010, 0x00000010); + nv_wr32(priv, 0x087004, 0x00000010); + + /* 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]); + + nv_wr32(priv, 0x087ff8, 0x00000000); + for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++) + nv_wr32(priv, 0x087ff4, nv98_pcrypt_data[i]); + + /* 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 00000000000..1c919f2af89 --- /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 00000000000..16a9afb1060 --- /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 00000000000..d93efbcf75b --- /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/disp/vga.c b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c new file mode 100644 index 00000000000..5a1c6847459 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c @@ -0,0 +1,215 @@ +/* + * 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/subdev.h> +#include <core/device.h> +#include <subdev/vga.h> + +u8 +nv_rdport(void *obj, int head, u16 port) +{ + struct nouveau_device *device = nv_device(obj); + + if (device->card_type >= NV_50) + return nv_rd08(obj, 0x601000 + port); + + if (port == 0x03c0 || port == 0x03c1 || /* AR */ + port == 0x03c2 || port == 0x03da || /* INP0 */ + port == 0x03d4 || port == 0x03d5) /* CR */ + return nv_rd08(obj, 0x601000 + (head * 0x2000) + port); + + if (port == 0x03c2 || port == 0x03cc || /* MISC */ + port == 0x03c4 || port == 0x03c5 || /* SR */ + port == 0x03ce || port == 0x03cf) { /* GR */ + if (device->card_type < NV_40) + head = 0; /* CR44 selects head */ + return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port); + } + + nv_error(obj, "unknown vga port 0x%04x\n", port); + return 0x00; +} + +void +nv_wrport(void *obj, int head, u16 port, u8 data) +{ + struct nouveau_device *device = nv_device(obj); + + if (device->card_type >= NV_50) + nv_wr08(obj, 0x601000 + port, data); + else + if (port == 0x03c0 || port == 0x03c1 || /* AR */ + port == 0x03c2 || port == 0x03da || /* INP0 */ + port == 0x03d4 || port == 0x03d5) /* CR */ + nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data); + else + if (port == 0x03c2 || port == 0x03cc || /* MISC */ + port == 0x03c4 || port == 0x03c5 || /* SR */ + port == 0x03ce || port == 0x03cf) { /* GR */ + if (device->card_type < NV_40) + head = 0; /* CR44 selects head */ + nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data); + } else + nv_error(obj, "unknown vga port 0x%04x\n", port); +} + +u8 +nv_rdvgas(void *obj, int head, u8 index) +{ + nv_wrport(obj, head, 0x03c4, index); + return nv_rdport(obj, head, 0x03c5); +} + +void +nv_wrvgas(void *obj, int head, u8 index, u8 value) +{ + nv_wrport(obj, head, 0x03c4, index); + nv_wrport(obj, head, 0x03c5, value); +} + +u8 +nv_rdvgag(void *obj, int head, u8 index) +{ + nv_wrport(obj, head, 0x03ce, index); + return nv_rdport(obj, head, 0x03cf); +} + +void +nv_wrvgag(void *obj, int head, u8 index, u8 value) +{ + nv_wrport(obj, head, 0x03ce, index); + nv_wrport(obj, head, 0x03cf, value); +} + +u8 +nv_rdvgac(void *obj, int head, u8 index) +{ + nv_wrport(obj, head, 0x03d4, index); + return nv_rdport(obj, head, 0x03d5); +} + +void +nv_wrvgac(void *obj, int head, u8 index, u8 value) +{ + nv_wrport(obj, head, 0x03d4, index); + nv_wrport(obj, head, 0x03d5, value); +} + +u8 +nv_rdvgai(void *obj, int head, u16 port, u8 index) +{ + if (port == 0x03c4) return nv_rdvgas(obj, head, index); + if (port == 0x03ce) return nv_rdvgag(obj, head, index); + if (port == 0x03d4) return nv_rdvgac(obj, head, index); + nv_error(obj, "unknown indexed vga port 0x%04x\n", port); + return 0x00; +} + +void +nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) +{ + if (port == 0x03c4) nv_wrvgas(obj, head, index, value); + else if (port == 0x03ce) nv_wrvgag(obj, head, index, value); + else if (port == 0x03d4) nv_wrvgac(obj, head, index, value); + else nv_error(obj, "unknown indexed vga port 0x%04x\n", port); +} + +bool +nv_lockvgac(void *obj, bool lock) +{ + bool locked = !nv_rdvgac(obj, 0, 0x1f); + u8 data = lock ? 0x99 : 0x57; + nv_wrvgac(obj, 0, 0x1f, data); + if (nv_device(obj)->chipset == 0x11) { + if (!(nv_rd32(obj, 0x001084) & 0x10000000)) + nv_wrvgac(obj, 1, 0x1f, data); + } + return locked; +} + +/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied) + * it affects only the 8 bit vga io regs, which we access using mmio at + * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d* + * in general, the set value of cr44 does not matter: reg access works as + * expected and values can be set for the appropriate head by using a 0x2000 + * offset as required + * however: + * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and + * cr44 must be set to 0 or 3 for accessing values on the correct head + * through the common 0xc03c* addresses + * b) in tied mode (4) head B is programmed to the values set on head A, and + * access using the head B addresses can have strange results, ergo we leave + * tied mode in init once we know to what cr44 should be restored on exit + * + * the owner parameter is slightly abused: + * 0 and 1 are treated as head values and so the set value is (owner * 3) + * other values are treated as literal values to set + */ +u8 +nv_rdvgaowner(void *obj) +{ + if (nv_device(obj)->card_type < NV_50) { + if (nv_device(obj)->chipset == 0x11) { + u32 tied = nv_rd32(obj, 0x001084) & 0x10000000; + if (tied == 0) { + u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80; + u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01; + u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80; + u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01; + if (slA && !tvA) return 0x00; + if (slB && !tvB) return 0x03; + if (slA) return 0x00; + if (slB) return 0x03; + return 0x00; + } + return 0x04; + } + + return nv_rdvgac(obj, 0, 0x44); + } + + nv_error(obj, "rdvgaowner after nv4x\n"); + return 0x00; +} + +void +nv_wrvgaowner(void *obj, u8 select) +{ + if (nv_device(obj)->card_type < NV_50) { + u8 owner = (select == 1) ? 3 : select; + if (nv_device(obj)->chipset == 0x11) { + /* workaround hw lockup bug */ + nv_rdvgac(obj, 0, 0x1f); + nv_rdvgac(obj, 1, 0x1f); + } + + nv_wrvgac(obj, 0, 0x44, owner); + + if (nv_device(obj)->chipset == 0x11) { + nv_wrvgac(obj, 0, 0x2e, owner); + nv_wrvgac(obj, 0, 0x2e, owner); + } + } else + nv_error(obj, "wrvgaowner after nv4x\n"); +} 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 00000000000..e1f013d3976 --- /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 00000000000..9f4cc2f3199 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c @@ -0,0 +1,185 @@ +/* + * 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 <core/class.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 nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaeng); + struct nouveau_gpuobj *gpuobj; + u32 flags0 = nv_mclass(dmaobj); + u32 flags2 = 0x00000000; + u64 offset = dmaobj->start & 0xfffff000; + u64 adjust = dmaobj->start & 0x00000fff; + u32 length = dmaobj->limit - dmaobj->start; + int ret; + + if (dmaobj->target == NV_MEM_TARGET_VM) { + if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) { + struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0]; + if (!dmaobj->start) + return nouveau_gpuobj_dup(parent, pgt, pgpuobj); + offset = nv_ro32(pgt, 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 NV_DEVICE_CLASS: + break; + case NV03_CHANNEL_DMA_CLASS: + case NV10_CHANNEL_DMA_CLASS: + case NV17_CHANNEL_DMA_CLASS: + case NV40_CHANNEL_DMA_CLASS: + ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj); + nouveau_object_ref(NULL, pobject); + *pobject = nv_object(gpuobj); + break; + default: + return -EINVAL; + } + + 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 00000000000..045d2565e28 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c @@ -0,0 +1,173 @@ +/* + * 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 <core/class.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 NV_DEVICE_CLASS: + break; + case NV50_CHANNEL_DMA_CLASS: + case NV84_CHANNEL_DMA_CLASS: + case NV50_CHANNEL_IND_CLASS: + case NV84_CHANNEL_IND_CLASS: + ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj); + nouveau_object_ref(NULL, pobject); + *pobject = nv_object(gpuobj); + break; + default: + return -EINVAL; + } + + 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 00000000000..5baa0869553 --- /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 00000000000..bbb43c67c2a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c @@ -0,0 +1,181 @@ +/* + * 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); +} + +static int +nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object) +{ + int engidx = nv_hclass(priv) & 0xff; + + while (object && object->parent) { + if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) && + (nv_hclass(object->parent) & 0xff) == engidx) + return nouveau_fifo_chan(object)->chid; + object = object->parent; + } + + return -1; +} + +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; + + priv->chid = nouveau_fifo_chid; + 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 new file mode 100644 index 00000000000..ea76e3e8c9c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c @@ -0,0 +1,630 @@ +/* + * 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/ramht.h> + +#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 }, + { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 }, + {} +}; + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + +int +nv04_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 |= 0x00010000; + break; + case NVDEV_ENGINE_MPEG: + context |= 0x00020000; + break; + default: + return -EINVAL; + } + + 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); +} + +int +nv04_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *object) +{ + nv_engctx(object)->addr = nouveau_fifo_chan(parent)->chid; + return 0; +} + +static int +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 nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo_chan *chan; + struct nv03_channel_dma_class *args = data; + int ret; + + 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; + nv_parent(chan)->context_attach = nv04_fifo_context_attach; + 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 + 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; + + do { + nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000); + } while ((++c)->bits); + + nouveau_fifo_channel_destroy(&chan->base); +} + +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) + 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; +} + +int +nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend) +{ + 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; + u32 data = chan->ramfc; + u32 chid; + + /* prevent fifo context switches */ + 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(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 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(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(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[] = { + { NV03_CHANNEL_DMA_CLASS, &nv04_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ + +int +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 nv04_fifo_base *base; + int ret; + + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + return 0; +} + +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, + }, +}; + +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ + +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; + + 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); +} + +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; + + nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); + nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001); + + spin_unlock_irqrestore(&priv->base.lock, flags); +} + +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]; +} + +static bool +nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data) +{ + 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(&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 = nouveau_namedb_get(nv_namedb(chan), data); + if (unlikely(!bind)) + break; + + 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); + } + + nouveau_namedb_put(bind); + break; + default: + engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE); + if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) + break; + + 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(&priv->base.lock, flags); + return handled; +} + +void +nv04_fifo_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_device *device = nv_device(subdev); + struct nv04_fifo_priv *priv = (void *)subdev; + uint32_t status, reassign; + int cnt = 0; + + 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(priv, NV03_PFIFO_CACHES, 0); + + 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; + int ptr; + + /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before + * wrapping on my G80 chips, but CACHE1 isn't big + * enough for this much data.. Tests show that it + * wraps around to the start at GET=0x800.. No clue + * as to why.. + */ + ptr = (get & 0x7ff) >> 2; + + if (device->card_type < NV_40) { + mthd = nv_rd32(priv, + NV04_PFIFO_CACHE1_METHOD(ptr)); + data = nv_rd32(priv, + NV04_PFIFO_CACHE1_DATA(ptr)); + } else { + mthd = nv_rd32(priv, + NV40_PFIFO_CACHE1_METHOD(ptr)); + data = nv_rd32(priv, + NV40_PFIFO_CACHE1_DATA(ptr)); + } + + 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(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0); + nv_wr32(priv, NV03_PFIFO_INTR_0, + NV_PFIFO_INTR_CACHE_ERROR); + + 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(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(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(priv, 0x003364, 0x00000000); + if (dma_get != dma_put || ho_get != ho_put) { + nv_wr32(priv, 0x003244, dma_put); + nv_wr32(priv, 0x003328, ho_put); + } else + if (ib_get != ib_put) { + nv_wr32(priv, 0x003334, ib_put); + } + } else { + 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(priv, 0x003244, dma_put); + } + + 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; + } + + if (status & NV_PFIFO_INTR_SEMAPHORE) { + uint32_t sem; + + status &= ~NV_PFIFO_INTR_SEMAPHORE; + nv_wr32(priv, NV03_PFIFO_INTR_0, + NV_PFIFO_INTR_SEMAPHORE); + + sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE); + nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + + nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + } + + if (device->card_type == NV_50) { + if (status & 0x00000010) { + nv50_fb_trap(nouveau_fb(priv), 1); + status &= ~0x00000010; + nv_wr32(priv, 0x002100, 0x00000010); + } + } + + if (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(priv, NV03_PFIFO_CACHES, reassign); + } + + if (status) { + nv_info(priv, "still angry after %d spins, halt\n", cnt); + nv_wr32(priv, 0x002140, 0); + nv_wr32(priv, 0x000140, 0); + } + + nv_wr32(priv, 0x000100, 0x00000100); +} + +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 nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_fifo_priv *priv; + int ret; + + 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); + nouveau_ramht_ref(NULL, &priv->ramht); + nouveau_fifo_destroy(&priv->base); +} + +int +nv04_fifo_init(struct nouveau_object *object) +{ + struct nv04_fifo_priv *priv = (void *)object; + int ret; + + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); + nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + + 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); + + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + + 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 00000000000..496a4b4fdfa --- /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 new file mode 100644 index 00000000000..4ba75422b89 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c @@ -0,0 +1,171 @@ +/* + * 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/ramht.h> + +#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 }, + { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, + { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 }, + {} +}; + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + +static int +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 nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo_chan *chan; + struct nv03_channel_dma_class *args = data; + int ret; + + 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; + nv_parent(chan)->context_attach = nv04_fifo_context_attach; + 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; +} + +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, +}; + +static struct nouveau_oclass +nv10_fifo_sclass[] = { + { NV10_CHANNEL_DMA_CLASS, &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 + ******************************************************************************/ + +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 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) + 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 new file mode 100644 index 00000000000..b96e6b0ae2b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c @@ -0,0 +1,208 @@ +/* + * 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/ramht.h> + +#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 }, + { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, + { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 }, + { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE }, + { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP }, + { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT }, + { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE }, + { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE }, + {} +}; + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + +static int +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 nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo_chan *chan; + struct nv03_channel_dma_class *args = data; + int ret; + + 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; + nv_parent(chan)->context_attach = nv04_fifo_context_attach; + 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; +} + +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, +}; + +static struct nouveau_oclass +nv17_fifo_sclass[] = { + { NV17_CHANNEL_DMA_CLASS, &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_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) + 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; +} + +static int +nv17_fifo_init(struct nouveau_object *object) +{ + struct nv04_fifo_priv *priv = (void *)object; + int ret; + + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); + nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + + 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(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + + 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 +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 new file mode 100644 index 00000000000..559c3b4e1b8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c @@ -0,0 +1,349 @@ +/* + * 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/ramht.h> + +#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 }, + { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 2, 28, 0x18, 28, 0x002058 }, + { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 }, + { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE }, + { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP }, + { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT }, + { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE }, + { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE }, + { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE }, + { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE }, + { 32, 0, 0x40, 0, 0x0032e4 }, + { 32, 0, 0x44, 0, 0x0032e8 }, + { 32, 0, 0x4c, 0, 0x002088 }, + { 32, 0, 0x50, 0, 0x003300 }, + { 32, 0, 0x54, 0, 0x00330c }, + {} +}; + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + +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_attach(struct nouveau_object *parent, + 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; + + 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_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4; + nv_mask(priv, 0x002500, 0x00000001, 0x00000000); + + if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid) + nv_wr32(priv, reg, nv_engctx(engctx)->addr); + nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); + + nv_mask(priv, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&priv->base.lock, flags); + return 0; +} + +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; + + 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); + + 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 nv03_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, 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[] = { + { NV40_CHANNEL_DMA_CLASS, &nv40_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ + +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, + }, +}; + +/******************************************************************************* + * 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) + 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 nouveau_object *object) +{ + struct nv04_fifo_priv *priv = (void *)object; + struct nouveau_fb *pfb = nouveau_fb(object); + int ret; + + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, 0x002040, 0x000000ff); + nv_wr32(priv, 0x002044, 0x2101ffff); + nv_wr32(priv, 0x002058, 0x00000001); + + 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 (nv_device(priv)->chipset) { + case 0x47: + case 0x49: + case 0x4b: + nv_wr32(priv, 0x002230, 0x00000001); + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x45: + case 0x48: + nv_wr32(priv, 0x002220, 0x00030002); + break; + default: + nv_wr32(priv, 0x002230, 0x00000000); + nv_wr32(priv, 0x002220, ((pfb->ram.size - 512 * 1024 + + priv->ramfc->addr) >> 16) | + 0x00030000); + break; + } + + nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + + 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 +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 new file mode 100644 index 00000000000..536e7634a00 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c @@ -0,0 +1,502 @@ +/* + * 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/client.h> +#include <core/engctx.h> +#include <core/ramht.h> +#include <core/class.h> +#include <core/math.h> + +#include <subdev/timer.h> +#include <subdev/bar.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> + +#include "nv50.h" + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + +void +nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) +{ + 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 = priv->base.min, p = 0; i < priv->base.max; i++) { + if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000) + nv_wo32(cur, p++ * 4, i); + } + + bar->flush(bar); + + nv_wr32(priv, 0x0032f4, cur->addr >> 12); + nv_wr32(priv, 0x0032ec, p); + nv_wr32(priv, 0x002500, 0x00000101); +} + +static int +nv50_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *object) +{ + 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; + } + + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + 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 int +nv50_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, 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: + * + * PFIFO will hang forever if the connected engines don't report + * that they've processed the context switch request. + * + * In order for the kickoff to work, we need to ensure all the + * connected engines are in a state where they can answer. + * + * Newer chipsets don't seem to suffer from this issue, and well, + * there's also a "ignore these engines" bitmask reg we can use + * if we hit the issue there.. + */ + me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001); + + /* do the kickoff... */ + 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; + } + + nv_wr32(priv, 0x00b860, me); + return ret; +} + +static int +nv50_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 : context |= 0x00200000; break; + default: + return -EINVAL; + } + + 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_chan_ctor_dma(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 nv03_channel_dma_class *args = data; + 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; + + 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; + + ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht); + if (ret) + return ret; + + nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x3c, 0x003f6078); + nv_wo32(base->ramfc, 0x44, 0x01003fff); + nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nv_wo32(base->ramfc, 0x4c, 0xffffffff); + 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; +} + +static int +nv50_fifo_chan_ctor_ind(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_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; + + 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; + + 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_chan_init(struct nouveau_object *object) +{ + 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; + + nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); + nv50_fifo_playlist_update(priv); + return 0; +} + +int +nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend) +{ + 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); +} + +static struct nouveau_ofuncs +nv50_fifo_ofuncs_dma = { + .ctor = nv50_fifo_chan_ctor_dma, + .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_ofuncs +nv50_fifo_ofuncs_ind = { + .ctor = nv50_fifo_chan_ctor_ind, + .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[] = { + { NV50_CHANNEL_DMA_CLASS, &nv50_fifo_ofuncs_dma }, + { NV50_CHANNEL_IND_CLASS, &nv50_fifo_ofuncs_ind }, + {} +}; + +/******************************************************************************* + * 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 nv50_fifo_base *base; + int ret; + + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + 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; + + return 0; +} + +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 nv50_fifo_priv *priv; + int ret; + + ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[0]); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[1]); + if (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 00000000000..3a9ceb315c2 --- /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 new file mode 100644 index 00000000000..b4fd26d8f16 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c @@ -0,0 +1,420 @@ +/* + * 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/client.h> +#include <core/engctx.h> +#include <core/ramht.h> +#include <core/class.h> +#include <core/math.h> + +#include <subdev/timer.h> +#include <subdev/bar.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> + +#include "nv50.h" + +/******************************************************************************* + * FIFO channel objects + ******************************************************************************/ + +static int +nv84_fifo_context_attach(struct nouveau_object *parent, + struct nouveau_object *object) +{ + 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; + } + + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + 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 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, save, engn; + bool done; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break; + case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break; + case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break; + case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; 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); + + save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn); + nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); + done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff); + nv_wr32(priv, 0x002520, save); + if (!done) { + nv_error(priv, "channel %d unload timeout\n", chan->base.chid); + if (suspend) + return -EBUSY; + } + return 0; +} + +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; + } + + return nouveau_ramht_insert(chan->ramht, 0, handle, context); +} + +static int +nv84_fifo_chan_ctor_dma(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 nv03_channel_dma_class *args = data; + 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) | + (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; + + ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht); + if (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; + + nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x3c, 0x003f6078); + nv_wo32(base->ramfc, 0x44, 0x01003fff); + nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nv_wo32(base->ramfc, 0x4c, 0xffffffff); + 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 int +nv84_fifo_chan_ctor_ind(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 nv50_channel_ind_class *args = data; + 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) | + (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; + + ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht); + if (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 int +nv84_fifo_chan_init(struct nouveau_object *object) +{ + 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; + + nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); + nv50_fifo_playlist_update(priv); + return 0; +} + +static struct nouveau_ofuncs +nv84_fifo_ofuncs_dma = { + .ctor = nv84_fifo_chan_ctor_dma, + .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, +}; + +static struct nouveau_ofuncs +nv84_fifo_ofuncs_ind = { + .ctor = nv84_fifo_chan_ctor_ind, + .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, +}; + +static struct nouveau_oclass +nv84_fifo_sclass[] = { + { NV84_CHANNEL_DMA_CLASS, &nv84_fifo_ofuncs_dma }, + { NV84_CHANNEL_IND_CLASS, &nv84_fifo_ofuncs_ind }, + {} +}; + +/******************************************************************************* + * FIFO context - basically just the instmem reserved for the channel + ******************************************************************************/ + +static 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; + + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 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; + + 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; + + return 0; +} + +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, + }, +}; + +/******************************************************************************* + * PFIFO engine + ******************************************************************************/ + +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 nv50_fifo_priv *priv; + int ret; + + ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[0]); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, + &priv->playlist[1]); + if (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 new file mode 100644 index 00000000000..6f21be60055 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -0,0 +1,647 @@ +/* + * 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/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 <subdev/timer.h> +#include <subdev/bar.h> +#include <subdev/vm.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> + +struct nvc0_fifo_priv { + struct nouveau_fifo base; + struct nouveau_gpuobj *playlist[2]; + int cur_playlist; + struct { + struct nouveau_gpuobj *mem; + struct nouveau_vma bar; + } user; + 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 nvc0_fifo_priv *priv) +{ + 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 < 128; i++) { + if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1)) + continue; + nv_wo32(cur, p + 0, i); + nv_wo32(cur, p + 4, 0x00000004); + p += 8; + } + bar->flush(bar); + + 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_attach(struct nouveau_object *parent, + struct nouveau_object *object) +{ + 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; + + 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; + } + + 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_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + } + + 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 int +nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend, + struct nouveau_object *object) +{ + 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; + } + + 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_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 nvc0_fifo_priv *priv = (void *)engine; + struct nvc0_fifo_base *base = (void *)parent; + struct nvc0_fifo_chan *chan; + struct nv50_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, 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; +} + +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; + + ret = nouveau_fifo_channel_init(&chan->base); + if (ret) + return ret; + + nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); + nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); + nvc0_fifo_playlist_update(priv); + return 0; +} + +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_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + nvc0_fifo_playlist_update(priv); + nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); + + return nouveau_fifo_channel_fini(&chan->base, suspend); +} + +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, +}; + +static struct nouveau_oclass +nvc0_fifo_sclass[] = { + { NVC0_CHANNEL_IND_CLASS, &nvc0_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - instmem heap and vm setup + ******************************************************************************/ + +static int +nvc0_fifo_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_fifo_base *base; + int ret; + + 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; + + 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; + + 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 + ******************************************************************************/ + +static const struct nouveau_enum nvc0_fifo_fault_unit[] = { + { 0x00, "PGRAPH" }, + { 0x03, "PEEPHOLE" }, + { 0x04, "BAR1" }, + { 0x05, "BAR3" }, + { 0x07, "PFIFO" }, + { 0x10, "PBSP" }, + { 0x11, "PPPP" }, + { 0x13, "PCOUNTER" }, + { 0x14, "PVP" }, + { 0x15, "PCOPY0" }, + { 0x16, "PCOPY1" }, + { 0x17, "PDAEMON" }, + {} +}; + +static const struct nouveau_enum nvc0_fifo_fault_reason[] = { + { 0x00, "PT_NOT_PRESENT" }, + { 0x01, "PT_TOO_SHORT" }, + { 0x02, "PAGE_NOT_PRESENT" }, + { 0x03, "VM_LIMIT_EXCEEDED" }, + { 0x04, "NO_CHANNEL" }, + { 0x05, "PAGE_SYSTEM_ONLY" }, + { 0x06, "PAGE_READ_ONLY" }, + { 0x0a, "COMPRESSED_SYSRAM" }, + { 0x0c, "INVALID_STORAGE_TYPE" }, + {} +}; + +static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = { + { 0x01, "PCOPY0" }, + { 0x02, "PCOPY1" }, + { 0x04, "DISPATCH" }, + { 0x05, "CTXCTL" }, + { 0x06, "PFIFO" }, + { 0x07, "BAR_READ" }, + { 0x08, "BAR_WRITE" }, + { 0x0b, "PVP" }, + { 0x0c, "PPPP" }, + { 0x0d, "PBSP" }, + { 0x11, "PCOUNTER" }, + { 0x12, "PDAEMON" }, + { 0x14, "CCACHE" }, + { 0x15, "CCACHE_POST" }, + {} +}; + +static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = { + { 0x01, "TEX" }, + { 0x0c, "ESETUP" }, + { 0x0e, "CTXCTL" }, + { 0x0f, "PROP" }, + {} +}; + +static const struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = { +/* { 0x00008000, "" } seen with null ib push */ + { 0x00200000, "ILLEGAL_MTHD" }, + { 0x00800000, "EMPTY_SUBC" }, + {} +}; + +static void +nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit) +{ + u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); + u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); + u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); + u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + u32 client = (stat & 0x00001f00) >> 8; + + switch (unit) { + case 3: /* PEEPHOLE */ + nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + break; + case 4: /* BAR1 */ + nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + break; + case 5: /* BAR3 */ + nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + break; + default: + break; + } + + 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); + if (stat & 0x00000040) { + printk("/"); + nouveau_enum_print(nvc0_fifo_fault_hubclient, client); + } else { + printk("/GPC%d/", (stat & 0x1f000000) >> 24); + nouveau_enum_print(nvc0_fifo_fault_gpcclient, client); + } + printk(" on channel 0x%010llx\n", (u64)inst << 12); +} + +static int +nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) +{ + struct nvc0_fifo_chan *chan = NULL; + struct nouveau_handle *bind; + unsigned long flags; + int ret = -EINVAL; + + 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); + } + +out: + spin_unlock_irqrestore(&priv->base.lock, flags); + return ret; +} + +static void +nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) +{ + 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_swmthd(priv, chid, 0x0500, 0x00000000)) + show &= ~0x00200000; + } + } + + if (stat & 0x00800000) { + if (!nvc0_fifo_swmthd(priv, chid, mthd, data)) + show &= ~0x00800000; + } + + if (show) { + nv_error(priv, "SUBFIFO%d:", unit); + nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); + 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(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); + nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); +} + +static void +nvc0_fifo_intr(struct nouveau_subdev *subdev) +{ + 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(priv, "unknown status 0x00000100\n"); + nv_wr32(priv, 0x002100, 0x00000100); + stat &= ~0x00000100; + } + + if (stat & 0x10000000) { + u32 units = nv_rd32(priv, 0x00259c); + u32 u = units; + + while (u) { + int i = ffs(u) - 1; + nvc0_fifo_isr_vm_fault(priv, i); + u &= ~(1 << i); + } + + nv_wr32(priv, 0x00259c, units); + stat &= ~0x10000000; + } + + if (stat & 0x20000000) { + u32 units = nv_rd32(priv, 0x0025a0); + u32 u = units; + + while (u) { + int i = ffs(u) - 1; + nvc0_fifo_isr_subfifo_intr(priv, i); + u &= ~(1 << i); + } + + nv_wr32(priv, 0x0025a0, units); + stat &= ~0x20000000; + } + + if (stat & 0x40000000) { + nv_warn(priv, "unknown status 0x40000000\n"); + nv_mask(priv, 0x002a00, 0x00000000, 0x00000000); + stat &= ~0x40000000; + } + + if (stat) { + 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_dtor(struct nouveau_object *object) +{ + 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]); + + nouveau_fifo_destroy(&priv->base); +} + +static int +nvc0_fifo_init(struct nouveau_object *object) +{ + struct nvc0_fifo_priv *priv = (void *)object; + int ret, i; + + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, 0x000204, 0xffffffff); + nv_wr32(priv, 0x002204, 0xffffffff); + + priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204)); + nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr); + + /* 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 */ + } + + /* 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 */ + } + + nv_mask(priv, 0x002200, 0x00000001, 0x00000001); + nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + + 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 new file mode 100644 index 00000000000..36e81b6fafb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -0,0 +1,628 @@ +/* + * 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/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 <subdev/timer.h> +#include <subdev/bar.h> +#include <subdev/vm.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> + +#define _(a,b) { (a), ((1 << (a)) | (b)) } +static const struct { + int subdev; + u32 mask; +} fifo_engine[] = { + _(NVDEV_ENGINE_GR , (1 << NVDEV_ENGINE_SW)), + _(NVDEV_ENGINE_VP , 0), + _(NVDEV_ENGINE_PPP , 0), + _(NVDEV_ENGINE_BSP , 0), + _(NVDEV_ENGINE_COPY0 , 0), + _(NVDEV_ENGINE_COPY1 , 0), + _(NVDEV_ENGINE_VENC , 0), +}; +#undef _ +#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) + +struct nve0_fifo_engn { + struct nouveau_gpuobj *playlist[2]; + int cur_playlist; +}; + +struct nve0_fifo_priv { + struct nouveau_fifo base; + struct nve0_fifo_engn engine[FIFO_ENGINE_NR]; + struct { + struct nouveau_gpuobj *mem; + struct nouveau_vma bar; + } user; + 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 nve0_fifo_priv *priv, u32 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 i, p; + + cur = engn->playlist[engn->cur_playlist]; + if (unlikely(cur == NULL)) { + int ret = nouveau_gpuobj_new(nv_object(priv)->parent, NULL, + 0x8000, 0x1000, 0, &cur); + if (ret) { + nv_error(priv, "playlist alloc failed\n"); + return; + } + + engn->playlist[engn->cur_playlist] = cur; + } + + engn->cur_playlist = !engn->cur_playlist; + + 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; + } + bar->flush(bar); + + 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_attach(struct nouveau_object *parent, + struct nouveau_object *object) +{ + 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 : + case NVDEV_ENGINE_COPY0: + case NVDEV_ENGINE_COPY1: addr = 0x0210; break; + default: + return -EINVAL; + } + + 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_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + } + + 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 int +nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend, + struct nouveau_object *object) +{ + 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 : + case NVDEV_ENGINE_COPY0: + case NVDEV_ENGINE_COPY1: 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; + } + + return 0; +} + +static int +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 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 nve0_channel_ind_class *args = data; + u64 usermem, ioffset, ilength; + int ret, i; + + if (size < sizeof(*args)) + return -EINVAL; + + for (i = 0; i < FIFO_ENGINE_NR; i++) { + if (args->engine & (1 << i)) { + if (nouveau_engine(parent, fifo_engine[i].subdev)) { + args->engine = (1 << i); + break; + } + } + } + + if (i == FIFO_ENGINE_NR) + return -ENODEV; + + ret = nouveau_fifo_channel_create(parent, engine, oclass, 1, + priv->user.bar.offset, 0x200, + args->pushbuf, + fifo_engine[i].mask, &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; + chan->engine = i; + + 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; +} + +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; + + ret = nouveau_fifo_channel_init(&chan->base); + if (ret) + return ret; + + nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); + 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; +} + +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_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + nve0_fifo_playlist_update(priv, chan->engine); + nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); + + return nouveau_fifo_channel_fini(&chan->base, suspend); +} + +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, +}; + +static struct nouveau_oclass +nve0_fifo_sclass[] = { + { NVE0_CHANNEL_IND_CLASS, &nve0_fifo_ofuncs }, + {} +}; + +/******************************************************************************* + * FIFO context - instmem heap and vm setup + ******************************************************************************/ + +static int +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_base *base; + int ret; + + ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + 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; + + 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 + ******************************************************************************/ + +static const struct nouveau_enum nve0_fifo_fault_unit[] = { + {} +}; + +static const struct nouveau_enum nve0_fifo_fault_reason[] = { + { 0x00, "PT_NOT_PRESENT" }, + { 0x01, "PT_TOO_SHORT" }, + { 0x02, "PAGE_NOT_PRESENT" }, + { 0x03, "VM_LIMIT_EXCEEDED" }, + { 0x04, "NO_CHANNEL" }, + { 0x05, "PAGE_SYSTEM_ONLY" }, + { 0x06, "PAGE_READ_ONLY" }, + { 0x0a, "COMPRESSED_SYSRAM" }, + { 0x0c, "INVALID_STORAGE_TYPE" }, + {} +}; + +static const struct nouveau_enum nve0_fifo_fault_hubclient[] = { + {} +}; + +static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = { + {} +}; + +static const struct nouveau_bitfield nve0_fifo_subfifo_intr[] = { + { 0x00200000, "ILLEGAL_MTHD" }, + { 0x00800000, "EMPTY_SUBC" }, + {} +}; + +static void +nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit) +{ + 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_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); + if (stat & 0x00000040) { + printk("/"); + nouveau_enum_print(nve0_fifo_fault_hubclient, client); + } else { + printk("/GPC%d/", (stat & 0x1f000000) >> 24); + nouveau_enum_print(nve0_fifo_fault_gpcclient, client); + } + printk(" on channel 0x%010llx\n", (u64)inst << 12); +} + +static int +nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) +{ + struct nve0_fifo_chan *chan = NULL; + struct nouveau_handle *bind; + unsigned long flags; + int ret = -EINVAL; + + 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); + } + +out: + spin_unlock_irqrestore(&priv->base.lock, flags); + return ret; +} + +static void +nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit) +{ + 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_swmthd(priv, chid, 0x0500, 0x00000000)) + show &= ~0x00200000; + } + } + + if (stat & 0x00800000) { + if (!nve0_fifo_swmthd(priv, chid, mthd, data)) + show &= ~0x00800000; + } + + if (show) { + nv_error(priv, "SUBFIFO%d:", unit); + nouveau_bitfield_print(nve0_fifo_subfifo_intr, show); + 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(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); + nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); +} + +static void +nve0_fifo_intr(struct nouveau_subdev *subdev) +{ + struct nve0_fifo_priv *priv = (void *)subdev; + u32 mask = nv_rd32(priv, 0x002140); + u32 stat = nv_rd32(priv, 0x002100) & mask; + + if (stat & 0x00000100) { + nv_warn(priv, "unknown status 0x00000100\n"); + nv_wr32(priv, 0x002100, 0x00000100); + stat &= ~0x00000100; + } + + if (stat & 0x10000000) { + u32 units = nv_rd32(priv, 0x00259c); + u32 u = units; + + while (u) { + int i = ffs(u) - 1; + nve0_fifo_isr_vm_fault(priv, i); + u &= ~(1 << i); + } + + nv_wr32(priv, 0x00259c, units); + stat &= ~0x10000000; + } + + if (stat & 0x20000000) { + u32 units = nv_rd32(priv, 0x0025a0); + u32 u = units; + + while (u) { + int i = ffs(u) - 1; + nve0_fifo_isr_subfifo_intr(priv, i); + u &= ~(1 << i); + } + + nv_wr32(priv, 0x0025a0, units); + stat &= ~0x20000000; + } + + if (stat & 0x40000000) { + nv_warn(priv, "unknown status 0x40000000\n"); + nv_mask(priv, 0x002a00, 0x00000000, 0x00000000); + stat &= ~0x40000000; + } + + if (stat) { + 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_dtor(struct nouveau_object *object) +{ + 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 < ARRAY_SIZE(priv->engine); i++) { + nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]); + nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]); + } + + nouveau_fifo_destroy(&priv->base); +} + +static int +nve0_fifo_init(struct nouveau_object *object) +{ + struct nve0_fifo_priv *priv = (void *)object; + int ret, i; + + ret = nouveau_fifo_init(&priv->base); + if (ret) + return ret; + + /* 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); + + /* 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 */ + } + + nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + + 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 new file mode 100644 index 00000000000..e1947013d3b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h @@ -0,0 +1,129 @@ +#ifndef __NOUVEAU_GRCTX_H__ +#define __NOUVEAU_GRCTX_H__ + +struct nouveau_grctx { + struct nouveau_device *device; + + enum { + NOUVEAU_GRCTX_PROG, + NOUVEAU_GRCTX_VALS + } mode; + void *data; + + 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, u32 inst) +{ + u32 *ctxprog = ctx->data; + + if (ctx->mode != NOUVEAU_GRCTX_PROG) + return; + + BUG_ON(ctx->ctxprog_len == ctx->ctxprog_max); + ctxprog[ctx->ctxprog_len++] = inst; +} + +static inline void +cp_lsr(struct nouveau_grctx *ctx, u32 val) +{ + cp_out(ctx, CP_LOAD_SR | val); +} + +static inline void +cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length) +{ + ctx->ctxprog_reg = (reg - 0x00400000) >> 2; + + ctx->ctxvals_base = ctx->ctxvals_pos; + ctx->ctxvals_pos = ctx->ctxvals_base + length; + + if (length > (CP_CTX_COUNT >> CP_CTX_COUNT_SHIFT)) { + cp_lsr(ctx, length); + length = 0; + } + + cp_out(ctx, CP_CTX | (length << CP_CTX_COUNT_SHIFT) | ctx->ctxprog_reg); +} + +static inline void +cp_name(struct nouveau_grctx *ctx, int name) +{ + u32 *ctxprog = ctx->data; + int i; + + if (ctx->mode != NOUVEAU_GRCTX_PROG) + return; + + ctx->ctxprog_label[name] = ctx->ctxprog_len; + for (i = 0; i < ctx->ctxprog_len; i++) { + if ((ctxprog[i] & 0xfff00000) != 0xff400000) + continue; + if ((ctxprog[i] & CP_BRA_IP) != ((name) << CP_BRA_IP_SHIFT)) + continue; + ctxprog[i] = (ctxprog[i] & 0x00ff00ff) | + (ctx->ctxprog_len << CP_BRA_IP_SHIFT); + } +} + +static inline void +_cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name) +{ + int ip = 0; + + if (mod != 2) { + ip = ctx->ctxprog_label[name] << CP_BRA_IP_SHIFT; + if (ip == 0) + ip = 0xff000000 | (name << CP_BRA_IP_SHIFT); + } + + cp_out(ctx, CP_BRA | (mod << 18) | ip | flag | + (state ? 0 : CP_BRA_IF_CLEAR)); +} +#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n) +#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n) +#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0) + +static inline void +_cp_wait(struct nouveau_grctx *ctx, int flag, int state) +{ + cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0)); +} +#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s) + +static inline void +_cp_set(struct nouveau_grctx *ctx, int flag, int state) +{ + cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0)); +} +#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s) + +static inline void +cp_pos(struct nouveau_grctx *ctx, int offset) +{ + ctx->ctxvals_pos = offset; + ctx->ctxvals_base = ctx->ctxvals_pos; + + cp_lsr(ctx, ctx->ctxvals_pos); + cp_out(ctx, CP_SET_CONTEXT_POINTER); +} + +static inline void +gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val) +{ + if (ctx->mode != NOUVEAU_GRCTX_VALS) + return; + + reg = (reg - 0x00400000) / 4; + reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base; + + nv_wo32(ctx->data, reg * 4, val); +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c new file mode 100644 index 00000000000..e45035efb8c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c @@ -0,0 +1,689 @@ +/* + * Copyright 2009 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> + +/* 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 + * correct operation. We'll implement additional handling if/when we + * discover it's necessary. + * + * - On context save, NVIDIA set 0x400314 bit 0 to 1 if the "3D state" + * flag is set, this gets saved into the context. + * - On context save, the context program for all cards load nsource + * into a flag register and check for ILLEGAL_MTHD. If it's set, + * opcode 0x60000d is called before resuming normal operation. + * - Some context programs check more conditions than the above. NV44 + * checks: ((nsource & 0x0857) || (0x400718 & 0x0100) || (intr & 0x0001)) + * and calls 0x60000d before resuming normal operation. + * - At the very beginning of NVIDIA's context programs, flag 9 is checked + * and if true 0x800001 is called with count=0, pos=0, the flag is cleared + * and then the ctxprog is aborted. It looks like a complicated NOP, + * its purpose is unknown. + * - In the section of code that loads the per-vs state, NVIDIA check + * flag 10. If it's set, they only transfer the small 0x300 byte block + * of state + the state for a single vs as opposed to the state for + * all vs units. It doesn't seem likely that it'll occur in normal + * operation, especially seeing as it appears NVIDIA may have screwed + * up the ctxprogs for some cards and have an invalid instruction + * rather than a cp_lsr(ctx, dwords_for_1_vs_unit) instruction. + * - There's a number of places where context offset 0 (where we place + * the PRAMIN offset of the context) is loaded into either 0x408000, + * 0x408004 or 0x408008. Not sure what's up there either. + * - The ctxprogs for some cards save 0x400a00 again during the cleanup + * path for auto-loadctx. + */ + +#define CP_FLAG_CLEAR 0 +#define CP_FLAG_SET 1 +#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0) +#define CP_FLAG_SWAP_DIRECTION_LOAD 0 +#define CP_FLAG_SWAP_DIRECTION_SAVE 1 +#define CP_FLAG_USER_SAVE ((0 * 32) + 5) +#define CP_FLAG_USER_SAVE_NOT_PENDING 0 +#define CP_FLAG_USER_SAVE_PENDING 1 +#define CP_FLAG_USER_LOAD ((0 * 32) + 6) +#define CP_FLAG_USER_LOAD_NOT_PENDING 0 +#define CP_FLAG_USER_LOAD_PENDING 1 +#define CP_FLAG_STATUS ((3 * 32) + 0) +#define CP_FLAG_STATUS_IDLE 0 +#define CP_FLAG_STATUS_BUSY 1 +#define CP_FLAG_AUTO_SAVE ((3 * 32) + 4) +#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0 +#define CP_FLAG_AUTO_SAVE_PENDING 1 +#define CP_FLAG_AUTO_LOAD ((3 * 32) + 5) +#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0 +#define CP_FLAG_AUTO_LOAD_PENDING 1 +#define CP_FLAG_UNK54 ((3 * 32) + 6) +#define CP_FLAG_UNK54_CLEAR 0 +#define CP_FLAG_UNK54_SET 1 +#define CP_FLAG_ALWAYS ((3 * 32) + 8) +#define CP_FLAG_ALWAYS_FALSE 0 +#define CP_FLAG_ALWAYS_TRUE 1 +#define CP_FLAG_UNK57 ((3 * 32) + 9) +#define CP_FLAG_UNK57_CLEAR 0 +#define CP_FLAG_UNK57_SET 1 + +#define CP_CTX 0x00100000 +#define CP_CTX_COUNT 0x000fc000 +#define CP_CTX_COUNT_SHIFT 14 +#define CP_CTX_REG 0x00003fff +#define CP_LOAD_SR 0x00200000 +#define CP_LOAD_SR_VALUE 0x000fffff +#define CP_BRA 0x00400000 +#define CP_BRA_IP 0x0000ff00 +#define CP_BRA_IP_SHIFT 8 +#define CP_BRA_IF_CLEAR 0x00000080 +#define CP_BRA_FLAG 0x0000007f +#define CP_WAIT 0x00500000 +#define CP_WAIT_SET 0x00000080 +#define CP_WAIT_FLAG 0x0000007f +#define CP_SET 0x00700000 +#define CP_SET_1 0x00000080 +#define CP_SET_FLAG 0x0000007f +#define CP_NEXT_TO_SWAP 0x00600007 +#define CP_NEXT_TO_CURRENT 0x00600009 +#define CP_SET_CONTEXT_POINTER 0x0060000a +#define CP_END 0x0060000e +#define CP_LOAD_MAGIC_UNK01 0x00800001 /* unknown */ +#define CP_LOAD_MAGIC_NV44TCL 0x00800029 /* per-vs state (0x4497) */ +#define CP_LOAD_MAGIC_NV40TCL 0x00800041 /* per-vs state (0x4097) */ + +#include "nv40.h" +#include "ctx.h" + +/* TODO: + * - get vs count from 0x1540 + */ + +static int +nv40_graph_vs_count(struct nouveau_device *device) +{ + + switch (device->chipset) { + case 0x47: + case 0x49: + case 0x4b: + return 8; + case 0x40: + return 6; + case 0x41: + case 0x42: + return 5; + case 0x43: + case 0x44: + case 0x46: + case 0x4a: + return 3; + case 0x4c: + case 0x4e: + case 0x67: + default: + return 1; + } +} + + +enum cp_label { + cp_check_load = 1, + cp_setup_auto_load, + cp_setup_load, + cp_setup_save, + cp_swap_state, + cp_swap_state3d_3_is_save, + cp_prepare_exit, + cp_exit, +}; + +static void +nv40_graph_construct_general(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i; + + cp_ctx(ctx, 0x4000a4, 1); + gr_def(ctx, 0x4000a4, 0x00000008); + cp_ctx(ctx, 0x400144, 58); + gr_def(ctx, 0x400144, 0x00000001); + cp_ctx(ctx, 0x400314, 1); + gr_def(ctx, 0x400314, 0x00000000); + cp_ctx(ctx, 0x400400, 10); + cp_ctx(ctx, 0x400480, 10); + cp_ctx(ctx, 0x400500, 19); + gr_def(ctx, 0x400514, 0x00040000); + gr_def(ctx, 0x400524, 0x55555555); + gr_def(ctx, 0x400528, 0x55555555); + gr_def(ctx, 0x40052c, 0x55555555); + gr_def(ctx, 0x400530, 0x55555555); + cp_ctx(ctx, 0x400560, 6); + gr_def(ctx, 0x400568, 0x0000ffff); + gr_def(ctx, 0x40056c, 0x0000ffff); + cp_ctx(ctx, 0x40057c, 5); + cp_ctx(ctx, 0x400710, 3); + gr_def(ctx, 0x400710, 0x20010001); + gr_def(ctx, 0x400714, 0x0f73ef00); + cp_ctx(ctx, 0x400724, 1); + gr_def(ctx, 0x400724, 0x02008821); + cp_ctx(ctx, 0x400770, 3); + if (device->chipset == 0x40) { + cp_ctx(ctx, 0x400814, 4); + cp_ctx(ctx, 0x400828, 5); + cp_ctx(ctx, 0x400840, 5); + gr_def(ctx, 0x400850, 0x00000040); + cp_ctx(ctx, 0x400858, 4); + gr_def(ctx, 0x400858, 0x00000040); + gr_def(ctx, 0x40085c, 0x00000040); + gr_def(ctx, 0x400864, 0x80000000); + cp_ctx(ctx, 0x40086c, 9); + gr_def(ctx, 0x40086c, 0x80000000); + gr_def(ctx, 0x400870, 0x80000000); + gr_def(ctx, 0x400874, 0x80000000); + gr_def(ctx, 0x400878, 0x80000000); + gr_def(ctx, 0x400888, 0x00000040); + gr_def(ctx, 0x40088c, 0x80000000); + cp_ctx(ctx, 0x4009c0, 8); + gr_def(ctx, 0x4009cc, 0x80000000); + gr_def(ctx, 0x4009dc, 0x80000000); + } else { + cp_ctx(ctx, 0x400840, 20); + if (nv44_graph_class(ctx->device)) { + for (i = 0; i < 8; i++) + gr_def(ctx, 0x400860 + (i * 4), 0x00000001); + } + gr_def(ctx, 0x400880, 0x00000040); + gr_def(ctx, 0x400884, 0x00000040); + gr_def(ctx, 0x400888, 0x00000040); + cp_ctx(ctx, 0x400894, 11); + gr_def(ctx, 0x400894, 0x00000040); + 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 (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 (device->chipset) { + case 0x47: + case 0x49: + case 0x4b: + cp_ctx(ctx, 0x403448, 1); + gr_def(ctx, 0x403448, 0x00001010); + break; + default: + cp_ctx(ctx, 0x403440, 1); + switch (device->chipset) { + case 0x40: + gr_def(ctx, 0x403440, 0x00000010); + break; + case 0x44: + case 0x46: + case 0x4a: + gr_def(ctx, 0x403440, 0x00003010); + break; + case 0x41: + case 0x42: + case 0x43: + case 0x4c: + case 0x4e: + case 0x67: + default: + gr_def(ctx, 0x403440, 0x00001010); + break; + } + break; + } +} + +static void +nv40_graph_construct_state3d(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i; + + if (device->chipset == 0x40) { + cp_ctx(ctx, 0x401880, 51); + gr_def(ctx, 0x401940, 0x00000100); + } else + 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 (device->chipset == 0x46) + cp_ctx(ctx, 0x401900, 16); + cp_ctx(ctx, 0x401940, 3); + } + cp_ctx(ctx, 0x40194c, 18); + gr_def(ctx, 0x401954, 0x00000111); + gr_def(ctx, 0x401958, 0x00080060); + gr_def(ctx, 0x401974, 0x00000080); + gr_def(ctx, 0x401978, 0xffff0000); + gr_def(ctx, 0x40197c, 0x00000001); + gr_def(ctx, 0x401990, 0x46400000); + if (device->chipset == 0x40) { + cp_ctx(ctx, 0x4019a0, 2); + cp_ctx(ctx, 0x4019ac, 5); + } else { + cp_ctx(ctx, 0x4019a0, 1); + cp_ctx(ctx, 0x4019b4, 3); + } + gr_def(ctx, 0x4019bc, 0xffff0000); + switch (device->chipset) { + case 0x46: + case 0x47: + case 0x49: + case 0x4b: + cp_ctx(ctx, 0x4019c0, 18); + for (i = 0; i < 16; i++) + gr_def(ctx, 0x4019c0 + (i * 4), 0x88888888); + break; + } + cp_ctx(ctx, 0x401a08, 8); + gr_def(ctx, 0x401a10, 0x0fff0000); + gr_def(ctx, 0x401a14, 0x0fff0000); + gr_def(ctx, 0x401a1c, 0x00011100); + cp_ctx(ctx, 0x401a2c, 4); + cp_ctx(ctx, 0x401a44, 26); + for (i = 0; i < 16; i++) + gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000); + gr_def(ctx, 0x401a8c, 0x4b7fffff); + if (device->chipset == 0x40) { + cp_ctx(ctx, 0x401ab8, 3); + } else { + cp_ctx(ctx, 0x401ab8, 1); + cp_ctx(ctx, 0x401ac0, 1); + } + cp_ctx(ctx, 0x401ad0, 8); + gr_def(ctx, 0x401ad0, 0x30201000); + gr_def(ctx, 0x401ad4, 0x70605040); + gr_def(ctx, 0x401ad8, 0xb8a89888); + gr_def(ctx, 0x401adc, 0xf8e8d8c8); + cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1); + gr_def(ctx, 0x401b10, 0x40100000); + 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); + gr_def(ctx, 0x401b68, 0x435185d6); + gr_def(ctx, 0x401b6c, 0x2155b699); + gr_def(ctx, 0x401b70, 0xfedcba98); + gr_def(ctx, 0x401b74, 0x00000098); + gr_def(ctx, 0x401b84, 0xffffffff); + gr_def(ctx, 0x401b88, 0x00ff7000); + gr_def(ctx, 0x401b8c, 0x0000ffff); + 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); + cp_ctx(ctx, 0x401bc0, 9); + gr_def(ctx, 0x401be0, 0x00ffff00); + cp_ctx(ctx, 0x401c00, 192); + for (i = 0; i < 16; i++) { /* fragment texture units */ + gr_def(ctx, 0x401c40 + (i * 4), 0x00018488); + gr_def(ctx, 0x401c80 + (i * 4), 0x00028202); + gr_def(ctx, 0x401d00 + (i * 4), 0x0000aae4); + gr_def(ctx, 0x401d40 + (i * 4), 0x01012000); + gr_def(ctx, 0x401d80 + (i * 4), 0x00080008); + gr_def(ctx, 0x401e00 + (i * 4), 0x00100008); + } + for (i = 0; i < 4; i++) { /* vertex texture units */ + gr_def(ctx, 0x401e90 + (i * 4), 0x0001bc80); + gr_def(ctx, 0x401ea0 + (i * 4), 0x00000202); + gr_def(ctx, 0x401ec0 + (i * 4), 0x00000008); + gr_def(ctx, 0x401ee0 + (i * 4), 0x00080008); + } + cp_ctx(ctx, 0x400f5c, 3); + gr_def(ctx, 0x400f5c, 0x00000002); + cp_ctx(ctx, 0x400f84, 1); +} + +static void +nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i; + + cp_ctx(ctx, 0x402000, 1); + cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2); + switch (device->chipset) { + case 0x40: + gr_def(ctx, 0x402404, 0x00000001); + break; + case 0x4c: + case 0x4e: + case 0x67: + gr_def(ctx, 0x402404, 0x00000020); + break; + case 0x46: + case 0x49: + case 0x4b: + gr_def(ctx, 0x402404, 0x00000421); + break; + default: + gr_def(ctx, 0x402404, 0x00000021); + } + if (device->chipset != 0x40) + gr_def(ctx, 0x402408, 0x030c30c3); + switch (device->chipset) { + case 0x44: + case 0x46: + case 0x4a: + case 0x4c: + case 0x4e: + case 0x67: + cp_ctx(ctx, 0x402440, 1); + gr_def(ctx, 0x402440, 0x00011001); + break; + default: + break; + } + cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9); + gr_def(ctx, 0x402488, 0x3e020200); + gr_def(ctx, 0x40248c, 0x00ffffff); + switch (device->chipset) { + case 0x40: + gr_def(ctx, 0x402490, 0x60103f00); + break; + case 0x47: + gr_def(ctx, 0x402490, 0x40103f00); + break; + case 0x41: + case 0x42: + case 0x49: + case 0x4b: + gr_def(ctx, 0x402490, 0x20103f00); + break; + default: + gr_def(ctx, 0x402490, 0x0c103f00); + break; + } + gr_def(ctx, 0x40249c, device->chipset <= 0x43 ? + 0x00020000 : 0x00040000); + cp_ctx(ctx, 0x402500, 31); + gr_def(ctx, 0x402530, 0x00008100); + 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 (device->chipset) { + case 0x47: + case 0x49: + case 0x4b: + cp_ctx(ctx, 0x402864, 1); + gr_def(ctx, 0x402864, 0x00001001); + cp_ctx(ctx, 0x402870, 3); + gr_def(ctx, 0x402878, 0x00000003); + if (device->chipset != 0x47) { /* belong at end!! */ + cp_ctx(ctx, 0x402900, 1); + cp_ctx(ctx, 0x402940, 1); + cp_ctx(ctx, 0x402980, 1); + cp_ctx(ctx, 0x4029c0, 1); + cp_ctx(ctx, 0x402a00, 1); + cp_ctx(ctx, 0x402a40, 1); + cp_ctx(ctx, 0x402a80, 1); + cp_ctx(ctx, 0x402ac0, 1); + } + break; + case 0x40: + cp_ctx(ctx, 0x402844, 1); + gr_def(ctx, 0x402844, 0x00000001); + cp_ctx(ctx, 0x402850, 1); + break; + default: + cp_ctx(ctx, 0x402844, 1); + gr_def(ctx, 0x402844, 0x00001001); + cp_ctx(ctx, 0x402850, 2); + gr_def(ctx, 0x402854, 0x00000003); + break; + } + + cp_ctx(ctx, 0x402c00, 4); + gr_def(ctx, 0x402c00, device->chipset == 0x40 ? + 0x80800001 : 0x00888001); + switch (device->chipset) { + case 0x47: + case 0x49: + case 0x4b: + cp_ctx(ctx, 0x402c20, 40); + for (i = 0; i < 32; i++) + gr_def(ctx, 0x402c40 + (i * 4), 0xffffffff); + cp_ctx(ctx, 0x4030b8, 13); + gr_def(ctx, 0x4030dc, 0x00000005); + gr_def(ctx, 0x4030e8, 0x0000ffff); + break; + default: + cp_ctx(ctx, 0x402c10, 4); + if (device->chipset == 0x40) + cp_ctx(ctx, 0x402c20, 36); + else + if (device->chipset <= 0x42) + cp_ctx(ctx, 0x402c20, 24); + else + if (device->chipset <= 0x4a) + cp_ctx(ctx, 0x402c20, 16); + else + cp_ctx(ctx, 0x402c20, 8); + cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13); + gr_def(ctx, 0x402cd4, 0x00000005); + if (device->chipset != 0x40) + gr_def(ctx, 0x402ce0, 0x0000ffff); + break; + } + + 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 (device->chipset != 0x40) { + cp_ctx(ctx, 0x403600, 1); + gr_def(ctx, 0x403600, 0x00000001); + } + cp_ctx(ctx, 0x403800, 1); + + cp_ctx(ctx, 0x403c18, 1); + gr_def(ctx, 0x403c18, 0x00000001); + switch (device->chipset) { + case 0x46: + case 0x47: + case 0x49: + case 0x4b: + cp_ctx(ctx, 0x405018, 1); + gr_def(ctx, 0x405018, 0x08e00001); + cp_ctx(ctx, 0x405c24, 1); + gr_def(ctx, 0x405c24, 0x000e3000); + break; + } + if (device->chipset != 0x4e) + cp_ctx(ctx, 0x405800, 11); + cp_ctx(ctx, 0x407000, 1); +} + +static void +nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx) +{ + int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684; + + cp_out (ctx, 0x300000); + cp_lsr (ctx, len - 4); + cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save); + cp_lsr (ctx, len); + cp_name(ctx, cp_swap_state3d_3_is_save); + cp_out (ctx, 0x800001); + + ctx->ctxvals_pos += len; +} + +static void +nv40_graph_construct_shader(struct nouveau_grctx *ctx) +{ + 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->device); + vs_nr_b0 = 363; + 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 (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(device) ? 0x4980/4 : 0x4a40/4; + } + + cp_lsr(ctx, vs_len * vs_nr + 0x300/4); + cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041); + + offset = ctx->ctxvals_pos; + ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len)); + + if (ctx->mode != NOUVEAU_GRCTX_VALS) + return; + + offset += 0x0280/4; + for (i = 0; i < 16; i++, offset += 2) + nv_wo32(obj, offset * 4, 0x3f800000); + + for (vs = 0; vs < vs_nr; vs++, offset += vs_len) { + for (i = 0; i < vs_nr_b0 * 6; i += 6) + nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001); + for (i = 0; i < vs_nr_b1 * 4; i += 4) + nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000); + } +} + +static void +nv40_grctx_generate(struct nouveau_grctx *ctx) +{ + /* decide whether we're loading/unloading the context */ + cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save); + cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save); + + cp_name(ctx, cp_check_load); + cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load); + cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load); + cp_bra (ctx, ALWAYS, TRUE, cp_exit); + + /* setup for context load */ + cp_name(ctx, cp_setup_auto_load); + cp_wait(ctx, STATUS, IDLE); + cp_out (ctx, CP_NEXT_TO_SWAP); + cp_name(ctx, cp_setup_load); + cp_wait(ctx, STATUS, IDLE); + cp_set (ctx, SWAP_DIRECTION, LOAD); + cp_out (ctx, 0x00910880); /* ?? */ + cp_out (ctx, 0x00901ffe); /* ?? */ + cp_out (ctx, 0x01940000); /* ?? */ + cp_lsr (ctx, 0x20); + cp_out (ctx, 0x0060000b); /* ?? */ + cp_wait(ctx, UNK57, CLEAR); + cp_out (ctx, 0x0060000c); /* ?? */ + cp_bra (ctx, ALWAYS, TRUE, cp_swap_state); + + /* setup for context save */ + cp_name(ctx, cp_setup_save); + cp_set (ctx, SWAP_DIRECTION, SAVE); + + /* general PGRAPH state */ + cp_name(ctx, cp_swap_state); + cp_pos (ctx, 0x00020/4); + nv40_graph_construct_general(ctx); + cp_wait(ctx, STATUS, IDLE); + + /* 3D state, block 1 */ + cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit); + nv40_graph_construct_state3d(ctx); + cp_wait(ctx, STATUS, IDLE); + + /* 3D state, block 2 */ + nv40_graph_construct_state3d_2(ctx); + + /* Some other block of "random" state */ + nv40_graph_construct_state3d_3(ctx); + + /* Per-vertex shader state */ + cp_pos (ctx, ctx->ctxvals_pos); + nv40_graph_construct_shader(ctx); + + /* pre-exit state updates */ + cp_name(ctx, cp_prepare_exit); + cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load); + cp_bra (ctx, USER_SAVE, PENDING, cp_exit); + cp_out (ctx, CP_NEXT_TO_CURRENT); + + cp_name(ctx, cp_exit); + cp_set (ctx, USER_SAVE, NOT_PENDING); + cp_set (ctx, USER_LOAD, NOT_PENDING); + cp_out (ctx, CP_END); +} + +void +nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem) +{ + nv40_grctx_generate(&(struct nouveau_grctx) { + .device = device, + .mode = NOUVEAU_GRCTX_VALS, + .data = mem, + }); +} + +void +nv40_grctx_init(struct nouveau_device *device, u32 *size) +{ + u32 ctxprog[256], i; + struct nouveau_grctx ctx = { + .device = device, + .mode = NOUVEAU_GRCTX_PROG, + .data = ctxprog, + .ctxprog_max = ARRAY_SIZE(ctxprog) + }; + + nv40_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; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c new file mode 100644 index 00000000000..552fdbd45eb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c @@ -0,0 +1,3341 @@ +/* + * Copyright 2009 Marcin Kościelnicki + * + * 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. + */ + +#include <core/gpuobj.h> + +#define CP_FLAG_CLEAR 0 +#define CP_FLAG_SET 1 +#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0) +#define CP_FLAG_SWAP_DIRECTION_LOAD 0 +#define CP_FLAG_SWAP_DIRECTION_SAVE 1 +#define CP_FLAG_UNK01 ((0 * 32) + 1) +#define CP_FLAG_UNK01_CLEAR 0 +#define CP_FLAG_UNK01_SET 1 +#define CP_FLAG_UNK03 ((0 * 32) + 3) +#define CP_FLAG_UNK03_CLEAR 0 +#define CP_FLAG_UNK03_SET 1 +#define CP_FLAG_USER_SAVE ((0 * 32) + 5) +#define CP_FLAG_USER_SAVE_NOT_PENDING 0 +#define CP_FLAG_USER_SAVE_PENDING 1 +#define CP_FLAG_USER_LOAD ((0 * 32) + 6) +#define CP_FLAG_USER_LOAD_NOT_PENDING 0 +#define CP_FLAG_USER_LOAD_PENDING 1 +#define CP_FLAG_UNK0B ((0 * 32) + 0xb) +#define CP_FLAG_UNK0B_CLEAR 0 +#define CP_FLAG_UNK0B_SET 1 +#define CP_FLAG_XFER_SWITCH ((0 * 32) + 0xe) +#define CP_FLAG_XFER_SWITCH_DISABLE 0 +#define CP_FLAG_XFER_SWITCH_ENABLE 1 +#define CP_FLAG_STATE ((0 * 32) + 0x1c) +#define CP_FLAG_STATE_STOPPED 0 +#define CP_FLAG_STATE_RUNNING 1 +#define CP_FLAG_UNK1D ((0 * 32) + 0x1d) +#define CP_FLAG_UNK1D_CLEAR 0 +#define CP_FLAG_UNK1D_SET 1 +#define CP_FLAG_UNK20 ((1 * 32) + 0) +#define CP_FLAG_UNK20_CLEAR 0 +#define CP_FLAG_UNK20_SET 1 +#define CP_FLAG_STATUS ((2 * 32) + 0) +#define CP_FLAG_STATUS_BUSY 0 +#define CP_FLAG_STATUS_IDLE 1 +#define CP_FLAG_AUTO_SAVE ((2 * 32) + 4) +#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0 +#define CP_FLAG_AUTO_SAVE_PENDING 1 +#define CP_FLAG_AUTO_LOAD ((2 * 32) + 5) +#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0 +#define CP_FLAG_AUTO_LOAD_PENDING 1 +#define CP_FLAG_NEWCTX ((2 * 32) + 10) +#define CP_FLAG_NEWCTX_BUSY 0 +#define CP_FLAG_NEWCTX_DONE 1 +#define CP_FLAG_XFER ((2 * 32) + 11) +#define CP_FLAG_XFER_IDLE 0 +#define CP_FLAG_XFER_BUSY 1 +#define CP_FLAG_ALWAYS ((2 * 32) + 13) +#define CP_FLAG_ALWAYS_FALSE 0 +#define CP_FLAG_ALWAYS_TRUE 1 +#define CP_FLAG_INTR ((2 * 32) + 15) +#define CP_FLAG_INTR_NOT_PENDING 0 +#define CP_FLAG_INTR_PENDING 1 + +#define CP_CTX 0x00100000 +#define CP_CTX_COUNT 0x000f0000 +#define CP_CTX_COUNT_SHIFT 16 +#define CP_CTX_REG 0x00003fff +#define CP_LOAD_SR 0x00200000 +#define CP_LOAD_SR_VALUE 0x000fffff +#define CP_BRA 0x00400000 +#define CP_BRA_IP 0x0001ff00 +#define CP_BRA_IP_SHIFT 8 +#define CP_BRA_IF_CLEAR 0x00000080 +#define CP_BRA_FLAG 0x0000007f +#define CP_WAIT 0x00500000 +#define CP_WAIT_SET 0x00000080 +#define CP_WAIT_FLAG 0x0000007f +#define CP_SET 0x00700000 +#define CP_SET_1 0x00000080 +#define CP_SET_FLAG 0x0000007f +#define CP_NEWCTX 0x00600004 +#define CP_NEXT_TO_SWAP 0x00600005 +#define CP_SET_CONTEXT_POINTER 0x00600006 +#define CP_SET_XFER_POINTER 0x00600007 +#define CP_ENABLE 0x00600009 +#define CP_END 0x0060000c +#define CP_NEXT_TO_CURRENT 0x0060000d +#define CP_DISABLE1 0x0090ffff +#define CP_DISABLE2 0x0091ffff +#define CP_XFER_1 0x008000ff +#define CP_XFER_2 0x008800ff +#define CP_SEEK_1 0x00c000ff +#define CP_SEEK_2 0x00c800ff + +#include "nv50.h" +#include "ctx.h" + +#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) +#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac) + +/* + * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's + * the GPU itself that does context-switching, but it needs a special + * microcode to do it. And it's the driver's task to supply this microcode, + * further known as ctxprog, as well as the initial context values, known + * as ctxvals. + * + * Without ctxprog, you cannot switch contexts. Not even in software, since + * the majority of context [xfer strands] isn't accessible directly. You're + * stuck with a single channel, and you also suffer all the problems resulting + * from missing ctxvals, since you cannot load them. + * + * Without ctxvals, you're stuck with PGRAPH's default context. It's enough to + * run 2d operations, but trying to utilise 3d or CUDA will just lock you up, + * since you don't have... some sort of needed setup. + * + * Nouveau will just disable acceleration if not given ctxprog + ctxvals, since + * it's too much hassle to handle no-ctxprog as a special case. + */ + +/* + * How ctxprogs work. + * + * The ctxprog is written in its own kind of microcode, with very small and + * crappy set of available commands. You upload it to a small [512 insns] + * area of memory on PGRAPH, and it'll be run when PFIFO wants PGRAPH to + * switch channel. or when the driver explicitely requests it. Stuff visible + * to ctxprog consists of: PGRAPH MMIO registers, PGRAPH context strands, + * the per-channel context save area in VRAM [known as ctxvals or grctx], + * 4 flags registers, a scratch register, two grctx pointers, plus many + * random poorly-understood details. + * + * When ctxprog runs, it's supposed to check what operations are asked of it, + * save old context if requested, optionally reset PGRAPH and switch to the + * new channel, and load the new context. Context consists of three major + * parts: subset of MMIO registers and two "xfer areas". + */ + +/* TODO: + * - document unimplemented bits compared to nvidia + * - NVAx: make a TP subroutine, use it. + * - use 0x4008fc instead of 0x1540? + */ + +enum cp_label { + cp_check_load = 1, + cp_setup_auto_load, + cp_setup_load, + cp_setup_save, + cp_swap_state, + cp_prepare_exit, + cp_exit, +}; + +static void nv50_graph_construct_mmio(struct nouveau_grctx *ctx); +static void nv50_graph_construct_xfer1(struct nouveau_grctx *ctx); +static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx); + +/* Main function: construct the ctxprog skeleton, call the other functions. */ + +static int +nv50_grctx_generate(struct nouveau_grctx *ctx) +{ + cp_set (ctx, STATE, RUNNING); + cp_set (ctx, XFER_SWITCH, ENABLE); + /* decide whether we're loading/unloading the context */ + cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save); + cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save); + + cp_name(ctx, cp_check_load); + cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load); + cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load); + cp_bra (ctx, ALWAYS, TRUE, cp_prepare_exit); + + /* setup for context load */ + cp_name(ctx, cp_setup_auto_load); + cp_out (ctx, CP_DISABLE1); + cp_out (ctx, CP_DISABLE2); + cp_out (ctx, CP_ENABLE); + cp_out (ctx, CP_NEXT_TO_SWAP); + cp_set (ctx, UNK01, SET); + cp_name(ctx, cp_setup_load); + cp_out (ctx, CP_NEWCTX); + cp_wait(ctx, NEWCTX, BUSY); + cp_set (ctx, UNK1D, CLEAR); + cp_set (ctx, SWAP_DIRECTION, LOAD); + cp_bra (ctx, UNK0B, SET, cp_prepare_exit); + cp_bra (ctx, ALWAYS, TRUE, cp_swap_state); + + /* setup for context save */ + cp_name(ctx, cp_setup_save); + cp_set (ctx, UNK1D, SET); + cp_wait(ctx, STATUS, BUSY); + cp_wait(ctx, INTR, PENDING); + cp_bra (ctx, STATUS, BUSY, cp_setup_save); + cp_set (ctx, UNK01, SET); + cp_set (ctx, SWAP_DIRECTION, SAVE); + + /* general PGRAPH state */ + cp_name(ctx, cp_swap_state); + cp_set (ctx, UNK03, SET); + cp_pos (ctx, 0x00004/4); + cp_ctx (ctx, 0x400828, 1); /* needed. otherwise, flickering happens. */ + cp_pos (ctx, 0x00100/4); + nv50_graph_construct_mmio(ctx); + nv50_graph_construct_xfer1(ctx); + nv50_graph_construct_xfer2(ctx); + + cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load); + + cp_set (ctx, UNK20, SET); + cp_set (ctx, SWAP_DIRECTION, SAVE); /* no idea why this is needed, but fixes at least one lockup. */ + cp_lsr (ctx, ctx->ctxvals_base); + cp_out (ctx, CP_SET_XFER_POINTER); + cp_lsr (ctx, 4); + cp_out (ctx, CP_SEEK_1); + cp_out (ctx, CP_XFER_1); + cp_wait(ctx, XFER, BUSY); + + /* pre-exit state updates */ + cp_name(ctx, cp_prepare_exit); + cp_set (ctx, UNK01, CLEAR); + cp_set (ctx, UNK03, CLEAR); + cp_set (ctx, UNK1D, CLEAR); + + cp_bra (ctx, USER_SAVE, PENDING, cp_exit); + cp_out (ctx, CP_NEXT_TO_CURRENT); + + cp_name(ctx, cp_exit); + cp_set (ctx, USER_SAVE, NOT_PENDING); + cp_set (ctx, USER_LOAD, NOT_PENDING); + cp_set (ctx, XFER_SWITCH, DISABLE); + cp_set (ctx, STATE, STOPPED); + cp_out (ctx, CP_END); + ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */ + + return 0; +} + +void +nv50_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem) +{ + nv50_grctx_generate(&(struct nouveau_grctx) { + .device = device, + .mode = NOUVEAU_GRCTX_VALS, + .data = mem, + }); +} + +int +nv50_grctx_init(struct nouveau_device *device, u32 *size) +{ + u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i; + struct nouveau_grctx ctx = { + .device = device, + .mode = NOUVEAU_GRCTX_PROG, + .data = ctxprog, + .ctxprog_max = 512, + }; + + 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; +} + +/* + * Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which + * registers to save/restore and the default values for them. + */ + +static void +nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx); + +static void +nv50_graph_construct_mmio(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i, j; + int offset, base; + 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 (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(device->chipset)) + gr_def(ctx, 0x400894, 0x00001000); + gr_def(ctx, 0x4008e8, 0x00000003); + gr_def(ctx, 0x4008ec, 0x00001000); + if (device->chipset == 0x50) + cp_ctx(ctx, 0x400908, 0xb); + else if (device->chipset < 0xa0) + cp_ctx(ctx, 0x400908, 0xc); + else + cp_ctx(ctx, 0x400908, 0xe); + + if (device->chipset >= 0xa0) + cp_ctx(ctx, 0x400b00, 0x1); + if (IS_NVA3F(device->chipset)) { + cp_ctx(ctx, 0x400b10, 0x1); + gr_def(ctx, 0x400b10, 0x0001629d); + cp_ctx(ctx, 0x400b20, 0x1); + gr_def(ctx, 0x400b20, 0x0001629d); + } + + nv50_graph_construct_mmio_ddata(ctx); + + /* 0C00: VFETCH */ + cp_ctx(ctx, 0x400c08, 0x2); + gr_def(ctx, 0x400c08, 0x0000fe0c); + + /* 1000 */ + if (device->chipset < 0xa0) { + cp_ctx(ctx, 0x401008, 0x4); + gr_def(ctx, 0x401014, 0x00001000); + } else if (!IS_NVA3F(device->chipset)) { + cp_ctx(ctx, 0x401008, 0x5); + gr_def(ctx, 0x401018, 0x00001000); + } else { + cp_ctx(ctx, 0x401008, 0x5); + gr_def(ctx, 0x401018, 0x00004000); + } + + /* 1400 */ + cp_ctx(ctx, 0x401400, 0x8); + cp_ctx(ctx, 0x401424, 0x3); + if (device->chipset == 0x50) + gr_def(ctx, 0x40142c, 0x0001fd87); + else + gr_def(ctx, 0x40142c, 0x00000187); + cp_ctx(ctx, 0x401540, 0x5); + gr_def(ctx, 0x401550, 0x00001018); + + /* 1800: STREAMOUT */ + cp_ctx(ctx, 0x401814, 0x1); + gr_def(ctx, 0x401814, 0x000000ff); + if (device->chipset == 0x50) { + cp_ctx(ctx, 0x40181c, 0xe); + gr_def(ctx, 0x401850, 0x00000004); + } else if (device->chipset < 0xa0) { + cp_ctx(ctx, 0x40181c, 0xf); + gr_def(ctx, 0x401854, 0x00000004); + } else { + cp_ctx(ctx, 0x40181c, 0x13); + gr_def(ctx, 0x401864, 0x00000004); + } + + /* 1C00 */ + cp_ctx(ctx, 0x401c00, 0x1); + switch (device->chipset) { + case 0x50: + gr_def(ctx, 0x401c00, 0x0001005f); + break; + case 0x84: + case 0x86: + case 0x94: + gr_def(ctx, 0x401c00, 0x044d00df); + break; + case 0x92: + case 0x96: + case 0x98: + case 0xa0: + case 0xaa: + case 0xac: + gr_def(ctx, 0x401c00, 0x042500df); + break; + case 0xa3: + case 0xa5: + case 0xa8: + case 0xaf: + gr_def(ctx, 0x401c00, 0x142500df); + break; + } + + /* 2000 */ + + /* 2400 */ + cp_ctx(ctx, 0x402400, 0x1); + if (device->chipset == 0x50) + cp_ctx(ctx, 0x402408, 0x1); + else + cp_ctx(ctx, 0x402408, 0x2); + gr_def(ctx, 0x402408, 0x00000600); + + /* 2800: CSCHED */ + cp_ctx(ctx, 0x402800, 0x1); + if (device->chipset == 0x50) + gr_def(ctx, 0x402800, 0x00000006); + + /* 2C00: ZCULL */ + cp_ctx(ctx, 0x402c08, 0x6); + if (device->chipset != 0x50) + gr_def(ctx, 0x402c14, 0x01000000); + gr_def(ctx, 0x402c18, 0x000000ff); + if (device->chipset == 0x50) + cp_ctx(ctx, 0x402ca0, 0x1); + else + cp_ctx(ctx, 0x402ca0, 0x2); + if (device->chipset < 0xa0) + gr_def(ctx, 0x402ca0, 0x00000400); + else if (!IS_NVA3F(device->chipset)) + gr_def(ctx, 0x402ca0, 0x00000800); + else + gr_def(ctx, 0x402ca0, 0x00000400); + cp_ctx(ctx, 0x402cac, 0x4); + + /* 3000: ENG2D */ + cp_ctx(ctx, 0x403004, 0x1); + gr_def(ctx, 0x403004, 0x00000001); + + /* 3400 */ + if (device->chipset >= 0xa0) { + cp_ctx(ctx, 0x403404, 0x1); + gr_def(ctx, 0x403404, 0x00000001); + } + + /* 5000: CCACHE */ + cp_ctx(ctx, 0x405000, 0x1); + switch (device->chipset) { + case 0x50: + gr_def(ctx, 0x405000, 0x00300080); + break; + case 0x84: + case 0xa0: + case 0xa3: + case 0xa5: + case 0xa8: + case 0xaa: + case 0xac: + case 0xaf: + gr_def(ctx, 0x405000, 0x000e0080); + break; + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + gr_def(ctx, 0x405000, 0x00000080); + break; + } + cp_ctx(ctx, 0x405014, 0x1); + gr_def(ctx, 0x405014, 0x00000004); + cp_ctx(ctx, 0x40501c, 0x1); + cp_ctx(ctx, 0x405024, 0x1); + cp_ctx(ctx, 0x40502c, 0x1); + + /* 6000? */ + if (device->chipset == 0x50) + cp_ctx(ctx, 0x4063e0, 0x1); + + /* 6800: M2MF */ + 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 (device->chipset == 0x98) + gr_def(ctx, 0x406818, 0x00000f80); + else + gr_def(ctx, 0x406818, 0x00001f80); + if (IS_NVA3F(device->chipset)) + gr_def(ctx, 0x40681c, 0x00000030); + cp_ctx(ctx, 0x406830, 0x3); + } + + /* 7000: per-ROP group state */ + for (i = 0; i < 8; i++) { + if (units & (1<<(i+16))) { + cp_ctx(ctx, 0x407000 + (i<<8), 3); + if (device->chipset == 0x50) + gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820); + 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 (device->chipset == 0x50) { + cp_ctx(ctx, 0x407010 + (i<<8), 1); + } 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 (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 (device->chipset != 0xa5) + gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa); + else + gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa); + 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 (device->chipset < 0xa0) + cp_ctx(ctx, 0x407094 + (i<<8), 1); + else if (!IS_NVA3F(device->chipset)) + cp_ctx(ctx, 0x407094 + (i<<8), 3); + else { + cp_ctx(ctx, 0x407094 + (i<<8), 4); + gr_def(ctx, 0x4070a0 + (i<<8), 1); + } + } + } + + cp_ctx(ctx, 0x407c00, 0x3); + if (device->chipset < 0x90) + gr_def(ctx, 0x407c00, 0x00010040); + else if (device->chipset < 0xa0) + gr_def(ctx, 0x407c00, 0x00390040); + else + gr_def(ctx, 0x407c00, 0x003d0040); + gr_def(ctx, 0x407c08, 0x00000022); + if (device->chipset >= 0xa0) { + cp_ctx(ctx, 0x407c10, 0x3); + cp_ctx(ctx, 0x407c20, 0x1); + cp_ctx(ctx, 0x407c2c, 0x1); + } + + if (device->chipset < 0xa0) { + cp_ctx(ctx, 0x407d00, 0x9); + } else { + cp_ctx(ctx, 0x407d00, 0x15); + } + if (device->chipset == 0x98) + gr_def(ctx, 0x407d08, 0x00380040); + else { + if (device->chipset < 0x90) + gr_def(ctx, 0x407d08, 0x00010040); + else if (device->chipset < 0xa0) + gr_def(ctx, 0x407d08, 0x00390040); + else + gr_def(ctx, 0x407d08, 0x003d0040); + gr_def(ctx, 0x407d0c, 0x00000022); + } + + /* 8000+: per-TP state */ + for (i = 0; i < 10; i++) { + if (units & (1<<i)) { + if (device->chipset < 0xa0) + base = 0x408000 + (i<<12); + else + base = 0x408000 + (i<<11); + if (device->chipset < 0xa0) + offset = base + 0xc00; + else + offset = base + 0x80; + cp_ctx(ctx, offset + 0x00, 1); + gr_def(ctx, offset + 0x00, 0x0000ff0a); + cp_ctx(ctx, offset + 0x08, 1); + + /* per-MP state */ + for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) { + if (!(units & (1 << (j+24)))) continue; + if (device->chipset < 0xa0) + offset = base + 0x200 + (j<<7); + else + offset = base + 0x100 + (j<<7); + cp_ctx(ctx, offset, 0x20); + gr_def(ctx, offset + 0x00, 0x01800000); + gr_def(ctx, offset + 0x04, 0x00160000); + gr_def(ctx, offset + 0x08, 0x01800000); + gr_def(ctx, offset + 0x18, 0x0003ffff); + switch (device->chipset) { + case 0x50: + gr_def(ctx, offset + 0x1c, 0x00080000); + break; + case 0x84: + gr_def(ctx, offset + 0x1c, 0x00880000); + break; + case 0x86: + gr_def(ctx, offset + 0x1c, 0x018c0000); + break; + case 0x92: + case 0x96: + case 0x98: + gr_def(ctx, offset + 0x1c, 0x118c0000); + break; + case 0x94: + gr_def(ctx, offset + 0x1c, 0x10880000); + break; + case 0xa0: + case 0xa5: + gr_def(ctx, offset + 0x1c, 0x310c0000); + break; + case 0xa3: + case 0xa8: + case 0xaa: + case 0xac: + case 0xaf: + gr_def(ctx, offset + 0x1c, 0x300c0000); + break; + } + gr_def(ctx, offset + 0x40, 0x00010401); + 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 (device->chipset == 0x50) + gr_def(ctx, offset + 0x5c, 0x00000080); + else + gr_def(ctx, offset + 0x5c, 0x08000080); + if (device->chipset >= 0xa0) + gr_def(ctx, offset + 0x68, 0x0000003e); + } + + if (device->chipset < 0xa0) + cp_ctx(ctx, base + 0x300, 0x4); + else + cp_ctx(ctx, base + 0x300, 0x5); + if (device->chipset == 0x50) + gr_def(ctx, base + 0x304, 0x00007070); + else if (device->chipset < 0xa0) + gr_def(ctx, base + 0x304, 0x00027070); + else if (!IS_NVA3F(device->chipset)) + gr_def(ctx, base + 0x304, 0x01127070); + else + gr_def(ctx, base + 0x304, 0x05127070); + + if (device->chipset < 0xa0) + cp_ctx(ctx, base + 0x318, 1); + else + cp_ctx(ctx, base + 0x320, 1); + if (device->chipset == 0x50) + gr_def(ctx, base + 0x318, 0x0003ffff); + else if (device->chipset < 0xa0) + gr_def(ctx, base + 0x318, 0x03ffffff); + else + gr_def(ctx, base + 0x320, 0x07ffffff); + + if (device->chipset < 0xa0) + cp_ctx(ctx, base + 0x324, 5); + else + cp_ctx(ctx, base + 0x328, 4); + + if (device->chipset < 0xa0) { + cp_ctx(ctx, base + 0x340, 9); + offset = base + 0x340; + } else if (!IS_NVA3F(device->chipset)) { + cp_ctx(ctx, base + 0x33c, 0xb); + offset = base + 0x344; + } else { + cp_ctx(ctx, base + 0x33c, 0xd); + offset = base + 0x344; + } + gr_def(ctx, offset + 0x0, 0x00120407); + gr_def(ctx, offset + 0x4, 0x05091507); + if (device->chipset == 0x84) + gr_def(ctx, offset + 0x8, 0x05100202); + else + gr_def(ctx, offset + 0x8, 0x05010202); + gr_def(ctx, offset + 0xc, 0x00030201); + if (device->chipset == 0xa3) + cp_ctx(ctx, base + 0x36c, 1); + + cp_ctx(ctx, base + 0x400, 2); + gr_def(ctx, base + 0x404, 0x00000040); + cp_ctx(ctx, base + 0x40c, 2); + gr_def(ctx, base + 0x40c, 0x0d0c0b0a); + gr_def(ctx, base + 0x410, 0x00141210); + + if (device->chipset < 0xa0) + offset = base + 0x800; + else + offset = base + 0x500; + cp_ctx(ctx, offset, 6); + gr_def(ctx, offset + 0x0, 0x000001f0); + gr_def(ctx, offset + 0x4, 0x00000001); + gr_def(ctx, offset + 0x8, 0x00000003); + 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 (device->chipset == 0x50) + gr_def(ctx, offset + 0x1c, 0x00000040); + else + gr_def(ctx, offset + 0x1c, 0x00000100); + gr_def(ctx, offset + 0x20, 0x00003800); + + if (device->chipset >= 0xa0) { + cp_ctx(ctx, base + 0x54c, 2); + 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 (device->chipset < 0xa0) + offset = base + 0xa00; + else + offset = base + 0x680; + cp_ctx(ctx, offset, 1); + gr_def(ctx, offset, 0x00404040); + + if (device->chipset < 0xa0) + offset = base + 0xe00; + else + offset = base + 0x700; + cp_ctx(ctx, offset, 2); + if (device->chipset < 0xa0) + gr_def(ctx, offset, 0x0077f005); + else if (device->chipset == 0xa5) + gr_def(ctx, offset, 0x6cf7f007); + else if (device->chipset == 0xa8) + gr_def(ctx, offset, 0x6cfff007); + else if (device->chipset == 0xac) + gr_def(ctx, offset, 0x0cfff007); + else + gr_def(ctx, offset, 0x0cf7f007); + if (device->chipset == 0x50) + gr_def(ctx, offset + 0x4, 0x00007fff); + 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 (device->chipset == 0x50) { + cp_ctx(ctx, offset + 0x50, 9); + gr_def(ctx, offset + 0x54, 0x000003ff); + gr_def(ctx, offset + 0x58, 0x00000003); + gr_def(ctx, offset + 0x5c, 0x00000003); + gr_def(ctx, offset + 0x60, 0x000001ff); + gr_def(ctx, offset + 0x64, 0x0000001f); + gr_def(ctx, offset + 0x68, 0x0000000f); + gr_def(ctx, offset + 0x6c, 0x0000000f); + } else if (device->chipset < 0xa0) { + cp_ctx(ctx, offset + 0x50, 1); + cp_ctx(ctx, offset + 0x70, 1); + } else { + cp_ctx(ctx, offset + 0x50, 1); + cp_ctx(ctx, offset + 0x60, 5); + } + } + } +} + +static void +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++) + nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val); + ctx->ctxvals_pos += num; +} + +static void +nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int base, num; + base = ctx->ctxvals_pos; + + /* tesla state */ + dd_emit(ctx, 1, 0); /* 00000001 UNK0F90 */ + dd_emit(ctx, 1, 0); /* 00000001 UNK135C */ + + /* SRC_TIC state */ + dd_emit(ctx, 1, 0); /* 00000007 SRC_TILE_MODE_Z */ + dd_emit(ctx, 1, 2); /* 00000007 SRC_TILE_MODE_Y */ + 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 (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 */ + + /* turing state */ + dd_emit(ctx, 1, 0); /* 0000000f TEXTURES_LOG2 */ + dd_emit(ctx, 1, 0); /* 0000000f SAMPLERS_LOG2 */ + dd_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */ + dd_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */ + dd_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */ + dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */ + dd_emit(ctx, 1, 1); /* 0000ffff BLOCK_ALLOC_THREADS */ + dd_emit(ctx, 1, 1); /* 00000001 LANES32 */ + dd_emit(ctx, 1, 0); /* 000000ff UNK370 */ + dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_UNK */ + dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_COUNT */ + dd_emit(ctx, 1, 1); /* 000000ff UNK384 bits 8-15 */ + dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */ + dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */ + dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */ + dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_X */ + dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_XMY */ + dd_emit(ctx, 1, 0); /* 00000001 BLOCKDIM_XMY_OVERFLOW */ + dd_emit(ctx, 1, 1); /* 0003ffff BLOCKDIM_XMYMZ */ + dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_Y */ + 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(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 */ + dd_emit(ctx, 1, 7); /* 00000007 LOCAL_WARPS_LOG_ALLOC */ + dd_emit(ctx, 1, 1); /* 00000007 STACK_WARPS_NO_CLAMP */ + dd_emit(ctx, 1, 7); /* 00000007 STACK_WARPS_LOG_ALLOC */ + dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */ + dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */ + dd_emit(ctx, 1, 1); /* 000007ff BLOCK_ALLOC_THREADS */ + + /* compat 2d state */ + if (device->chipset == 0x50) { + dd_emit(ctx, 4, 0); /* 0000ffff clip X, Y, W, H */ + + dd_emit(ctx, 1, 1); /* ffffffff chroma COLOR_FORMAT */ + + dd_emit(ctx, 1, 1); /* ffffffff pattern COLOR_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff pattern SHAPE */ + dd_emit(ctx, 1, 1); /* ffffffff pattern PATTERN_SELECT */ + + dd_emit(ctx, 1, 0xa); /* ffffffff surf2d SRC_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff surf2d DMA_SRC */ + dd_emit(ctx, 1, 0); /* 000000ff surf2d SRC_ADDRESS_HIGH */ + dd_emit(ctx, 1, 0); /* ffffffff surf2d SRC_ADDRESS_LOW */ + dd_emit(ctx, 1, 0x40); /* 0000ffff surf2d SRC_PITCH */ + dd_emit(ctx, 1, 0); /* 0000000f surf2d SRC_TILE_MODE_Z */ + dd_emit(ctx, 1, 2); /* 0000000f surf2d SRC_TILE_MODE_Y */ + dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_HEIGHT */ + dd_emit(ctx, 1, 1); /* 00000001 surf2d SRC_LINEAR */ + dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_WIDTH */ + + dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_X */ + dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_Y */ + dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_X */ + dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_Y */ + dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_X */ + dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_Y */ + dd_emit(ctx, 1, 1); /* ffffffff gdirect COLOR_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff gdirect OPERATION */ + dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_X */ + dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_Y */ + + dd_emit(ctx, 1, 0); /* 0000ffff blit SRC_Y */ + dd_emit(ctx, 1, 0); /* ffffffff blit OPERATION */ + + dd_emit(ctx, 1, 0); /* ffffffff ifc OPERATION */ + + dd_emit(ctx, 1, 0); /* ffffffff iifc INDEX_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff iifc LUT_OFFSET */ + dd_emit(ctx, 1, 4); /* ffffffff iifc COLOR_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff iifc OPERATION */ + } + + /* m2mf state */ + dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_COUNT */ + dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_LENGTH_IN */ + dd_emit(ctx, 2, 0); /* ffffffff m2mf OFFSET_IN, OFFSET_OUT */ + dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_OUT */ + dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_OUT */ + dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_OUT_Z */ + dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_OUT */ + dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_OUT_X, Y */ + dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_OUT */ + dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_IN */ + dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_IN */ + dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_IN_Z */ + dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_IN */ + dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_IN_X, Y */ + dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_IN */ + + /* more compat 2d state */ + if (device->chipset == 0x50) { + dd_emit(ctx, 1, 1); /* ffffffff line COLOR_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff line OPERATION */ + + dd_emit(ctx, 1, 1); /* ffffffff triangle COLOR_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff triangle OPERATION */ + + dd_emit(ctx, 1, 0); /* 0000000f sifm TILE_MODE_Z */ + dd_emit(ctx, 1, 2); /* 0000000f sifm TILE_MODE_Y */ + dd_emit(ctx, 1, 0); /* 000000ff sifm FORMAT_FILTER */ + dd_emit(ctx, 1, 1); /* 000000ff sifm FORMAT_ORIGIN */ + dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_PITCH */ + dd_emit(ctx, 1, 1); /* 00000001 sifm SRC_LINEAR */ + dd_emit(ctx, 1, 0); /* 000000ff sifm SRC_OFFSET_HIGH */ + dd_emit(ctx, 1, 0); /* ffffffff sifm SRC_OFFSET */ + dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_HEIGHT */ + dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_WIDTH */ + dd_emit(ctx, 1, 3); /* ffffffff sifm COLOR_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff sifm OPERATION */ + + dd_emit(ctx, 1, 0); /* ffffffff sifc OPERATION */ + } + + /* tesla state */ + dd_emit(ctx, 1, 0); /* 0000000f GP_TEXTURES_LOG2 */ + dd_emit(ctx, 1, 0); /* 0000000f GP_SAMPLERS_LOG2 */ + dd_emit(ctx, 1, 0); /* 000000ff */ + dd_emit(ctx, 1, 0); /* ffffffff */ + dd_emit(ctx, 1, 4); /* 000000ff UNK12B0_0 */ + dd_emit(ctx, 1, 0x70); /* 000000ff UNK12B0_1 */ + dd_emit(ctx, 1, 0x80); /* 000000ff UNK12B0_3 */ + 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(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 (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 (device->chipset == 0x50) { + dd_emit(ctx, 1, 0); /* 000000ff SEMANTIC_LAYER */ + dd_emit(ctx, 1, 0); /* 00000001 */ + } else { + dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_PTSZ.ENABLE */ + dd_emit(ctx, 1, 0x29); /* 000000ff SEMANTIC_PTSZ.PTSZ_ID */ + dd_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM */ + dd_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ + dd_emit(ctx, 1, 8); /* 0000000f SMENATIC_CLIP.CLIP_HIGH */ + dd_emit(ctx, 1, 4); /* 000000ff SEMANTIC_CLIP.CLIP_LO */ + dd_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */ + dd_emit(ctx, 1, 0); /* 00000001 UNK1900 */ + } + dd_emit(ctx, 1, 0); /* 00000007 RT_CONTROL_MAP0 */ + dd_emit(ctx, 1, 1); /* 00000007 RT_CONTROL_MAP1 */ + dd_emit(ctx, 1, 2); /* 00000007 RT_CONTROL_MAP2 */ + dd_emit(ctx, 1, 3); /* 00000007 RT_CONTROL_MAP3 */ + dd_emit(ctx, 1, 4); /* 00000007 RT_CONTROL_MAP4 */ + dd_emit(ctx, 1, 5); /* 00000007 RT_CONTROL_MAP5 */ + dd_emit(ctx, 1, 6); /* 00000007 RT_CONTROL_MAP6 */ + dd_emit(ctx, 1, 7); /* 00000007 RT_CONTROL_MAP7 */ + dd_emit(ctx, 1, 1); /* 0000000f RT_CONTROL_COUNT */ + dd_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_UNK */ + 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 (device->chipset != 0x50) + dd_emit(ctx, 3, 0); /* 1, 1, 1 */ + else + dd_emit(ctx, 2, 0); /* 1, 1 */ + dd_emit(ctx, 1, 0); /* ffffffff GP_ENABLE */ + 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(device->chipset)) { + dd_emit(ctx, 1, 3); /* 00000003 */ + dd_emit(ctx, 1, 0); /* 00000001 UNK1418. Alone. */ + } + 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 (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 */ + dd_emit(ctx, 1, 0xc); /* 000000ff FP_INTERPOLANT_CTRL.OFFSET */ + dd_emit(ctx, 1, 1); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */ + dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */ + dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */ + dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */ + 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 (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 (device->chipset != 0x50) + dd_emit(ctx, 8, 0); /* 00000001 */ + 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 */ + dd_emit(ctx, 1, 0); /* 000000ff VTX_ATTR_DEFINE.ATTR */ + } + dd_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ + dd_emit(ctx, 1, 0x14); /* 0000001f ZETA_FORMAT */ + 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(device->chipset)) + dd_emit(ctx, 1, 0); /* 00000001 */ + dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_BACK */ + 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 (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 (device->chipset != 0x50) { + dd_emit(ctx, 1, 0xe00); /* 7fff */ + dd_emit(ctx, 1, 0x1000); /* 7fff */ + dd_emit(ctx, 1, 0x1e00); /* 7fff */ + } + dd_emit(ctx, 1, 0); /* 00000001 BEGIN_END_ACTIVE */ + dd_emit(ctx, 1, 1); /* 00000001 POLYGON_MODE_??? */ + dd_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */ + dd_emit(ctx, 1, 1); /* 000000ff FP_REG_ALLOC_TEMP... without /4? */ + dd_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */ + dd_emit(ctx, 1, 1); /* 00000001 */ + dd_emit(ctx, 1, 0); /* 00000001 */ + 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(device->chipset)) + dd_emit(ctx, 1, 0x200); + dd_emit(ctx, 1, 0); /* 00000001 */ + if (device->chipset < 0xa0) { + dd_emit(ctx, 1, 1); /* 00000001 */ + dd_emit(ctx, 1, 0x70); /* 000000ff */ + dd_emit(ctx, 1, 0x80); /* 000000ff */ + dd_emit(ctx, 1, 0); /* 000000ff */ + dd_emit(ctx, 1, 0); /* 00000001 */ + dd_emit(ctx, 1, 1); /* 00000001 */ + dd_emit(ctx, 1, 0x70); /* 000000ff */ + dd_emit(ctx, 1, 0x80); /* 000000ff */ + dd_emit(ctx, 1, 0); /* 000000ff */ + } else { + dd_emit(ctx, 1, 1); /* 00000001 */ + dd_emit(ctx, 1, 0xf0); /* 000000ff */ + dd_emit(ctx, 1, 0xff); /* 000000ff */ + dd_emit(ctx, 1, 0); /* 000000ff */ + dd_emit(ctx, 1, 0); /* 00000001 */ + dd_emit(ctx, 1, 1); /* 00000001 */ + dd_emit(ctx, 1, 0xf0); /* 000000ff */ + dd_emit(ctx, 1, 0xff); /* 000000ff */ + dd_emit(ctx, 1, 0); /* 000000ff */ + dd_emit(ctx, 1, 9); /* 0000003f UNK114C.COMP,SIZE */ + } + + /* eng2d state */ + dd_emit(ctx, 1, 0); /* 00000001 eng2d COLOR_KEY_ENABLE */ + dd_emit(ctx, 1, 0); /* 00000007 eng2d COLOR_KEY_FORMAT */ + dd_emit(ctx, 1, 1); /* ffffffff eng2d DST_DEPTH */ + dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DST_FORMAT */ + dd_emit(ctx, 1, 0); /* ffffffff eng2d DST_LAYER */ + dd_emit(ctx, 1, 1); /* 00000001 eng2d DST_LINEAR */ + dd_emit(ctx, 1, 0); /* 00000007 eng2d PATTERN_COLOR_FORMAT */ + dd_emit(ctx, 1, 0); /* 00000007 eng2d OPERATION */ + dd_emit(ctx, 1, 0); /* 00000003 eng2d PATTERN_SELECT */ + dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SIFC_FORMAT */ + dd_emit(ctx, 1, 0); /* 00000001 eng2d SIFC_BITMAP_ENABLE */ + dd_emit(ctx, 1, 2); /* 00000003 eng2d SIFC_BITMAP_UNK808 */ + dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DU_DX_FRACT */ + dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DU_DX_INT */ + dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DV_DY_FRACT */ + dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DV_DY_INT */ + dd_emit(ctx, 1, 0); /* 00000001 eng2d BLIT_CONTROL_FILTER */ + dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DRAW_COLOR_FORMAT */ + dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SRC_FORMAT */ + dd_emit(ctx, 1, 1); /* 00000001 eng2d SRC_LINEAR #2 */ + + num = ctx->ctxvals_pos - base; + ctx->ctxvals_pos = base; + if (IS_NVA3F(device->chipset)) + cp_ctx(ctx, 0x404800, num); + else + cp_ctx(ctx, 0x405400, num); +} + +/* + * xfer areas. These are a pain. + * + * There are 2 xfer areas: the first one is big and contains all sorts of + * stuff, the second is small and contains some per-TP context. + * + * Each area is split into 8 "strands". The areas, when saved to grctx, + * are made of 8-word blocks. Each block contains a single word from + * each strand. The strands are independent of each other, their + * addresses are unrelated to each other, and data in them is closely + * packed together. The strand layout varies a bit between cards: here + * and there, a single word is thrown out in the middle and the whole + * strand is offset by a bit from corresponding one on another chipset. + * For this reason, addresses of stuff in strands are almost useless. + * Knowing sequence of stuff and size of gaps between them is much more + * useful, and that's how we build the strands in our generator. + * + * NVA0 takes this mess to a whole new level by cutting the old strands + * into a few dozen pieces [known as genes], rearranging them randomly, + * and putting them back together to make new strands. Hopefully these + * genes correspond more or less directly to the same PGRAPH subunits + * as in 400040 register. + * + * The most common value in default context is 0, and when the genes + * are separated by 0's, gene bounduaries are quite speculative... + * some of them can be clearly deduced, others can be guessed, and yet + * others won't be resolved without figuring out the real meaning of + * given ctxval. For the same reason, ending point of each strand + * is unknown. Except for strand 0, which is the longest strand and + * its end corresponds to end of the whole xfer. + * + * An unsolved mystery is the seek instruction: it takes an argument + * in bits 8-18, and that argument is clearly the place in strands to + * seek to... but the offsets don't seem to correspond to offsets as + * seen in grctx. Perhaps there's another, real, not randomly-changing + * addressing in strands, and the xfer insn just happens to skip over + * the unused bits? NV10-NV30 PIPE comes to mind... + * + * As far as I know, there's no way to access the xfer areas directly + * without the help of ctxprog. + */ + +static void +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++) + nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val); + ctx->ctxvals_pos += num << 3; +} + +/* Gene declarations... */ + +static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx); +static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx); +static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx); + +static void +nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i; + int offset; + int size = 0; + u32 units = nv_rd32 (ctx->device, 0x1540); + + offset = (ctx->ctxvals_pos+0x3f)&~0x3f; + ctx->ctxvals_base = offset; + + if (device->chipset < 0xa0) { + /* Strand 0 */ + ctx->ctxvals_pos = offset; + nv50_graph_construct_gene_dispatch(ctx); + nv50_graph_construct_gene_m2mf(ctx); + nv50_graph_construct_gene_unk24xx(ctx); + nv50_graph_construct_gene_clipid(ctx); + nv50_graph_construct_gene_zcull(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 1 */ + ctx->ctxvals_pos = offset + 0x1; + nv50_graph_construct_gene_vfetch(ctx); + nv50_graph_construct_gene_eng2d(ctx); + nv50_graph_construct_gene_csched(ctx); + nv50_graph_construct_gene_ropm1(ctx); + nv50_graph_construct_gene_ropm2(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 2 */ + ctx->ctxvals_pos = offset + 0x2; + nv50_graph_construct_gene_ccache(ctx); + nv50_graph_construct_gene_unk1cxx(ctx); + nv50_graph_construct_gene_strmout(ctx); + nv50_graph_construct_gene_unk14xx(ctx); + nv50_graph_construct_gene_unk10xx(ctx); + nv50_graph_construct_gene_unk34xx(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 3: per-ROP group state */ + ctx->ctxvals_pos = offset + 3; + for (i = 0; i < 6; i++) + if (units & (1 << (i + 16))) + nv50_graph_construct_gene_ropc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strands 4-7: per-TP state */ + for (i = 0; i < 4; i++) { + ctx->ctxvals_pos = offset + 4 + i; + if (units & (1 << (2 * i))) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << (2 * i + 1))) + nv50_graph_construct_xfer_tp(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + } + } else { + /* Strand 0 */ + ctx->ctxvals_pos = offset; + nv50_graph_construct_gene_dispatch(ctx); + nv50_graph_construct_gene_m2mf(ctx); + nv50_graph_construct_gene_unk34xx(ctx); + nv50_graph_construct_gene_csched(ctx); + nv50_graph_construct_gene_unk1cxx(ctx); + nv50_graph_construct_gene_strmout(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 1 */ + ctx->ctxvals_pos = offset + 1; + nv50_graph_construct_gene_unk10xx(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 2 */ + ctx->ctxvals_pos = offset + 2; + if (device->chipset == 0xa0) + nv50_graph_construct_gene_unk14xx(ctx); + nv50_graph_construct_gene_unk24xx(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 3 */ + ctx->ctxvals_pos = offset + 3; + nv50_graph_construct_gene_vfetch(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 4 */ + ctx->ctxvals_pos = offset + 4; + nv50_graph_construct_gene_ccache(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 5 */ + ctx->ctxvals_pos = offset + 5; + nv50_graph_construct_gene_ropm2(ctx); + nv50_graph_construct_gene_ropm1(ctx); + /* per-ROP context */ + for (i = 0; i < 8; i++) + if (units & (1<<(i+16))) + nv50_graph_construct_gene_ropc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 6 */ + ctx->ctxvals_pos = offset + 6; + nv50_graph_construct_gene_zcull(ctx); + nv50_graph_construct_gene_clipid(ctx); + nv50_graph_construct_gene_eng2d(ctx); + if (units & (1 << 0)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 1)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 2)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 3)) + nv50_graph_construct_xfer_tp(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 7 */ + ctx->ctxvals_pos = offset + 7; + if (device->chipset == 0xa0) { + if (units & (1 << 4)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 5)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 6)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 7)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 8)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 9)) + nv50_graph_construct_xfer_tp(ctx); + } else { + nv50_graph_construct_gene_unk14xx(ctx); + } + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + } + + ctx->ctxvals_pos = offset + size * 8; + ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f; + cp_lsr (ctx, offset); + cp_out (ctx, CP_SET_XFER_POINTER); + cp_lsr (ctx, size); + cp_out (ctx, CP_SEEK_1); + cp_out (ctx, CP_XFER_1); + cp_wait(ctx, XFER, BUSY); +} + +/* + * non-trivial demagiced parts of ctx init go here + */ + +static void +nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx) +{ + /* start of strand 0 */ + struct nouveau_device *device = ctx->device; + /* SEEK */ + if (device->chipset == 0x50) + xf_emit(ctx, 5, 0); + else if (!IS_NVA3F(device->chipset)) + xf_emit(ctx, 6, 0); + else + xf_emit(ctx, 4, 0); + /* SEEK */ + /* the PGRAPH's internal FIFO */ + 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(device->chipset)) + xf_emit(ctx, 3, 0); + /* SEEK */ + /* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */ + xf_emit(ctx, 9, 0); + /* SEEK */ + xf_emit(ctx, 9, 0); + /* SEEK */ + xf_emit(ctx, 9, 0); + /* SEEK */ + xf_emit(ctx, 9, 0); + /* SEEK */ + if (device->chipset < 0x90) + xf_emit(ctx, 4, 0); + /* SEEK */ + xf_emit(ctx, 2, 0); + /* SEEK */ + xf_emit(ctx, 6*2, 0); + xf_emit(ctx, 2, 0); + /* SEEK */ + xf_emit(ctx, 2, 0); + /* SEEK */ + xf_emit(ctx, 6*2, 0); + xf_emit(ctx, 2, 0); + /* SEEK */ + if (device->chipset == 0x50) + xf_emit(ctx, 0x1c, 0); + else if (device->chipset < 0xa0) + xf_emit(ctx, 0x1e, 0); + else + xf_emit(ctx, 0x22, 0); + /* SEEK */ + xf_emit(ctx, 0x15, 0); +} + +static void +nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx) +{ + /* Strand 0, right after dispatch */ + struct nouveau_device *device = ctx->device; + int smallm2mf = 0; + if (device->chipset < 0x92 || device->chipset == 0x98) + smallm2mf = 1; + /* SEEK */ + xf_emit (ctx, 1, 0); /* DMA_NOTIFY instance >> 4 */ + xf_emit (ctx, 1, 0); /* DMA_BUFFER_IN instance >> 4 */ + xf_emit (ctx, 1, 0); /* DMA_BUFFER_OUT instance >> 4 */ + xf_emit (ctx, 1, 0); /* OFFSET_IN */ + xf_emit (ctx, 1, 0); /* OFFSET_OUT */ + xf_emit (ctx, 1, 0); /* PITCH_IN */ + xf_emit (ctx, 1, 0); /* PITCH_OUT */ + xf_emit (ctx, 1, 0); /* LINE_LENGTH */ + xf_emit (ctx, 1, 0); /* LINE_COUNT */ + xf_emit (ctx, 1, 0x21); /* FORMAT: bits 0-4 INPUT_INC, bits 5-9 OUTPUT_INC */ + xf_emit (ctx, 1, 1); /* LINEAR_IN */ + xf_emit (ctx, 1, 0x2); /* TILING_MODE_IN: bits 0-2 y tiling, bits 3-5 z tiling */ + xf_emit (ctx, 1, 0x100); /* TILING_PITCH_IN */ + xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_IN */ + xf_emit (ctx, 1, 1); /* TILING_DEPTH_IN */ + xf_emit (ctx, 1, 0); /* TILING_POSITION_IN_Z */ + xf_emit (ctx, 1, 0); /* TILING_POSITION_IN */ + xf_emit (ctx, 1, 1); /* LINEAR_OUT */ + xf_emit (ctx, 1, 0x2); /* TILING_MODE_OUT: bits 0-2 y tiling, bits 3-5 z tiling */ + xf_emit (ctx, 1, 0x100); /* TILING_PITCH_OUT */ + xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_OUT */ + xf_emit (ctx, 1, 1); /* TILING_DEPTH_OUT */ + xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT_Z */ + xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT */ + xf_emit (ctx, 1, 0); /* OFFSET_IN_HIGH */ + xf_emit (ctx, 1, 0); /* OFFSET_OUT_HIGH */ + /* SEEK */ + if (smallm2mf) + xf_emit(ctx, 0x40, 0); /* 20 * ffffffff, 3ffff */ + else + xf_emit(ctx, 0x100, 0); /* 80 * ffffffff, 3ffff */ + xf_emit(ctx, 4, 0); /* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */ + /* SEEK */ + if (smallm2mf) + xf_emit(ctx, 0x400, 0); /* ffffffff */ + else + xf_emit(ctx, 0x800, 0); /* ffffffff */ + xf_emit(ctx, 4, 0); /* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */ + /* SEEK */ + xf_emit(ctx, 0x40, 0); /* 20 * bits ffffffff, 3ffff */ + xf_emit(ctx, 0x6, 0); /* 1f, 0, 1f, 0, 1f, 0 */ +} + +static void +nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + xf_emit(ctx, 2, 0); /* RO */ + xf_emit(ctx, 0x800, 0); /* ffffffff */ + switch (device->chipset) { + case 0x50: + case 0x92: + case 0xa0: + xf_emit(ctx, 0x2b, 0); + break; + case 0x84: + xf_emit(ctx, 0x29, 0); + break; + case 0x94: + case 0x96: + case 0xa3: + xf_emit(ctx, 0x27, 0); + break; + case 0x86: + case 0x98: + case 0xa5: + case 0xa8: + case 0xaa: + case 0xac: + case 0xaf: + xf_emit(ctx, 0x25, 0); + break; + } + /* CB bindings, 0x80 of them. first word is address >> 8, second is + * size >> 4 | valid << 24 */ + xf_emit(ctx, 0x100, 0); /* ffffffff CB_DEF */ + xf_emit(ctx, 1, 0); /* 0000007f CB_ADDR_BUFFER */ + xf_emit(ctx, 1, 0); /* 0 */ + xf_emit(ctx, 0x30, 0); /* ff SET_PROGRAM_CB */ + xf_emit(ctx, 1, 0); /* 3f last SET_PROGRAM_CB */ + xf_emit(ctx, 4, 0); /* RO */ + xf_emit(ctx, 0x100, 0); /* ffffffff */ + xf_emit(ctx, 8, 0); /* 1f, 0, 0, ... */ + xf_emit(ctx, 8, 0); /* ffffffff */ + xf_emit(ctx, 4, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 3 */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_CODE_CB */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_TIC */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_TSC */ + xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */ + xf_emit(ctx, 1, 0); /* 000000ff TIC_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff TIC_ADDRESS_LOW */ + xf_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */ + xf_emit(ctx, 1, 0); /* 000000ff TSC_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff TSC_ADDRESS_LOW */ + xf_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */ + xf_emit(ctx, 1, 0); /* 000000ff VP_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff VP_ADDRESS_LOW */ + xf_emit(ctx, 1, 0); /* 00ffffff VP_START_ID */ + xf_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0); /* 000000ff GP_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff GP_ADDRESS_LOW */ + xf_emit(ctx, 1, 0); /* 00ffffff GP_START_ID */ + xf_emit(ctx, 1, 0); /* 000000ff FP_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */ + xf_emit(ctx, 1, 0); /* 00ffffff FP_START_ID */ +} + +static void +nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx) +{ + 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 */ + xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ + 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 (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 (device->chipset) { + case 0x50: + case 0x86: + case 0x98: + case 0xaa: + case 0xac: + xf_emit(ctx, 0xa0, 0); /* ffffffff */ + break; + case 0x84: + case 0x92: + case 0x94: + case 0x96: + xf_emit(ctx, 0x120, 0); + break; + case 0xa5: + case 0xa8: + xf_emit(ctx, 0x100, 0); /* ffffffff */ + break; + case 0xa0: + case 0xa3: + case 0xaf: + xf_emit(ctx, 0x400, 0); /* ffffffff */ + break; + } + xf_emit(ctx, 4, 0); /* 3f, 0, 0, 0 */ + xf_emit(ctx, 4, 0); /* ffffffff */ + } + 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 */ + xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ + xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_TEMP */ + xf_emit(ctx, 1, 1); /* 00000001 RASTERIZE_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */ + xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ + xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ +} + +static void +nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx) +{ + 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 */ + xf_emit(ctx, 0x10, 0x04000000); /* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */ + xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */ + xf_emit(ctx, 0x20, 0); /* ffffffff POLYGON_STIPPLE */ + xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */ + xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */ + xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ + xf_emit(ctx, 1, 0); /* 00000007 */ + xf_emit(ctx, 1, 0x1fe21); /* 0001ffff tesla UNK0FAC */ + if (device->chipset >= 0xa0) + xf_emit(ctx, 1, 0x0fac6881); + if (IS_NVA3F(device->chipset)) { + xf_emit(ctx, 1, 1); + xf_emit(ctx, 3, 0); + } +} + +static void +nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + /* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */ + if (device->chipset != 0x50) { + xf_emit(ctx, 5, 0); /* ffffffff */ + xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* 000003ff */ + xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */ + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 2, 4); /* 7f, ff */ + xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + } + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + 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 (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 (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 */ + xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0F8C */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */ + xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 0); /* 0000000f */ + if (device->chipset == 0x50) + xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */ + else + xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */ + xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ + xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ + xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */ + xf_emit(ctx, 3, 0); /* f, 0, 0 */ + xf_emit(ctx, 3, 0); /* ffffffff last VIEWPORT_SCALE? */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */ + xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */ + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_TRANSLATE */ + xf_emit(ctx, 3, 0); /* f, 0, 0 */ + xf_emit(ctx, 3, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 2, 0x88); /* 000001ff tesla UNK19D8 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */ + xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */ + xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ + xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ + xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */ + xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ + xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 0); /* 0000000f */ + xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */ + 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(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 (device->chipset != 0x50) { + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* 000003ff */ + } + xf_emit(ctx, 0x20, 0); /* 10xbits ffffffff, 3fffff. SCISSOR_* */ + xf_emit(ctx, 1, 0); /* f */ + xf_emit(ctx, 1, 0); /* 0? */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 003fffff */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */ + xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ + xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ + xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ + xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ + xf_emit(ctx, 1, 0); /* 0000000f */ +} + +static void +nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx) +{ + 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 */ + xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ + xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ + xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ + xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */ + xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */ + xf_emit(ctx, 1, 0); /* 00000001 */ + 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 */ + xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */ + xf_emit(ctx, 1, 0); /* 0000ffff */ + xf_emit(ctx, 1, 0); /* 00000001 UNK0FB0 */ + xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */ + xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ + xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */ + 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_FUNC_REF */ + 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 */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ + xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */ + xf_emit(ctx, 1, 0); /* 00000007 */ + 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 */ + xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ + xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */ + /* SEEK */ + xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */ + xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */ + xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */ + xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */ + xf_emit(ctx, 1, 0x10); /* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */ + 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 (device->chipset != 0x50) + xf_emit(ctx, 1, 0); /* 0fffffff tesla UNK1104 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK151C */ +} + +static void +nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx) +{ + /* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* 00000007 UNK0FB4 */ + /* SEEK */ + xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_HORIZ */ + xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_VERT */ + xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */ + xf_emit(ctx, 2, 0x04000000); /* 07ffffff UNK1508 */ + xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */ + xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_WIDTH */ + xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ID */ + xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff CLIPID_ADDRESS_LOW */ + xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_HEIGHT */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_CLIPID */ +} + +static void +nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i; + /* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */ + /* SEEK */ + xf_emit(ctx, 0x33, 0); + /* SEEK */ + xf_emit(ctx, 2, 0); + /* SEEK */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + /* SEEK */ + 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 */ + xf_emit(ctx, 8, 0); /* 0? */ + xf_emit(ctx, 9, 0); /* ffffffff, 7ff */ + + xf_emit(ctx, 4, 0); /* RO */ + xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ + xf_emit(ctx, 1, 0); /* 1ff */ + xf_emit(ctx, 8, 0); /* 0? */ + xf_emit(ctx, 9, 0); /* ffffffff, 7ff */ + } else { + xf_emit(ctx, 0xc, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ + xf_emit(ctx, 1, 0); /* 1ff */ + xf_emit(ctx, 8, 0); /* 0? */ + + /* SEEK */ + xf_emit(ctx, 0xc, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ + xf_emit(ctx, 1, 0); /* 1ff */ + xf_emit(ctx, 8, 0); /* 0? */ + } + /* SEEK */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + 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 (device->chipset != 0x50) + xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ + xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ + xf_emit(ctx, 1, 1); /* 00000001 */ + /* SEEK */ + 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 */ + xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */ + xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + xf_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM_ID */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0); /* 0000000f */ + xf_emit(ctx, 1, 1); /* 00000001 */ + for (i = 0; i < 10; i++) { + /* SEEK */ + xf_emit(ctx, 0x40, 0); /* ffffffff */ + xf_emit(ctx, 0x10, 0); /* 3, 0, 0.... */ + xf_emit(ctx, 0x10, 0); /* ffffffff */ + } + /* SEEK */ + xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_CTRL */ + xf_emit(ctx, 1, 1); /* 00000001 */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */ + 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 (device->chipset != 0x50) + xf_emit(ctx, 1, 0); /* 000003ff */ +} + +static void +nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) +{ + 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(device->chipset)) + acnt = 0x20; + /* SEEK */ + if (device->chipset >= 0xa0) { + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK13A4 */ + xf_emit(ctx, 1, 1); /* 00000fff tesla UNK1318 */ + } + xf_emit(ctx, 1, 0); /* ffffffff VERTEX_BUFFER_FIRST */ + xf_emit(ctx, 1, 0); /* 00000001 PRIMITIVE_RESTART_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 UNK0DE8 */ + xf_emit(ctx, 1, 0); /* ffffffff PRIMITIVE_RESTART_INDEX */ + xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ + xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ + xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATR_MASK_UNK0DD0 */ + xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ + xf_emit(ctx, 1, 0x20); /* 0000ffff tesla UNK129C */ + xf_emit(ctx, 1, 0); /* 000000ff turing UNK370??? */ + xf_emit(ctx, 1, 0); /* 0000ffff turing USER_PARAM_COUNT */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + /* SEEK */ + if (IS_NVA3F(device->chipset)) + xf_emit(ctx, 0xb, 0); /* RO */ + else if (device->chipset >= 0xa0) + xf_emit(ctx, 0x9, 0); /* RO */ + else + xf_emit(ctx, 0x8, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* 00000001 EDGE_FLAG */ + xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ + /* SEEK */ + xf_emit(ctx, 0xc, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* 7f/ff */ + xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */ + xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ + xf_emit(ctx, 1, 4); /* 000001ff UNK1A28 */ + xf_emit(ctx, 1, 8); /* 000001ff UNK0DF0 */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + if (device->chipset == 0x50) + xf_emit(ctx, 1, 0x3ff); /* 3ff tesla UNK0D68 */ + else + xf_emit(ctx, 1, 0x7ff); /* 7ff tesla UNK0D68 */ + if (device->chipset == 0xa8) + xf_emit(ctx, 1, 0x1e00); /* 7fff */ + /* SEEK */ + xf_emit(ctx, 0xc, 0); /* RO or close */ + /* SEEK */ + 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 (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(device->chipset)) { + xf_emit(ctx, 0x10, 0); /* 0? */ + xf_emit(ctx, 2, 0); /* weird... */ + xf_emit(ctx, 2, 0); /* RO */ + } else { + xf_emit(ctx, 8, 0); /* 0? */ + xf_emit(ctx, 1, 0); /* weird... */ + xf_emit(ctx, 2, 0); /* RO */ + } + /* SEEK */ + 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 (device->chipset >= 0xa0) + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1118? */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */ + xf_emit(ctx, 1, 0); /* f/1f */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */ + xf_emit(ctx, 1, 0); /* f/1f */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* RO */ + xf_emit(ctx, 2, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK111C? */ + xf_emit(ctx, 1, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* 000000ff UNK15F4_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff UNK15F4_ADDRESS_LOW */ + xf_emit(ctx, 1, 0); /* 000000ff UNK0F84_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff UNK0F84_ADDRESS_LOW */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */ + xf_emit(ctx, 3, 0); /* f/1f */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* 00000fff VERTEX_ARRAY_STRIDE */ + xf_emit(ctx, 3, 0); /* f/1f */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_LOW */ + xf_emit(ctx, 3, 0); /* f/1f */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_ARRAY_HIGH */ + xf_emit(ctx, 3, 0); /* f/1f */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_LIMIT_LOW */ + xf_emit(ctx, 3, 0); /* f/1f */ + /* SEEK */ + xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_LIMIT_HIGH */ + xf_emit(ctx, 3, 0); /* f/1f */ + /* SEEK */ + if (IS_NVA3F(device->chipset)) { + xf_emit(ctx, acnt, 0); /* f */ + xf_emit(ctx, 3, 0); /* f/1f */ + } + /* SEEK */ + 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 (device->chipset < 0xa0) { + xf_emit(ctx, 0x41, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 0x11, 0); /* RO */ + } else if (!IS_NVA3F(device->chipset)) + xf_emit(ctx, 0x50, 0); /* RO */ + else + xf_emit(ctx, 0x58, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ + xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ + xf_emit(ctx, 1, 1); /* 1 UNK0DEC */ + /* SEEK */ + xf_emit(ctx, acnt*4, 0); /* ffffffff VTX_ATTR */ + xf_emit(ctx, 4, 0); /* f/1f, 0, 0, 0 */ + /* SEEK */ + if (IS_NVA3F(device->chipset)) + xf_emit(ctx, 0x1d, 0); /* RO */ + else + xf_emit(ctx, 0x16, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ + xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ + /* SEEK */ + if (device->chipset < 0xa0) + xf_emit(ctx, 8, 0); /* RO */ + 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 (device->chipset == 0xa0) + rep = 0xc; + else + rep = 4; + for (i = 0; i < rep; i++) { + /* SEEK */ + 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 */ + xf_emit(ctx, 4, 0); /* ffffffff */ + } + /* SEEK */ + xf_emit(ctx, 1, 0); /* 113/111 */ + xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ + xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ + xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATTR_MASK_UNK0DD0 */ + xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + /* SEEK */ + if (IS_NVA3F(device->chipset)) + xf_emit(ctx, 7, 0); /* weird... */ + else + xf_emit(ctx, 5, 0); /* weird... */ +} + +static void +nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx) +{ + 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 (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 */ + xf_emit(ctx, 2, 1); /* 0000ffff IFC_CLIP_W, H */ + xf_emit(ctx, 1, 0); /* 00000001 IFC_CLIP_ENABLE */ + } + xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ + xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */ + xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */ + xf_emit(ctx, 1, 0x11); /* 3f[NV50]/7f[NV84+] DST_FORMAT */ + xf_emit(ctx, 1, 0); /* 0001ffff DRAW_POINT_X */ + xf_emit(ctx, 1, 8); /* 0000000f DRAW_UNK58C */ + xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_X_FRACT */ + xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_X_INT */ + xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_Y_FRACT */ + xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_Y_INT */ + xf_emit(ctx, 1, 0); /* 000fffff SIFC_DX_DU_FRACT */ + xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DX_DU_INT */ + xf_emit(ctx, 1, 0); /* 000fffff SIFC_DY_DV_FRACT */ + xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DY_DV_INT */ + xf_emit(ctx, 1, 1); /* 0000ffff SIFC_WIDTH */ + xf_emit(ctx, 1, 1); /* 0000ffff SIFC_HEIGHT */ + xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */ + xf_emit(ctx, 1, 2); /* 00000003 SIFC_BITMAP_UNK808 */ + xf_emit(ctx, 1, 0); /* 00000003 SIFC_BITMAP_LINE_PACK_MODE */ + xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_LSB_FIRST */ + xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_ENABLE */ + xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_X */ + xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_Y */ + xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */ + xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */ + xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */ + xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */ + xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_W */ + xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_H */ + xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_X_FRACT */ + xf_emit(ctx, 1, 0); /* 0001ffff BLIT_SRC_X_INT */ + xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_Y_FRACT */ + xf_emit(ctx, 1, 0); /* 00000001 UNK888 */ + xf_emit(ctx, 1, 4); /* 0000003f UNK884 */ + xf_emit(ctx, 1, 0); /* 00000007 UNK880 */ + xf_emit(ctx, 1, 1); /* 0000001f tesla UNK0FB8 */ + xf_emit(ctx, 1, 0x15); /* 000000ff tesla UNK128C */ + xf_emit(ctx, 2, 0); /* 00000007, ffff0ff3 */ + xf_emit(ctx, 1, 0); /* 00000001 UNK260 */ + xf_emit(ctx, 1, 0x4444480); /* 1fffffff UNK870 */ + /* SEEK */ + xf_emit(ctx, 0x10, 0); + /* SEEK */ + xf_emit(ctx, 0x27, 0); +} + +static void +nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx) +{ + 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??? */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */ + xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ + xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + xf_emit(ctx, 1, 0); /* 000003ff */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* ffffffff turing UNK364 */ + xf_emit(ctx, 1, 0); /* 0000000f turing UNK36C */ + xf_emit(ctx, 1, 0); /* 0000ffff USER_PARAM_COUNT */ + xf_emit(ctx, 1, 0x100); /* 00ffffff turing UNK384 */ + xf_emit(ctx, 1, 0); /* 0000000f turing UNK2A0 */ + xf_emit(ctx, 1, 0); /* 0000ffff GRIDID */ + xf_emit(ctx, 1, 0x10001); /* ffffffff GRIDDIM_XY */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */ + xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */ + xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */ + xf_emit(ctx, 1, 1); /* 00000001 LANES32 */ + xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */ + xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */ + /* SEEK */ + xf_emit(ctx, 0x40, 0); /* ffffffff USER_PARAM */ + switch (device->chipset) { + case 0x50: + case 0x92: + xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ + xf_emit(ctx, 0x80, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 0x10*2, 0); /* ffffffff, 1f */ + break; + case 0x84: + xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ + xf_emit(ctx, 0x60, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */ + break; + case 0x94: + case 0x96: + xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ + xf_emit(ctx, 0x40, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 8*2, 0); /* ffffffff, 1f */ + break; + case 0x86: + case 0x98: + xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */ + xf_emit(ctx, 0x10, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */ + break; + case 0xa0: + xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ + xf_emit(ctx, 0xf0, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 0x1e*2, 0); /* ffffffff, 1f */ + break; + case 0xa3: + xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ + xf_emit(ctx, 0x60, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */ + break; + case 0xa5: + case 0xaf: + xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ + xf_emit(ctx, 0x30, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 6*2, 0); /* ffffffff, 1f */ + break; + case 0xaa: + xf_emit(ctx, 0x12, 0); + break; + case 0xa8: + case 0xac: + xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */ + xf_emit(ctx, 0x10, 0); /* fff */ + xf_emit(ctx, 2, 0); /* ff, fff */ + xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */ + break; + } + xf_emit(ctx, 1, 0); /* 0000000f */ + xf_emit(ctx, 1, 0); /* 00000000 */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 0000001f */ + xf_emit(ctx, 4, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 4, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 000000ff */ +} + +static void +nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) +{ + 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 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */ + xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */ + xf_emit(ctx, 3, 0); /* 00000001 POLYGON_OFFSET_*_ENABLE */ + xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */ + xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */ + xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ + xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ + xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_UNITS */ + xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_FACTOR */ + xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */ + xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */ + xf_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_LINEAR */ + 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(device->chipset)) + xf_emit(ctx, 1, 3); /* 00000003 UNK16B4 */ + 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 */ + xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ + xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ + xf_emit(ctx, 1, 5); /* 0000000f UNK1408 */ + xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */ + xf_emit(ctx, 1, 0); /* ffffffff POINT_SIZE */ + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* 00000007 tesla UNK0FB4 */ + if (device->chipset != 0x50) { + xf_emit(ctx, 1, 0); /* 3ff */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK1110 */ + } + 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 */ + xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */ + xf_emit(ctx, 0x20, 0); /* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK187C */ + xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ + xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + xf_emit(ctx, 1, 5); /* 0000000f tesla UNK1220 */ + xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1A20 */ + 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 (device->chipset != 0x50) + xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ + if (device->chipset < 0xa0) + xf_emit(ctx, 0x1c, 0); /* RO */ + 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 */ + xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ + 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 (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 (device->chipset < 0xa0) + xf_emit(ctx, 0x25, 0); + else + xf_emit(ctx, 0x3b, 0); +} + +static void +nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx) +{ + 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 (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 (device->chipset == 0x50) + xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */ + else + xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + /* SEEK */ + xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */ + xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */ + 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 (device->chipset >= 0xa0) { + xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */ + xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */ + } + xf_emit(ctx, 1, 0); /* 0000ffff DMA_STRMOUT */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */ + xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */ + xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */ + xf_emit(ctx, 2, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + /* SEEK */ + xf_emit(ctx, 0x20, 0); /* ffffffff STRMOUT_MAP */ + xf_emit(ctx, 1, 0); /* 0000000f */ + xf_emit(ctx, 1, 0); /* 00000000? */ + xf_emit(ctx, 2, 0); /* ffffffff */ +} + +static void +nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx) +{ + 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(device->chipset)) + xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ +} + +static void +nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + /* SEEK */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 2, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */ + xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */ + xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ + xf_emit(ctx, 1, 0); /* 7 */ + /* SEEK */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */ + xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */ + xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */ + xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */ + xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */ + xf_emit(ctx, 1, 0); /* 00000001 eng2d UNK260 */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + xf_emit(ctx, 1, 0); /* 00000007 */ + if (IS_NVA3F(device->chipset)) + xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ +} + +static void +nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int magic2; + if (device->chipset == 0x50) { + magic2 = 0x00003e60; + } else if (!IS_NVA3F(device->chipset)) { + magic2 = 0x001ffe67; + } else { + magic2 = 0x00087e67; + } + xf_emit(ctx, 1, 0); /* f/7 MUTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ + xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ + xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ + 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(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 (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 */ + xf_emit(ctx, 1, 0x10); /* 3ff/ff VIEW_VOLUME_CLIP_CTRL */ + xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */ + 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 (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 (device->chipset != 0xa0) { + if (IS_NVA3F(device->chipset)) + xf_emit(ctx, 1, 0); /* 0000000f UNK15C8 */ + else + xf_emit(ctx, 1, 0x15); /* ff */ + } + } + xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ + 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 */ + 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); /* 00000001 STENCIL_FRONT_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ + xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ + xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */ + xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ + 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 */ + xf_emit(ctx, 1, 0); /* 0000000f */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */ + 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_FUNC_REF */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ + xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ + xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */ + xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ + xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ + xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ + 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 */ + xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */ + 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_FUNC_REF */ + 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 */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ + xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */ + xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 2, 0); /* ffff0ff3, ffff */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */ + xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + 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 (device->chipset >= 0xa0) { + xf_emit(ctx, 2, 0); + xf_emit(ctx, 1, 0x1001); + xf_emit(ctx, 0xb, 0); + } else { + xf_emit(ctx, 1, 0); /* 00000007 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + } + xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ + 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 (device->chipset != 0x50) { + xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */ + xf_emit(ctx, 1, 0); /* 000000ff */ + } + xf_emit(ctx, 1, 0); /* 00000007 OPERATION */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ + xf_emit(ctx, 2, 1); /* 00000007 BLEND_EQUATION_RGB, ALPHA */ + xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ + xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ + xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */ + xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ + xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ + xf_emit(ctx, 1, 0); /* 00000001 */ + 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(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 */ + xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ + xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */ + xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */ + xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */ + xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */ + xf_emit(ctx, 2, 0); /* 00000001 */ + xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ + xf_emit(ctx, 1, 0); /* 0000000f */ + xf_emit(ctx, 1, 0); /* 00000003 */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 2, 0); /* 00000001 */ + xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* 000003ff */ + } else if (device->chipset >= 0xa0) { + xf_emit(ctx, 2, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* 00000007 */ + xf_emit(ctx, 1, 0); /* 00000003 */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 2, 0); /* 00000001 */ + } else { + xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1430 */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ + } + 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 (device->chipset >= 0xa0) + xf_emit(ctx, 2, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* 000003ff */ + xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ + xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ + xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ + 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_ALPHA */ + xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ + xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ + 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 (device->chipset >= 0xa0) + xf_emit(ctx, 1, 0); /* 00000001 UNK12E4? NVA3+ only? */ + 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 */ + xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */ + xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ + xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */ + xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK15C4 */ + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */ + } + xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ + xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ + xf_emit(ctx, 1, 0); /* 00000007 PATTERN_COLOR_FORMAT */ + xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_COLOR */ + xf_emit(ctx, 1, 0); /* 00000001 PATTERN_MONO_FORMAT */ + xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_BITMAP */ + xf_emit(ctx, 1, 0); /* 00000003 PATTERN_SELECT */ + xf_emit(ctx, 1, 0); /* 000000ff ROP */ + xf_emit(ctx, 1, 0); /* ffffffff BETA1 */ + xf_emit(ctx, 1, 0); /* ffffffff BETA4 */ + xf_emit(ctx, 1, 0); /* 00000007 OPERATION */ + xf_emit(ctx, 0x50, 0); /* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */ +} + +static void +nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int magic3; + switch (device->chipset) { + case 0x50: + magic3 = 0x1000; + break; + case 0x86: + case 0x98: + case 0xa8: + case 0xaa: + case 0xac: + case 0xaf: + magic3 = 0x1e00; + break; + default: + magic3 = 0; + } + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 4); /* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */ + 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(device->chipset)) + xf_emit(ctx, 0x1f, 0); /* ffffffff */ + 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 (device->chipset >= 0xa0) + xf_emit(ctx, 1, 0x03020100); /* ffffffff */ + else + xf_emit(ctx, 1, 0x00608080); /* fffffff VP_RESULT_MAP_0 */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 2, 0); /* 111/113, 7f/ff */ + xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ + if (magic3) + xf_emit(ctx, 1, magic3); /* 00007fff tesla UNK141C */ + xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 0); /* 111/113 */ + xf_emit(ctx, 0x1f, 0); /* ffffffff GP_RESULT_MAP_1 up */ + xf_emit(ctx, 1, 0); /* 0000001f */ + xf_emit(ctx, 1, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ + xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0x03020100); /* ffffffff GP_RESULT_MAP_0 */ + xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */ + if (magic3) + xf_emit(ctx, 1, magic3); /* 7fff tesla UNK141C */ + xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 0); /* 111/113 */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */ + xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 0); /* 00000003 tesla UNK13A0 */ + xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + xf_emit(ctx, 1, 0); /* 111/113 */ + 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 (device->chipset < 0xa0) + xf_emit(ctx, 0xa20, 0); /* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */ + else if (!IS_NVA3F(device->chipset)) + xf_emit(ctx, 0x210, 0); /* ffffffff */ + else + xf_emit(ctx, 0x410, 0); /* ffffffff */ + xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ + xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */ + xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ +} + +static void +nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int magic1, magic2; + if (device->chipset == 0x50) { + magic1 = 0x3ff; + magic2 = 0x00003e60; + } else if (!IS_NVA3F(device->chipset)) { + magic1 = 0x7ff; + magic2 = 0x001ffe67; + } else { + magic1 = 0x7ff; + magic2 = 0x00087e67; + } + 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(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 */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ + xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ + xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR */ + xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */ + xf_emit(ctx, 1, 0); /* 00000001 UNK0FDC */ + xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ + xf_emit(ctx, 1, 0); /* ff[NV50]/3ff[NV84+] */ + xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ + xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_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 */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ + xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */ + xf_emit(ctx, 1, 0); /* 7 */ + xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ + xf_emit(ctx, 1, 0); /* ffffffff COLOR_KEY */ + xf_emit(ctx, 1, 0); /* 00000001 COLOR_KEY_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000007 COLOR_KEY_FORMAT */ + xf_emit(ctx, 2, 0); /* ffffffff SIFC_BITMAP_COLOR */ + 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(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 (device->chipset >= 0xa0) { + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK16B4 */ + xf_emit(ctx, 1, 0); /* 00000003 */ + } else { + xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */ + } + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ + xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ + xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ + xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ + 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(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 */ + xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ + xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_RGB */ + xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_RGB */ + xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_ALPHA */ + xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_ALPHA */ + xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ + } + xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ + xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ + xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */ + xf_emit(ctx, 1, 0); /* 7 */ + xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ + xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ + xf_emit(ctx, 1, 0); /* 00000007 OPERATION */ + 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(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 */ + xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ + xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ + xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ + xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ + 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 */ + xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 8, 1); /* 00000001 UNK19E0 */ + xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ + 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(device->chipset)) + xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ + if (device->chipset == 0x50) + xf_emit(ctx, 1, 0); /* ff */ + else + xf_emit(ctx, 3, 0); /* 1, 7, 3ff */ + xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ + xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000007 */ + xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ + xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ + xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ + xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ + xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */ + xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */ + xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */ + xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + xf_emit(ctx, 1, magic1); /* 3ff/7ff tesla UNK0D68 */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + 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(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 */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_LOCAL */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_STACK */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_DST */ + xf_emit(ctx, 1, 0); /* 7 */ + xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 8, 0); /* 000000ff RT_ADDRESS_HIGH */ + xf_emit(ctx, 8, 0); /* ffffffff RT_LAYER_STRIDE */ + xf_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */ + xf_emit(ctx, 8, 8); /* 0000007f RT_TILE_MODE */ + xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 8, 0x400); /* 0fffffff RT_HORIZ */ + xf_emit(ctx, 8, 0x300); /* 0000ffff RT_VERT */ + xf_emit(ctx, 1, 1); /* 00001fff RT_ARRAY_MODE */ + xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 1, 0x20); /* 00000fff DST_TILE_MODE */ + xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ + xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */ + xf_emit(ctx, 1, 0); /* 000007ff DST_LAYER */ + xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ + xf_emit(ctx, 1, 0); /* ffffffff DST_ADDRESS_LOW */ + xf_emit(ctx, 1, 0); /* 000000ff DST_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0x40); /* 0007ffff DST_PITCH */ + xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */ + xf_emit(ctx, 1, 0); /* 0000ffff */ + xf_emit(ctx, 1, 3); /* 00000003 tesla UNK15AC */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + 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(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 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_ZETA */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ + xf_emit(ctx, 2, 0); /* ffff, ff/3ff */ + xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ + xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ + xf_emit(ctx, 1, 0); /* 00000007 */ + xf_emit(ctx, 1, 0); /* ffffffff ZETA_LAYER_STRIDE */ + xf_emit(ctx, 1, 0); /* 000000ff ZETA_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff ZETA_ADDRESS_LOW */ + xf_emit(ctx, 1, 4); /* 00000007 ZETA_TILE_MODE */ + xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ + xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ + xf_emit(ctx, 1, 0x400); /* 0fffffff ZETA_HORIZ */ + xf_emit(ctx, 1, 0x300); /* 0000ffff ZETA_VERT */ + 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(device->chipset)) + xf_emit(ctx, 1, 0); /* 00000001 */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ + xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ + xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ + 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(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 (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 */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ + xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */ + xf_emit(ctx, 1, 0); /* ff/3ff */ + xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ + xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */ + xf_emit(ctx, 1, 0); /* 00000007 */ + 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(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 (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 */ + xf_emit(ctx, 1, 4); /* 7 */ + xf_emit(ctx, 1, 0); /* 1 */ + xf_emit(ctx, 2, 1); /* 1 */ + xf_emit(ctx, 2, 0); /* 7, f */ + xf_emit(ctx, 1, 1); /* 1 */ + xf_emit(ctx, 1, 0); /* 7/f */ + if (IS_NVA3F(device->chipset)) + xf_emit(ctx, 0x9, 0); /* 1 */ + else + xf_emit(ctx, 0x8, 0); /* 1 */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 8, 1); /* 1 */ + xf_emit(ctx, 1, 0x11); /* 7f */ + xf_emit(ctx, 7, 0); /* 7f */ + xf_emit(ctx, 1, 0xfac6881); /* fffffff */ + xf_emit(ctx, 1, 0xf); /* f */ + xf_emit(ctx, 7, 0); /* f */ + 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(device->chipset)) { + xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ + xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ + } + } +} + +static void +nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + xf_emit(ctx, 2, 0); /* 1 LINKED_TSC. yes, 2. */ + 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 (device->chipset == 0x50) + xf_emit(ctx, 1, 0); /* 3 BLIT_CONTROL */ + else + xf_emit(ctx, 2, 0); /* 3ff, 1 */ + xf_emit(ctx, 1, 0x2a712488); /* ffffffff SRC_TIC_0 */ + xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_1 */ + xf_emit(ctx, 1, 0x4085c000); /* ffffffff SRC_TIC_2 */ + xf_emit(ctx, 1, 0x40); /* ffffffff SRC_TIC_3 */ + xf_emit(ctx, 1, 0x100); /* ffffffff SRC_TIC_4 */ + 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 (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(device->chipset)) { + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */ + xf_emit(ctx, 1, 0); /* 00000003 */ + xf_emit(ctx, 1, 0); /* 000003ff */ + xf_emit(ctx, 1, 0); /* 00000003 */ + xf_emit(ctx, 1, 0); /* 000003ff */ + xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1664 / turing UNK03E8 */ + xf_emit(ctx, 1, 0); /* 00000003 */ + xf_emit(ctx, 1, 0); /* 000003ff */ + } else { + xf_emit(ctx, 0x6, 0); + } + xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_TEXTURE */ + xf_emit(ctx, 1, 0); /* 0000ffff DMA_SRC */ +} + +static void +nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx) +{ + 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 */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */ + xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */ + xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */ + xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */ + 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(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 */ + xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ + xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ + xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */ + xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ + xf_emit(ctx, 1, 0); /* ffff0ff3 */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */ + xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */ + xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */ + xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */ + xf_emit(ctx, 1, 0x30201000); /* ffffffff tesla UNK1670 */ + xf_emit(ctx, 1, 0x70605040); /* ffffffff tesla UNK1670 */ + xf_emit(ctx, 1, 0xb8a89888); /* ffffffff tesla UNK1670 */ + xf_emit(ctx, 1, 0xf8e8d8c8); /* ffffffff tesla UNK1670 */ + xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ + xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ +} + +static void +nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx) +{ + 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); + nv50_graph_construct_xfer_unk8cxx(ctx); + } else { + nv50_graph_construct_xfer_tex(ctx); + nv50_graph_construct_xfer_tprop(ctx); + nv50_graph_construct_xfer_unk8cxx(ctx); + nv50_graph_construct_xfer_unk84xx(ctx); + } +} + +static void +nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i, mpcnt = 2; + switch (device->chipset) { + case 0x98: + case 0xaa: + mpcnt = 1; + break; + case 0x50: + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0xa8: + case 0xac: + mpcnt = 2; + break; + case 0xa0: + case 0xa3: + case 0xa5: + case 0xaf: + mpcnt = 3; + break; + } + for (i = 0; i < mpcnt; i++) { + xf_emit(ctx, 1, 0); /* ff */ + xf_emit(ctx, 1, 0x80); /* ffffffff tesla UNK1404 */ + xf_emit(ctx, 1, 0x80007004); /* ffffffff tesla UNK12B0 */ + xf_emit(ctx, 1, 0x04000400); /* ffffffff */ + 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 (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 (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(device->chipset)) + xf_emit(ctx, 0xb, 0); /* RO */ + 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 (device->chipset >= 0xa0) { + xf_emit(ctx, 1, 0x1fe21); /* 0003ffff tesla UNK0FAC */ + } + xf_emit(ctx, 3, 0); /* 7fff, 0, 0 */ + xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ + xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ + xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */ + xf_emit(ctx, 1, 1); /* 00000001 LANES32 */ + xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */ + xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */ + xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */ + 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(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 */ + xf_emit(ctx, 1, 0); /* ff FP_ADDRESS_HIGH */ + xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */ + xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ + xf_emit(ctx, 1, 0); /* 000000ff FRAG_COLOR_CLAMP_EN */ + xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */ + xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */ + xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */ + 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(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 */ + xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */ + xf_emit(ctx, 1, 4); /* ffffffff tesla UNK1400 */ + xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ + xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ + xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ + 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_ALPHA */ + 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(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 */ + xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ + xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */ + xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */ + xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ + xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ + xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */ + xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ + } + xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */ + xf_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */ + /* XXX: demagic this part some day */ + if (device->chipset == 0x50) + xf_emit(ctx, 0x3a0, 0); + else if (device->chipset < 0x94) + xf_emit(ctx, 0x3a2, 0); + else if (device->chipset == 0x98 || device->chipset == 0xaa) + xf_emit(ctx, 0x39f, 0); + else + xf_emit(ctx, 0x3a3, 0); + xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ + xf_emit(ctx, 1, 0); /* 7 OPERATION */ + xf_emit(ctx, 1, 1); /* 1 DST_LINEAR */ + xf_emit(ctx, 0x2d, 0); +} + +static void +nv50_graph_construct_xfer2(struct nouveau_grctx *ctx) +{ + struct nouveau_device *device = ctx->device; + int i; + u32 offset; + u32 units = nv_rd32 (ctx->device, 0x1540); + int size = 0; + + offset = (ctx->ctxvals_pos+0x3f)&~0x3f; + + if (device->chipset < 0xa0) { + for (i = 0; i < 8; i++) { + ctx->ctxvals_pos = offset + i; + /* that little bugger belongs to csched. No idea + * what it's doing here. */ + if (i == 0) + xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */ + if (units & (1 << i)) + nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + } + } else { + /* Strand 0: TPs 0, 1 */ + ctx->ctxvals_pos = offset; + /* that little bugger belongs to csched. No idea + * what it's doing here. */ + xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */ + if (units & (1 << 0)) + nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 1)) + nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 1: TPs 2, 3 */ + ctx->ctxvals_pos = offset + 1; + if (units & (1 << 2)) + nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 3)) + nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 2: TPs 4, 5, 6 */ + ctx->ctxvals_pos = offset + 2; + if (units & (1 << 4)) + nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 5)) + nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 6)) + nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 3: TPs 7, 8, 9 */ + ctx->ctxvals_pos = offset + 3; + if (units & (1 << 7)) + nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 8)) + nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 9)) + nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + } + ctx->ctxvals_pos = offset + size * 8; + ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f; + cp_lsr (ctx, offset); + cp_out (ctx, CP_SET_XFER_POINTER); + cp_lsr (ctx, size); + cp_out (ctx, CP_SEEK_2); + cp_out (ctx, CP_XFER_2); + cp_wait(ctx, XFER, BUSY); +} diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c new file mode 100644 index 00000000000..0b7951a8594 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c @@ -0,0 +1,3039 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nvc0.h" + +void +nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data) +{ + nv_wr32(priv, 0x400204, data); + nv_wr32(priv, 0x400200, icmd); + while (nv_rd32(priv, 0x400700) & 2) {} +} + +int +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 + 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(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); + return ret; + } + + /* PGD pointer */ + nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000)); + nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000)); + nv_wo32(chan, 0x0208, 0xffffffff); + nv_wo32(chan, 0x020c, 0x000000ff); + + /* PGT[0] pointer */ + nv_wo32(chan, 0x1000, 0x00000000); + nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8); + + /* identity-map the whole "channel" into its own vm */ + for (i = 0; i < size / 4096; i++) { + u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1; + nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr)); + nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr)); + } + + /* context pointer (virt) */ + nv_wo32(chan, 0x0210, 0x00080004); + nv_wo32(chan, 0x0214, 0x00000000); + + 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->data = priv->mmio_data; + info->mmio = priv->mmio_list; + info->addr = 0x2000 + (i * 8); + info->priv = priv; + info->buffer_nr = 0; + + 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_wo32(chan, 0x8001c, 1); + nv_wo32(chan, 0x80020, 0); + nv_wo32(chan, 0x80028, 0); + nv_wo32(chan, 0x8002c, 0); + bar->flush(bar); + return 0; + } + + /* HUB_FUC(SET_CHAN) */ + nv_wr32(priv, 0x409840, 0x80000000); + 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"); + nvc0_graph_ctxctl_debug(priv); + nouveau_gpuobj_ref(NULL, &info->chan); + return -EBUSY; + } + + return 0; +} + +void +nvc0_grctx_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access) +{ + info->buffer[info->buffer_nr] = info->addr; + info->buffer[info->buffer_nr] += (align - 1); + info->buffer[info->buffer_nr] &= ~(align - 1); + info->addr = info->buffer[info->buffer_nr++] + size; + + info->data->size = size; + info->data->align = align; + info->data->access = access; + info->data++; +} + +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; + info->mmio->buffer = buf; + info->mmio++; + + if (shift) + data |= info->buffer[buf] >> shift; + nv_wr32(priv, addr, data); +} + +int +nvc0_grctx_fini(struct nvc0_grctx *info) +{ + struct nvc0_graph_priv *priv = info->priv; + int i; + + /* trigger a context unload by unsetting the "next channel valid" bit + * and faking a context switch interrupt + */ + nv_mask(priv, 0x409b04, 0x80000000, 0x00000000); + nv_wr32(priv, 0x409000, 0x00000100); + if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) { + nv_error(priv, "grctx template channel unload timeout\n"); + return -EBUSY; + } + + priv->data = kmalloc(priv->size, GFP_KERNEL); + if (priv->data) { + for (i = 0; i < priv->size; i += 4) + priv->data[i / 4] = nv_ro32(info->chan, 0x80000 + i); + } + + nouveau_gpuobj_ref(NULL, &info->chan); + return priv->data ? 0 : -ENOMEM; +} + +static void +nvc0_grctx_generate_9097(struct nvc0_graph_priv *priv) +{ + u32 fermi = nvc0_graph_class(priv); + u32 mthd; + + nv_mthd(priv, 0x9097, 0x0800, 0x00000000); + nv_mthd(priv, 0x9097, 0x0840, 0x00000000); + nv_mthd(priv, 0x9097, 0x0880, 0x00000000); + nv_mthd(priv, 0x9097, 0x08c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0900, 0x00000000); + nv_mthd(priv, 0x9097, 0x0940, 0x00000000); + nv_mthd(priv, 0x9097, 0x0980, 0x00000000); + nv_mthd(priv, 0x9097, 0x09c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0804, 0x00000000); + nv_mthd(priv, 0x9097, 0x0844, 0x00000000); + nv_mthd(priv, 0x9097, 0x0884, 0x00000000); + nv_mthd(priv, 0x9097, 0x08c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0904, 0x00000000); + nv_mthd(priv, 0x9097, 0x0944, 0x00000000); + nv_mthd(priv, 0x9097, 0x0984, 0x00000000); + nv_mthd(priv, 0x9097, 0x09c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0808, 0x00000400); + nv_mthd(priv, 0x9097, 0x0848, 0x00000400); + nv_mthd(priv, 0x9097, 0x0888, 0x00000400); + nv_mthd(priv, 0x9097, 0x08c8, 0x00000400); + nv_mthd(priv, 0x9097, 0x0908, 0x00000400); + nv_mthd(priv, 0x9097, 0x0948, 0x00000400); + nv_mthd(priv, 0x9097, 0x0988, 0x00000400); + nv_mthd(priv, 0x9097, 0x09c8, 0x00000400); + nv_mthd(priv, 0x9097, 0x080c, 0x00000300); + nv_mthd(priv, 0x9097, 0x084c, 0x00000300); + nv_mthd(priv, 0x9097, 0x088c, 0x00000300); + nv_mthd(priv, 0x9097, 0x08cc, 0x00000300); + nv_mthd(priv, 0x9097, 0x090c, 0x00000300); + nv_mthd(priv, 0x9097, 0x094c, 0x00000300); + nv_mthd(priv, 0x9097, 0x098c, 0x00000300); + nv_mthd(priv, 0x9097, 0x09cc, 0x00000300); + nv_mthd(priv, 0x9097, 0x0810, 0x000000cf); + nv_mthd(priv, 0x9097, 0x0850, 0x00000000); + nv_mthd(priv, 0x9097, 0x0890, 0x00000000); + nv_mthd(priv, 0x9097, 0x08d0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0910, 0x00000000); + nv_mthd(priv, 0x9097, 0x0950, 0x00000000); + nv_mthd(priv, 0x9097, 0x0990, 0x00000000); + nv_mthd(priv, 0x9097, 0x09d0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0814, 0x00000040); + nv_mthd(priv, 0x9097, 0x0854, 0x00000040); + nv_mthd(priv, 0x9097, 0x0894, 0x00000040); + nv_mthd(priv, 0x9097, 0x08d4, 0x00000040); + nv_mthd(priv, 0x9097, 0x0914, 0x00000040); + nv_mthd(priv, 0x9097, 0x0954, 0x00000040); + nv_mthd(priv, 0x9097, 0x0994, 0x00000040); + nv_mthd(priv, 0x9097, 0x09d4, 0x00000040); + nv_mthd(priv, 0x9097, 0x0818, 0x00000001); + nv_mthd(priv, 0x9097, 0x0858, 0x00000001); + nv_mthd(priv, 0x9097, 0x0898, 0x00000001); + nv_mthd(priv, 0x9097, 0x08d8, 0x00000001); + nv_mthd(priv, 0x9097, 0x0918, 0x00000001); + nv_mthd(priv, 0x9097, 0x0958, 0x00000001); + nv_mthd(priv, 0x9097, 0x0998, 0x00000001); + nv_mthd(priv, 0x9097, 0x09d8, 0x00000001); + nv_mthd(priv, 0x9097, 0x081c, 0x00000000); + nv_mthd(priv, 0x9097, 0x085c, 0x00000000); + nv_mthd(priv, 0x9097, 0x089c, 0x00000000); + nv_mthd(priv, 0x9097, 0x08dc, 0x00000000); + nv_mthd(priv, 0x9097, 0x091c, 0x00000000); + nv_mthd(priv, 0x9097, 0x095c, 0x00000000); + nv_mthd(priv, 0x9097, 0x099c, 0x00000000); + nv_mthd(priv, 0x9097, 0x09dc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0820, 0x00000000); + nv_mthd(priv, 0x9097, 0x0860, 0x00000000); + nv_mthd(priv, 0x9097, 0x08a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x08e0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0920, 0x00000000); + nv_mthd(priv, 0x9097, 0x0960, 0x00000000); + nv_mthd(priv, 0x9097, 0x09a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x09e0, 0x00000000); + nv_mthd(priv, 0x9097, 0x2700, 0x00000000); + nv_mthd(priv, 0x9097, 0x2720, 0x00000000); + nv_mthd(priv, 0x9097, 0x2740, 0x00000000); + nv_mthd(priv, 0x9097, 0x2760, 0x00000000); + nv_mthd(priv, 0x9097, 0x2780, 0x00000000); + nv_mthd(priv, 0x9097, 0x27a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x27c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x27e0, 0x00000000); + nv_mthd(priv, 0x9097, 0x2704, 0x00000000); + nv_mthd(priv, 0x9097, 0x2724, 0x00000000); + nv_mthd(priv, 0x9097, 0x2744, 0x00000000); + nv_mthd(priv, 0x9097, 0x2764, 0x00000000); + nv_mthd(priv, 0x9097, 0x2784, 0x00000000); + nv_mthd(priv, 0x9097, 0x27a4, 0x00000000); + nv_mthd(priv, 0x9097, 0x27c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x27e4, 0x00000000); + nv_mthd(priv, 0x9097, 0x2708, 0x00000000); + nv_mthd(priv, 0x9097, 0x2728, 0x00000000); + nv_mthd(priv, 0x9097, 0x2748, 0x00000000); + nv_mthd(priv, 0x9097, 0x2768, 0x00000000); + nv_mthd(priv, 0x9097, 0x2788, 0x00000000); + nv_mthd(priv, 0x9097, 0x27a8, 0x00000000); + nv_mthd(priv, 0x9097, 0x27c8, 0x00000000); + nv_mthd(priv, 0x9097, 0x27e8, 0x00000000); + nv_mthd(priv, 0x9097, 0x270c, 0x00000000); + nv_mthd(priv, 0x9097, 0x272c, 0x00000000); + nv_mthd(priv, 0x9097, 0x274c, 0x00000000); + nv_mthd(priv, 0x9097, 0x276c, 0x00000000); + nv_mthd(priv, 0x9097, 0x278c, 0x00000000); + nv_mthd(priv, 0x9097, 0x27ac, 0x00000000); + nv_mthd(priv, 0x9097, 0x27cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x27ec, 0x00000000); + nv_mthd(priv, 0x9097, 0x2710, 0x00014000); + nv_mthd(priv, 0x9097, 0x2730, 0x00014000); + nv_mthd(priv, 0x9097, 0x2750, 0x00014000); + nv_mthd(priv, 0x9097, 0x2770, 0x00014000); + nv_mthd(priv, 0x9097, 0x2790, 0x00014000); + nv_mthd(priv, 0x9097, 0x27b0, 0x00014000); + nv_mthd(priv, 0x9097, 0x27d0, 0x00014000); + nv_mthd(priv, 0x9097, 0x27f0, 0x00014000); + nv_mthd(priv, 0x9097, 0x2714, 0x00000040); + nv_mthd(priv, 0x9097, 0x2734, 0x00000040); + nv_mthd(priv, 0x9097, 0x2754, 0x00000040); + nv_mthd(priv, 0x9097, 0x2774, 0x00000040); + nv_mthd(priv, 0x9097, 0x2794, 0x00000040); + nv_mthd(priv, 0x9097, 0x27b4, 0x00000040); + nv_mthd(priv, 0x9097, 0x27d4, 0x00000040); + nv_mthd(priv, 0x9097, 0x27f4, 0x00000040); + nv_mthd(priv, 0x9097, 0x1c00, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c10, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c20, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c30, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c40, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c50, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c60, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c70, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c80, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c90, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ca0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cb0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cc0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cd0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ce0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cf0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c04, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c14, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c24, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c34, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c44, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c54, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c64, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c74, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c84, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c94, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ca4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cb4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cc4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cd4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ce4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cf4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c08, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c18, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c28, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c38, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c48, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c58, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c68, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c78, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c88, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c98, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ca8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cb8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cc8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cd8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ce8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cf8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c0c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c1c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c2c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c3c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c4c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c5c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c6c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c7c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c8c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1c9c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cac, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cbc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ccc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cdc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cec, 0x00000000); + nv_mthd(priv, 0x9097, 0x1cfc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d00, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d10, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d20, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d30, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d40, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d50, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d60, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d70, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d80, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d90, 0x00000000); + nv_mthd(priv, 0x9097, 0x1da0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1db0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dc0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dd0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1de0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1df0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d04, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d14, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d24, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d34, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d44, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d54, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d64, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d74, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d84, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d94, 0x00000000); + nv_mthd(priv, 0x9097, 0x1da4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1db4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dc4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dd4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1de4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1df4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d08, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d18, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d28, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d38, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d48, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d58, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d68, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d78, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d88, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d98, 0x00000000); + nv_mthd(priv, 0x9097, 0x1da8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1db8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dc8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dd8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1de8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1df8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d0c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d1c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d2c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d3c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d4c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d5c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d6c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d7c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d8c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1d9c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dac, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dbc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dcc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ddc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dec, 0x00000000); + nv_mthd(priv, 0x9097, 0x1dfc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f00, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f08, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f10, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f18, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f20, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f28, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f30, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f38, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f40, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f48, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f50, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f58, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f60, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f68, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f70, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f78, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f04, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f0c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f14, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f1c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f24, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f2c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f34, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f3c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f44, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f4c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f54, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f5c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f64, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f6c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f74, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f7c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f80, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f88, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f90, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f98, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fa0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fa8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fb0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fb8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fc0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fc8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fd0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fd8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fe0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fe8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ff0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ff8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f84, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f8c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f94, 0x00000000); + nv_mthd(priv, 0x9097, 0x1f9c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fa4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fac, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fb4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fbc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fc4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fcc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fd4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fdc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fe4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1fec, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ff4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1ffc, 0x00000000); + nv_mthd(priv, 0x9097, 0x2200, 0x00000022); + nv_mthd(priv, 0x9097, 0x2210, 0x00000022); + nv_mthd(priv, 0x9097, 0x2220, 0x00000022); + nv_mthd(priv, 0x9097, 0x2230, 0x00000022); + nv_mthd(priv, 0x9097, 0x2240, 0x00000022); + nv_mthd(priv, 0x9097, 0x2000, 0x00000000); + nv_mthd(priv, 0x9097, 0x2040, 0x00000011); + nv_mthd(priv, 0x9097, 0x2080, 0x00000020); + nv_mthd(priv, 0x9097, 0x20c0, 0x00000030); + nv_mthd(priv, 0x9097, 0x2100, 0x00000040); + nv_mthd(priv, 0x9097, 0x2140, 0x00000051); + nv_mthd(priv, 0x9097, 0x200c, 0x00000001); + nv_mthd(priv, 0x9097, 0x204c, 0x00000001); + nv_mthd(priv, 0x9097, 0x208c, 0x00000001); + nv_mthd(priv, 0x9097, 0x20cc, 0x00000001); + nv_mthd(priv, 0x9097, 0x210c, 0x00000001); + nv_mthd(priv, 0x9097, 0x214c, 0x00000001); + nv_mthd(priv, 0x9097, 0x2010, 0x00000000); + nv_mthd(priv, 0x9097, 0x2050, 0x00000000); + nv_mthd(priv, 0x9097, 0x2090, 0x00000001); + nv_mthd(priv, 0x9097, 0x20d0, 0x00000002); + nv_mthd(priv, 0x9097, 0x2110, 0x00000003); + nv_mthd(priv, 0x9097, 0x2150, 0x00000004); + nv_mthd(priv, 0x9097, 0x0380, 0x00000000); + nv_mthd(priv, 0x9097, 0x03a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x03c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x03e0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0384, 0x00000000); + nv_mthd(priv, 0x9097, 0x03a4, 0x00000000); + nv_mthd(priv, 0x9097, 0x03c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x03e4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0388, 0x00000000); + nv_mthd(priv, 0x9097, 0x03a8, 0x00000000); + nv_mthd(priv, 0x9097, 0x03c8, 0x00000000); + nv_mthd(priv, 0x9097, 0x03e8, 0x00000000); + nv_mthd(priv, 0x9097, 0x038c, 0x00000000); + nv_mthd(priv, 0x9097, 0x03ac, 0x00000000); + nv_mthd(priv, 0x9097, 0x03cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x03ec, 0x00000000); + nv_mthd(priv, 0x9097, 0x0700, 0x00000000); + nv_mthd(priv, 0x9097, 0x0710, 0x00000000); + nv_mthd(priv, 0x9097, 0x0720, 0x00000000); + nv_mthd(priv, 0x9097, 0x0730, 0x00000000); + nv_mthd(priv, 0x9097, 0x0704, 0x00000000); + nv_mthd(priv, 0x9097, 0x0714, 0x00000000); + nv_mthd(priv, 0x9097, 0x0724, 0x00000000); + nv_mthd(priv, 0x9097, 0x0734, 0x00000000); + nv_mthd(priv, 0x9097, 0x0708, 0x00000000); + nv_mthd(priv, 0x9097, 0x0718, 0x00000000); + nv_mthd(priv, 0x9097, 0x0728, 0x00000000); + nv_mthd(priv, 0x9097, 0x0738, 0x00000000); + nv_mthd(priv, 0x9097, 0x2800, 0x00000000); + nv_mthd(priv, 0x9097, 0x2804, 0x00000000); + nv_mthd(priv, 0x9097, 0x2808, 0x00000000); + nv_mthd(priv, 0x9097, 0x280c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2810, 0x00000000); + nv_mthd(priv, 0x9097, 0x2814, 0x00000000); + nv_mthd(priv, 0x9097, 0x2818, 0x00000000); + nv_mthd(priv, 0x9097, 0x281c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2820, 0x00000000); + nv_mthd(priv, 0x9097, 0x2824, 0x00000000); + nv_mthd(priv, 0x9097, 0x2828, 0x00000000); + nv_mthd(priv, 0x9097, 0x282c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2830, 0x00000000); + nv_mthd(priv, 0x9097, 0x2834, 0x00000000); + nv_mthd(priv, 0x9097, 0x2838, 0x00000000); + nv_mthd(priv, 0x9097, 0x283c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2840, 0x00000000); + nv_mthd(priv, 0x9097, 0x2844, 0x00000000); + nv_mthd(priv, 0x9097, 0x2848, 0x00000000); + nv_mthd(priv, 0x9097, 0x284c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2850, 0x00000000); + nv_mthd(priv, 0x9097, 0x2854, 0x00000000); + nv_mthd(priv, 0x9097, 0x2858, 0x00000000); + nv_mthd(priv, 0x9097, 0x285c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2860, 0x00000000); + nv_mthd(priv, 0x9097, 0x2864, 0x00000000); + nv_mthd(priv, 0x9097, 0x2868, 0x00000000); + nv_mthd(priv, 0x9097, 0x286c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2870, 0x00000000); + nv_mthd(priv, 0x9097, 0x2874, 0x00000000); + nv_mthd(priv, 0x9097, 0x2878, 0x00000000); + nv_mthd(priv, 0x9097, 0x287c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2880, 0x00000000); + nv_mthd(priv, 0x9097, 0x2884, 0x00000000); + nv_mthd(priv, 0x9097, 0x2888, 0x00000000); + nv_mthd(priv, 0x9097, 0x288c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2890, 0x00000000); + nv_mthd(priv, 0x9097, 0x2894, 0x00000000); + nv_mthd(priv, 0x9097, 0x2898, 0x00000000); + nv_mthd(priv, 0x9097, 0x289c, 0x00000000); + nv_mthd(priv, 0x9097, 0x28a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x28a4, 0x00000000); + nv_mthd(priv, 0x9097, 0x28a8, 0x00000000); + nv_mthd(priv, 0x9097, 0x28ac, 0x00000000); + nv_mthd(priv, 0x9097, 0x28b0, 0x00000000); + nv_mthd(priv, 0x9097, 0x28b4, 0x00000000); + nv_mthd(priv, 0x9097, 0x28b8, 0x00000000); + nv_mthd(priv, 0x9097, 0x28bc, 0x00000000); + nv_mthd(priv, 0x9097, 0x28c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x28c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x28c8, 0x00000000); + nv_mthd(priv, 0x9097, 0x28cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x28d0, 0x00000000); + nv_mthd(priv, 0x9097, 0x28d4, 0x00000000); + nv_mthd(priv, 0x9097, 0x28d8, 0x00000000); + nv_mthd(priv, 0x9097, 0x28dc, 0x00000000); + nv_mthd(priv, 0x9097, 0x28e0, 0x00000000); + nv_mthd(priv, 0x9097, 0x28e4, 0x00000000); + nv_mthd(priv, 0x9097, 0x28e8, 0x00000000); + nv_mthd(priv, 0x9097, 0x28ec, 0x00000000); + nv_mthd(priv, 0x9097, 0x28f0, 0x00000000); + nv_mthd(priv, 0x9097, 0x28f4, 0x00000000); + nv_mthd(priv, 0x9097, 0x28f8, 0x00000000); + nv_mthd(priv, 0x9097, 0x28fc, 0x00000000); + nv_mthd(priv, 0x9097, 0x2900, 0x00000000); + nv_mthd(priv, 0x9097, 0x2904, 0x00000000); + nv_mthd(priv, 0x9097, 0x2908, 0x00000000); + nv_mthd(priv, 0x9097, 0x290c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2910, 0x00000000); + nv_mthd(priv, 0x9097, 0x2914, 0x00000000); + nv_mthd(priv, 0x9097, 0x2918, 0x00000000); + nv_mthd(priv, 0x9097, 0x291c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2920, 0x00000000); + nv_mthd(priv, 0x9097, 0x2924, 0x00000000); + nv_mthd(priv, 0x9097, 0x2928, 0x00000000); + nv_mthd(priv, 0x9097, 0x292c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2930, 0x00000000); + nv_mthd(priv, 0x9097, 0x2934, 0x00000000); + nv_mthd(priv, 0x9097, 0x2938, 0x00000000); + nv_mthd(priv, 0x9097, 0x293c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2940, 0x00000000); + nv_mthd(priv, 0x9097, 0x2944, 0x00000000); + nv_mthd(priv, 0x9097, 0x2948, 0x00000000); + nv_mthd(priv, 0x9097, 0x294c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2950, 0x00000000); + nv_mthd(priv, 0x9097, 0x2954, 0x00000000); + nv_mthd(priv, 0x9097, 0x2958, 0x00000000); + nv_mthd(priv, 0x9097, 0x295c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2960, 0x00000000); + nv_mthd(priv, 0x9097, 0x2964, 0x00000000); + nv_mthd(priv, 0x9097, 0x2968, 0x00000000); + nv_mthd(priv, 0x9097, 0x296c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2970, 0x00000000); + nv_mthd(priv, 0x9097, 0x2974, 0x00000000); + nv_mthd(priv, 0x9097, 0x2978, 0x00000000); + nv_mthd(priv, 0x9097, 0x297c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2980, 0x00000000); + nv_mthd(priv, 0x9097, 0x2984, 0x00000000); + nv_mthd(priv, 0x9097, 0x2988, 0x00000000); + nv_mthd(priv, 0x9097, 0x298c, 0x00000000); + nv_mthd(priv, 0x9097, 0x2990, 0x00000000); + nv_mthd(priv, 0x9097, 0x2994, 0x00000000); + nv_mthd(priv, 0x9097, 0x2998, 0x00000000); + nv_mthd(priv, 0x9097, 0x299c, 0x00000000); + nv_mthd(priv, 0x9097, 0x29a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x29a4, 0x00000000); + nv_mthd(priv, 0x9097, 0x29a8, 0x00000000); + nv_mthd(priv, 0x9097, 0x29ac, 0x00000000); + nv_mthd(priv, 0x9097, 0x29b0, 0x00000000); + nv_mthd(priv, 0x9097, 0x29b4, 0x00000000); + nv_mthd(priv, 0x9097, 0x29b8, 0x00000000); + nv_mthd(priv, 0x9097, 0x29bc, 0x00000000); + nv_mthd(priv, 0x9097, 0x29c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x29c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x29c8, 0x00000000); + nv_mthd(priv, 0x9097, 0x29cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x29d0, 0x00000000); + nv_mthd(priv, 0x9097, 0x29d4, 0x00000000); + nv_mthd(priv, 0x9097, 0x29d8, 0x00000000); + nv_mthd(priv, 0x9097, 0x29dc, 0x00000000); + nv_mthd(priv, 0x9097, 0x29e0, 0x00000000); + nv_mthd(priv, 0x9097, 0x29e4, 0x00000000); + nv_mthd(priv, 0x9097, 0x29e8, 0x00000000); + nv_mthd(priv, 0x9097, 0x29ec, 0x00000000); + nv_mthd(priv, 0x9097, 0x29f0, 0x00000000); + nv_mthd(priv, 0x9097, 0x29f4, 0x00000000); + nv_mthd(priv, 0x9097, 0x29f8, 0x00000000); + nv_mthd(priv, 0x9097, 0x29fc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a00, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a20, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a40, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a60, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a80, 0x00000000); + nv_mthd(priv, 0x9097, 0x0aa0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ac0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ae0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b00, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b20, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b40, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b60, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b80, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ba0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bc0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0be0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a04, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a24, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a44, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a64, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a84, 0x00000000); + nv_mthd(priv, 0x9097, 0x0aa4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ac4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ae4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b04, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b24, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b44, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b64, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b84, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ba4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bc4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0be4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a08, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a28, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a48, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a68, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a88, 0x00000000); + nv_mthd(priv, 0x9097, 0x0aa8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ac8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ae8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b08, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b28, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b48, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b68, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b88, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ba8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bc8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0be8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a0c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a2c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a4c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a6c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a8c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0aac, 0x00000000); + nv_mthd(priv, 0x9097, 0x0acc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0aec, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b0c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b2c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b4c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b6c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b8c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bac, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bcc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bec, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a10, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a30, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a50, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a70, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a90, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ab0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ad0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0af0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b10, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b30, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b50, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b70, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b90, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bb0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bd0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bf0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a14, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a34, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a54, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a74, 0x00000000); + nv_mthd(priv, 0x9097, 0x0a94, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ab4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ad4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0af4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b14, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b34, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b54, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b74, 0x00000000); + nv_mthd(priv, 0x9097, 0x0b94, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bb4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bd4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0bf4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c00, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c10, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c20, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c30, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c40, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c50, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c60, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c70, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c80, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c90, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ca0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cb0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cc0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cd0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ce0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cf0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c04, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c14, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c24, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c34, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c44, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c54, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c64, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c74, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c84, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c94, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ca4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cb4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cc4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cd4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ce4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cf4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c08, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c18, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c28, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c38, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c48, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c58, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c68, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c78, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c88, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c98, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ca8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cb8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cc8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cd8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ce8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0cf8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0c0c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c1c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c2c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c3c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c4c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c5c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c6c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c7c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c8c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0c9c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0cac, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0cbc, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0ccc, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0cdc, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0cec, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0cfc, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0d00, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d08, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d10, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d18, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d20, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d28, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d30, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d38, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d04, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d0c, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d14, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d1c, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d24, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d2c, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d34, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d3c, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e00, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e10, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e20, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e30, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e40, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e50, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e60, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e70, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e80, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e90, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ea0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0eb0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ec0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ed0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ee0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ef0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0e04, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e14, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e24, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e34, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e44, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e54, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e64, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e74, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e84, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e94, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ea4, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0eb4, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ec4, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ed4, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ee4, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ef4, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e08, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e18, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e28, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e38, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e48, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e58, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e68, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e78, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e88, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0e98, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ea8, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0eb8, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ec8, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ed8, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ee8, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0ef8, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d40, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d48, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d50, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d58, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d44, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d4c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d54, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d5c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1e00, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e20, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e40, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e60, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e80, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ea0, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ec0, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ee0, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e04, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e24, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e44, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e64, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e84, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ea4, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ec4, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ee4, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e08, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e28, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e48, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e68, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e88, 0x00000002); + nv_mthd(priv, 0x9097, 0x1ea8, 0x00000002); + nv_mthd(priv, 0x9097, 0x1ec8, 0x00000002); + nv_mthd(priv, 0x9097, 0x1ee8, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e0c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e2c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e4c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e6c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e8c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1eac, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ecc, 0x00000001); + nv_mthd(priv, 0x9097, 0x1eec, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e10, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e30, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e50, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e70, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e90, 0x00000001); + nv_mthd(priv, 0x9097, 0x1eb0, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ed0, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ef0, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e14, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e34, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e54, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e74, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e94, 0x00000002); + nv_mthd(priv, 0x9097, 0x1eb4, 0x00000002); + nv_mthd(priv, 0x9097, 0x1ed4, 0x00000002); + nv_mthd(priv, 0x9097, 0x1ef4, 0x00000002); + nv_mthd(priv, 0x9097, 0x1e18, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e38, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e58, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e78, 0x00000001); + nv_mthd(priv, 0x9097, 0x1e98, 0x00000001); + nv_mthd(priv, 0x9097, 0x1eb8, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ed8, 0x00000001); + nv_mthd(priv, 0x9097, 0x1ef8, 0x00000001); + if (fermi == 0x9097) { + for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4) + nv_mthd(priv, 0x9097, mthd, 0x00000000); + } + nv_mthd(priv, 0x9097, 0x030c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1944, 0x00000000); + nv_mthd(priv, 0x9097, 0x1514, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d68, 0x0000ffff); + nv_mthd(priv, 0x9097, 0x121c, 0x0fac6881); + nv_mthd(priv, 0x9097, 0x0fac, 0x00000001); + nv_mthd(priv, 0x9097, 0x1538, 0x00000001); + nv_mthd(priv, 0x9097, 0x0fe0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0fe4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0fe8, 0x00000014); + nv_mthd(priv, 0x9097, 0x0fec, 0x00000040); + nv_mthd(priv, 0x9097, 0x0ff0, 0x00000000); + nv_mthd(priv, 0x9097, 0x179c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1228, 0x00000400); + nv_mthd(priv, 0x9097, 0x122c, 0x00000300); + nv_mthd(priv, 0x9097, 0x1230, 0x00010001); + nv_mthd(priv, 0x9097, 0x07f8, 0x00000000); + nv_mthd(priv, 0x9097, 0x15b4, 0x00000001); + nv_mthd(priv, 0x9097, 0x15cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1534, 0x00000000); + nv_mthd(priv, 0x9097, 0x0fb0, 0x00000000); + nv_mthd(priv, 0x9097, 0x15d0, 0x00000000); + nv_mthd(priv, 0x9097, 0x153c, 0x00000000); + nv_mthd(priv, 0x9097, 0x16b4, 0x00000003); + nv_mthd(priv, 0x9097, 0x0fbc, 0x0000ffff); + nv_mthd(priv, 0x9097, 0x0fc0, 0x0000ffff); + nv_mthd(priv, 0x9097, 0x0fc4, 0x0000ffff); + nv_mthd(priv, 0x9097, 0x0fc8, 0x0000ffff); + nv_mthd(priv, 0x9097, 0x0df8, 0x00000000); + nv_mthd(priv, 0x9097, 0x0dfc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1948, 0x00000000); + nv_mthd(priv, 0x9097, 0x1970, 0x00000001); + nv_mthd(priv, 0x9097, 0x161c, 0x000009f0); + nv_mthd(priv, 0x9097, 0x0dcc, 0x00000010); + nv_mthd(priv, 0x9097, 0x163c, 0x00000000); + nv_mthd(priv, 0x9097, 0x15e4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1160, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1164, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1168, 0x25e00040); + nv_mthd(priv, 0x9097, 0x116c, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1170, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1174, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1178, 0x25e00040); + nv_mthd(priv, 0x9097, 0x117c, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1180, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1184, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1188, 0x25e00040); + nv_mthd(priv, 0x9097, 0x118c, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1190, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1194, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1198, 0x25e00040); + nv_mthd(priv, 0x9097, 0x119c, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11a0, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11a4, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11a8, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11ac, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11b0, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11b4, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11b8, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11bc, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11c0, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11c4, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11c8, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11cc, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11d0, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11d4, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11d8, 0x25e00040); + nv_mthd(priv, 0x9097, 0x11dc, 0x25e00040); + nv_mthd(priv, 0x9097, 0x1880, 0x00000000); + nv_mthd(priv, 0x9097, 0x1884, 0x00000000); + nv_mthd(priv, 0x9097, 0x1888, 0x00000000); + nv_mthd(priv, 0x9097, 0x188c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1890, 0x00000000); + nv_mthd(priv, 0x9097, 0x1894, 0x00000000); + nv_mthd(priv, 0x9097, 0x1898, 0x00000000); + nv_mthd(priv, 0x9097, 0x189c, 0x00000000); + nv_mthd(priv, 0x9097, 0x18a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x18a4, 0x00000000); + nv_mthd(priv, 0x9097, 0x18a8, 0x00000000); + nv_mthd(priv, 0x9097, 0x18ac, 0x00000000); + nv_mthd(priv, 0x9097, 0x18b0, 0x00000000); + nv_mthd(priv, 0x9097, 0x18b4, 0x00000000); + nv_mthd(priv, 0x9097, 0x18b8, 0x00000000); + nv_mthd(priv, 0x9097, 0x18bc, 0x00000000); + nv_mthd(priv, 0x9097, 0x18c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x18c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x18c8, 0x00000000); + nv_mthd(priv, 0x9097, 0x18cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x18d0, 0x00000000); + nv_mthd(priv, 0x9097, 0x18d4, 0x00000000); + nv_mthd(priv, 0x9097, 0x18d8, 0x00000000); + nv_mthd(priv, 0x9097, 0x18dc, 0x00000000); + nv_mthd(priv, 0x9097, 0x18e0, 0x00000000); + nv_mthd(priv, 0x9097, 0x18e4, 0x00000000); + nv_mthd(priv, 0x9097, 0x18e8, 0x00000000); + nv_mthd(priv, 0x9097, 0x18ec, 0x00000000); + nv_mthd(priv, 0x9097, 0x18f0, 0x00000000); + nv_mthd(priv, 0x9097, 0x18f4, 0x00000000); + nv_mthd(priv, 0x9097, 0x18f8, 0x00000000); + nv_mthd(priv, 0x9097, 0x18fc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f84, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f88, 0x00000000); + nv_mthd(priv, 0x9097, 0x17c8, 0x00000000); + nv_mthd(priv, 0x9097, 0x17cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x17d0, 0x000000ff); + nv_mthd(priv, 0x9097, 0x17d4, 0xffffffff); + nv_mthd(priv, 0x9097, 0x17d8, 0x00000002); + nv_mthd(priv, 0x9097, 0x17dc, 0x00000000); + nv_mthd(priv, 0x9097, 0x15f4, 0x00000000); + nv_mthd(priv, 0x9097, 0x15f8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1434, 0x00000000); + nv_mthd(priv, 0x9097, 0x1438, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d74, 0x00000000); + nv_mthd(priv, 0x9097, 0x0dec, 0x00000001); + nv_mthd(priv, 0x9097, 0x13a4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1318, 0x00000001); + nv_mthd(priv, 0x9097, 0x1644, 0x00000000); + nv_mthd(priv, 0x9097, 0x0748, 0x00000000); + nv_mthd(priv, 0x9097, 0x0de8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1648, 0x00000000); + nv_mthd(priv, 0x9097, 0x12a4, 0x00000000); + nv_mthd(priv, 0x9097, 0x1120, 0x00000000); + nv_mthd(priv, 0x9097, 0x1124, 0x00000000); + nv_mthd(priv, 0x9097, 0x1128, 0x00000000); + nv_mthd(priv, 0x9097, 0x112c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1118, 0x00000000); + nv_mthd(priv, 0x9097, 0x164c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1658, 0x00000000); + nv_mthd(priv, 0x9097, 0x1910, 0x00000290); + nv_mthd(priv, 0x9097, 0x1518, 0x00000000); + nv_mthd(priv, 0x9097, 0x165c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1520, 0x00000000); + nv_mthd(priv, 0x9097, 0x1604, 0x00000000); + nv_mthd(priv, 0x9097, 0x1570, 0x00000000); + nv_mthd(priv, 0x9097, 0x13b0, 0x3f800000); + nv_mthd(priv, 0x9097, 0x13b4, 0x3f800000); + nv_mthd(priv, 0x9097, 0x020c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1670, 0x30201000); + nv_mthd(priv, 0x9097, 0x1674, 0x70605040); + nv_mthd(priv, 0x9097, 0x1678, 0xb8a89888); + nv_mthd(priv, 0x9097, 0x167c, 0xf8e8d8c8); + nv_mthd(priv, 0x9097, 0x166c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1680, 0x00ffff00); + nv_mthd(priv, 0x9097, 0x12d0, 0x00000003); + nv_mthd(priv, 0x9097, 0x12d4, 0x00000002); + nv_mthd(priv, 0x9097, 0x1684, 0x00000000); + nv_mthd(priv, 0x9097, 0x1688, 0x00000000); + nv_mthd(priv, 0x9097, 0x0dac, 0x00001b02); + nv_mthd(priv, 0x9097, 0x0db0, 0x00001b02); + nv_mthd(priv, 0x9097, 0x0db4, 0x00000000); + nv_mthd(priv, 0x9097, 0x168c, 0x00000000); + nv_mthd(priv, 0x9097, 0x15bc, 0x00000000); + nv_mthd(priv, 0x9097, 0x156c, 0x00000000); + nv_mthd(priv, 0x9097, 0x187c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1110, 0x00000001); + nv_mthd(priv, 0x9097, 0x0dc0, 0x00000000); + nv_mthd(priv, 0x9097, 0x0dc4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0dc8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1234, 0x00000000); + nv_mthd(priv, 0x9097, 0x1690, 0x00000000); + nv_mthd(priv, 0x9097, 0x12ac, 0x00000001); + nv_mthd(priv, 0x9097, 0x02c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0790, 0x00000000); + nv_mthd(priv, 0x9097, 0x0794, 0x00000000); + nv_mthd(priv, 0x9097, 0x0798, 0x00000000); + nv_mthd(priv, 0x9097, 0x079c, 0x00000000); + nv_mthd(priv, 0x9097, 0x07a0, 0x00000000); + nv_mthd(priv, 0x9097, 0x077c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1000, 0x00000010); + nv_mthd(priv, 0x9097, 0x10fc, 0x00000000); + nv_mthd(priv, 0x9097, 0x1290, 0x00000000); + nv_mthd(priv, 0x9097, 0x0218, 0x00000010); + nv_mthd(priv, 0x9097, 0x12d8, 0x00000000); + nv_mthd(priv, 0x9097, 0x12dc, 0x00000010); + nv_mthd(priv, 0x9097, 0x0d94, 0x00000001); + nv_mthd(priv, 0x9097, 0x155c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1560, 0x00000000); + nv_mthd(priv, 0x9097, 0x1564, 0x00001fff); + nv_mthd(priv, 0x9097, 0x1574, 0x00000000); + nv_mthd(priv, 0x9097, 0x1578, 0x00000000); + nv_mthd(priv, 0x9097, 0x157c, 0x003fffff); + nv_mthd(priv, 0x9097, 0x1354, 0x00000000); + nv_mthd(priv, 0x9097, 0x1664, 0x00000000); + nv_mthd(priv, 0x9097, 0x1610, 0x00000012); + nv_mthd(priv, 0x9097, 0x1608, 0x00000000); + nv_mthd(priv, 0x9097, 0x160c, 0x00000000); + nv_mthd(priv, 0x9097, 0x162c, 0x00000003); + nv_mthd(priv, 0x9097, 0x0210, 0x00000000); + nv_mthd(priv, 0x9097, 0x0320, 0x00000000); + nv_mthd(priv, 0x9097, 0x0324, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0328, 0x3f800000); + nv_mthd(priv, 0x9097, 0x032c, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0330, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0334, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0338, 0x3f800000); + nv_mthd(priv, 0x9097, 0x0750, 0x00000000); + nv_mthd(priv, 0x9097, 0x0760, 0x39291909); + nv_mthd(priv, 0x9097, 0x0764, 0x79695949); + nv_mthd(priv, 0x9097, 0x0768, 0xb9a99989); + nv_mthd(priv, 0x9097, 0x076c, 0xf9e9d9c9); + nv_mthd(priv, 0x9097, 0x0770, 0x30201000); + nv_mthd(priv, 0x9097, 0x0774, 0x70605040); + nv_mthd(priv, 0x9097, 0x0778, 0x00009080); + nv_mthd(priv, 0x9097, 0x0780, 0x39291909); + nv_mthd(priv, 0x9097, 0x0784, 0x79695949); + nv_mthd(priv, 0x9097, 0x0788, 0xb9a99989); + nv_mthd(priv, 0x9097, 0x078c, 0xf9e9d9c9); + nv_mthd(priv, 0x9097, 0x07d0, 0x30201000); + nv_mthd(priv, 0x9097, 0x07d4, 0x70605040); + nv_mthd(priv, 0x9097, 0x07d8, 0x00009080); + nv_mthd(priv, 0x9097, 0x037c, 0x00000001); + nv_mthd(priv, 0x9097, 0x0740, 0x00000000); + nv_mthd(priv, 0x9097, 0x0744, 0x00000000); + nv_mthd(priv, 0x9097, 0x2600, 0x00000000); + nv_mthd(priv, 0x9097, 0x1918, 0x00000000); + nv_mthd(priv, 0x9097, 0x191c, 0x00000900); + nv_mthd(priv, 0x9097, 0x1920, 0x00000405); + nv_mthd(priv, 0x9097, 0x1308, 0x00000001); + nv_mthd(priv, 0x9097, 0x1924, 0x00000000); + nv_mthd(priv, 0x9097, 0x13ac, 0x00000000); + nv_mthd(priv, 0x9097, 0x192c, 0x00000001); + nv_mthd(priv, 0x9097, 0x193c, 0x00002c1c); + nv_mthd(priv, 0x9097, 0x0d7c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f8c, 0x00000000); + nv_mthd(priv, 0x9097, 0x02c0, 0x00000001); + nv_mthd(priv, 0x9097, 0x1510, 0x00000000); + nv_mthd(priv, 0x9097, 0x1940, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ff4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0ff8, 0x00000000); + nv_mthd(priv, 0x9097, 0x194c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1950, 0x00000000); + nv_mthd(priv, 0x9097, 0x1968, 0x00000000); + nv_mthd(priv, 0x9097, 0x1590, 0x0000003f); + nv_mthd(priv, 0x9097, 0x07e8, 0x00000000); + nv_mthd(priv, 0x9097, 0x07ec, 0x00000000); + nv_mthd(priv, 0x9097, 0x07f0, 0x00000000); + nv_mthd(priv, 0x9097, 0x07f4, 0x00000000); + nv_mthd(priv, 0x9097, 0x196c, 0x00000011); + nv_mthd(priv, 0x9097, 0x197c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0fcc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0fd0, 0x00000000); + nv_mthd(priv, 0x9097, 0x02d8, 0x00000040); + nv_mthd(priv, 0x9097, 0x1980, 0x00000080); + nv_mthd(priv, 0x9097, 0x1504, 0x00000080); + nv_mthd(priv, 0x9097, 0x1984, 0x00000000); + nv_mthd(priv, 0x9097, 0x0300, 0x00000001); + nv_mthd(priv, 0x9097, 0x13a8, 0x00000000); + nv_mthd(priv, 0x9097, 0x12ec, 0x00000000); + nv_mthd(priv, 0x9097, 0x1310, 0x00000000); + nv_mthd(priv, 0x9097, 0x1314, 0x00000001); + nv_mthd(priv, 0x9097, 0x1380, 0x00000000); + nv_mthd(priv, 0x9097, 0x1384, 0x00000001); + nv_mthd(priv, 0x9097, 0x1388, 0x00000001); + nv_mthd(priv, 0x9097, 0x138c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1390, 0x00000001); + nv_mthd(priv, 0x9097, 0x1394, 0x00000000); + nv_mthd(priv, 0x9097, 0x139c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1398, 0x00000000); + nv_mthd(priv, 0x9097, 0x1594, 0x00000000); + nv_mthd(priv, 0x9097, 0x1598, 0x00000001); + nv_mthd(priv, 0x9097, 0x159c, 0x00000001); + nv_mthd(priv, 0x9097, 0x15a0, 0x00000001); + nv_mthd(priv, 0x9097, 0x15a4, 0x00000001); + nv_mthd(priv, 0x9097, 0x0f54, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f58, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f5c, 0x00000000); + nv_mthd(priv, 0x9097, 0x19bc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f9c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0fa0, 0x00000000); + nv_mthd(priv, 0x9097, 0x12cc, 0x00000000); + nv_mthd(priv, 0x9097, 0x12e8, 0x00000000); + nv_mthd(priv, 0x9097, 0x130c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1360, 0x00000000); + nv_mthd(priv, 0x9097, 0x1364, 0x00000000); + nv_mthd(priv, 0x9097, 0x1368, 0x00000000); + nv_mthd(priv, 0x9097, 0x136c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1370, 0x00000000); + nv_mthd(priv, 0x9097, 0x1374, 0x00000000); + nv_mthd(priv, 0x9097, 0x1378, 0x00000000); + nv_mthd(priv, 0x9097, 0x137c, 0x00000000); + nv_mthd(priv, 0x9097, 0x133c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1340, 0x00000001); + nv_mthd(priv, 0x9097, 0x1344, 0x00000002); + nv_mthd(priv, 0x9097, 0x1348, 0x00000001); + nv_mthd(priv, 0x9097, 0x134c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1350, 0x00000002); + nv_mthd(priv, 0x9097, 0x1358, 0x00000001); + nv_mthd(priv, 0x9097, 0x12e4, 0x00000000); + nv_mthd(priv, 0x9097, 0x131c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1320, 0x00000000); + nv_mthd(priv, 0x9097, 0x1324, 0x00000000); + nv_mthd(priv, 0x9097, 0x1328, 0x00000000); + nv_mthd(priv, 0x9097, 0x19c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1140, 0x00000000); + nv_mthd(priv, 0x9097, 0x19c4, 0x00000000); + nv_mthd(priv, 0x9097, 0x19c8, 0x00001500); + nv_mthd(priv, 0x9097, 0x135c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f90, 0x00000000); + nv_mthd(priv, 0x9097, 0x19e0, 0x00000001); + nv_mthd(priv, 0x9097, 0x19e4, 0x00000001); + nv_mthd(priv, 0x9097, 0x19e8, 0x00000001); + nv_mthd(priv, 0x9097, 0x19ec, 0x00000001); + nv_mthd(priv, 0x9097, 0x19f0, 0x00000001); + nv_mthd(priv, 0x9097, 0x19f4, 0x00000001); + nv_mthd(priv, 0x9097, 0x19f8, 0x00000001); + nv_mthd(priv, 0x9097, 0x19fc, 0x00000001); + nv_mthd(priv, 0x9097, 0x19cc, 0x00000001); + nv_mthd(priv, 0x9097, 0x15b8, 0x00000000); + nv_mthd(priv, 0x9097, 0x1a00, 0x00001111); + nv_mthd(priv, 0x9097, 0x1a04, 0x00000000); + nv_mthd(priv, 0x9097, 0x1a08, 0x00000000); + nv_mthd(priv, 0x9097, 0x1a0c, 0x00000000); + nv_mthd(priv, 0x9097, 0x1a10, 0x00000000); + nv_mthd(priv, 0x9097, 0x1a14, 0x00000000); + nv_mthd(priv, 0x9097, 0x1a18, 0x00000000); + nv_mthd(priv, 0x9097, 0x1a1c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d6c, 0xffff0000); + nv_mthd(priv, 0x9097, 0x0d70, 0xffff0000); + nv_mthd(priv, 0x9097, 0x10f8, 0x00001010); + nv_mthd(priv, 0x9097, 0x0d80, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d84, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d88, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d8c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0d90, 0x00000000); + nv_mthd(priv, 0x9097, 0x0da0, 0x00000000); + nv_mthd(priv, 0x9097, 0x1508, 0x80000000); + nv_mthd(priv, 0x9097, 0x150c, 0x40000000); + nv_mthd(priv, 0x9097, 0x1668, 0x00000000); + nv_mthd(priv, 0x9097, 0x0318, 0x00000008); + nv_mthd(priv, 0x9097, 0x031c, 0x00000008); + nv_mthd(priv, 0x9097, 0x0d9c, 0x00000001); + nv_mthd(priv, 0x9097, 0x07dc, 0x00000000); + nv_mthd(priv, 0x9097, 0x074c, 0x00000055); + nv_mthd(priv, 0x9097, 0x1420, 0x00000003); + nv_mthd(priv, 0x9097, 0x17bc, 0x00000000); + nv_mthd(priv, 0x9097, 0x17c0, 0x00000000); + nv_mthd(priv, 0x9097, 0x17c4, 0x00000001); + nv_mthd(priv, 0x9097, 0x1008, 0x00000008); + nv_mthd(priv, 0x9097, 0x100c, 0x00000040); + nv_mthd(priv, 0x9097, 0x1010, 0x0000012c); + nv_mthd(priv, 0x9097, 0x0d60, 0x00000040); + nv_mthd(priv, 0x9097, 0x075c, 0x00000003); + nv_mthd(priv, 0x9097, 0x1018, 0x00000020); + nv_mthd(priv, 0x9097, 0x101c, 0x00000001); + nv_mthd(priv, 0x9097, 0x1020, 0x00000020); + nv_mthd(priv, 0x9097, 0x1024, 0x00000001); + nv_mthd(priv, 0x9097, 0x1444, 0x00000000); + nv_mthd(priv, 0x9097, 0x1448, 0x00000000); + nv_mthd(priv, 0x9097, 0x144c, 0x00000000); + nv_mthd(priv, 0x9097, 0x0360, 0x20164010); + nv_mthd(priv, 0x9097, 0x0364, 0x00000020); + nv_mthd(priv, 0x9097, 0x0368, 0x00000000); + nv_mthd(priv, 0x9097, 0x0de4, 0x00000000); + nv_mthd(priv, 0x9097, 0x0204, 0x00000006); + nv_mthd(priv, 0x9097, 0x0208, 0x00000000); + nv_mthd(priv, 0x9097, 0x02cc, 0x003fffff); + nv_mthd(priv, 0x9097, 0x02d0, 0x00000c48); + nv_mthd(priv, 0x9097, 0x1220, 0x00000005); + nv_mthd(priv, 0x9097, 0x0fdc, 0x00000000); + nv_mthd(priv, 0x9097, 0x0f98, 0x00300008); + nv_mthd(priv, 0x9097, 0x1284, 0x04000080); + nv_mthd(priv, 0x9097, 0x1450, 0x00300008); + nv_mthd(priv, 0x9097, 0x1454, 0x04000080); + nv_mthd(priv, 0x9097, 0x0214, 0x00000000); + /* in trace, right after 0x90c0, not here */ + nv_mthd(priv, 0x9097, 0x3410, 0x80002006); +} + +static void +nvc0_grctx_generate_9197(struct nvc0_graph_priv *priv) +{ + u32 fermi = nvc0_graph_class(priv); + u32 mthd; + + if (fermi == 0x9197) { + for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4) + nv_mthd(priv, 0x9197, mthd, 0x00000000); + } + nv_mthd(priv, 0x9197, 0x02e4, 0x0000b001); +} + +static void +nvc0_grctx_generate_9297(struct nvc0_graph_priv *priv) +{ + u32 fermi = nvc0_graph_class(priv); + u32 mthd; + + if (fermi == 0x9297) { + for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4) + nv_mthd(priv, 0x9297, mthd, 0x00000000); + } + nv_mthd(priv, 0x9297, 0x036c, 0x00000000); + nv_mthd(priv, 0x9297, 0x0370, 0x00000000); + nv_mthd(priv, 0x9297, 0x07a4, 0x00000000); + nv_mthd(priv, 0x9297, 0x07a8, 0x00000000); + nv_mthd(priv, 0x9297, 0x0374, 0x00000000); + nv_mthd(priv, 0x9297, 0x0378, 0x00000020); +} + +static void +nvc0_grctx_generate_902d(struct nvc0_graph_priv *priv) +{ + nv_mthd(priv, 0x902d, 0x0200, 0x000000cf); + nv_mthd(priv, 0x902d, 0x0204, 0x00000001); + nv_mthd(priv, 0x902d, 0x0208, 0x00000020); + nv_mthd(priv, 0x902d, 0x020c, 0x00000001); + nv_mthd(priv, 0x902d, 0x0210, 0x00000000); + nv_mthd(priv, 0x902d, 0x0214, 0x00000080); + nv_mthd(priv, 0x902d, 0x0218, 0x00000100); + nv_mthd(priv, 0x902d, 0x021c, 0x00000100); + nv_mthd(priv, 0x902d, 0x0220, 0x00000000); + nv_mthd(priv, 0x902d, 0x0224, 0x00000000); + nv_mthd(priv, 0x902d, 0x0230, 0x000000cf); + nv_mthd(priv, 0x902d, 0x0234, 0x00000001); + nv_mthd(priv, 0x902d, 0x0238, 0x00000020); + nv_mthd(priv, 0x902d, 0x023c, 0x00000001); + nv_mthd(priv, 0x902d, 0x0244, 0x00000080); + nv_mthd(priv, 0x902d, 0x0248, 0x00000100); + nv_mthd(priv, 0x902d, 0x024c, 0x00000100); +} + +static void +nvc0_grctx_generate_9039(struct nvc0_graph_priv *priv) +{ + nv_mthd(priv, 0x9039, 0x030c, 0x00000000); + nv_mthd(priv, 0x9039, 0x0310, 0x00000000); + nv_mthd(priv, 0x9039, 0x0314, 0x00000000); + nv_mthd(priv, 0x9039, 0x0320, 0x00000000); + nv_mthd(priv, 0x9039, 0x0238, 0x00000000); + nv_mthd(priv, 0x9039, 0x023c, 0x00000000); + nv_mthd(priv, 0x9039, 0x0318, 0x00000000); + nv_mthd(priv, 0x9039, 0x031c, 0x00000000); +} + +static void +nvc0_grctx_generate_90c0(struct nvc0_graph_priv *priv) +{ + int 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); + nv_mthd(priv, 0x90c0, 0x2724 + (i * 0x40), 0x00000000); + nv_mthd(priv, 0x90c0, 0x2708 + (i * 0x40), 0x00000000); + nv_mthd(priv, 0x90c0, 0x2728 + (i * 0x40), 0x00000000); + } + nv_mthd(priv, 0x90c0, 0x270c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x272c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x274c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x276c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x278c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x27ac, 0x00000000); + nv_mthd(priv, 0x90c0, 0x27cc, 0x00000000); + nv_mthd(priv, 0x90c0, 0x27ec, 0x00000000); + 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); + nv_mthd(priv, 0x90c0, 0x2734 + (i * 0x40), 0x00000040); + } + nv_mthd(priv, 0x90c0, 0x030c, 0x00000001); + nv_mthd(priv, 0x90c0, 0x1944, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0758, 0x00000100); + nv_mthd(priv, 0x90c0, 0x02c4, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0790, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0794, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0798, 0x00000000); + nv_mthd(priv, 0x90c0, 0x079c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x07a0, 0x00000000); + nv_mthd(priv, 0x90c0, 0x077c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0204, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0208, 0x00000000); + nv_mthd(priv, 0x90c0, 0x020c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0214, 0x00000000); + nv_mthd(priv, 0x90c0, 0x024c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x0d94, 0x00000001); + nv_mthd(priv, 0x90c0, 0x1608, 0x00000000); + nv_mthd(priv, 0x90c0, 0x160c, 0x00000000); + nv_mthd(priv, 0x90c0, 0x1664, 0x00000000); +} + +static void +nvc0_grctx_generate_dispatch(struct nvc0_graph_priv *priv) +{ + int i; + + nv_wr32(priv, 0x404004, 0x00000000); + nv_wr32(priv, 0x404008, 0x00000000); + nv_wr32(priv, 0x40400c, 0x00000000); + nv_wr32(priv, 0x404010, 0x00000000); + nv_wr32(priv, 0x404014, 0x00000000); + nv_wr32(priv, 0x404018, 0x00000000); + nv_wr32(priv, 0x40401c, 0x00000000); + nv_wr32(priv, 0x404020, 0x00000000); + nv_wr32(priv, 0x404024, 0x00000000); + nv_wr32(priv, 0x404028, 0x00000000); + nv_wr32(priv, 0x40402c, 0x00000000); + nv_wr32(priv, 0x404044, 0x00000000); + nv_wr32(priv, 0x404094, 0x00000000); + nv_wr32(priv, 0x404098, 0x00000000); + nv_wr32(priv, 0x40409c, 0x00000000); + nv_wr32(priv, 0x4040a0, 0x00000000); + nv_wr32(priv, 0x4040a4, 0x00000000); + nv_wr32(priv, 0x4040a8, 0x00000000); + nv_wr32(priv, 0x4040ac, 0x00000000); + nv_wr32(priv, 0x4040b0, 0x00000000); + nv_wr32(priv, 0x4040b4, 0x00000000); + nv_wr32(priv, 0x4040b8, 0x00000000); + nv_wr32(priv, 0x4040bc, 0x00000000); + nv_wr32(priv, 0x4040c0, 0x00000000); + nv_wr32(priv, 0x4040c4, 0x00000000); + nv_wr32(priv, 0x4040c8, 0xf0000087); + nv_wr32(priv, 0x4040d4, 0x00000000); + nv_wr32(priv, 0x4040d8, 0x00000000); + nv_wr32(priv, 0x4040dc, 0x00000000); + nv_wr32(priv, 0x4040e0, 0x00000000); + nv_wr32(priv, 0x4040e4, 0x00000000); + nv_wr32(priv, 0x4040e8, 0x00001000); + nv_wr32(priv, 0x4040f8, 0x00000000); + nv_wr32(priv, 0x404130, 0x00000000); + nv_wr32(priv, 0x404134, 0x00000000); + nv_wr32(priv, 0x404138, 0x20000040); + nv_wr32(priv, 0x404150, 0x0000002e); + nv_wr32(priv, 0x404154, 0x00000400); + nv_wr32(priv, 0x404158, 0x00000200); + nv_wr32(priv, 0x404164, 0x00000055); + nv_wr32(priv, 0x404168, 0x00000000); + nv_wr32(priv, 0x404174, 0x00000000); + nv_wr32(priv, 0x404178, 0x00000000); + nv_wr32(priv, 0x40417c, 0x00000000); + for (i = 0; i < 8; i++) + nv_wr32(priv, 0x404200 + (i * 4), 0x00000000); /* subc */ +} + +static void +nvc0_grctx_generate_macro(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x404404, 0x00000000); + nv_wr32(priv, 0x404408, 0x00000000); + nv_wr32(priv, 0x40440c, 0x00000000); + nv_wr32(priv, 0x404410, 0x00000000); + nv_wr32(priv, 0x404414, 0x00000000); + nv_wr32(priv, 0x404418, 0x00000000); + nv_wr32(priv, 0x40441c, 0x00000000); + nv_wr32(priv, 0x404420, 0x00000000); + nv_wr32(priv, 0x404424, 0x00000000); + nv_wr32(priv, 0x404428, 0x00000000); + nv_wr32(priv, 0x40442c, 0x00000000); + nv_wr32(priv, 0x404430, 0x00000000); + nv_wr32(priv, 0x404434, 0x00000000); + nv_wr32(priv, 0x404438, 0x00000000); + nv_wr32(priv, 0x404460, 0x00000000); + nv_wr32(priv, 0x404464, 0x00000000); + nv_wr32(priv, 0x404468, 0x00ffffff); + nv_wr32(priv, 0x40446c, 0x00000000); + nv_wr32(priv, 0x404480, 0x00000001); + nv_wr32(priv, 0x404498, 0x00000001); +} + +static void +nvc0_grctx_generate_m2mf(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x404604, 0x00000015); + nv_wr32(priv, 0x404608, 0x00000000); + nv_wr32(priv, 0x40460c, 0x00002e00); + nv_wr32(priv, 0x404610, 0x00000100); + nv_wr32(priv, 0x404618, 0x00000000); + nv_wr32(priv, 0x40461c, 0x00000000); + nv_wr32(priv, 0x404620, 0x00000000); + nv_wr32(priv, 0x404624, 0x00000000); + nv_wr32(priv, 0x404628, 0x00000000); + nv_wr32(priv, 0x40462c, 0x00000000); + nv_wr32(priv, 0x404630, 0x00000000); + nv_wr32(priv, 0x404634, 0x00000000); + nv_wr32(priv, 0x404638, 0x00000004); + nv_wr32(priv, 0x40463c, 0x00000000); + nv_wr32(priv, 0x404640, 0x00000000); + nv_wr32(priv, 0x404644, 0x00000000); + nv_wr32(priv, 0x404648, 0x00000000); + nv_wr32(priv, 0x40464c, 0x00000000); + nv_wr32(priv, 0x404650, 0x00000000); + nv_wr32(priv, 0x404654, 0x00000000); + nv_wr32(priv, 0x404658, 0x00000000); + nv_wr32(priv, 0x40465c, 0x007f0100); + nv_wr32(priv, 0x404660, 0x00000000); + nv_wr32(priv, 0x404664, 0x00000000); + nv_wr32(priv, 0x404668, 0x00000000); + nv_wr32(priv, 0x40466c, 0x00000000); + nv_wr32(priv, 0x404670, 0x00000000); + nv_wr32(priv, 0x404674, 0x00000000); + nv_wr32(priv, 0x404678, 0x00000000); + nv_wr32(priv, 0x40467c, 0x00000002); + nv_wr32(priv, 0x404680, 0x00000000); + nv_wr32(priv, 0x404684, 0x00000000); + nv_wr32(priv, 0x404688, 0x00000000); + nv_wr32(priv, 0x40468c, 0x00000000); + nv_wr32(priv, 0x404690, 0x00000000); + nv_wr32(priv, 0x404694, 0x00000000); + nv_wr32(priv, 0x404698, 0x00000000); + nv_wr32(priv, 0x40469c, 0x00000000); + nv_wr32(priv, 0x4046a0, 0x007f0080); + nv_wr32(priv, 0x4046a4, 0x00000000); + nv_wr32(priv, 0x4046a8, 0x00000000); + nv_wr32(priv, 0x4046ac, 0x00000000); + nv_wr32(priv, 0x4046b0, 0x00000000); + nv_wr32(priv, 0x4046b4, 0x00000000); + nv_wr32(priv, 0x4046b8, 0x00000000); + nv_wr32(priv, 0x4046bc, 0x00000000); + nv_wr32(priv, 0x4046c0, 0x00000000); + nv_wr32(priv, 0x4046c4, 0x00000000); + nv_wr32(priv, 0x4046c8, 0x00000000); + nv_wr32(priv, 0x4046cc, 0x00000000); + nv_wr32(priv, 0x4046d0, 0x00000000); + nv_wr32(priv, 0x4046d4, 0x00000000); + nv_wr32(priv, 0x4046d8, 0x00000000); + nv_wr32(priv, 0x4046dc, 0x00000000); + nv_wr32(priv, 0x4046e0, 0x00000000); + nv_wr32(priv, 0x4046e4, 0x00000000); + nv_wr32(priv, 0x4046e8, 0x00000000); + nv_wr32(priv, 0x4046f0, 0x00000000); + nv_wr32(priv, 0x4046f4, 0x00000000); +} + +static void +nvc0_grctx_generate_unk47xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x404700, 0x00000000); + nv_wr32(priv, 0x404704, 0x00000000); + nv_wr32(priv, 0x404708, 0x00000000); + nv_wr32(priv, 0x40470c, 0x00000000); + nv_wr32(priv, 0x404710, 0x00000000); + nv_wr32(priv, 0x404714, 0x00000000); + nv_wr32(priv, 0x404718, 0x00000000); + nv_wr32(priv, 0x40471c, 0x00000000); + nv_wr32(priv, 0x404720, 0x00000000); + nv_wr32(priv, 0x404724, 0x00000000); + nv_wr32(priv, 0x404728, 0x00000000); + nv_wr32(priv, 0x40472c, 0x00000000); + nv_wr32(priv, 0x404730, 0x00000000); + nv_wr32(priv, 0x404734, 0x00000100); + nv_wr32(priv, 0x404738, 0x00000000); + nv_wr32(priv, 0x40473c, 0x00000000); + nv_wr32(priv, 0x404740, 0x00000000); + nv_wr32(priv, 0x404744, 0x00000000); + nv_wr32(priv, 0x404748, 0x00000000); + nv_wr32(priv, 0x40474c, 0x00000000); + nv_wr32(priv, 0x404750, 0x00000000); + nv_wr32(priv, 0x404754, 0x00000000); +} + +static void +nvc0_grctx_generate_shaders(struct nvc0_graph_priv *priv) +{ + + if (nv_device(priv)->chipset == 0xd9) { + nv_wr32(priv, 0x405800, 0x0f8000bf); + nv_wr32(priv, 0x405830, 0x02180218); + nv_wr32(priv, 0x405834, 0x08000000); + } else + if (nv_device(priv)->chipset == 0xc1) { + nv_wr32(priv, 0x405800, 0x0f8000bf); + nv_wr32(priv, 0x405830, 0x02180218); + nv_wr32(priv, 0x405834, 0x00000000); + } else { + nv_wr32(priv, 0x405800, 0x078000bf); + nv_wr32(priv, 0x405830, 0x02180000); + nv_wr32(priv, 0x405834, 0x00000000); + } + nv_wr32(priv, 0x405838, 0x00000000); + nv_wr32(priv, 0x405854, 0x00000000); + nv_wr32(priv, 0x405870, 0x00000001); + nv_wr32(priv, 0x405874, 0x00000001); + nv_wr32(priv, 0x405878, 0x00000001); + nv_wr32(priv, 0x40587c, 0x00000001); + nv_wr32(priv, 0x405a00, 0x00000000); + nv_wr32(priv, 0x405a04, 0x00000000); + nv_wr32(priv, 0x405a18, 0x00000000); +} + +static void +nvc0_grctx_generate_unk60xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x406020, 0x000103c1); + nv_wr32(priv, 0x406028, 0x00000001); + nv_wr32(priv, 0x40602c, 0x00000001); + nv_wr32(priv, 0x406030, 0x00000001); + nv_wr32(priv, 0x406034, 0x00000001); +} + +static void +nvc0_grctx_generate_unk64xx(struct nvc0_graph_priv *priv) +{ + + nv_wr32(priv, 0x4064a8, 0x00000000); + nv_wr32(priv, 0x4064ac, 0x00003fff); + nv_wr32(priv, 0x4064b4, 0x00000000); + nv_wr32(priv, 0x4064b8, 0x00000000); + if (nv_device(priv)->chipset == 0xd9) + nv_wr32(priv, 0x4064bc, 0x00000000); + 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 nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x407804, 0x00000023); + nv_wr32(priv, 0x40780c, 0x0a418820); + nv_wr32(priv, 0x407810, 0x062080e6); + nv_wr32(priv, 0x407814, 0x020398a4); + nv_wr32(priv, 0x407818, 0x0e629062); + nv_wr32(priv, 0x40781c, 0x0a418820); + nv_wr32(priv, 0x407820, 0x000000e6); + nv_wr32(priv, 0x4078bc, 0x00000103); +} + +static void +nvc0_grctx_generate_ccache(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x408000, 0x00000000); + nv_wr32(priv, 0x408004, 0x00000000); + nv_wr32(priv, 0x408008, 0x00000018); + nv_wr32(priv, 0x40800c, 0x00000000); + nv_wr32(priv, 0x408010, 0x00000000); + nv_wr32(priv, 0x408014, 0x00000069); + nv_wr32(priv, 0x408018, 0xe100e100); + nv_wr32(priv, 0x408064, 0x00000000); +} + +static void +nvc0_grctx_generate_rop(struct nvc0_graph_priv *priv) +{ + int chipset = nv_device(priv)->chipset; + + /* ROPC_BROADCAST */ + nv_wr32(priv, 0x408800, 0x02802a3c); + nv_wr32(priv, 0x408804, 0x00000040); + if (chipset == 0xd9) { + nv_wr32(priv, 0x408808, 0x1043e005); + nv_wr32(priv, 0x408900, 0x3080b801); + nv_wr32(priv, 0x408904, 0x1043e005); + nv_wr32(priv, 0x408908, 0x00c8102f); + } else + if (chipset == 0xc1) { + nv_wr32(priv, 0x408808, 0x1003e005); + nv_wr32(priv, 0x408900, 0x3080b801); + nv_wr32(priv, 0x408904, 0x62000001); + nv_wr32(priv, 0x408908, 0x00c80929); + } else { + nv_wr32(priv, 0x408808, 0x0003e00d); + nv_wr32(priv, 0x408900, 0x3080b801); + nv_wr32(priv, 0x408904, 0x02000001); + nv_wr32(priv, 0x408908, 0x00c80929); + } + nv_wr32(priv, 0x40890c, 0x00000000); + nv_wr32(priv, 0x408980, 0x0000011d); +} + +static void +nvc0_grctx_generate_gpc(struct nvc0_graph_priv *priv) +{ + int chipset = nv_device(priv)->chipset; + int i; + + /* GPC_BROADCAST */ + nv_wr32(priv, 0x418380, 0x00000016); + nv_wr32(priv, 0x418400, 0x38004e00); + nv_wr32(priv, 0x418404, 0x71e0ffff); + nv_wr32(priv, 0x418408, 0x00000000); + nv_wr32(priv, 0x41840c, 0x00001008); + nv_wr32(priv, 0x418410, 0x0fff0fff); + nv_wr32(priv, 0x418414, chipset != 0xd9 ? 0x00200fff : 0x02200fff); + nv_wr32(priv, 0x418450, 0x00000000); + nv_wr32(priv, 0x418454, 0x00000000); + nv_wr32(priv, 0x418458, 0x00000000); + nv_wr32(priv, 0x41845c, 0x00000000); + nv_wr32(priv, 0x418460, 0x00000000); + nv_wr32(priv, 0x418464, 0x00000000); + nv_wr32(priv, 0x418468, 0x00000001); + nv_wr32(priv, 0x41846c, 0x00000000); + nv_wr32(priv, 0x418470, 0x00000000); + nv_wr32(priv, 0x418600, 0x0000001f); + nv_wr32(priv, 0x418684, 0x0000000f); + nv_wr32(priv, 0x418700, 0x00000002); + nv_wr32(priv, 0x418704, 0x00000080); + nv_wr32(priv, 0x418708, 0x00000000); + nv_wr32(priv, 0x41870c, chipset != 0xd9 ? 0x07c80000 : 0x00000000); + nv_wr32(priv, 0x418710, 0x00000000); + nv_wr32(priv, 0x418800, chipset != 0xd9 ? 0x0006860a : 0x7006860a); + nv_wr32(priv, 0x418808, 0x00000000); + nv_wr32(priv, 0x41880c, 0x00000000); + nv_wr32(priv, 0x418810, 0x00000000); + nv_wr32(priv, 0x418828, 0x00008442); + if (chipset == 0xc1 || chipset == 0xd9) + nv_wr32(priv, 0x418830, 0x10000001); + else + nv_wr32(priv, 0x418830, 0x00000001); + nv_wr32(priv, 0x4188d8, 0x00000008); + nv_wr32(priv, 0x4188e0, 0x01000000); + nv_wr32(priv, 0x4188e8, 0x00000000); + nv_wr32(priv, 0x4188ec, 0x00000000); + nv_wr32(priv, 0x4188f0, 0x00000000); + nv_wr32(priv, 0x4188f4, 0x00000000); + nv_wr32(priv, 0x4188f8, 0x00000000); + if (chipset == 0xd9) + nv_wr32(priv, 0x4188fc, 0x20100008); + else if (chipset == 0xc1) + nv_wr32(priv, 0x4188fc, 0x00100018); + else + nv_wr32(priv, 0x4188fc, 0x00100000); + nv_wr32(priv, 0x41891c, 0x00ff00ff); + nv_wr32(priv, 0x418924, 0x00000000); + nv_wr32(priv, 0x418928, 0x00ffff00); + nv_wr32(priv, 0x41892c, 0x0000ff00); + for (i = 0; i < 8; i++) { + nv_wr32(priv, 0x418a00 + (i * 0x20), 0x00000000); + nv_wr32(priv, 0x418a04 + (i * 0x20), 0x00000000); + nv_wr32(priv, 0x418a08 + (i * 0x20), 0x00000000); + nv_wr32(priv, 0x418a0c + (i * 0x20), 0x00010000); + nv_wr32(priv, 0x418a10 + (i * 0x20), 0x00000000); + nv_wr32(priv, 0x418a14 + (i * 0x20), 0x00000000); + nv_wr32(priv, 0x418a18 + (i * 0x20), 0x00000000); + } + nv_wr32(priv, 0x418b00, chipset != 0xd9 ? 0x00000000 : 0x00000006); + nv_wr32(priv, 0x418b08, 0x0a418820); + nv_wr32(priv, 0x418b0c, 0x062080e6); + nv_wr32(priv, 0x418b10, 0x020398a4); + nv_wr32(priv, 0x418b14, 0x0e629062); + nv_wr32(priv, 0x418b18, 0x0a418820); + nv_wr32(priv, 0x418b1c, 0x000000e6); + nv_wr32(priv, 0x418bb8, 0x00000103); + nv_wr32(priv, 0x418c08, 0x00000001); + nv_wr32(priv, 0x418c10, 0x00000000); + nv_wr32(priv, 0x418c14, 0x00000000); + nv_wr32(priv, 0x418c18, 0x00000000); + nv_wr32(priv, 0x418c1c, 0x00000000); + nv_wr32(priv, 0x418c20, 0x00000000); + nv_wr32(priv, 0x418c24, 0x00000000); + nv_wr32(priv, 0x418c28, 0x00000000); + nv_wr32(priv, 0x418c2c, 0x00000000); + if (chipset == 0xc1 || chipset == 0xd9) + nv_wr32(priv, 0x418c6c, 0x00000001); + nv_wr32(priv, 0x418c80, 0x20200004); + nv_wr32(priv, 0x418c8c, 0x00000001); + nv_wr32(priv, 0x419000, 0x00000780); + nv_wr32(priv, 0x419004, 0x00000000); + nv_wr32(priv, 0x419008, 0x00000000); + nv_wr32(priv, 0x419014, 0x00000004); +} + +static void +nvc0_grctx_generate_tp(struct nvc0_graph_priv *priv) +{ + int chipset = nv_device(priv)->chipset; + + /* GPC_BROADCAST.TP_BROADCAST */ + nv_wr32(priv, 0x419818, 0x00000000); + nv_wr32(priv, 0x41983c, 0x00038bc7); + nv_wr32(priv, 0x419848, 0x00000000); + if (chipset == 0xc1 || chipset == 0xd9) + nv_wr32(priv, 0x419864, 0x00000129); + else + nv_wr32(priv, 0x419864, 0x0000012a); + nv_wr32(priv, 0x419888, 0x00000000); + nv_wr32(priv, 0x419a00, 0x000001f0); + nv_wr32(priv, 0x419a04, 0x00000001); + nv_wr32(priv, 0x419a08, 0x00000023); + nv_wr32(priv, 0x419a0c, 0x00020000); + nv_wr32(priv, 0x419a10, 0x00000000); + nv_wr32(priv, 0x419a14, 0x00000200); + nv_wr32(priv, 0x419a1c, 0x00000000); + nv_wr32(priv, 0x419a20, 0x00000800); + if (chipset == 0xd9) + nv_wr32(priv, 0x00419ac4, 0x0017f440); + else if (chipset != 0xc0 && chipset != 0xc8) + nv_wr32(priv, 0x00419ac4, 0x0007f440); + nv_wr32(priv, 0x419b00, 0x0a418820); + nv_wr32(priv, 0x419b04, 0x062080e6); + nv_wr32(priv, 0x419b08, 0x020398a4); + nv_wr32(priv, 0x419b0c, 0x0e629062); + nv_wr32(priv, 0x419b10, 0x0a418820); + nv_wr32(priv, 0x419b14, 0x000000e6); + nv_wr32(priv, 0x419bd0, 0x00900103); + if (chipset == 0xc1 || chipset == 0xd9) + nv_wr32(priv, 0x419be0, 0x00400001); + else + nv_wr32(priv, 0x419be0, 0x00000001); + nv_wr32(priv, 0x419be4, 0x00000000); + nv_wr32(priv, 0x419c00, chipset != 0xd9 ? 0x00000002 : 0x0000000a); + nv_wr32(priv, 0x419c04, 0x00000006); + nv_wr32(priv, 0x419c08, 0x00000002); + nv_wr32(priv, 0x419c20, 0x00000000); + if (nv_device(priv)->chipset == 0xd9) { + nv_wr32(priv, 0x419c24, 0x00084210); + nv_wr32(priv, 0x419c28, 0x3cf3cf3c); + nv_wr32(priv, 0x419cb0, 0x00020048); + } else + if (chipset == 0xce || chipset == 0xcf) { + nv_wr32(priv, 0x419cb0, 0x00020048); + } else { + nv_wr32(priv, 0x419cb0, 0x00060048); + } + nv_wr32(priv, 0x419ce8, 0x00000000); + nv_wr32(priv, 0x419cf4, 0x00000183); + if (chipset == 0xc1 || chipset == 0xd9) + nv_wr32(priv, 0x419d20, 0x12180000); + else + nv_wr32(priv, 0x419d20, 0x02180000); + nv_wr32(priv, 0x419d24, 0x00001fff); + if (chipset == 0xc1 || chipset == 0xd9) + nv_wr32(priv, 0x419d44, 0x02180218); + nv_wr32(priv, 0x419e04, 0x00000000); + nv_wr32(priv, 0x419e08, 0x00000000); + nv_wr32(priv, 0x419e0c, 0x00000000); + nv_wr32(priv, 0x419e10, 0x00000002); + nv_wr32(priv, 0x419e44, 0x001beff2); + nv_wr32(priv, 0x419e48, 0x00000000); + nv_wr32(priv, 0x419e4c, 0x0000000f); + nv_wr32(priv, 0x419e50, 0x00000000); + nv_wr32(priv, 0x419e54, 0x00000000); + nv_wr32(priv, 0x419e58, 0x00000000); + nv_wr32(priv, 0x419e5c, 0x00000000); + nv_wr32(priv, 0x419e60, 0x00000000); + nv_wr32(priv, 0x419e64, 0x00000000); + nv_wr32(priv, 0x419e68, 0x00000000); + nv_wr32(priv, 0x419e6c, 0x00000000); + nv_wr32(priv, 0x419e70, 0x00000000); + nv_wr32(priv, 0x419e74, 0x00000000); + nv_wr32(priv, 0x419e78, 0x00000000); + nv_wr32(priv, 0x419e7c, 0x00000000); + nv_wr32(priv, 0x419e80, 0x00000000); + nv_wr32(priv, 0x419e84, 0x00000000); + nv_wr32(priv, 0x419e88, 0x00000000); + nv_wr32(priv, 0x419e8c, 0x00000000); + nv_wr32(priv, 0x419e90, 0x00000000); + nv_wr32(priv, 0x419e98, 0x00000000); + if (chipset != 0xc0 && chipset != 0xc8) + nv_wr32(priv, 0x419ee0, 0x00011110); + nv_wr32(priv, 0x419f50, 0x00000000); + nv_wr32(priv, 0x419f54, 0x00000000); + if (chipset != 0xc0 && chipset != 0xc8) + nv_wr32(priv, 0x419f58, 0x00000000); +} + +int +nvc0_grctx_generate(struct nvc0_graph_priv *priv) +{ + struct nvc0_grctx info; + int ret, i, gpc, tpc, id; + u32 fermi = nvc0_graph_class(priv); + u32 r000260, tmp; + + ret = nvc0_grctx_init(priv, &info); + if (ret) + return ret; + + r000260 = nv_rd32(priv, 0x000260); + nv_wr32(priv, 0x000260, r000260 & ~1); + nv_wr32(priv, 0x400208, 0x00000000); + + nvc0_grctx_generate_dispatch(priv); + nvc0_grctx_generate_macro(priv); + nvc0_grctx_generate_m2mf(priv); + nvc0_grctx_generate_unk47xx(priv); + nvc0_grctx_generate_shaders(priv); + nvc0_grctx_generate_unk60xx(priv); + nvc0_grctx_generate_unk64xx(priv); + nvc0_grctx_generate_tpbus(priv); + nvc0_grctx_generate_ccache(priv); + nvc0_grctx_generate_rop(priv); + nvc0_grctx_generate_gpc(priv); + nvc0_grctx_generate_tp(priv); + + nv_wr32(priv, 0x404154, 0x00000000); + + /* generate per-context mmio list data */ + mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); + mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); + mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); + mmio_list(0x408004, 0x00000000, 8, 0); + mmio_list(0x408008, 0x80000018, 0, 0); + mmio_list(0x40800c, 0x00000000, 8, 1); + mmio_list(0x408010, 0x80000000, 0, 0); + mmio_list(0x418810, 0x80000000, 12, 2); + mmio_list(0x419848, 0x10000000, 12, 2); + mmio_list(0x419004, 0x00000000, 8, 1); + mmio_list(0x419008, 0x00000000, 0, 0); + mmio_list(0x418808, 0x00000000, 8, 0); + mmio_list(0x41880c, 0x80000018, 0, 0); + if (nv_device(priv)->chipset != 0xc1) { + tmp = 0x02180000; + mmio_list(0x405830, tmp, 0, 0); + 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; + } + } + } else { + tmp = 0x02180000; + mmio_list(0x405830, 0x00000218 | tmp, 0, 0); + mmio_list(0x4064c4, 0x0086ffff, 0, 0); + 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 < priv->tpc_nr[gpc]; tpc++) { + u32 reg = TPC_UNIT(gpc, tpc, 0x0544); + mmio_list(reg, tmp, 0, 0); + tmp += 0x0324; + } + } + } + + for (tpc = 0, id = 0; tpc < 4; tpc++) { + 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); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + id++; + } + + 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 < priv->gpc_nr; i++) + tmp |= priv->tpc_nr[i] << (i * 4); + nv_wr32(priv, 0x406028, tmp); + nv_wr32(priv, 0x405870, tmp); + + nv_wr32(priv, 0x40602c, 0x00000000); + nv_wr32(priv, 0x405874, 0x00000000); + nv_wr32(priv, 0x406030, 0x00000000); + nv_wr32(priv, 0x405878, 0x00000000); + nv_wr32(priv, 0x406034, 0x00000000); + nv_wr32(priv, 0x40587c, 0x00000000); + + if (1) { + u8 tpcnr[GPC_MAX], data[TPC_MAX]; + + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memset(data, 0x1f, sizeof(data)); + + gpc = -1; + for (tpc = 0; tpc < priv->tpc_total; tpc++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpcnr[gpc]--; + data[tpc] = gpc; + } + + for (i = 0; i < 4; i++) + nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]); + } + + if (1) { + u32 data[6] = {}, data2[2] = {}; + u8 tpcnr[GPC_MAX]; + u8 shift, ntpcv; + + /* calculate first set of magics */ + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + + gpc = -1; + for (tpc = 0; tpc < priv->tpc_total; tpc++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpcnr[gpc]--; + + data[tpc / 6] |= gpc << ((tpc % 6) * 5); + } + + for (; tpc < 32; tpc++) + data[tpc / 6] |= 7 << ((tpc % 6) * 5); + + /* and the second... */ + shift = 0; + ntpcv = priv->tpc_total; + while (!(ntpcv & (1 << 4))) { + ntpcv <<= 1; + shift++; + } + + data2[0] = (ntpcv << 16); + data2[0] |= (shift << 21); + data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24); + for (i = 1; i < 7; i++) + data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); + + /* GPC_BROADCAST */ + 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, (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, (priv->tpc_total << 8) | + priv->magic_not_rop_nr); + for (i = 0; i < 6; i++) + nv_wr32(priv, 0x40780c + (i * 4), data[i]); + } + + if (1) { + u32 tpc_mask = 0, tpc_set = 0; + u8 tpcnr[GPC_MAX], a, b; + + 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 * (priv->tpc_total - 1)) / 32; + if (a != b) { + b = a; + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + + tpc_set |= 1 << ((gpc * 8) + tpc); + } + + nv_wr32(priv, 0x406800 + (i * 0x20), tpc_set); + nv_wr32(priv, 0x406c00 + (i * 0x20), tpc_set ^ tpc_mask); + } + } + + nv_wr32(priv, 0x400208, 0x80000000); + + nv_icmd(priv, 0x00001000, 0x00000004); + nv_icmd(priv, 0x000000a9, 0x0000ffff); + nv_icmd(priv, 0x00000038, 0x0fac6881); + nv_icmd(priv, 0x0000003d, 0x00000001); + nv_icmd(priv, 0x000000e8, 0x00000400); + nv_icmd(priv, 0x000000e9, 0x00000400); + nv_icmd(priv, 0x000000ea, 0x00000400); + nv_icmd(priv, 0x000000eb, 0x00000400); + nv_icmd(priv, 0x000000ec, 0x00000400); + nv_icmd(priv, 0x000000ed, 0x00000400); + nv_icmd(priv, 0x000000ee, 0x00000400); + nv_icmd(priv, 0x000000ef, 0x00000400); + nv_icmd(priv, 0x00000078, 0x00000300); + nv_icmd(priv, 0x00000079, 0x00000300); + nv_icmd(priv, 0x0000007a, 0x00000300); + nv_icmd(priv, 0x0000007b, 0x00000300); + nv_icmd(priv, 0x0000007c, 0x00000300); + nv_icmd(priv, 0x0000007d, 0x00000300); + nv_icmd(priv, 0x0000007e, 0x00000300); + nv_icmd(priv, 0x0000007f, 0x00000300); + nv_icmd(priv, 0x00000050, 0x00000011); + nv_icmd(priv, 0x00000058, 0x00000008); + nv_icmd(priv, 0x00000059, 0x00000008); + nv_icmd(priv, 0x0000005a, 0x00000008); + nv_icmd(priv, 0x0000005b, 0x00000008); + nv_icmd(priv, 0x0000005c, 0x00000008); + nv_icmd(priv, 0x0000005d, 0x00000008); + nv_icmd(priv, 0x0000005e, 0x00000008); + nv_icmd(priv, 0x0000005f, 0x00000008); + nv_icmd(priv, 0x00000208, 0x00000001); + nv_icmd(priv, 0x00000209, 0x00000001); + nv_icmd(priv, 0x0000020a, 0x00000001); + nv_icmd(priv, 0x0000020b, 0x00000001); + nv_icmd(priv, 0x0000020c, 0x00000001); + nv_icmd(priv, 0x0000020d, 0x00000001); + nv_icmd(priv, 0x0000020e, 0x00000001); + nv_icmd(priv, 0x0000020f, 0x00000001); + nv_icmd(priv, 0x00000081, 0x00000001); + nv_icmd(priv, 0x00000085, 0x00000004); + nv_icmd(priv, 0x00000088, 0x00000400); + nv_icmd(priv, 0x00000090, 0x00000300); + nv_icmd(priv, 0x00000098, 0x00001001); + nv_icmd(priv, 0x000000e3, 0x00000001); + nv_icmd(priv, 0x000000da, 0x00000001); + nv_icmd(priv, 0x000000f8, 0x00000003); + nv_icmd(priv, 0x000000fa, 0x00000001); + nv_icmd(priv, 0x0000009f, 0x0000ffff); + nv_icmd(priv, 0x000000a0, 0x0000ffff); + nv_icmd(priv, 0x000000a1, 0x0000ffff); + nv_icmd(priv, 0x000000a2, 0x0000ffff); + nv_icmd(priv, 0x000000b1, 0x00000001); + nv_icmd(priv, 0x000000b2, 0x00000000); + nv_icmd(priv, 0x000000b3, 0x00000000); + nv_icmd(priv, 0x000000b4, 0x00000000); + nv_icmd(priv, 0x000000b5, 0x00000000); + nv_icmd(priv, 0x000000b6, 0x00000000); + nv_icmd(priv, 0x000000b7, 0x00000000); + nv_icmd(priv, 0x000000b8, 0x00000000); + nv_icmd(priv, 0x000000b9, 0x00000000); + nv_icmd(priv, 0x000000ba, 0x00000000); + nv_icmd(priv, 0x000000bb, 0x00000000); + nv_icmd(priv, 0x000000bc, 0x00000000); + nv_icmd(priv, 0x000000bd, 0x00000000); + nv_icmd(priv, 0x000000be, 0x00000000); + nv_icmd(priv, 0x000000bf, 0x00000000); + nv_icmd(priv, 0x000000c0, 0x00000000); + nv_icmd(priv, 0x000000c1, 0x00000000); + nv_icmd(priv, 0x000000c2, 0x00000000); + nv_icmd(priv, 0x000000c3, 0x00000000); + nv_icmd(priv, 0x000000c4, 0x00000000); + nv_icmd(priv, 0x000000c5, 0x00000000); + nv_icmd(priv, 0x000000c6, 0x00000000); + nv_icmd(priv, 0x000000c7, 0x00000000); + nv_icmd(priv, 0x000000c8, 0x00000000); + nv_icmd(priv, 0x000000c9, 0x00000000); + nv_icmd(priv, 0x000000ca, 0x00000000); + nv_icmd(priv, 0x000000cb, 0x00000000); + nv_icmd(priv, 0x000000cc, 0x00000000); + nv_icmd(priv, 0x000000cd, 0x00000000); + nv_icmd(priv, 0x000000ce, 0x00000000); + nv_icmd(priv, 0x000000cf, 0x00000000); + nv_icmd(priv, 0x000000d0, 0x00000000); + nv_icmd(priv, 0x000000d1, 0x00000000); + nv_icmd(priv, 0x000000d2, 0x00000000); + nv_icmd(priv, 0x000000d3, 0x00000000); + nv_icmd(priv, 0x000000d4, 0x00000000); + nv_icmd(priv, 0x000000d5, 0x00000000); + nv_icmd(priv, 0x000000d6, 0x00000000); + nv_icmd(priv, 0x000000d7, 0x00000000); + nv_icmd(priv, 0x000000d8, 0x00000000); + nv_icmd(priv, 0x000000d9, 0x00000000); + nv_icmd(priv, 0x00000210, 0x00000040); + nv_icmd(priv, 0x00000211, 0x00000040); + nv_icmd(priv, 0x00000212, 0x00000040); + nv_icmd(priv, 0x00000213, 0x00000040); + nv_icmd(priv, 0x00000214, 0x00000040); + nv_icmd(priv, 0x00000215, 0x00000040); + nv_icmd(priv, 0x00000216, 0x00000040); + nv_icmd(priv, 0x00000217, 0x00000040); + if (nv_device(priv)->chipset == 0xd9) { + for (i = 0x0400; i <= 0x0417; i++) + nv_icmd(priv, i, 0x00000040); + } + nv_icmd(priv, 0x00000218, 0x0000c080); + nv_icmd(priv, 0x00000219, 0x0000c080); + nv_icmd(priv, 0x0000021a, 0x0000c080); + nv_icmd(priv, 0x0000021b, 0x0000c080); + nv_icmd(priv, 0x0000021c, 0x0000c080); + nv_icmd(priv, 0x0000021d, 0x0000c080); + nv_icmd(priv, 0x0000021e, 0x0000c080); + nv_icmd(priv, 0x0000021f, 0x0000c080); + if (nv_device(priv)->chipset == 0xd9) { + for (i = 0x0440; i <= 0x0457; i++) + nv_icmd(priv, i, 0x0000c080); + } + nv_icmd(priv, 0x000000ad, 0x0000013e); + nv_icmd(priv, 0x000000e1, 0x00000010); + nv_icmd(priv, 0x00000290, 0x00000000); + nv_icmd(priv, 0x00000291, 0x00000000); + nv_icmd(priv, 0x00000292, 0x00000000); + nv_icmd(priv, 0x00000293, 0x00000000); + nv_icmd(priv, 0x00000294, 0x00000000); + nv_icmd(priv, 0x00000295, 0x00000000); + nv_icmd(priv, 0x00000296, 0x00000000); + nv_icmd(priv, 0x00000297, 0x00000000); + nv_icmd(priv, 0x00000298, 0x00000000); + nv_icmd(priv, 0x00000299, 0x00000000); + nv_icmd(priv, 0x0000029a, 0x00000000); + nv_icmd(priv, 0x0000029b, 0x00000000); + nv_icmd(priv, 0x0000029c, 0x00000000); + nv_icmd(priv, 0x0000029d, 0x00000000); + nv_icmd(priv, 0x0000029e, 0x00000000); + nv_icmd(priv, 0x0000029f, 0x00000000); + nv_icmd(priv, 0x000003b0, 0x00000000); + nv_icmd(priv, 0x000003b1, 0x00000000); + nv_icmd(priv, 0x000003b2, 0x00000000); + nv_icmd(priv, 0x000003b3, 0x00000000); + nv_icmd(priv, 0x000003b4, 0x00000000); + nv_icmd(priv, 0x000003b5, 0x00000000); + nv_icmd(priv, 0x000003b6, 0x00000000); + nv_icmd(priv, 0x000003b7, 0x00000000); + nv_icmd(priv, 0x000003b8, 0x00000000); + nv_icmd(priv, 0x000003b9, 0x00000000); + nv_icmd(priv, 0x000003ba, 0x00000000); + nv_icmd(priv, 0x000003bb, 0x00000000); + nv_icmd(priv, 0x000003bc, 0x00000000); + nv_icmd(priv, 0x000003bd, 0x00000000); + nv_icmd(priv, 0x000003be, 0x00000000); + nv_icmd(priv, 0x000003bf, 0x00000000); + nv_icmd(priv, 0x000002a0, 0x00000000); + nv_icmd(priv, 0x000002a1, 0x00000000); + nv_icmd(priv, 0x000002a2, 0x00000000); + nv_icmd(priv, 0x000002a3, 0x00000000); + nv_icmd(priv, 0x000002a4, 0x00000000); + nv_icmd(priv, 0x000002a5, 0x00000000); + nv_icmd(priv, 0x000002a6, 0x00000000); + nv_icmd(priv, 0x000002a7, 0x00000000); + nv_icmd(priv, 0x000002a8, 0x00000000); + nv_icmd(priv, 0x000002a9, 0x00000000); + nv_icmd(priv, 0x000002aa, 0x00000000); + nv_icmd(priv, 0x000002ab, 0x00000000); + nv_icmd(priv, 0x000002ac, 0x00000000); + nv_icmd(priv, 0x000002ad, 0x00000000); + nv_icmd(priv, 0x000002ae, 0x00000000); + nv_icmd(priv, 0x000002af, 0x00000000); + nv_icmd(priv, 0x00000420, 0x00000000); + nv_icmd(priv, 0x00000421, 0x00000000); + nv_icmd(priv, 0x00000422, 0x00000000); + nv_icmd(priv, 0x00000423, 0x00000000); + nv_icmd(priv, 0x00000424, 0x00000000); + nv_icmd(priv, 0x00000425, 0x00000000); + nv_icmd(priv, 0x00000426, 0x00000000); + nv_icmd(priv, 0x00000427, 0x00000000); + nv_icmd(priv, 0x00000428, 0x00000000); + nv_icmd(priv, 0x00000429, 0x00000000); + nv_icmd(priv, 0x0000042a, 0x00000000); + nv_icmd(priv, 0x0000042b, 0x00000000); + nv_icmd(priv, 0x0000042c, 0x00000000); + nv_icmd(priv, 0x0000042d, 0x00000000); + nv_icmd(priv, 0x0000042e, 0x00000000); + nv_icmd(priv, 0x0000042f, 0x00000000); + nv_icmd(priv, 0x000002b0, 0x00000000); + nv_icmd(priv, 0x000002b1, 0x00000000); + nv_icmd(priv, 0x000002b2, 0x00000000); + nv_icmd(priv, 0x000002b3, 0x00000000); + nv_icmd(priv, 0x000002b4, 0x00000000); + nv_icmd(priv, 0x000002b5, 0x00000000); + nv_icmd(priv, 0x000002b6, 0x00000000); + nv_icmd(priv, 0x000002b7, 0x00000000); + nv_icmd(priv, 0x000002b8, 0x00000000); + nv_icmd(priv, 0x000002b9, 0x00000000); + nv_icmd(priv, 0x000002ba, 0x00000000); + nv_icmd(priv, 0x000002bb, 0x00000000); + nv_icmd(priv, 0x000002bc, 0x00000000); + nv_icmd(priv, 0x000002bd, 0x00000000); + nv_icmd(priv, 0x000002be, 0x00000000); + nv_icmd(priv, 0x000002bf, 0x00000000); + nv_icmd(priv, 0x00000430, 0x00000000); + nv_icmd(priv, 0x00000431, 0x00000000); + nv_icmd(priv, 0x00000432, 0x00000000); + nv_icmd(priv, 0x00000433, 0x00000000); + nv_icmd(priv, 0x00000434, 0x00000000); + nv_icmd(priv, 0x00000435, 0x00000000); + nv_icmd(priv, 0x00000436, 0x00000000); + nv_icmd(priv, 0x00000437, 0x00000000); + nv_icmd(priv, 0x00000438, 0x00000000); + nv_icmd(priv, 0x00000439, 0x00000000); + nv_icmd(priv, 0x0000043a, 0x00000000); + nv_icmd(priv, 0x0000043b, 0x00000000); + nv_icmd(priv, 0x0000043c, 0x00000000); + nv_icmd(priv, 0x0000043d, 0x00000000); + nv_icmd(priv, 0x0000043e, 0x00000000); + nv_icmd(priv, 0x0000043f, 0x00000000); + nv_icmd(priv, 0x000002c0, 0x00000000); + nv_icmd(priv, 0x000002c1, 0x00000000); + nv_icmd(priv, 0x000002c2, 0x00000000); + nv_icmd(priv, 0x000002c3, 0x00000000); + nv_icmd(priv, 0x000002c4, 0x00000000); + nv_icmd(priv, 0x000002c5, 0x00000000); + nv_icmd(priv, 0x000002c6, 0x00000000); + nv_icmd(priv, 0x000002c7, 0x00000000); + nv_icmd(priv, 0x000002c8, 0x00000000); + nv_icmd(priv, 0x000002c9, 0x00000000); + nv_icmd(priv, 0x000002ca, 0x00000000); + nv_icmd(priv, 0x000002cb, 0x00000000); + nv_icmd(priv, 0x000002cc, 0x00000000); + nv_icmd(priv, 0x000002cd, 0x00000000); + nv_icmd(priv, 0x000002ce, 0x00000000); + nv_icmd(priv, 0x000002cf, 0x00000000); + nv_icmd(priv, 0x000004d0, 0x00000000); + nv_icmd(priv, 0x000004d1, 0x00000000); + nv_icmd(priv, 0x000004d2, 0x00000000); + nv_icmd(priv, 0x000004d3, 0x00000000); + nv_icmd(priv, 0x000004d4, 0x00000000); + nv_icmd(priv, 0x000004d5, 0x00000000); + nv_icmd(priv, 0x000004d6, 0x00000000); + nv_icmd(priv, 0x000004d7, 0x00000000); + nv_icmd(priv, 0x000004d8, 0x00000000); + nv_icmd(priv, 0x000004d9, 0x00000000); + nv_icmd(priv, 0x000004da, 0x00000000); + nv_icmd(priv, 0x000004db, 0x00000000); + nv_icmd(priv, 0x000004dc, 0x00000000); + nv_icmd(priv, 0x000004dd, 0x00000000); + nv_icmd(priv, 0x000004de, 0x00000000); + nv_icmd(priv, 0x000004df, 0x00000000); + nv_icmd(priv, 0x00000720, 0x00000000); + nv_icmd(priv, 0x00000721, 0x00000000); + nv_icmd(priv, 0x00000722, 0x00000000); + nv_icmd(priv, 0x00000723, 0x00000000); + nv_icmd(priv, 0x00000724, 0x00000000); + nv_icmd(priv, 0x00000725, 0x00000000); + nv_icmd(priv, 0x00000726, 0x00000000); + nv_icmd(priv, 0x00000727, 0x00000000); + nv_icmd(priv, 0x00000728, 0x00000000); + nv_icmd(priv, 0x00000729, 0x00000000); + nv_icmd(priv, 0x0000072a, 0x00000000); + nv_icmd(priv, 0x0000072b, 0x00000000); + nv_icmd(priv, 0x0000072c, 0x00000000); + nv_icmd(priv, 0x0000072d, 0x00000000); + nv_icmd(priv, 0x0000072e, 0x00000000); + nv_icmd(priv, 0x0000072f, 0x00000000); + nv_icmd(priv, 0x000008c0, 0x00000000); + nv_icmd(priv, 0x000008c1, 0x00000000); + nv_icmd(priv, 0x000008c2, 0x00000000); + nv_icmd(priv, 0x000008c3, 0x00000000); + nv_icmd(priv, 0x000008c4, 0x00000000); + nv_icmd(priv, 0x000008c5, 0x00000000); + nv_icmd(priv, 0x000008c6, 0x00000000); + nv_icmd(priv, 0x000008c7, 0x00000000); + nv_icmd(priv, 0x000008c8, 0x00000000); + nv_icmd(priv, 0x000008c9, 0x00000000); + nv_icmd(priv, 0x000008ca, 0x00000000); + nv_icmd(priv, 0x000008cb, 0x00000000); + nv_icmd(priv, 0x000008cc, 0x00000000); + nv_icmd(priv, 0x000008cd, 0x00000000); + nv_icmd(priv, 0x000008ce, 0x00000000); + nv_icmd(priv, 0x000008cf, 0x00000000); + nv_icmd(priv, 0x00000890, 0x00000000); + nv_icmd(priv, 0x00000891, 0x00000000); + nv_icmd(priv, 0x00000892, 0x00000000); + nv_icmd(priv, 0x00000893, 0x00000000); + nv_icmd(priv, 0x00000894, 0x00000000); + nv_icmd(priv, 0x00000895, 0x00000000); + nv_icmd(priv, 0x00000896, 0x00000000); + nv_icmd(priv, 0x00000897, 0x00000000); + nv_icmd(priv, 0x00000898, 0x00000000); + nv_icmd(priv, 0x00000899, 0x00000000); + nv_icmd(priv, 0x0000089a, 0x00000000); + nv_icmd(priv, 0x0000089b, 0x00000000); + nv_icmd(priv, 0x0000089c, 0x00000000); + nv_icmd(priv, 0x0000089d, 0x00000000); + nv_icmd(priv, 0x0000089e, 0x00000000); + nv_icmd(priv, 0x0000089f, 0x00000000); + nv_icmd(priv, 0x000008e0, 0x00000000); + nv_icmd(priv, 0x000008e1, 0x00000000); + nv_icmd(priv, 0x000008e2, 0x00000000); + nv_icmd(priv, 0x000008e3, 0x00000000); + nv_icmd(priv, 0x000008e4, 0x00000000); + nv_icmd(priv, 0x000008e5, 0x00000000); + nv_icmd(priv, 0x000008e6, 0x00000000); + nv_icmd(priv, 0x000008e7, 0x00000000); + nv_icmd(priv, 0x000008e8, 0x00000000); + nv_icmd(priv, 0x000008e9, 0x00000000); + nv_icmd(priv, 0x000008ea, 0x00000000); + nv_icmd(priv, 0x000008eb, 0x00000000); + nv_icmd(priv, 0x000008ec, 0x00000000); + nv_icmd(priv, 0x000008ed, 0x00000000); + nv_icmd(priv, 0x000008ee, 0x00000000); + nv_icmd(priv, 0x000008ef, 0x00000000); + nv_icmd(priv, 0x000008a0, 0x00000000); + nv_icmd(priv, 0x000008a1, 0x00000000); + nv_icmd(priv, 0x000008a2, 0x00000000); + nv_icmd(priv, 0x000008a3, 0x00000000); + nv_icmd(priv, 0x000008a4, 0x00000000); + nv_icmd(priv, 0x000008a5, 0x00000000); + nv_icmd(priv, 0x000008a6, 0x00000000); + nv_icmd(priv, 0x000008a7, 0x00000000); + nv_icmd(priv, 0x000008a8, 0x00000000); + nv_icmd(priv, 0x000008a9, 0x00000000); + nv_icmd(priv, 0x000008aa, 0x00000000); + nv_icmd(priv, 0x000008ab, 0x00000000); + nv_icmd(priv, 0x000008ac, 0x00000000); + nv_icmd(priv, 0x000008ad, 0x00000000); + nv_icmd(priv, 0x000008ae, 0x00000000); + nv_icmd(priv, 0x000008af, 0x00000000); + nv_icmd(priv, 0x000008f0, 0x00000000); + nv_icmd(priv, 0x000008f1, 0x00000000); + nv_icmd(priv, 0x000008f2, 0x00000000); + nv_icmd(priv, 0x000008f3, 0x00000000); + nv_icmd(priv, 0x000008f4, 0x00000000); + nv_icmd(priv, 0x000008f5, 0x00000000); + nv_icmd(priv, 0x000008f6, 0x00000000); + nv_icmd(priv, 0x000008f7, 0x00000000); + nv_icmd(priv, 0x000008f8, 0x00000000); + nv_icmd(priv, 0x000008f9, 0x00000000); + nv_icmd(priv, 0x000008fa, 0x00000000); + nv_icmd(priv, 0x000008fb, 0x00000000); + nv_icmd(priv, 0x000008fc, 0x00000000); + nv_icmd(priv, 0x000008fd, 0x00000000); + nv_icmd(priv, 0x000008fe, 0x00000000); + nv_icmd(priv, 0x000008ff, 0x00000000); + nv_icmd(priv, 0x0000094c, 0x000000ff); + nv_icmd(priv, 0x0000094d, 0xffffffff); + nv_icmd(priv, 0x0000094e, 0x00000002); + nv_icmd(priv, 0x000002ec, 0x00000001); + nv_icmd(priv, 0x00000303, 0x00000001); + nv_icmd(priv, 0x000002e6, 0x00000001); + nv_icmd(priv, 0x00000466, 0x00000052); + nv_icmd(priv, 0x00000301, 0x3f800000); + nv_icmd(priv, 0x00000304, 0x30201000); + nv_icmd(priv, 0x00000305, 0x70605040); + nv_icmd(priv, 0x00000306, 0xb8a89888); + nv_icmd(priv, 0x00000307, 0xf8e8d8c8); + nv_icmd(priv, 0x0000030a, 0x00ffff00); + nv_icmd(priv, 0x0000030b, 0x0000001a); + nv_icmd(priv, 0x0000030c, 0x00000001); + nv_icmd(priv, 0x00000318, 0x00000001); + nv_icmd(priv, 0x00000340, 0x00000000); + nv_icmd(priv, 0x00000375, 0x00000001); + nv_icmd(priv, 0x00000351, 0x00000100); + nv_icmd(priv, 0x0000037d, 0x00000006); + nv_icmd(priv, 0x000003a0, 0x00000002); + nv_icmd(priv, 0x000003aa, 0x00000001); + nv_icmd(priv, 0x000003a9, 0x00000001); + nv_icmd(priv, 0x00000380, 0x00000001); + nv_icmd(priv, 0x00000360, 0x00000040); + nv_icmd(priv, 0x00000366, 0x00000000); + nv_icmd(priv, 0x00000367, 0x00000000); + nv_icmd(priv, 0x00000368, 0x00001fff); + nv_icmd(priv, 0x00000370, 0x00000000); + nv_icmd(priv, 0x00000371, 0x00000000); + nv_icmd(priv, 0x00000372, 0x003fffff); + nv_icmd(priv, 0x0000037a, 0x00000012); + nv_icmd(priv, 0x000005e0, 0x00000022); + nv_icmd(priv, 0x000005e1, 0x00000022); + nv_icmd(priv, 0x000005e2, 0x00000022); + nv_icmd(priv, 0x000005e3, 0x00000022); + nv_icmd(priv, 0x000005e4, 0x00000022); + nv_icmd(priv, 0x00000619, 0x00000003); + nv_icmd(priv, 0x00000811, 0x00000003); + nv_icmd(priv, 0x00000812, 0x00000004); + nv_icmd(priv, 0x00000813, 0x00000006); + nv_icmd(priv, 0x00000814, 0x00000008); + nv_icmd(priv, 0x00000815, 0x0000000b); + nv_icmd(priv, 0x00000800, 0x00000001); + nv_icmd(priv, 0x00000801, 0x00000001); + nv_icmd(priv, 0x00000802, 0x00000001); + nv_icmd(priv, 0x00000803, 0x00000001); + nv_icmd(priv, 0x00000804, 0x00000001); + nv_icmd(priv, 0x00000805, 0x00000001); + nv_icmd(priv, 0x00000632, 0x00000001); + nv_icmd(priv, 0x00000633, 0x00000002); + nv_icmd(priv, 0x00000634, 0x00000003); + nv_icmd(priv, 0x00000635, 0x00000004); + nv_icmd(priv, 0x00000654, 0x3f800000); + nv_icmd(priv, 0x00000657, 0x3f800000); + nv_icmd(priv, 0x00000655, 0x3f800000); + nv_icmd(priv, 0x00000656, 0x3f800000); + nv_icmd(priv, 0x000006cd, 0x3f800000); + nv_icmd(priv, 0x000007f5, 0x3f800000); + nv_icmd(priv, 0x000007dc, 0x39291909); + nv_icmd(priv, 0x000007dd, 0x79695949); + nv_icmd(priv, 0x000007de, 0xb9a99989); + nv_icmd(priv, 0x000007df, 0xf9e9d9c9); + nv_icmd(priv, 0x000007e8, 0x00003210); + nv_icmd(priv, 0x000007e9, 0x00007654); + nv_icmd(priv, 0x000007ea, 0x00000098); + nv_icmd(priv, 0x000007ec, 0x39291909); + nv_icmd(priv, 0x000007ed, 0x79695949); + nv_icmd(priv, 0x000007ee, 0xb9a99989); + nv_icmd(priv, 0x000007ef, 0xf9e9d9c9); + nv_icmd(priv, 0x000007f0, 0x00003210); + nv_icmd(priv, 0x000007f1, 0x00007654); + nv_icmd(priv, 0x000007f2, 0x00000098); + nv_icmd(priv, 0x000005a5, 0x00000001); + nv_icmd(priv, 0x00000980, 0x00000000); + nv_icmd(priv, 0x00000981, 0x00000000); + nv_icmd(priv, 0x00000982, 0x00000000); + nv_icmd(priv, 0x00000983, 0x00000000); + nv_icmd(priv, 0x00000984, 0x00000000); + nv_icmd(priv, 0x00000985, 0x00000000); + nv_icmd(priv, 0x00000986, 0x00000000); + nv_icmd(priv, 0x00000987, 0x00000000); + nv_icmd(priv, 0x00000988, 0x00000000); + nv_icmd(priv, 0x00000989, 0x00000000); + nv_icmd(priv, 0x0000098a, 0x00000000); + nv_icmd(priv, 0x0000098b, 0x00000000); + nv_icmd(priv, 0x0000098c, 0x00000000); + nv_icmd(priv, 0x0000098d, 0x00000000); + nv_icmd(priv, 0x0000098e, 0x00000000); + nv_icmd(priv, 0x0000098f, 0x00000000); + nv_icmd(priv, 0x00000990, 0x00000000); + nv_icmd(priv, 0x00000991, 0x00000000); + nv_icmd(priv, 0x00000992, 0x00000000); + nv_icmd(priv, 0x00000993, 0x00000000); + nv_icmd(priv, 0x00000994, 0x00000000); + nv_icmd(priv, 0x00000995, 0x00000000); + nv_icmd(priv, 0x00000996, 0x00000000); + nv_icmd(priv, 0x00000997, 0x00000000); + nv_icmd(priv, 0x00000998, 0x00000000); + nv_icmd(priv, 0x00000999, 0x00000000); + nv_icmd(priv, 0x0000099a, 0x00000000); + nv_icmd(priv, 0x0000099b, 0x00000000); + nv_icmd(priv, 0x0000099c, 0x00000000); + nv_icmd(priv, 0x0000099d, 0x00000000); + nv_icmd(priv, 0x0000099e, 0x00000000); + nv_icmd(priv, 0x0000099f, 0x00000000); + nv_icmd(priv, 0x000009a0, 0x00000000); + nv_icmd(priv, 0x000009a1, 0x00000000); + nv_icmd(priv, 0x000009a2, 0x00000000); + nv_icmd(priv, 0x000009a3, 0x00000000); + nv_icmd(priv, 0x000009a4, 0x00000000); + nv_icmd(priv, 0x000009a5, 0x00000000); + nv_icmd(priv, 0x000009a6, 0x00000000); + nv_icmd(priv, 0x000009a7, 0x00000000); + nv_icmd(priv, 0x000009a8, 0x00000000); + nv_icmd(priv, 0x000009a9, 0x00000000); + nv_icmd(priv, 0x000009aa, 0x00000000); + nv_icmd(priv, 0x000009ab, 0x00000000); + nv_icmd(priv, 0x000009ac, 0x00000000); + nv_icmd(priv, 0x000009ad, 0x00000000); + nv_icmd(priv, 0x000009ae, 0x00000000); + nv_icmd(priv, 0x000009af, 0x00000000); + nv_icmd(priv, 0x000009b0, 0x00000000); + nv_icmd(priv, 0x000009b1, 0x00000000); + nv_icmd(priv, 0x000009b2, 0x00000000); + nv_icmd(priv, 0x000009b3, 0x00000000); + nv_icmd(priv, 0x000009b4, 0x00000000); + nv_icmd(priv, 0x000009b5, 0x00000000); + nv_icmd(priv, 0x000009b6, 0x00000000); + nv_icmd(priv, 0x000009b7, 0x00000000); + nv_icmd(priv, 0x000009b8, 0x00000000); + nv_icmd(priv, 0x000009b9, 0x00000000); + nv_icmd(priv, 0x000009ba, 0x00000000); + nv_icmd(priv, 0x000009bb, 0x00000000); + nv_icmd(priv, 0x000009bc, 0x00000000); + nv_icmd(priv, 0x000009bd, 0x00000000); + nv_icmd(priv, 0x000009be, 0x00000000); + nv_icmd(priv, 0x000009bf, 0x00000000); + nv_icmd(priv, 0x000009c0, 0x00000000); + nv_icmd(priv, 0x000009c1, 0x00000000); + nv_icmd(priv, 0x000009c2, 0x00000000); + nv_icmd(priv, 0x000009c3, 0x00000000); + nv_icmd(priv, 0x000009c4, 0x00000000); + nv_icmd(priv, 0x000009c5, 0x00000000); + nv_icmd(priv, 0x000009c6, 0x00000000); + nv_icmd(priv, 0x000009c7, 0x00000000); + nv_icmd(priv, 0x000009c8, 0x00000000); + nv_icmd(priv, 0x000009c9, 0x00000000); + nv_icmd(priv, 0x000009ca, 0x00000000); + nv_icmd(priv, 0x000009cb, 0x00000000); + nv_icmd(priv, 0x000009cc, 0x00000000); + nv_icmd(priv, 0x000009cd, 0x00000000); + nv_icmd(priv, 0x000009ce, 0x00000000); + nv_icmd(priv, 0x000009cf, 0x00000000); + nv_icmd(priv, 0x000009d0, 0x00000000); + nv_icmd(priv, 0x000009d1, 0x00000000); + nv_icmd(priv, 0x000009d2, 0x00000000); + nv_icmd(priv, 0x000009d3, 0x00000000); + nv_icmd(priv, 0x000009d4, 0x00000000); + nv_icmd(priv, 0x000009d5, 0x00000000); + nv_icmd(priv, 0x000009d6, 0x00000000); + nv_icmd(priv, 0x000009d7, 0x00000000); + nv_icmd(priv, 0x000009d8, 0x00000000); + nv_icmd(priv, 0x000009d9, 0x00000000); + nv_icmd(priv, 0x000009da, 0x00000000); + nv_icmd(priv, 0x000009db, 0x00000000); + nv_icmd(priv, 0x000009dc, 0x00000000); + nv_icmd(priv, 0x000009dd, 0x00000000); + nv_icmd(priv, 0x000009de, 0x00000000); + nv_icmd(priv, 0x000009df, 0x00000000); + nv_icmd(priv, 0x000009e0, 0x00000000); + nv_icmd(priv, 0x000009e1, 0x00000000); + nv_icmd(priv, 0x000009e2, 0x00000000); + nv_icmd(priv, 0x000009e3, 0x00000000); + nv_icmd(priv, 0x000009e4, 0x00000000); + nv_icmd(priv, 0x000009e5, 0x00000000); + nv_icmd(priv, 0x000009e6, 0x00000000); + nv_icmd(priv, 0x000009e7, 0x00000000); + nv_icmd(priv, 0x000009e8, 0x00000000); + nv_icmd(priv, 0x000009e9, 0x00000000); + nv_icmd(priv, 0x000009ea, 0x00000000); + nv_icmd(priv, 0x000009eb, 0x00000000); + nv_icmd(priv, 0x000009ec, 0x00000000); + nv_icmd(priv, 0x000009ed, 0x00000000); + nv_icmd(priv, 0x000009ee, 0x00000000); + nv_icmd(priv, 0x000009ef, 0x00000000); + nv_icmd(priv, 0x000009f0, 0x00000000); + nv_icmd(priv, 0x000009f1, 0x00000000); + nv_icmd(priv, 0x000009f2, 0x00000000); + nv_icmd(priv, 0x000009f3, 0x00000000); + nv_icmd(priv, 0x000009f4, 0x00000000); + nv_icmd(priv, 0x000009f5, 0x00000000); + nv_icmd(priv, 0x000009f6, 0x00000000); + nv_icmd(priv, 0x000009f7, 0x00000000); + nv_icmd(priv, 0x000009f8, 0x00000000); + nv_icmd(priv, 0x000009f9, 0x00000000); + nv_icmd(priv, 0x000009fa, 0x00000000); + nv_icmd(priv, 0x000009fb, 0x00000000); + nv_icmd(priv, 0x000009fc, 0x00000000); + nv_icmd(priv, 0x000009fd, 0x00000000); + nv_icmd(priv, 0x000009fe, 0x00000000); + nv_icmd(priv, 0x000009ff, 0x00000000); + nv_icmd(priv, 0x00000468, 0x00000004); + nv_icmd(priv, 0x0000046c, 0x00000001); + nv_icmd(priv, 0x00000470, 0x00000000); + nv_icmd(priv, 0x00000471, 0x00000000); + nv_icmd(priv, 0x00000472, 0x00000000); + nv_icmd(priv, 0x00000473, 0x00000000); + nv_icmd(priv, 0x00000474, 0x00000000); + nv_icmd(priv, 0x00000475, 0x00000000); + nv_icmd(priv, 0x00000476, 0x00000000); + nv_icmd(priv, 0x00000477, 0x00000000); + nv_icmd(priv, 0x00000478, 0x00000000); + nv_icmd(priv, 0x00000479, 0x00000000); + nv_icmd(priv, 0x0000047a, 0x00000000); + nv_icmd(priv, 0x0000047b, 0x00000000); + nv_icmd(priv, 0x0000047c, 0x00000000); + nv_icmd(priv, 0x0000047d, 0x00000000); + nv_icmd(priv, 0x0000047e, 0x00000000); + nv_icmd(priv, 0x0000047f, 0x00000000); + nv_icmd(priv, 0x00000480, 0x00000000); + nv_icmd(priv, 0x00000481, 0x00000000); + nv_icmd(priv, 0x00000482, 0x00000000); + nv_icmd(priv, 0x00000483, 0x00000000); + nv_icmd(priv, 0x00000484, 0x00000000); + nv_icmd(priv, 0x00000485, 0x00000000); + nv_icmd(priv, 0x00000486, 0x00000000); + nv_icmd(priv, 0x00000487, 0x00000000); + nv_icmd(priv, 0x00000488, 0x00000000); + nv_icmd(priv, 0x00000489, 0x00000000); + nv_icmd(priv, 0x0000048a, 0x00000000); + nv_icmd(priv, 0x0000048b, 0x00000000); + nv_icmd(priv, 0x0000048c, 0x00000000); + nv_icmd(priv, 0x0000048d, 0x00000000); + nv_icmd(priv, 0x0000048e, 0x00000000); + nv_icmd(priv, 0x0000048f, 0x00000000); + nv_icmd(priv, 0x00000490, 0x00000000); + nv_icmd(priv, 0x00000491, 0x00000000); + nv_icmd(priv, 0x00000492, 0x00000000); + nv_icmd(priv, 0x00000493, 0x00000000); + nv_icmd(priv, 0x00000494, 0x00000000); + nv_icmd(priv, 0x00000495, 0x00000000); + nv_icmd(priv, 0x00000496, 0x00000000); + nv_icmd(priv, 0x00000497, 0x00000000); + nv_icmd(priv, 0x00000498, 0x00000000); + nv_icmd(priv, 0x00000499, 0x00000000); + nv_icmd(priv, 0x0000049a, 0x00000000); + nv_icmd(priv, 0x0000049b, 0x00000000); + nv_icmd(priv, 0x0000049c, 0x00000000); + nv_icmd(priv, 0x0000049d, 0x00000000); + nv_icmd(priv, 0x0000049e, 0x00000000); + nv_icmd(priv, 0x0000049f, 0x00000000); + nv_icmd(priv, 0x000004a0, 0x00000000); + nv_icmd(priv, 0x000004a1, 0x00000000); + nv_icmd(priv, 0x000004a2, 0x00000000); + nv_icmd(priv, 0x000004a3, 0x00000000); + nv_icmd(priv, 0x000004a4, 0x00000000); + nv_icmd(priv, 0x000004a5, 0x00000000); + nv_icmd(priv, 0x000004a6, 0x00000000); + nv_icmd(priv, 0x000004a7, 0x00000000); + nv_icmd(priv, 0x000004a8, 0x00000000); + nv_icmd(priv, 0x000004a9, 0x00000000); + nv_icmd(priv, 0x000004aa, 0x00000000); + nv_icmd(priv, 0x000004ab, 0x00000000); + nv_icmd(priv, 0x000004ac, 0x00000000); + nv_icmd(priv, 0x000004ad, 0x00000000); + nv_icmd(priv, 0x000004ae, 0x00000000); + nv_icmd(priv, 0x000004af, 0x00000000); + nv_icmd(priv, 0x000004b0, 0x00000000); + nv_icmd(priv, 0x000004b1, 0x00000000); + nv_icmd(priv, 0x000004b2, 0x00000000); + nv_icmd(priv, 0x000004b3, 0x00000000); + nv_icmd(priv, 0x000004b4, 0x00000000); + nv_icmd(priv, 0x000004b5, 0x00000000); + nv_icmd(priv, 0x000004b6, 0x00000000); + nv_icmd(priv, 0x000004b7, 0x00000000); + nv_icmd(priv, 0x000004b8, 0x00000000); + nv_icmd(priv, 0x000004b9, 0x00000000); + nv_icmd(priv, 0x000004ba, 0x00000000); + nv_icmd(priv, 0x000004bb, 0x00000000); + nv_icmd(priv, 0x000004bc, 0x00000000); + nv_icmd(priv, 0x000004bd, 0x00000000); + nv_icmd(priv, 0x000004be, 0x00000000); + nv_icmd(priv, 0x000004bf, 0x00000000); + nv_icmd(priv, 0x000004c0, 0x00000000); + nv_icmd(priv, 0x000004c1, 0x00000000); + nv_icmd(priv, 0x000004c2, 0x00000000); + nv_icmd(priv, 0x000004c3, 0x00000000); + nv_icmd(priv, 0x000004c4, 0x00000000); + nv_icmd(priv, 0x000004c5, 0x00000000); + nv_icmd(priv, 0x000004c6, 0x00000000); + nv_icmd(priv, 0x000004c7, 0x00000000); + nv_icmd(priv, 0x000004c8, 0x00000000); + nv_icmd(priv, 0x000004c9, 0x00000000); + nv_icmd(priv, 0x000004ca, 0x00000000); + nv_icmd(priv, 0x000004cb, 0x00000000); + nv_icmd(priv, 0x000004cc, 0x00000000); + nv_icmd(priv, 0x000004cd, 0x00000000); + nv_icmd(priv, 0x000004ce, 0x00000000); + nv_icmd(priv, 0x000004cf, 0x00000000); + nv_icmd(priv, 0x00000510, 0x3f800000); + nv_icmd(priv, 0x00000511, 0x3f800000); + nv_icmd(priv, 0x00000512, 0x3f800000); + nv_icmd(priv, 0x00000513, 0x3f800000); + nv_icmd(priv, 0x00000514, 0x3f800000); + nv_icmd(priv, 0x00000515, 0x3f800000); + nv_icmd(priv, 0x00000516, 0x3f800000); + nv_icmd(priv, 0x00000517, 0x3f800000); + nv_icmd(priv, 0x00000518, 0x3f800000); + nv_icmd(priv, 0x00000519, 0x3f800000); + nv_icmd(priv, 0x0000051a, 0x3f800000); + nv_icmd(priv, 0x0000051b, 0x3f800000); + nv_icmd(priv, 0x0000051c, 0x3f800000); + nv_icmd(priv, 0x0000051d, 0x3f800000); + nv_icmd(priv, 0x0000051e, 0x3f800000); + nv_icmd(priv, 0x0000051f, 0x3f800000); + nv_icmd(priv, 0x00000520, 0x000002b6); + nv_icmd(priv, 0x00000529, 0x00000001); + nv_icmd(priv, 0x00000530, 0xffff0000); + nv_icmd(priv, 0x00000531, 0xffff0000); + nv_icmd(priv, 0x00000532, 0xffff0000); + nv_icmd(priv, 0x00000533, 0xffff0000); + nv_icmd(priv, 0x00000534, 0xffff0000); + nv_icmd(priv, 0x00000535, 0xffff0000); + nv_icmd(priv, 0x00000536, 0xffff0000); + nv_icmd(priv, 0x00000537, 0xffff0000); + nv_icmd(priv, 0x00000538, 0xffff0000); + nv_icmd(priv, 0x00000539, 0xffff0000); + nv_icmd(priv, 0x0000053a, 0xffff0000); + nv_icmd(priv, 0x0000053b, 0xffff0000); + nv_icmd(priv, 0x0000053c, 0xffff0000); + nv_icmd(priv, 0x0000053d, 0xffff0000); + nv_icmd(priv, 0x0000053e, 0xffff0000); + nv_icmd(priv, 0x0000053f, 0xffff0000); + nv_icmd(priv, 0x00000585, 0x0000003f); + nv_icmd(priv, 0x00000576, 0x00000003); + 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); + nv_icmd(priv, 0x00000583, 0x00000080); + nv_icmd(priv, 0x000005c2, 0x00000001); + nv_icmd(priv, 0x00000638, 0x00000001); + nv_icmd(priv, 0x00000639, 0x00000001); + nv_icmd(priv, 0x0000063a, 0x00000002); + nv_icmd(priv, 0x0000063b, 0x00000001); + nv_icmd(priv, 0x0000063c, 0x00000001); + nv_icmd(priv, 0x0000063d, 0x00000002); + nv_icmd(priv, 0x0000063e, 0x00000001); + nv_icmd(priv, 0x000008b8, 0x00000001); + nv_icmd(priv, 0x000008b9, 0x00000001); + nv_icmd(priv, 0x000008ba, 0x00000001); + nv_icmd(priv, 0x000008bb, 0x00000001); + nv_icmd(priv, 0x000008bc, 0x00000001); + nv_icmd(priv, 0x000008bd, 0x00000001); + nv_icmd(priv, 0x000008be, 0x00000001); + nv_icmd(priv, 0x000008bf, 0x00000001); + nv_icmd(priv, 0x00000900, 0x00000001); + nv_icmd(priv, 0x00000901, 0x00000001); + nv_icmd(priv, 0x00000902, 0x00000001); + nv_icmd(priv, 0x00000903, 0x00000001); + nv_icmd(priv, 0x00000904, 0x00000001); + nv_icmd(priv, 0x00000905, 0x00000001); + nv_icmd(priv, 0x00000906, 0x00000001); + nv_icmd(priv, 0x00000907, 0x00000001); + nv_icmd(priv, 0x00000908, 0x00000002); + nv_icmd(priv, 0x00000909, 0x00000002); + nv_icmd(priv, 0x0000090a, 0x00000002); + nv_icmd(priv, 0x0000090b, 0x00000002); + nv_icmd(priv, 0x0000090c, 0x00000002); + nv_icmd(priv, 0x0000090d, 0x00000002); + nv_icmd(priv, 0x0000090e, 0x00000002); + nv_icmd(priv, 0x0000090f, 0x00000002); + nv_icmd(priv, 0x00000910, 0x00000001); + nv_icmd(priv, 0x00000911, 0x00000001); + nv_icmd(priv, 0x00000912, 0x00000001); + nv_icmd(priv, 0x00000913, 0x00000001); + nv_icmd(priv, 0x00000914, 0x00000001); + nv_icmd(priv, 0x00000915, 0x00000001); + nv_icmd(priv, 0x00000916, 0x00000001); + nv_icmd(priv, 0x00000917, 0x00000001); + nv_icmd(priv, 0x00000918, 0x00000001); + nv_icmd(priv, 0x00000919, 0x00000001); + nv_icmd(priv, 0x0000091a, 0x00000001); + nv_icmd(priv, 0x0000091b, 0x00000001); + nv_icmd(priv, 0x0000091c, 0x00000001); + nv_icmd(priv, 0x0000091d, 0x00000001); + nv_icmd(priv, 0x0000091e, 0x00000001); + nv_icmd(priv, 0x0000091f, 0x00000001); + nv_icmd(priv, 0x00000920, 0x00000002); + nv_icmd(priv, 0x00000921, 0x00000002); + nv_icmd(priv, 0x00000922, 0x00000002); + nv_icmd(priv, 0x00000923, 0x00000002); + nv_icmd(priv, 0x00000924, 0x00000002); + nv_icmd(priv, 0x00000925, 0x00000002); + nv_icmd(priv, 0x00000926, 0x00000002); + nv_icmd(priv, 0x00000927, 0x00000002); + nv_icmd(priv, 0x00000928, 0x00000001); + nv_icmd(priv, 0x00000929, 0x00000001); + nv_icmd(priv, 0x0000092a, 0x00000001); + nv_icmd(priv, 0x0000092b, 0x00000001); + nv_icmd(priv, 0x0000092c, 0x00000001); + nv_icmd(priv, 0x0000092d, 0x00000001); + nv_icmd(priv, 0x0000092e, 0x00000001); + nv_icmd(priv, 0x0000092f, 0x00000001); + nv_icmd(priv, 0x00000648, 0x00000001); + nv_icmd(priv, 0x00000649, 0x00000001); + nv_icmd(priv, 0x0000064a, 0x00000001); + nv_icmd(priv, 0x0000064b, 0x00000001); + nv_icmd(priv, 0x0000064c, 0x00000001); + nv_icmd(priv, 0x0000064d, 0x00000001); + nv_icmd(priv, 0x0000064e, 0x00000001); + nv_icmd(priv, 0x0000064f, 0x00000001); + nv_icmd(priv, 0x00000650, 0x00000001); + nv_icmd(priv, 0x00000658, 0x0000000f); + nv_icmd(priv, 0x000007ff, 0x0000000a); + nv_icmd(priv, 0x0000066a, 0x40000000); + nv_icmd(priv, 0x0000066b, 0x10000000); + nv_icmd(priv, 0x0000066c, 0xffff0000); + nv_icmd(priv, 0x0000066d, 0xffff0000); + nv_icmd(priv, 0x000007af, 0x00000008); + nv_icmd(priv, 0x000007b0, 0x00000008); + nv_icmd(priv, 0x000007f6, 0x00000001); + nv_icmd(priv, 0x000006b2, 0x00000055); + nv_icmd(priv, 0x000007ad, 0x00000003); + nv_icmd(priv, 0x00000937, 0x00000001); + nv_icmd(priv, 0x00000971, 0x00000008); + nv_icmd(priv, 0x00000972, 0x00000040); + nv_icmd(priv, 0x00000973, 0x0000012c); + nv_icmd(priv, 0x0000097c, 0x00000040); + nv_icmd(priv, 0x00000979, 0x00000003); + nv_icmd(priv, 0x00000975, 0x00000020); + nv_icmd(priv, 0x00000976, 0x00000001); + nv_icmd(priv, 0x00000977, 0x00000020); + nv_icmd(priv, 0x00000978, 0x00000001); + nv_icmd(priv, 0x00000957, 0x00000003); + nv_icmd(priv, 0x0000095e, 0x20164010); + nv_icmd(priv, 0x0000095f, 0x00000020); + if (nv_device(priv)->chipset == 0xd9) + nv_icmd(priv, 0x0000097d, 0x00000020); + nv_icmd(priv, 0x00000683, 0x00000006); + nv_icmd(priv, 0x00000685, 0x003fffff); + nv_icmd(priv, 0x00000687, 0x00000c48); + nv_icmd(priv, 0x000006a0, 0x00000005); + nv_icmd(priv, 0x00000840, 0x00300008); + nv_icmd(priv, 0x00000841, 0x04000080); + nv_icmd(priv, 0x00000842, 0x00300008); + nv_icmd(priv, 0x00000843, 0x04000080); + nv_icmd(priv, 0x00000818, 0x00000000); + nv_icmd(priv, 0x00000819, 0x00000000); + nv_icmd(priv, 0x0000081a, 0x00000000); + nv_icmd(priv, 0x0000081b, 0x00000000); + nv_icmd(priv, 0x0000081c, 0x00000000); + nv_icmd(priv, 0x0000081d, 0x00000000); + nv_icmd(priv, 0x0000081e, 0x00000000); + nv_icmd(priv, 0x0000081f, 0x00000000); + nv_icmd(priv, 0x00000848, 0x00000000); + nv_icmd(priv, 0x00000849, 0x00000000); + nv_icmd(priv, 0x0000084a, 0x00000000); + nv_icmd(priv, 0x0000084b, 0x00000000); + nv_icmd(priv, 0x0000084c, 0x00000000); + nv_icmd(priv, 0x0000084d, 0x00000000); + nv_icmd(priv, 0x0000084e, 0x00000000); + nv_icmd(priv, 0x0000084f, 0x00000000); + nv_icmd(priv, 0x00000850, 0x00000000); + nv_icmd(priv, 0x00000851, 0x00000000); + nv_icmd(priv, 0x00000852, 0x00000000); + nv_icmd(priv, 0x00000853, 0x00000000); + nv_icmd(priv, 0x00000854, 0x00000000); + nv_icmd(priv, 0x00000855, 0x00000000); + nv_icmd(priv, 0x00000856, 0x00000000); + nv_icmd(priv, 0x00000857, 0x00000000); + nv_icmd(priv, 0x00000738, 0x00000000); + nv_icmd(priv, 0x000006aa, 0x00000001); + nv_icmd(priv, 0x000006ab, 0x00000002); + nv_icmd(priv, 0x000006ac, 0x00000080); + nv_icmd(priv, 0x000006ad, 0x00000100); + nv_icmd(priv, 0x000006ae, 0x00000100); + nv_icmd(priv, 0x000006b1, 0x00000011); + nv_icmd(priv, 0x000006bb, 0x000000cf); + nv_icmd(priv, 0x000006ce, 0x2a712488); + nv_icmd(priv, 0x00000739, 0x4085c000); + nv_icmd(priv, 0x0000073a, 0x00000080); + nv_icmd(priv, 0x00000786, 0x80000100); + nv_icmd(priv, 0x0000073c, 0x00010100); + nv_icmd(priv, 0x0000073d, 0x02800000); + nv_icmd(priv, 0x00000787, 0x000000cf); + nv_icmd(priv, 0x0000078c, 0x00000008); + nv_icmd(priv, 0x00000792, 0x00000001); + nv_icmd(priv, 0x00000794, 0x00000001); + nv_icmd(priv, 0x00000795, 0x00000001); + nv_icmd(priv, 0x00000796, 0x00000001); + nv_icmd(priv, 0x00000797, 0x000000cf); + nv_icmd(priv, 0x00000836, 0x00000001); + nv_icmd(priv, 0x0000079a, 0x00000002); + nv_icmd(priv, 0x00000833, 0x04444480); + nv_icmd(priv, 0x000007a1, 0x00000001); + nv_icmd(priv, 0x000007a3, 0x00000001); + nv_icmd(priv, 0x000007a4, 0x00000001); + nv_icmd(priv, 0x000007a5, 0x00000001); + nv_icmd(priv, 0x00000831, 0x00000004); + nv_icmd(priv, 0x0000080c, 0x00000002); + nv_icmd(priv, 0x0000080d, 0x00000100); + nv_icmd(priv, 0x0000080e, 0x00000100); + nv_icmd(priv, 0x0000080f, 0x00000001); + nv_icmd(priv, 0x00000823, 0x00000002); + nv_icmd(priv, 0x00000824, 0x00000100); + nv_icmd(priv, 0x00000825, 0x00000100); + nv_icmd(priv, 0x00000826, 0x00000001); + nv_icmd(priv, 0x0000095d, 0x00000001); + nv_icmd(priv, 0x0000082b, 0x00000004); + nv_icmd(priv, 0x00000942, 0x00010001); + nv_icmd(priv, 0x00000943, 0x00000001); + nv_icmd(priv, 0x00000944, 0x00000022); + nv_icmd(priv, 0x000007c5, 0x00010001); + nv_icmd(priv, 0x00000834, 0x00000001); + nv_icmd(priv, 0x000007c7, 0x00000001); + nv_icmd(priv, 0x0000c1b0, 0x0000000f); + nv_icmd(priv, 0x0000c1b1, 0x0000000f); + nv_icmd(priv, 0x0000c1b2, 0x0000000f); + nv_icmd(priv, 0x0000c1b3, 0x0000000f); + nv_icmd(priv, 0x0000c1b4, 0x0000000f); + nv_icmd(priv, 0x0000c1b5, 0x0000000f); + nv_icmd(priv, 0x0000c1b6, 0x0000000f); + nv_icmd(priv, 0x0000c1b7, 0x0000000f); + nv_icmd(priv, 0x0000c1b8, 0x0fac6881); + nv_icmd(priv, 0x0000c1b9, 0x00fac688); + nv_icmd(priv, 0x0001e100, 0x00000001); + nv_icmd(priv, 0x00001000, 0x00000002); + nv_icmd(priv, 0x000006aa, 0x00000001); + nv_icmd(priv, 0x000006ad, 0x00000100); + nv_icmd(priv, 0x000006ae, 0x00000100); + nv_icmd(priv, 0x000006b1, 0x00000011); + nv_icmd(priv, 0x0000078c, 0x00000008); + nv_icmd(priv, 0x00000792, 0x00000001); + nv_icmd(priv, 0x00000794, 0x00000001); + nv_icmd(priv, 0x00000795, 0x00000001); + nv_icmd(priv, 0x00000796, 0x00000001); + nv_icmd(priv, 0x00000797, 0x000000cf); + nv_icmd(priv, 0x0000079a, 0x00000002); + nv_icmd(priv, 0x00000833, 0x04444480); + nv_icmd(priv, 0x000007a1, 0x00000001); + nv_icmd(priv, 0x000007a3, 0x00000001); + nv_icmd(priv, 0x000007a4, 0x00000001); + nv_icmd(priv, 0x000007a5, 0x00000001); + nv_icmd(priv, 0x00000831, 0x00000004); + nv_icmd(priv, 0x0001e100, 0x00000001); + nv_icmd(priv, 0x00001000, 0x00000014); + nv_icmd(priv, 0x00000351, 0x00000100); + nv_icmd(priv, 0x00000957, 0x00000003); + nv_icmd(priv, 0x0000095d, 0x00000001); + nv_icmd(priv, 0x0000082b, 0x00000004); + nv_icmd(priv, 0x00000942, 0x00010001); + nv_icmd(priv, 0x00000943, 0x00000001); + nv_icmd(priv, 0x000007c5, 0x00010001); + nv_icmd(priv, 0x00000834, 0x00000001); + nv_icmd(priv, 0x000007c7, 0x00000001); + nv_icmd(priv, 0x0001e100, 0x00000001); + nv_icmd(priv, 0x00001000, 0x00000001); + nv_icmd(priv, 0x0000080c, 0x00000002); + nv_icmd(priv, 0x0000080d, 0x00000100); + nv_icmd(priv, 0x0000080e, 0x00000100); + nv_icmd(priv, 0x0000080f, 0x00000001); + nv_icmd(priv, 0x00000823, 0x00000002); + nv_icmd(priv, 0x00000824, 0x00000100); + nv_icmd(priv, 0x00000825, 0x00000100); + nv_icmd(priv, 0x00000826, 0x00000001); + nv_icmd(priv, 0x0001e100, 0x00000001); + nv_wr32(priv, 0x400208, 0x00000000); + nv_wr32(priv, 0x404154, 0x00000400); + + nvc0_grctx_generate_9097(priv); + if (fermi >= 0x9197) + nvc0_grctx_generate_9197(priv); + if (fermi >= 0x9297) + nvc0_grctx_generate_9297(priv); + nvc0_grctx_generate_902d(priv); + nvc0_grctx_generate_9039(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 new file mode 100644 index 00000000000..6d8c63931ee --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c @@ -0,0 +1,2788 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nvc0.h" + +static void +nve0_grctx_generate_icmd(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x400208, 0x80000000); + nv_icmd(priv, 0x001000, 0x00000004); + nv_icmd(priv, 0x000039, 0x00000000); + nv_icmd(priv, 0x00003a, 0x00000000); + nv_icmd(priv, 0x00003b, 0x00000000); + nv_icmd(priv, 0x0000a9, 0x0000ffff); + nv_icmd(priv, 0x000038, 0x0fac6881); + nv_icmd(priv, 0x00003d, 0x00000001); + nv_icmd(priv, 0x0000e8, 0x00000400); + nv_icmd(priv, 0x0000e9, 0x00000400); + nv_icmd(priv, 0x0000ea, 0x00000400); + nv_icmd(priv, 0x0000eb, 0x00000400); + nv_icmd(priv, 0x0000ec, 0x00000400); + nv_icmd(priv, 0x0000ed, 0x00000400); + nv_icmd(priv, 0x0000ee, 0x00000400); + nv_icmd(priv, 0x0000ef, 0x00000400); + nv_icmd(priv, 0x000078, 0x00000300); + nv_icmd(priv, 0x000079, 0x00000300); + nv_icmd(priv, 0x00007a, 0x00000300); + nv_icmd(priv, 0x00007b, 0x00000300); + nv_icmd(priv, 0x00007c, 0x00000300); + nv_icmd(priv, 0x00007d, 0x00000300); + nv_icmd(priv, 0x00007e, 0x00000300); + nv_icmd(priv, 0x00007f, 0x00000300); + nv_icmd(priv, 0x000050, 0x00000011); + nv_icmd(priv, 0x000058, 0x00000008); + nv_icmd(priv, 0x000059, 0x00000008); + nv_icmd(priv, 0x00005a, 0x00000008); + nv_icmd(priv, 0x00005b, 0x00000008); + nv_icmd(priv, 0x00005c, 0x00000008); + nv_icmd(priv, 0x00005d, 0x00000008); + nv_icmd(priv, 0x00005e, 0x00000008); + nv_icmd(priv, 0x00005f, 0x00000008); + nv_icmd(priv, 0x000208, 0x00000001); + nv_icmd(priv, 0x000209, 0x00000001); + nv_icmd(priv, 0x00020a, 0x00000001); + nv_icmd(priv, 0x00020b, 0x00000001); + nv_icmd(priv, 0x00020c, 0x00000001); + nv_icmd(priv, 0x00020d, 0x00000001); + nv_icmd(priv, 0x00020e, 0x00000001); + nv_icmd(priv, 0x00020f, 0x00000001); + nv_icmd(priv, 0x000081, 0x00000001); + nv_icmd(priv, 0x000085, 0x00000004); + nv_icmd(priv, 0x000088, 0x00000400); + nv_icmd(priv, 0x000090, 0x00000300); + nv_icmd(priv, 0x000098, 0x00001001); + nv_icmd(priv, 0x0000e3, 0x00000001); + nv_icmd(priv, 0x0000da, 0x00000001); + nv_icmd(priv, 0x0000f8, 0x00000003); + nv_icmd(priv, 0x0000fa, 0x00000001); + nv_icmd(priv, 0x00009f, 0x0000ffff); + nv_icmd(priv, 0x0000a0, 0x0000ffff); + nv_icmd(priv, 0x0000a1, 0x0000ffff); + nv_icmd(priv, 0x0000a2, 0x0000ffff); + nv_icmd(priv, 0x0000b1, 0x00000001); + nv_icmd(priv, 0x0000ad, 0x0000013e); + nv_icmd(priv, 0x0000e1, 0x00000010); + nv_icmd(priv, 0x000290, 0x00000000); + nv_icmd(priv, 0x000291, 0x00000000); + nv_icmd(priv, 0x000292, 0x00000000); + nv_icmd(priv, 0x000293, 0x00000000); + nv_icmd(priv, 0x000294, 0x00000000); + nv_icmd(priv, 0x000295, 0x00000000); + nv_icmd(priv, 0x000296, 0x00000000); + nv_icmd(priv, 0x000297, 0x00000000); + nv_icmd(priv, 0x000298, 0x00000000); + nv_icmd(priv, 0x000299, 0x00000000); + nv_icmd(priv, 0x00029a, 0x00000000); + nv_icmd(priv, 0x00029b, 0x00000000); + nv_icmd(priv, 0x00029c, 0x00000000); + nv_icmd(priv, 0x00029d, 0x00000000); + nv_icmd(priv, 0x00029e, 0x00000000); + nv_icmd(priv, 0x00029f, 0x00000000); + nv_icmd(priv, 0x0003b0, 0x00000000); + nv_icmd(priv, 0x0003b1, 0x00000000); + nv_icmd(priv, 0x0003b2, 0x00000000); + nv_icmd(priv, 0x0003b3, 0x00000000); + nv_icmd(priv, 0x0003b4, 0x00000000); + nv_icmd(priv, 0x0003b5, 0x00000000); + nv_icmd(priv, 0x0003b6, 0x00000000); + nv_icmd(priv, 0x0003b7, 0x00000000); + nv_icmd(priv, 0x0003b8, 0x00000000); + nv_icmd(priv, 0x0003b9, 0x00000000); + nv_icmd(priv, 0x0003ba, 0x00000000); + nv_icmd(priv, 0x0003bb, 0x00000000); + nv_icmd(priv, 0x0003bc, 0x00000000); + nv_icmd(priv, 0x0003bd, 0x00000000); + nv_icmd(priv, 0x0003be, 0x00000000); + nv_icmd(priv, 0x0003bf, 0x00000000); + nv_icmd(priv, 0x0002a0, 0x00000000); + nv_icmd(priv, 0x0002a1, 0x00000000); + nv_icmd(priv, 0x0002a2, 0x00000000); + nv_icmd(priv, 0x0002a3, 0x00000000); + nv_icmd(priv, 0x0002a4, 0x00000000); + nv_icmd(priv, 0x0002a5, 0x00000000); + nv_icmd(priv, 0x0002a6, 0x00000000); + nv_icmd(priv, 0x0002a7, 0x00000000); + nv_icmd(priv, 0x0002a8, 0x00000000); + nv_icmd(priv, 0x0002a9, 0x00000000); + nv_icmd(priv, 0x0002aa, 0x00000000); + nv_icmd(priv, 0x0002ab, 0x00000000); + nv_icmd(priv, 0x0002ac, 0x00000000); + nv_icmd(priv, 0x0002ad, 0x00000000); + nv_icmd(priv, 0x0002ae, 0x00000000); + nv_icmd(priv, 0x0002af, 0x00000000); + nv_icmd(priv, 0x000420, 0x00000000); + nv_icmd(priv, 0x000421, 0x00000000); + nv_icmd(priv, 0x000422, 0x00000000); + nv_icmd(priv, 0x000423, 0x00000000); + nv_icmd(priv, 0x000424, 0x00000000); + nv_icmd(priv, 0x000425, 0x00000000); + nv_icmd(priv, 0x000426, 0x00000000); + nv_icmd(priv, 0x000427, 0x00000000); + nv_icmd(priv, 0x000428, 0x00000000); + nv_icmd(priv, 0x000429, 0x00000000); + nv_icmd(priv, 0x00042a, 0x00000000); + nv_icmd(priv, 0x00042b, 0x00000000); + nv_icmd(priv, 0x00042c, 0x00000000); + nv_icmd(priv, 0x00042d, 0x00000000); + nv_icmd(priv, 0x00042e, 0x00000000); + nv_icmd(priv, 0x00042f, 0x00000000); + nv_icmd(priv, 0x0002b0, 0x00000000); + nv_icmd(priv, 0x0002b1, 0x00000000); + nv_icmd(priv, 0x0002b2, 0x00000000); + nv_icmd(priv, 0x0002b3, 0x00000000); + nv_icmd(priv, 0x0002b4, 0x00000000); + nv_icmd(priv, 0x0002b5, 0x00000000); + nv_icmd(priv, 0x0002b6, 0x00000000); + nv_icmd(priv, 0x0002b7, 0x00000000); + nv_icmd(priv, 0x0002b8, 0x00000000); + nv_icmd(priv, 0x0002b9, 0x00000000); + nv_icmd(priv, 0x0002ba, 0x00000000); + nv_icmd(priv, 0x0002bb, 0x00000000); + nv_icmd(priv, 0x0002bc, 0x00000000); + nv_icmd(priv, 0x0002bd, 0x00000000); + nv_icmd(priv, 0x0002be, 0x00000000); + nv_icmd(priv, 0x0002bf, 0x00000000); + nv_icmd(priv, 0x000430, 0x00000000); + nv_icmd(priv, 0x000431, 0x00000000); + nv_icmd(priv, 0x000432, 0x00000000); + nv_icmd(priv, 0x000433, 0x00000000); + nv_icmd(priv, 0x000434, 0x00000000); + nv_icmd(priv, 0x000435, 0x00000000); + nv_icmd(priv, 0x000436, 0x00000000); + nv_icmd(priv, 0x000437, 0x00000000); + nv_icmd(priv, 0x000438, 0x00000000); + nv_icmd(priv, 0x000439, 0x00000000); + nv_icmd(priv, 0x00043a, 0x00000000); + nv_icmd(priv, 0x00043b, 0x00000000); + nv_icmd(priv, 0x00043c, 0x00000000); + nv_icmd(priv, 0x00043d, 0x00000000); + nv_icmd(priv, 0x00043e, 0x00000000); + nv_icmd(priv, 0x00043f, 0x00000000); + nv_icmd(priv, 0x0002c0, 0x00000000); + nv_icmd(priv, 0x0002c1, 0x00000000); + nv_icmd(priv, 0x0002c2, 0x00000000); + nv_icmd(priv, 0x0002c3, 0x00000000); + nv_icmd(priv, 0x0002c4, 0x00000000); + nv_icmd(priv, 0x0002c5, 0x00000000); + nv_icmd(priv, 0x0002c6, 0x00000000); + nv_icmd(priv, 0x0002c7, 0x00000000); + nv_icmd(priv, 0x0002c8, 0x00000000); + nv_icmd(priv, 0x0002c9, 0x00000000); + nv_icmd(priv, 0x0002ca, 0x00000000); + nv_icmd(priv, 0x0002cb, 0x00000000); + nv_icmd(priv, 0x0002cc, 0x00000000); + nv_icmd(priv, 0x0002cd, 0x00000000); + nv_icmd(priv, 0x0002ce, 0x00000000); + nv_icmd(priv, 0x0002cf, 0x00000000); + nv_icmd(priv, 0x0004d0, 0x00000000); + nv_icmd(priv, 0x0004d1, 0x00000000); + nv_icmd(priv, 0x0004d2, 0x00000000); + nv_icmd(priv, 0x0004d3, 0x00000000); + nv_icmd(priv, 0x0004d4, 0x00000000); + nv_icmd(priv, 0x0004d5, 0x00000000); + nv_icmd(priv, 0x0004d6, 0x00000000); + nv_icmd(priv, 0x0004d7, 0x00000000); + nv_icmd(priv, 0x0004d8, 0x00000000); + nv_icmd(priv, 0x0004d9, 0x00000000); + nv_icmd(priv, 0x0004da, 0x00000000); + nv_icmd(priv, 0x0004db, 0x00000000); + nv_icmd(priv, 0x0004dc, 0x00000000); + nv_icmd(priv, 0x0004dd, 0x00000000); + nv_icmd(priv, 0x0004de, 0x00000000); + nv_icmd(priv, 0x0004df, 0x00000000); + nv_icmd(priv, 0x000720, 0x00000000); + nv_icmd(priv, 0x000721, 0x00000000); + nv_icmd(priv, 0x000722, 0x00000000); + nv_icmd(priv, 0x000723, 0x00000000); + nv_icmd(priv, 0x000724, 0x00000000); + nv_icmd(priv, 0x000725, 0x00000000); + nv_icmd(priv, 0x000726, 0x00000000); + nv_icmd(priv, 0x000727, 0x00000000); + nv_icmd(priv, 0x000728, 0x00000000); + nv_icmd(priv, 0x000729, 0x00000000); + nv_icmd(priv, 0x00072a, 0x00000000); + nv_icmd(priv, 0x00072b, 0x00000000); + nv_icmd(priv, 0x00072c, 0x00000000); + nv_icmd(priv, 0x00072d, 0x00000000); + nv_icmd(priv, 0x00072e, 0x00000000); + nv_icmd(priv, 0x00072f, 0x00000000); + nv_icmd(priv, 0x0008c0, 0x00000000); + nv_icmd(priv, 0x0008c1, 0x00000000); + nv_icmd(priv, 0x0008c2, 0x00000000); + nv_icmd(priv, 0x0008c3, 0x00000000); + nv_icmd(priv, 0x0008c4, 0x00000000); + nv_icmd(priv, 0x0008c5, 0x00000000); + nv_icmd(priv, 0x0008c6, 0x00000000); + nv_icmd(priv, 0x0008c7, 0x00000000); + nv_icmd(priv, 0x0008c8, 0x00000000); + nv_icmd(priv, 0x0008c9, 0x00000000); + nv_icmd(priv, 0x0008ca, 0x00000000); + nv_icmd(priv, 0x0008cb, 0x00000000); + nv_icmd(priv, 0x0008cc, 0x00000000); + nv_icmd(priv, 0x0008cd, 0x00000000); + nv_icmd(priv, 0x0008ce, 0x00000000); + nv_icmd(priv, 0x0008cf, 0x00000000); + nv_icmd(priv, 0x000890, 0x00000000); + nv_icmd(priv, 0x000891, 0x00000000); + nv_icmd(priv, 0x000892, 0x00000000); + nv_icmd(priv, 0x000893, 0x00000000); + nv_icmd(priv, 0x000894, 0x00000000); + nv_icmd(priv, 0x000895, 0x00000000); + nv_icmd(priv, 0x000896, 0x00000000); + nv_icmd(priv, 0x000897, 0x00000000); + nv_icmd(priv, 0x000898, 0x00000000); + nv_icmd(priv, 0x000899, 0x00000000); + nv_icmd(priv, 0x00089a, 0x00000000); + nv_icmd(priv, 0x00089b, 0x00000000); + nv_icmd(priv, 0x00089c, 0x00000000); + nv_icmd(priv, 0x00089d, 0x00000000); + nv_icmd(priv, 0x00089e, 0x00000000); + nv_icmd(priv, 0x00089f, 0x00000000); + nv_icmd(priv, 0x0008e0, 0x00000000); + nv_icmd(priv, 0x0008e1, 0x00000000); + nv_icmd(priv, 0x0008e2, 0x00000000); + nv_icmd(priv, 0x0008e3, 0x00000000); + nv_icmd(priv, 0x0008e4, 0x00000000); + nv_icmd(priv, 0x0008e5, 0x00000000); + nv_icmd(priv, 0x0008e6, 0x00000000); + nv_icmd(priv, 0x0008e7, 0x00000000); + nv_icmd(priv, 0x0008e8, 0x00000000); + nv_icmd(priv, 0x0008e9, 0x00000000); + nv_icmd(priv, 0x0008ea, 0x00000000); + nv_icmd(priv, 0x0008eb, 0x00000000); + nv_icmd(priv, 0x0008ec, 0x00000000); + nv_icmd(priv, 0x0008ed, 0x00000000); + nv_icmd(priv, 0x0008ee, 0x00000000); + nv_icmd(priv, 0x0008ef, 0x00000000); + nv_icmd(priv, 0x0008a0, 0x00000000); + nv_icmd(priv, 0x0008a1, 0x00000000); + nv_icmd(priv, 0x0008a2, 0x00000000); + nv_icmd(priv, 0x0008a3, 0x00000000); + nv_icmd(priv, 0x0008a4, 0x00000000); + nv_icmd(priv, 0x0008a5, 0x00000000); + nv_icmd(priv, 0x0008a6, 0x00000000); + nv_icmd(priv, 0x0008a7, 0x00000000); + nv_icmd(priv, 0x0008a8, 0x00000000); + nv_icmd(priv, 0x0008a9, 0x00000000); + nv_icmd(priv, 0x0008aa, 0x00000000); + nv_icmd(priv, 0x0008ab, 0x00000000); + nv_icmd(priv, 0x0008ac, 0x00000000); + nv_icmd(priv, 0x0008ad, 0x00000000); + nv_icmd(priv, 0x0008ae, 0x00000000); + nv_icmd(priv, 0x0008af, 0x00000000); + nv_icmd(priv, 0x0008f0, 0x00000000); + nv_icmd(priv, 0x0008f1, 0x00000000); + nv_icmd(priv, 0x0008f2, 0x00000000); + nv_icmd(priv, 0x0008f3, 0x00000000); + nv_icmd(priv, 0x0008f4, 0x00000000); + nv_icmd(priv, 0x0008f5, 0x00000000); + nv_icmd(priv, 0x0008f6, 0x00000000); + nv_icmd(priv, 0x0008f7, 0x00000000); + nv_icmd(priv, 0x0008f8, 0x00000000); + nv_icmd(priv, 0x0008f9, 0x00000000); + nv_icmd(priv, 0x0008fa, 0x00000000); + nv_icmd(priv, 0x0008fb, 0x00000000); + nv_icmd(priv, 0x0008fc, 0x00000000); + nv_icmd(priv, 0x0008fd, 0x00000000); + nv_icmd(priv, 0x0008fe, 0x00000000); + nv_icmd(priv, 0x0008ff, 0x00000000); + nv_icmd(priv, 0x00094c, 0x000000ff); + nv_icmd(priv, 0x00094d, 0xffffffff); + nv_icmd(priv, 0x00094e, 0x00000002); + nv_icmd(priv, 0x0002ec, 0x00000001); + nv_icmd(priv, 0x000303, 0x00000001); + nv_icmd(priv, 0x0002e6, 0x00000001); + nv_icmd(priv, 0x000466, 0x00000052); + nv_icmd(priv, 0x000301, 0x3f800000); + nv_icmd(priv, 0x000304, 0x30201000); + nv_icmd(priv, 0x000305, 0x70605040); + nv_icmd(priv, 0x000306, 0xb8a89888); + nv_icmd(priv, 0x000307, 0xf8e8d8c8); + nv_icmd(priv, 0x00030a, 0x00ffff00); + nv_icmd(priv, 0x00030b, 0x0000001a); + nv_icmd(priv, 0x00030c, 0x00000001); + nv_icmd(priv, 0x000318, 0x00000001); + nv_icmd(priv, 0x000340, 0x00000000); + nv_icmd(priv, 0x000375, 0x00000001); + nv_icmd(priv, 0x00037d, 0x00000006); + nv_icmd(priv, 0x0003a0, 0x00000002); + nv_icmd(priv, 0x0003aa, 0x00000001); + nv_icmd(priv, 0x0003a9, 0x00000001); + nv_icmd(priv, 0x000380, 0x00000001); + nv_icmd(priv, 0x000383, 0x00000011); + nv_icmd(priv, 0x000360, 0x00000040); + nv_icmd(priv, 0x000366, 0x00000000); + nv_icmd(priv, 0x000367, 0x00000000); + nv_icmd(priv, 0x000368, 0x00000fff); + nv_icmd(priv, 0x000370, 0x00000000); + nv_icmd(priv, 0x000371, 0x00000000); + nv_icmd(priv, 0x000372, 0x000fffff); + nv_icmd(priv, 0x00037a, 0x00000012); + nv_icmd(priv, 0x000619, 0x00000003); + nv_icmd(priv, 0x000811, 0x00000003); + nv_icmd(priv, 0x000812, 0x00000004); + nv_icmd(priv, 0x000813, 0x00000006); + nv_icmd(priv, 0x000814, 0x00000008); + nv_icmd(priv, 0x000815, 0x0000000b); + nv_icmd(priv, 0x000800, 0x00000001); + nv_icmd(priv, 0x000801, 0x00000001); + nv_icmd(priv, 0x000802, 0x00000001); + nv_icmd(priv, 0x000803, 0x00000001); + nv_icmd(priv, 0x000804, 0x00000001); + nv_icmd(priv, 0x000805, 0x00000001); + nv_icmd(priv, 0x000632, 0x00000001); + nv_icmd(priv, 0x000633, 0x00000002); + nv_icmd(priv, 0x000634, 0x00000003); + nv_icmd(priv, 0x000635, 0x00000004); + nv_icmd(priv, 0x000654, 0x3f800000); + nv_icmd(priv, 0x000657, 0x3f800000); + nv_icmd(priv, 0x000655, 0x3f800000); + nv_icmd(priv, 0x000656, 0x3f800000); + nv_icmd(priv, 0x0006cd, 0x3f800000); + nv_icmd(priv, 0x0007f5, 0x3f800000); + nv_icmd(priv, 0x0007dc, 0x39291909); + nv_icmd(priv, 0x0007dd, 0x79695949); + nv_icmd(priv, 0x0007de, 0xb9a99989); + nv_icmd(priv, 0x0007df, 0xf9e9d9c9); + nv_icmd(priv, 0x0007e8, 0x00003210); + nv_icmd(priv, 0x0007e9, 0x00007654); + nv_icmd(priv, 0x0007ea, 0x00000098); + nv_icmd(priv, 0x0007ec, 0x39291909); + nv_icmd(priv, 0x0007ed, 0x79695949); + nv_icmd(priv, 0x0007ee, 0xb9a99989); + nv_icmd(priv, 0x0007ef, 0xf9e9d9c9); + nv_icmd(priv, 0x0007f0, 0x00003210); + nv_icmd(priv, 0x0007f1, 0x00007654); + nv_icmd(priv, 0x0007f2, 0x00000098); + nv_icmd(priv, 0x0005a5, 0x00000001); + nv_icmd(priv, 0x000980, 0x00000000); + nv_icmd(priv, 0x000981, 0x00000000); + nv_icmd(priv, 0x000982, 0x00000000); + nv_icmd(priv, 0x000983, 0x00000000); + nv_icmd(priv, 0x000984, 0x00000000); + nv_icmd(priv, 0x000985, 0x00000000); + nv_icmd(priv, 0x000986, 0x00000000); + nv_icmd(priv, 0x000987, 0x00000000); + nv_icmd(priv, 0x000988, 0x00000000); + nv_icmd(priv, 0x000989, 0x00000000); + nv_icmd(priv, 0x00098a, 0x00000000); + nv_icmd(priv, 0x00098b, 0x00000000); + nv_icmd(priv, 0x00098c, 0x00000000); + nv_icmd(priv, 0x00098d, 0x00000000); + nv_icmd(priv, 0x00098e, 0x00000000); + nv_icmd(priv, 0x00098f, 0x00000000); + nv_icmd(priv, 0x000990, 0x00000000); + nv_icmd(priv, 0x000991, 0x00000000); + nv_icmd(priv, 0x000992, 0x00000000); + nv_icmd(priv, 0x000993, 0x00000000); + nv_icmd(priv, 0x000994, 0x00000000); + nv_icmd(priv, 0x000995, 0x00000000); + nv_icmd(priv, 0x000996, 0x00000000); + nv_icmd(priv, 0x000997, 0x00000000); + nv_icmd(priv, 0x000998, 0x00000000); + nv_icmd(priv, 0x000999, 0x00000000); + nv_icmd(priv, 0x00099a, 0x00000000); + nv_icmd(priv, 0x00099b, 0x00000000); + nv_icmd(priv, 0x00099c, 0x00000000); + nv_icmd(priv, 0x00099d, 0x00000000); + nv_icmd(priv, 0x00099e, 0x00000000); + nv_icmd(priv, 0x00099f, 0x00000000); + nv_icmd(priv, 0x0009a0, 0x00000000); + nv_icmd(priv, 0x0009a1, 0x00000000); + nv_icmd(priv, 0x0009a2, 0x00000000); + nv_icmd(priv, 0x0009a3, 0x00000000); + nv_icmd(priv, 0x0009a4, 0x00000000); + nv_icmd(priv, 0x0009a5, 0x00000000); + nv_icmd(priv, 0x0009a6, 0x00000000); + nv_icmd(priv, 0x0009a7, 0x00000000); + nv_icmd(priv, 0x0009a8, 0x00000000); + nv_icmd(priv, 0x0009a9, 0x00000000); + nv_icmd(priv, 0x0009aa, 0x00000000); + nv_icmd(priv, 0x0009ab, 0x00000000); + nv_icmd(priv, 0x0009ac, 0x00000000); + nv_icmd(priv, 0x0009ad, 0x00000000); + nv_icmd(priv, 0x0009ae, 0x00000000); + nv_icmd(priv, 0x0009af, 0x00000000); + nv_icmd(priv, 0x0009b0, 0x00000000); + nv_icmd(priv, 0x0009b1, 0x00000000); + nv_icmd(priv, 0x0009b2, 0x00000000); + nv_icmd(priv, 0x0009b3, 0x00000000); + nv_icmd(priv, 0x0009b4, 0x00000000); + nv_icmd(priv, 0x0009b5, 0x00000000); + nv_icmd(priv, 0x0009b6, 0x00000000); + nv_icmd(priv, 0x0009b7, 0x00000000); + nv_icmd(priv, 0x0009b8, 0x00000000); + nv_icmd(priv, 0x0009b9, 0x00000000); + nv_icmd(priv, 0x0009ba, 0x00000000); + nv_icmd(priv, 0x0009bb, 0x00000000); + nv_icmd(priv, 0x0009bc, 0x00000000); + nv_icmd(priv, 0x0009bd, 0x00000000); + nv_icmd(priv, 0x0009be, 0x00000000); + nv_icmd(priv, 0x0009bf, 0x00000000); + nv_icmd(priv, 0x0009c0, 0x00000000); + nv_icmd(priv, 0x0009c1, 0x00000000); + nv_icmd(priv, 0x0009c2, 0x00000000); + nv_icmd(priv, 0x0009c3, 0x00000000); + nv_icmd(priv, 0x0009c4, 0x00000000); + nv_icmd(priv, 0x0009c5, 0x00000000); + nv_icmd(priv, 0x0009c6, 0x00000000); + nv_icmd(priv, 0x0009c7, 0x00000000); + nv_icmd(priv, 0x0009c8, 0x00000000); + nv_icmd(priv, 0x0009c9, 0x00000000); + nv_icmd(priv, 0x0009ca, 0x00000000); + nv_icmd(priv, 0x0009cb, 0x00000000); + nv_icmd(priv, 0x0009cc, 0x00000000); + nv_icmd(priv, 0x0009cd, 0x00000000); + nv_icmd(priv, 0x0009ce, 0x00000000); + nv_icmd(priv, 0x0009cf, 0x00000000); + nv_icmd(priv, 0x0009d0, 0x00000000); + nv_icmd(priv, 0x0009d1, 0x00000000); + nv_icmd(priv, 0x0009d2, 0x00000000); + nv_icmd(priv, 0x0009d3, 0x00000000); + nv_icmd(priv, 0x0009d4, 0x00000000); + nv_icmd(priv, 0x0009d5, 0x00000000); + nv_icmd(priv, 0x0009d6, 0x00000000); + nv_icmd(priv, 0x0009d7, 0x00000000); + nv_icmd(priv, 0x0009d8, 0x00000000); + nv_icmd(priv, 0x0009d9, 0x00000000); + nv_icmd(priv, 0x0009da, 0x00000000); + nv_icmd(priv, 0x0009db, 0x00000000); + nv_icmd(priv, 0x0009dc, 0x00000000); + nv_icmd(priv, 0x0009dd, 0x00000000); + nv_icmd(priv, 0x0009de, 0x00000000); + nv_icmd(priv, 0x0009df, 0x00000000); + nv_icmd(priv, 0x0009e0, 0x00000000); + nv_icmd(priv, 0x0009e1, 0x00000000); + nv_icmd(priv, 0x0009e2, 0x00000000); + nv_icmd(priv, 0x0009e3, 0x00000000); + nv_icmd(priv, 0x0009e4, 0x00000000); + nv_icmd(priv, 0x0009e5, 0x00000000); + nv_icmd(priv, 0x0009e6, 0x00000000); + nv_icmd(priv, 0x0009e7, 0x00000000); + nv_icmd(priv, 0x0009e8, 0x00000000); + nv_icmd(priv, 0x0009e9, 0x00000000); + nv_icmd(priv, 0x0009ea, 0x00000000); + nv_icmd(priv, 0x0009eb, 0x00000000); + nv_icmd(priv, 0x0009ec, 0x00000000); + nv_icmd(priv, 0x0009ed, 0x00000000); + nv_icmd(priv, 0x0009ee, 0x00000000); + nv_icmd(priv, 0x0009ef, 0x00000000); + nv_icmd(priv, 0x0009f0, 0x00000000); + nv_icmd(priv, 0x0009f1, 0x00000000); + nv_icmd(priv, 0x0009f2, 0x00000000); + nv_icmd(priv, 0x0009f3, 0x00000000); + nv_icmd(priv, 0x0009f4, 0x00000000); + nv_icmd(priv, 0x0009f5, 0x00000000); + nv_icmd(priv, 0x0009f6, 0x00000000); + nv_icmd(priv, 0x0009f7, 0x00000000); + nv_icmd(priv, 0x0009f8, 0x00000000); + nv_icmd(priv, 0x0009f9, 0x00000000); + nv_icmd(priv, 0x0009fa, 0x00000000); + nv_icmd(priv, 0x0009fb, 0x00000000); + nv_icmd(priv, 0x0009fc, 0x00000000); + nv_icmd(priv, 0x0009fd, 0x00000000); + nv_icmd(priv, 0x0009fe, 0x00000000); + nv_icmd(priv, 0x0009ff, 0x00000000); + nv_icmd(priv, 0x000468, 0x00000004); + nv_icmd(priv, 0x00046c, 0x00000001); + nv_icmd(priv, 0x000470, 0x00000000); + nv_icmd(priv, 0x000471, 0x00000000); + nv_icmd(priv, 0x000472, 0x00000000); + nv_icmd(priv, 0x000473, 0x00000000); + nv_icmd(priv, 0x000474, 0x00000000); + nv_icmd(priv, 0x000475, 0x00000000); + nv_icmd(priv, 0x000476, 0x00000000); + nv_icmd(priv, 0x000477, 0x00000000); + nv_icmd(priv, 0x000478, 0x00000000); + nv_icmd(priv, 0x000479, 0x00000000); + nv_icmd(priv, 0x00047a, 0x00000000); + nv_icmd(priv, 0x00047b, 0x00000000); + nv_icmd(priv, 0x00047c, 0x00000000); + nv_icmd(priv, 0x00047d, 0x00000000); + nv_icmd(priv, 0x00047e, 0x00000000); + nv_icmd(priv, 0x00047f, 0x00000000); + nv_icmd(priv, 0x000480, 0x00000000); + nv_icmd(priv, 0x000481, 0x00000000); + nv_icmd(priv, 0x000482, 0x00000000); + nv_icmd(priv, 0x000483, 0x00000000); + nv_icmd(priv, 0x000484, 0x00000000); + nv_icmd(priv, 0x000485, 0x00000000); + nv_icmd(priv, 0x000486, 0x00000000); + nv_icmd(priv, 0x000487, 0x00000000); + nv_icmd(priv, 0x000488, 0x00000000); + nv_icmd(priv, 0x000489, 0x00000000); + nv_icmd(priv, 0x00048a, 0x00000000); + nv_icmd(priv, 0x00048b, 0x00000000); + nv_icmd(priv, 0x00048c, 0x00000000); + nv_icmd(priv, 0x00048d, 0x00000000); + nv_icmd(priv, 0x00048e, 0x00000000); + nv_icmd(priv, 0x00048f, 0x00000000); + nv_icmd(priv, 0x000490, 0x00000000); + nv_icmd(priv, 0x000491, 0x00000000); + nv_icmd(priv, 0x000492, 0x00000000); + nv_icmd(priv, 0x000493, 0x00000000); + nv_icmd(priv, 0x000494, 0x00000000); + nv_icmd(priv, 0x000495, 0x00000000); + nv_icmd(priv, 0x000496, 0x00000000); + nv_icmd(priv, 0x000497, 0x00000000); + nv_icmd(priv, 0x000498, 0x00000000); + nv_icmd(priv, 0x000499, 0x00000000); + nv_icmd(priv, 0x00049a, 0x00000000); + nv_icmd(priv, 0x00049b, 0x00000000); + nv_icmd(priv, 0x00049c, 0x00000000); + nv_icmd(priv, 0x00049d, 0x00000000); + nv_icmd(priv, 0x00049e, 0x00000000); + nv_icmd(priv, 0x00049f, 0x00000000); + nv_icmd(priv, 0x0004a0, 0x00000000); + nv_icmd(priv, 0x0004a1, 0x00000000); + nv_icmd(priv, 0x0004a2, 0x00000000); + nv_icmd(priv, 0x0004a3, 0x00000000); + nv_icmd(priv, 0x0004a4, 0x00000000); + nv_icmd(priv, 0x0004a5, 0x00000000); + nv_icmd(priv, 0x0004a6, 0x00000000); + nv_icmd(priv, 0x0004a7, 0x00000000); + nv_icmd(priv, 0x0004a8, 0x00000000); + nv_icmd(priv, 0x0004a9, 0x00000000); + nv_icmd(priv, 0x0004aa, 0x00000000); + nv_icmd(priv, 0x0004ab, 0x00000000); + nv_icmd(priv, 0x0004ac, 0x00000000); + nv_icmd(priv, 0x0004ad, 0x00000000); + nv_icmd(priv, 0x0004ae, 0x00000000); + nv_icmd(priv, 0x0004af, 0x00000000); + nv_icmd(priv, 0x0004b0, 0x00000000); + nv_icmd(priv, 0x0004b1, 0x00000000); + nv_icmd(priv, 0x0004b2, 0x00000000); + nv_icmd(priv, 0x0004b3, 0x00000000); + nv_icmd(priv, 0x0004b4, 0x00000000); + nv_icmd(priv, 0x0004b5, 0x00000000); + nv_icmd(priv, 0x0004b6, 0x00000000); + nv_icmd(priv, 0x0004b7, 0x00000000); + nv_icmd(priv, 0x0004b8, 0x00000000); + nv_icmd(priv, 0x0004b9, 0x00000000); + nv_icmd(priv, 0x0004ba, 0x00000000); + nv_icmd(priv, 0x0004bb, 0x00000000); + nv_icmd(priv, 0x0004bc, 0x00000000); + nv_icmd(priv, 0x0004bd, 0x00000000); + nv_icmd(priv, 0x0004be, 0x00000000); + nv_icmd(priv, 0x0004bf, 0x00000000); + nv_icmd(priv, 0x0004c0, 0x00000000); + nv_icmd(priv, 0x0004c1, 0x00000000); + nv_icmd(priv, 0x0004c2, 0x00000000); + nv_icmd(priv, 0x0004c3, 0x00000000); + nv_icmd(priv, 0x0004c4, 0x00000000); + nv_icmd(priv, 0x0004c5, 0x00000000); + nv_icmd(priv, 0x0004c6, 0x00000000); + nv_icmd(priv, 0x0004c7, 0x00000000); + nv_icmd(priv, 0x0004c8, 0x00000000); + nv_icmd(priv, 0x0004c9, 0x00000000); + nv_icmd(priv, 0x0004ca, 0x00000000); + nv_icmd(priv, 0x0004cb, 0x00000000); + nv_icmd(priv, 0x0004cc, 0x00000000); + nv_icmd(priv, 0x0004cd, 0x00000000); + nv_icmd(priv, 0x0004ce, 0x00000000); + nv_icmd(priv, 0x0004cf, 0x00000000); + nv_icmd(priv, 0x000510, 0x3f800000); + nv_icmd(priv, 0x000511, 0x3f800000); + nv_icmd(priv, 0x000512, 0x3f800000); + nv_icmd(priv, 0x000513, 0x3f800000); + nv_icmd(priv, 0x000514, 0x3f800000); + nv_icmd(priv, 0x000515, 0x3f800000); + nv_icmd(priv, 0x000516, 0x3f800000); + nv_icmd(priv, 0x000517, 0x3f800000); + nv_icmd(priv, 0x000518, 0x3f800000); + nv_icmd(priv, 0x000519, 0x3f800000); + nv_icmd(priv, 0x00051a, 0x3f800000); + nv_icmd(priv, 0x00051b, 0x3f800000); + nv_icmd(priv, 0x00051c, 0x3f800000); + nv_icmd(priv, 0x00051d, 0x3f800000); + nv_icmd(priv, 0x00051e, 0x3f800000); + nv_icmd(priv, 0x00051f, 0x3f800000); + nv_icmd(priv, 0x000520, 0x000002b6); + nv_icmd(priv, 0x000529, 0x00000001); + nv_icmd(priv, 0x000530, 0xffff0000); + nv_icmd(priv, 0x000531, 0xffff0000); + nv_icmd(priv, 0x000532, 0xffff0000); + nv_icmd(priv, 0x000533, 0xffff0000); + nv_icmd(priv, 0x000534, 0xffff0000); + nv_icmd(priv, 0x000535, 0xffff0000); + nv_icmd(priv, 0x000536, 0xffff0000); + nv_icmd(priv, 0x000537, 0xffff0000); + nv_icmd(priv, 0x000538, 0xffff0000); + nv_icmd(priv, 0x000539, 0xffff0000); + nv_icmd(priv, 0x00053a, 0xffff0000); + nv_icmd(priv, 0x00053b, 0xffff0000); + nv_icmd(priv, 0x00053c, 0xffff0000); + nv_icmd(priv, 0x00053d, 0xffff0000); + nv_icmd(priv, 0x00053e, 0xffff0000); + nv_icmd(priv, 0x00053f, 0xffff0000); + nv_icmd(priv, 0x000585, 0x0000003f); + nv_icmd(priv, 0x000576, 0x00000003); + nv_icmd(priv, 0x00057b, 0x00000059); + nv_icmd(priv, 0x000586, 0x00000040); + nv_icmd(priv, 0x000582, 0x00000080); + nv_icmd(priv, 0x000583, 0x00000080); + nv_icmd(priv, 0x0005c2, 0x00000001); + nv_icmd(priv, 0x000638, 0x00000001); + nv_icmd(priv, 0x000639, 0x00000001); + nv_icmd(priv, 0x00063a, 0x00000002); + nv_icmd(priv, 0x00063b, 0x00000001); + nv_icmd(priv, 0x00063c, 0x00000001); + nv_icmd(priv, 0x00063d, 0x00000002); + nv_icmd(priv, 0x00063e, 0x00000001); + nv_icmd(priv, 0x0008b8, 0x00000001); + nv_icmd(priv, 0x0008b9, 0x00000001); + nv_icmd(priv, 0x0008ba, 0x00000001); + nv_icmd(priv, 0x0008bb, 0x00000001); + nv_icmd(priv, 0x0008bc, 0x00000001); + nv_icmd(priv, 0x0008bd, 0x00000001); + nv_icmd(priv, 0x0008be, 0x00000001); + nv_icmd(priv, 0x0008bf, 0x00000001); + nv_icmd(priv, 0x000900, 0x00000001); + nv_icmd(priv, 0x000901, 0x00000001); + nv_icmd(priv, 0x000902, 0x00000001); + nv_icmd(priv, 0x000903, 0x00000001); + nv_icmd(priv, 0x000904, 0x00000001); + nv_icmd(priv, 0x000905, 0x00000001); + nv_icmd(priv, 0x000906, 0x00000001); + nv_icmd(priv, 0x000907, 0x00000001); + nv_icmd(priv, 0x000908, 0x00000002); + nv_icmd(priv, 0x000909, 0x00000002); + nv_icmd(priv, 0x00090a, 0x00000002); + nv_icmd(priv, 0x00090b, 0x00000002); + nv_icmd(priv, 0x00090c, 0x00000002); + nv_icmd(priv, 0x00090d, 0x00000002); + nv_icmd(priv, 0x00090e, 0x00000002); + nv_icmd(priv, 0x00090f, 0x00000002); + nv_icmd(priv, 0x000910, 0x00000001); + nv_icmd(priv, 0x000911, 0x00000001); + nv_icmd(priv, 0x000912, 0x00000001); + nv_icmd(priv, 0x000913, 0x00000001); + nv_icmd(priv, 0x000914, 0x00000001); + nv_icmd(priv, 0x000915, 0x00000001); + nv_icmd(priv, 0x000916, 0x00000001); + nv_icmd(priv, 0x000917, 0x00000001); + nv_icmd(priv, 0x000918, 0x00000001); + nv_icmd(priv, 0x000919, 0x00000001); + nv_icmd(priv, 0x00091a, 0x00000001); + nv_icmd(priv, 0x00091b, 0x00000001); + nv_icmd(priv, 0x00091c, 0x00000001); + nv_icmd(priv, 0x00091d, 0x00000001); + nv_icmd(priv, 0x00091e, 0x00000001); + nv_icmd(priv, 0x00091f, 0x00000001); + nv_icmd(priv, 0x000920, 0x00000002); + nv_icmd(priv, 0x000921, 0x00000002); + nv_icmd(priv, 0x000922, 0x00000002); + nv_icmd(priv, 0x000923, 0x00000002); + nv_icmd(priv, 0x000924, 0x00000002); + nv_icmd(priv, 0x000925, 0x00000002); + nv_icmd(priv, 0x000926, 0x00000002); + nv_icmd(priv, 0x000927, 0x00000002); + nv_icmd(priv, 0x000928, 0x00000001); + nv_icmd(priv, 0x000929, 0x00000001); + nv_icmd(priv, 0x00092a, 0x00000001); + nv_icmd(priv, 0x00092b, 0x00000001); + nv_icmd(priv, 0x00092c, 0x00000001); + nv_icmd(priv, 0x00092d, 0x00000001); + nv_icmd(priv, 0x00092e, 0x00000001); + nv_icmd(priv, 0x00092f, 0x00000001); + nv_icmd(priv, 0x000648, 0x00000001); + nv_icmd(priv, 0x000649, 0x00000001); + nv_icmd(priv, 0x00064a, 0x00000001); + nv_icmd(priv, 0x00064b, 0x00000001); + nv_icmd(priv, 0x00064c, 0x00000001); + nv_icmd(priv, 0x00064d, 0x00000001); + nv_icmd(priv, 0x00064e, 0x00000001); + nv_icmd(priv, 0x00064f, 0x00000001); + nv_icmd(priv, 0x000650, 0x00000001); + nv_icmd(priv, 0x000658, 0x0000000f); + nv_icmd(priv, 0x0007ff, 0x0000000a); + nv_icmd(priv, 0x00066a, 0x40000000); + nv_icmd(priv, 0x00066b, 0x10000000); + nv_icmd(priv, 0x00066c, 0xffff0000); + nv_icmd(priv, 0x00066d, 0xffff0000); + nv_icmd(priv, 0x0007af, 0x00000008); + nv_icmd(priv, 0x0007b0, 0x00000008); + nv_icmd(priv, 0x0007f6, 0x00000001); + nv_icmd(priv, 0x0006b2, 0x00000055); + nv_icmd(priv, 0x0007ad, 0x00000003); + nv_icmd(priv, 0x000937, 0x00000001); + nv_icmd(priv, 0x000971, 0x00000008); + nv_icmd(priv, 0x000972, 0x00000040); + nv_icmd(priv, 0x000973, 0x0000012c); + nv_icmd(priv, 0x00097c, 0x00000040); + nv_icmd(priv, 0x000979, 0x00000003); + nv_icmd(priv, 0x000975, 0x00000020); + nv_icmd(priv, 0x000976, 0x00000001); + nv_icmd(priv, 0x000977, 0x00000020); + nv_icmd(priv, 0x000978, 0x00000001); + nv_icmd(priv, 0x000957, 0x00000003); + nv_icmd(priv, 0x00095e, 0x20164010); + nv_icmd(priv, 0x00095f, 0x00000020); + nv_icmd(priv, 0x00097d, 0x00000020); + nv_icmd(priv, 0x000683, 0x00000006); + nv_icmd(priv, 0x000685, 0x003fffff); + nv_icmd(priv, 0x000687, 0x003fffff); + nv_icmd(priv, 0x0006a0, 0x00000005); + nv_icmd(priv, 0x000840, 0x00400008); + nv_icmd(priv, 0x000841, 0x08000080); + nv_icmd(priv, 0x000842, 0x00400008); + nv_icmd(priv, 0x000843, 0x08000080); + nv_icmd(priv, 0x000818, 0x00000000); + nv_icmd(priv, 0x000819, 0x00000000); + nv_icmd(priv, 0x00081a, 0x00000000); + nv_icmd(priv, 0x00081b, 0x00000000); + nv_icmd(priv, 0x00081c, 0x00000000); + nv_icmd(priv, 0x00081d, 0x00000000); + nv_icmd(priv, 0x00081e, 0x00000000); + nv_icmd(priv, 0x00081f, 0x00000000); + nv_icmd(priv, 0x000848, 0x00000000); + nv_icmd(priv, 0x000849, 0x00000000); + nv_icmd(priv, 0x00084a, 0x00000000); + nv_icmd(priv, 0x00084b, 0x00000000); + nv_icmd(priv, 0x00084c, 0x00000000); + nv_icmd(priv, 0x00084d, 0x00000000); + nv_icmd(priv, 0x00084e, 0x00000000); + nv_icmd(priv, 0x00084f, 0x00000000); + nv_icmd(priv, 0x000850, 0x00000000); + nv_icmd(priv, 0x000851, 0x00000000); + nv_icmd(priv, 0x000852, 0x00000000); + nv_icmd(priv, 0x000853, 0x00000000); + nv_icmd(priv, 0x000854, 0x00000000); + nv_icmd(priv, 0x000855, 0x00000000); + nv_icmd(priv, 0x000856, 0x00000000); + nv_icmd(priv, 0x000857, 0x00000000); + nv_icmd(priv, 0x000738, 0x00000000); + nv_icmd(priv, 0x0006aa, 0x00000001); + nv_icmd(priv, 0x0006ab, 0x00000002); + nv_icmd(priv, 0x0006ac, 0x00000080); + nv_icmd(priv, 0x0006ad, 0x00000100); + nv_icmd(priv, 0x0006ae, 0x00000100); + nv_icmd(priv, 0x0006b1, 0x00000011); + nv_icmd(priv, 0x0006bb, 0x000000cf); + nv_icmd(priv, 0x0006ce, 0x2a712488); + nv_icmd(priv, 0x000739, 0x4085c000); + nv_icmd(priv, 0x00073a, 0x00000080); + nv_icmd(priv, 0x000786, 0x80000100); + nv_icmd(priv, 0x00073c, 0x00010100); + nv_icmd(priv, 0x00073d, 0x02800000); + nv_icmd(priv, 0x000787, 0x000000cf); + nv_icmd(priv, 0x00078c, 0x00000008); + nv_icmd(priv, 0x000792, 0x00000001); + nv_icmd(priv, 0x000794, 0x00000001); + nv_icmd(priv, 0x000795, 0x00000001); + nv_icmd(priv, 0x000796, 0x00000001); + nv_icmd(priv, 0x000797, 0x000000cf); + nv_icmd(priv, 0x000836, 0x00000001); + nv_icmd(priv, 0x00079a, 0x00000002); + nv_icmd(priv, 0x000833, 0x04444480); + nv_icmd(priv, 0x0007a1, 0x00000001); + nv_icmd(priv, 0x0007a3, 0x00000001); + nv_icmd(priv, 0x0007a4, 0x00000001); + nv_icmd(priv, 0x0007a5, 0x00000001); + nv_icmd(priv, 0x000831, 0x00000004); + nv_icmd(priv, 0x000b07, 0x00000002); + nv_icmd(priv, 0x000b08, 0x00000100); + nv_icmd(priv, 0x000b09, 0x00000100); + nv_icmd(priv, 0x000b0a, 0x00000001); + nv_icmd(priv, 0x000a04, 0x000000ff); + nv_icmd(priv, 0x000a0b, 0x00000040); + nv_icmd(priv, 0x00097f, 0x00000100); + nv_icmd(priv, 0x000a02, 0x00000001); + nv_icmd(priv, 0x000809, 0x00000007); + nv_icmd(priv, 0x00c221, 0x00000040); + nv_icmd(priv, 0x00c1b0, 0x0000000f); + nv_icmd(priv, 0x00c1b1, 0x0000000f); + nv_icmd(priv, 0x00c1b2, 0x0000000f); + nv_icmd(priv, 0x00c1b3, 0x0000000f); + nv_icmd(priv, 0x00c1b4, 0x0000000f); + nv_icmd(priv, 0x00c1b5, 0x0000000f); + nv_icmd(priv, 0x00c1b6, 0x0000000f); + nv_icmd(priv, 0x00c1b7, 0x0000000f); + nv_icmd(priv, 0x00c1b8, 0x0fac6881); + nv_icmd(priv, 0x00c1b9, 0x00fac688); + nv_icmd(priv, 0x00c401, 0x00000001); + nv_icmd(priv, 0x00c402, 0x00010001); + nv_icmd(priv, 0x00c403, 0x00000001); + nv_icmd(priv, 0x00c404, 0x00000001); + nv_icmd(priv, 0x00c40e, 0x00000020); + nv_icmd(priv, 0x00c500, 0x00000003); + nv_icmd(priv, 0x01e100, 0x00000001); + nv_icmd(priv, 0x001000, 0x00000002); + nv_icmd(priv, 0x0006aa, 0x00000001); + nv_icmd(priv, 0x0006ad, 0x00000100); + nv_icmd(priv, 0x0006ae, 0x00000100); + nv_icmd(priv, 0x0006b1, 0x00000011); + nv_icmd(priv, 0x00078c, 0x00000008); + nv_icmd(priv, 0x000792, 0x00000001); + nv_icmd(priv, 0x000794, 0x00000001); + nv_icmd(priv, 0x000795, 0x00000001); + nv_icmd(priv, 0x000796, 0x00000001); + nv_icmd(priv, 0x000797, 0x000000cf); + nv_icmd(priv, 0x00079a, 0x00000002); + nv_icmd(priv, 0x000833, 0x04444480); + nv_icmd(priv, 0x0007a1, 0x00000001); + nv_icmd(priv, 0x0007a3, 0x00000001); + nv_icmd(priv, 0x0007a4, 0x00000001); + nv_icmd(priv, 0x0007a5, 0x00000001); + nv_icmd(priv, 0x000831, 0x00000004); + nv_icmd(priv, 0x01e100, 0x00000001); + nv_icmd(priv, 0x001000, 0x00000008); + nv_icmd(priv, 0x000039, 0x00000000); + nv_icmd(priv, 0x00003a, 0x00000000); + nv_icmd(priv, 0x00003b, 0x00000000); + nv_icmd(priv, 0x000380, 0x00000001); + nv_icmd(priv, 0x000366, 0x00000000); + nv_icmd(priv, 0x000367, 0x00000000); + nv_icmd(priv, 0x000368, 0x00000fff); + nv_icmd(priv, 0x000370, 0x00000000); + nv_icmd(priv, 0x000371, 0x00000000); + nv_icmd(priv, 0x000372, 0x000fffff); + nv_icmd(priv, 0x000813, 0x00000006); + nv_icmd(priv, 0x000814, 0x00000008); + nv_icmd(priv, 0x000957, 0x00000003); + nv_icmd(priv, 0x000818, 0x00000000); + nv_icmd(priv, 0x000819, 0x00000000); + nv_icmd(priv, 0x00081a, 0x00000000); + nv_icmd(priv, 0x00081b, 0x00000000); + nv_icmd(priv, 0x00081c, 0x00000000); + nv_icmd(priv, 0x00081d, 0x00000000); + nv_icmd(priv, 0x00081e, 0x00000000); + nv_icmd(priv, 0x00081f, 0x00000000); + nv_icmd(priv, 0x000848, 0x00000000); + nv_icmd(priv, 0x000849, 0x00000000); + nv_icmd(priv, 0x00084a, 0x00000000); + nv_icmd(priv, 0x00084b, 0x00000000); + nv_icmd(priv, 0x00084c, 0x00000000); + nv_icmd(priv, 0x00084d, 0x00000000); + nv_icmd(priv, 0x00084e, 0x00000000); + nv_icmd(priv, 0x00084f, 0x00000000); + nv_icmd(priv, 0x000850, 0x00000000); + nv_icmd(priv, 0x000851, 0x00000000); + nv_icmd(priv, 0x000852, 0x00000000); + nv_icmd(priv, 0x000853, 0x00000000); + nv_icmd(priv, 0x000854, 0x00000000); + nv_icmd(priv, 0x000855, 0x00000000); + nv_icmd(priv, 0x000856, 0x00000000); + nv_icmd(priv, 0x000857, 0x00000000); + nv_icmd(priv, 0x000738, 0x00000000); + nv_icmd(priv, 0x000b07, 0x00000002); + nv_icmd(priv, 0x000b08, 0x00000100); + nv_icmd(priv, 0x000b09, 0x00000100); + nv_icmd(priv, 0x000b0a, 0x00000001); + nv_icmd(priv, 0x000a04, 0x000000ff); + nv_icmd(priv, 0x00097f, 0x00000100); + nv_icmd(priv, 0x000a02, 0x00000001); + nv_icmd(priv, 0x000809, 0x00000007); + nv_icmd(priv, 0x00c221, 0x00000040); + nv_icmd(priv, 0x00c401, 0x00000001); + nv_icmd(priv, 0x00c402, 0x00010001); + nv_icmd(priv, 0x00c403, 0x00000001); + nv_icmd(priv, 0x00c404, 0x00000001); + nv_icmd(priv, 0x00c40e, 0x00000020); + nv_icmd(priv, 0x00c500, 0x00000003); + nv_icmd(priv, 0x01e100, 0x00000001); + nv_icmd(priv, 0x001000, 0x00000001); + nv_icmd(priv, 0x000b07, 0x00000002); + nv_icmd(priv, 0x000b08, 0x00000100); + nv_icmd(priv, 0x000b09, 0x00000100); + nv_icmd(priv, 0x000b0a, 0x00000001); + nv_icmd(priv, 0x01e100, 0x00000001); + nv_wr32(priv, 0x400208, 0x00000000); +} + +static void +nve0_grctx_generate_a097(struct nvc0_graph_priv *priv) +{ + nv_mthd(priv, 0xa097, 0x0800, 0x00000000); + nv_mthd(priv, 0xa097, 0x0840, 0x00000000); + nv_mthd(priv, 0xa097, 0x0880, 0x00000000); + nv_mthd(priv, 0xa097, 0x08c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0900, 0x00000000); + nv_mthd(priv, 0xa097, 0x0940, 0x00000000); + nv_mthd(priv, 0xa097, 0x0980, 0x00000000); + nv_mthd(priv, 0xa097, 0x09c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0804, 0x00000000); + nv_mthd(priv, 0xa097, 0x0844, 0x00000000); + nv_mthd(priv, 0xa097, 0x0884, 0x00000000); + nv_mthd(priv, 0xa097, 0x08c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0904, 0x00000000); + nv_mthd(priv, 0xa097, 0x0944, 0x00000000); + nv_mthd(priv, 0xa097, 0x0984, 0x00000000); + nv_mthd(priv, 0xa097, 0x09c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0808, 0x00000400); + nv_mthd(priv, 0xa097, 0x0848, 0x00000400); + nv_mthd(priv, 0xa097, 0x0888, 0x00000400); + nv_mthd(priv, 0xa097, 0x08c8, 0x00000400); + nv_mthd(priv, 0xa097, 0x0908, 0x00000400); + nv_mthd(priv, 0xa097, 0x0948, 0x00000400); + nv_mthd(priv, 0xa097, 0x0988, 0x00000400); + nv_mthd(priv, 0xa097, 0x09c8, 0x00000400); + nv_mthd(priv, 0xa097, 0x080c, 0x00000300); + nv_mthd(priv, 0xa097, 0x084c, 0x00000300); + nv_mthd(priv, 0xa097, 0x088c, 0x00000300); + nv_mthd(priv, 0xa097, 0x08cc, 0x00000300); + nv_mthd(priv, 0xa097, 0x090c, 0x00000300); + nv_mthd(priv, 0xa097, 0x094c, 0x00000300); + nv_mthd(priv, 0xa097, 0x098c, 0x00000300); + nv_mthd(priv, 0xa097, 0x09cc, 0x00000300); + nv_mthd(priv, 0xa097, 0x0810, 0x000000cf); + nv_mthd(priv, 0xa097, 0x0850, 0x00000000); + nv_mthd(priv, 0xa097, 0x0890, 0x00000000); + nv_mthd(priv, 0xa097, 0x08d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0910, 0x00000000); + nv_mthd(priv, 0xa097, 0x0950, 0x00000000); + nv_mthd(priv, 0xa097, 0x0990, 0x00000000); + nv_mthd(priv, 0xa097, 0x09d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0814, 0x00000040); + nv_mthd(priv, 0xa097, 0x0854, 0x00000040); + nv_mthd(priv, 0xa097, 0x0894, 0x00000040); + nv_mthd(priv, 0xa097, 0x08d4, 0x00000040); + nv_mthd(priv, 0xa097, 0x0914, 0x00000040); + nv_mthd(priv, 0xa097, 0x0954, 0x00000040); + nv_mthd(priv, 0xa097, 0x0994, 0x00000040); + nv_mthd(priv, 0xa097, 0x09d4, 0x00000040); + nv_mthd(priv, 0xa097, 0x0818, 0x00000001); + nv_mthd(priv, 0xa097, 0x0858, 0x00000001); + nv_mthd(priv, 0xa097, 0x0898, 0x00000001); + nv_mthd(priv, 0xa097, 0x08d8, 0x00000001); + nv_mthd(priv, 0xa097, 0x0918, 0x00000001); + nv_mthd(priv, 0xa097, 0x0958, 0x00000001); + nv_mthd(priv, 0xa097, 0x0998, 0x00000001); + nv_mthd(priv, 0xa097, 0x09d8, 0x00000001); + nv_mthd(priv, 0xa097, 0x081c, 0x00000000); + nv_mthd(priv, 0xa097, 0x085c, 0x00000000); + nv_mthd(priv, 0xa097, 0x089c, 0x00000000); + nv_mthd(priv, 0xa097, 0x08dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x091c, 0x00000000); + nv_mthd(priv, 0xa097, 0x095c, 0x00000000); + nv_mthd(priv, 0xa097, 0x099c, 0x00000000); + nv_mthd(priv, 0xa097, 0x09dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0820, 0x00000000); + nv_mthd(priv, 0xa097, 0x0860, 0x00000000); + nv_mthd(priv, 0xa097, 0x08a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x08e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0920, 0x00000000); + nv_mthd(priv, 0xa097, 0x0960, 0x00000000); + nv_mthd(priv, 0xa097, 0x09a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x09e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c00, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c10, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c20, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c30, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c40, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c50, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c60, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c70, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c80, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c90, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ca0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cb0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cc0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cd0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ce0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cf0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c04, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c14, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c24, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c34, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c44, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c54, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c64, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c74, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c84, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c94, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ca4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cb4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cc4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cd4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ce4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cf4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c08, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c18, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c28, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c38, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c48, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c58, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c68, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c78, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c88, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c98, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ca8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cb8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cc8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cd8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ce8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cf8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c0c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c1c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c2c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c3c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c4c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c5c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c6c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c7c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c8c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1c9c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cac, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cbc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ccc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cdc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cec, 0x00000000); + nv_mthd(priv, 0xa097, 0x1cfc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d00, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d10, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d20, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d30, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d40, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d50, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d60, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d70, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d80, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d90, 0x00000000); + nv_mthd(priv, 0xa097, 0x1da0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1db0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dc0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dd0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1de0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1df0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d04, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d14, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d24, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d34, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d44, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d54, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d64, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d74, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d84, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d94, 0x00000000); + nv_mthd(priv, 0xa097, 0x1da4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1db4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dc4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dd4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1de4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1df4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d08, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d18, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d28, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d38, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d48, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d58, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d68, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d78, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d88, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d98, 0x00000000); + nv_mthd(priv, 0xa097, 0x1da8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1db8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dc8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dd8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1de8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1df8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d0c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d1c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d2c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d3c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d4c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d5c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d6c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d7c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d8c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1d9c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dac, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dbc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dcc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ddc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dec, 0x00000000); + nv_mthd(priv, 0xa097, 0x1dfc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f00, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f08, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f10, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f18, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f20, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f28, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f30, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f38, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f40, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f48, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f50, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f58, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f60, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f68, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f70, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f78, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f04, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f0c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f14, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f1c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f24, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f2c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f34, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f3c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f44, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f4c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f54, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f5c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f64, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f6c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f74, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f7c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f80, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f88, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f90, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f98, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fa0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fa8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fb0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fb8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fc0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fc8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fd0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fd8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fe0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fe8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ff0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ff8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f84, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f8c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f94, 0x00000000); + nv_mthd(priv, 0xa097, 0x1f9c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fa4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fac, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fb4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fbc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fc4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fcc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fd4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fdc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fe4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1fec, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ff4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1ffc, 0x00000000); + nv_mthd(priv, 0xa097, 0x2000, 0x00000000); + nv_mthd(priv, 0xa097, 0x2040, 0x00000011); + nv_mthd(priv, 0xa097, 0x2080, 0x00000020); + nv_mthd(priv, 0xa097, 0x20c0, 0x00000030); + nv_mthd(priv, 0xa097, 0x2100, 0x00000040); + nv_mthd(priv, 0xa097, 0x2140, 0x00000051); + nv_mthd(priv, 0xa097, 0x200c, 0x00000001); + nv_mthd(priv, 0xa097, 0x204c, 0x00000001); + nv_mthd(priv, 0xa097, 0x208c, 0x00000001); + nv_mthd(priv, 0xa097, 0x20cc, 0x00000001); + nv_mthd(priv, 0xa097, 0x210c, 0x00000001); + nv_mthd(priv, 0xa097, 0x214c, 0x00000001); + nv_mthd(priv, 0xa097, 0x2010, 0x00000000); + nv_mthd(priv, 0xa097, 0x2050, 0x00000000); + nv_mthd(priv, 0xa097, 0x2090, 0x00000001); + nv_mthd(priv, 0xa097, 0x20d0, 0x00000002); + nv_mthd(priv, 0xa097, 0x2110, 0x00000003); + nv_mthd(priv, 0xa097, 0x2150, 0x00000004); + nv_mthd(priv, 0xa097, 0x0380, 0x00000000); + nv_mthd(priv, 0xa097, 0x03a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x03c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x03e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0384, 0x00000000); + nv_mthd(priv, 0xa097, 0x03a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x03c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x03e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0388, 0x00000000); + nv_mthd(priv, 0xa097, 0x03a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x03c8, 0x00000000); + nv_mthd(priv, 0xa097, 0x03e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x038c, 0x00000000); + nv_mthd(priv, 0xa097, 0x03ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x03cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x03ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x0700, 0x00000000); + nv_mthd(priv, 0xa097, 0x0710, 0x00000000); + nv_mthd(priv, 0xa097, 0x0720, 0x00000000); + nv_mthd(priv, 0xa097, 0x0730, 0x00000000); + nv_mthd(priv, 0xa097, 0x0704, 0x00000000); + nv_mthd(priv, 0xa097, 0x0714, 0x00000000); + nv_mthd(priv, 0xa097, 0x0724, 0x00000000); + nv_mthd(priv, 0xa097, 0x0734, 0x00000000); + nv_mthd(priv, 0xa097, 0x0708, 0x00000000); + nv_mthd(priv, 0xa097, 0x0718, 0x00000000); + nv_mthd(priv, 0xa097, 0x0728, 0x00000000); + nv_mthd(priv, 0xa097, 0x0738, 0x00000000); + nv_mthd(priv, 0xa097, 0x2800, 0x00000000); + nv_mthd(priv, 0xa097, 0x2804, 0x00000000); + nv_mthd(priv, 0xa097, 0x2808, 0x00000000); + nv_mthd(priv, 0xa097, 0x280c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2810, 0x00000000); + nv_mthd(priv, 0xa097, 0x2814, 0x00000000); + nv_mthd(priv, 0xa097, 0x2818, 0x00000000); + nv_mthd(priv, 0xa097, 0x281c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2820, 0x00000000); + nv_mthd(priv, 0xa097, 0x2824, 0x00000000); + nv_mthd(priv, 0xa097, 0x2828, 0x00000000); + nv_mthd(priv, 0xa097, 0x282c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2830, 0x00000000); + nv_mthd(priv, 0xa097, 0x2834, 0x00000000); + nv_mthd(priv, 0xa097, 0x2838, 0x00000000); + nv_mthd(priv, 0xa097, 0x283c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2840, 0x00000000); + nv_mthd(priv, 0xa097, 0x2844, 0x00000000); + nv_mthd(priv, 0xa097, 0x2848, 0x00000000); + nv_mthd(priv, 0xa097, 0x284c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2850, 0x00000000); + nv_mthd(priv, 0xa097, 0x2854, 0x00000000); + nv_mthd(priv, 0xa097, 0x2858, 0x00000000); + nv_mthd(priv, 0xa097, 0x285c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2860, 0x00000000); + nv_mthd(priv, 0xa097, 0x2864, 0x00000000); + nv_mthd(priv, 0xa097, 0x2868, 0x00000000); + nv_mthd(priv, 0xa097, 0x286c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2870, 0x00000000); + nv_mthd(priv, 0xa097, 0x2874, 0x00000000); + nv_mthd(priv, 0xa097, 0x2878, 0x00000000); + nv_mthd(priv, 0xa097, 0x287c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2880, 0x00000000); + nv_mthd(priv, 0xa097, 0x2884, 0x00000000); + nv_mthd(priv, 0xa097, 0x2888, 0x00000000); + nv_mthd(priv, 0xa097, 0x288c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2890, 0x00000000); + nv_mthd(priv, 0xa097, 0x2894, 0x00000000); + nv_mthd(priv, 0xa097, 0x2898, 0x00000000); + nv_mthd(priv, 0xa097, 0x289c, 0x00000000); + nv_mthd(priv, 0xa097, 0x28a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x28a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x28a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x28ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x28b0, 0x00000000); + nv_mthd(priv, 0xa097, 0x28b4, 0x00000000); + nv_mthd(priv, 0xa097, 0x28b8, 0x00000000); + nv_mthd(priv, 0xa097, 0x28bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x28c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x28c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x28c8, 0x00000000); + nv_mthd(priv, 0xa097, 0x28cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x28d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x28d4, 0x00000000); + nv_mthd(priv, 0xa097, 0x28d8, 0x00000000); + nv_mthd(priv, 0xa097, 0x28dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x28e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x28e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x28e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x28ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x28f0, 0x00000000); + nv_mthd(priv, 0xa097, 0x28f4, 0x00000000); + nv_mthd(priv, 0xa097, 0x28f8, 0x00000000); + nv_mthd(priv, 0xa097, 0x28fc, 0x00000000); + nv_mthd(priv, 0xa097, 0x2900, 0x00000000); + nv_mthd(priv, 0xa097, 0x2904, 0x00000000); + nv_mthd(priv, 0xa097, 0x2908, 0x00000000); + nv_mthd(priv, 0xa097, 0x290c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2910, 0x00000000); + nv_mthd(priv, 0xa097, 0x2914, 0x00000000); + nv_mthd(priv, 0xa097, 0x2918, 0x00000000); + nv_mthd(priv, 0xa097, 0x291c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2920, 0x00000000); + nv_mthd(priv, 0xa097, 0x2924, 0x00000000); + nv_mthd(priv, 0xa097, 0x2928, 0x00000000); + nv_mthd(priv, 0xa097, 0x292c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2930, 0x00000000); + nv_mthd(priv, 0xa097, 0x2934, 0x00000000); + nv_mthd(priv, 0xa097, 0x2938, 0x00000000); + nv_mthd(priv, 0xa097, 0x293c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2940, 0x00000000); + nv_mthd(priv, 0xa097, 0x2944, 0x00000000); + nv_mthd(priv, 0xa097, 0x2948, 0x00000000); + nv_mthd(priv, 0xa097, 0x294c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2950, 0x00000000); + nv_mthd(priv, 0xa097, 0x2954, 0x00000000); + nv_mthd(priv, 0xa097, 0x2958, 0x00000000); + nv_mthd(priv, 0xa097, 0x295c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2960, 0x00000000); + nv_mthd(priv, 0xa097, 0x2964, 0x00000000); + nv_mthd(priv, 0xa097, 0x2968, 0x00000000); + nv_mthd(priv, 0xa097, 0x296c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2970, 0x00000000); + nv_mthd(priv, 0xa097, 0x2974, 0x00000000); + nv_mthd(priv, 0xa097, 0x2978, 0x00000000); + nv_mthd(priv, 0xa097, 0x297c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2980, 0x00000000); + nv_mthd(priv, 0xa097, 0x2984, 0x00000000); + nv_mthd(priv, 0xa097, 0x2988, 0x00000000); + nv_mthd(priv, 0xa097, 0x298c, 0x00000000); + nv_mthd(priv, 0xa097, 0x2990, 0x00000000); + nv_mthd(priv, 0xa097, 0x2994, 0x00000000); + nv_mthd(priv, 0xa097, 0x2998, 0x00000000); + nv_mthd(priv, 0xa097, 0x299c, 0x00000000); + nv_mthd(priv, 0xa097, 0x29a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x29a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x29a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x29ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x29b0, 0x00000000); + nv_mthd(priv, 0xa097, 0x29b4, 0x00000000); + nv_mthd(priv, 0xa097, 0x29b8, 0x00000000); + nv_mthd(priv, 0xa097, 0x29bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x29c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x29c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x29c8, 0x00000000); + nv_mthd(priv, 0xa097, 0x29cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x29d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x29d4, 0x00000000); + nv_mthd(priv, 0xa097, 0x29d8, 0x00000000); + nv_mthd(priv, 0xa097, 0x29dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x29e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x29e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x29e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x29ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x29f0, 0x00000000); + nv_mthd(priv, 0xa097, 0x29f4, 0x00000000); + nv_mthd(priv, 0xa097, 0x29f8, 0x00000000); + nv_mthd(priv, 0xa097, 0x29fc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a00, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a20, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a40, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a60, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a80, 0x00000000); + nv_mthd(priv, 0xa097, 0x0aa0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ac0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ae0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b00, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b20, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b40, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b60, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b80, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ba0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bc0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0be0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a04, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a24, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a44, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a64, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a84, 0x00000000); + nv_mthd(priv, 0xa097, 0x0aa4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ac4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ae4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b04, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b24, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b44, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b64, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b84, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ba4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bc4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0be4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a08, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a28, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a48, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a68, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a88, 0x00000000); + nv_mthd(priv, 0xa097, 0x0aa8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ac8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ae8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b08, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b28, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b48, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b68, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b88, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ba8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bc8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0be8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a0c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a2c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a4c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a6c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a8c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0aac, 0x00000000); + nv_mthd(priv, 0xa097, 0x0acc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0aec, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b0c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b2c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b4c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b6c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b8c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bac, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bcc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bec, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a10, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a30, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a50, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a70, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a90, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ab0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ad0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0af0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b10, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b30, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b50, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b70, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b90, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bb0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bd0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bf0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a14, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a34, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a54, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a74, 0x00000000); + nv_mthd(priv, 0xa097, 0x0a94, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ab4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ad4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0af4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b14, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b34, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b54, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b74, 0x00000000); + nv_mthd(priv, 0xa097, 0x0b94, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bb4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bd4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0bf4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c00, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c10, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c20, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c30, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c40, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c50, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c60, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c70, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c80, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c90, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ca0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cb0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cc0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cd0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ce0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cf0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c04, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c14, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c24, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c34, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c44, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c54, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c64, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c74, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c84, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c94, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ca4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cb4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cc4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cd4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ce4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cf4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c08, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c18, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c28, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c38, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c48, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c58, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c68, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c78, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c88, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c98, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ca8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cb8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cc8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cd8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ce8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0cf8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0c0c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c1c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c2c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c3c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c4c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c5c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c6c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c7c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c8c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0c9c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0cac, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0cbc, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0ccc, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0cdc, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0cec, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0cfc, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0d00, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d08, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d10, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d18, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d20, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d28, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d30, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d38, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d04, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d0c, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d14, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d1c, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d24, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d2c, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d34, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d3c, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e00, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e10, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e20, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e30, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e40, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e50, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e60, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e70, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e80, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e90, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ea0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0eb0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ec0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ed0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ee0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ef0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0e04, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e14, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e24, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e34, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e44, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e54, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e64, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e74, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e84, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e94, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ea4, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0eb4, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ec4, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ed4, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ee4, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ef4, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e08, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e18, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e28, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e38, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e48, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e58, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e68, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e78, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e88, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0e98, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ea8, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0eb8, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ec8, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ed8, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ee8, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0ef8, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d40, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d48, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d50, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d58, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d44, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d4c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d54, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d5c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1e00, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e20, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e40, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e60, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e80, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ea0, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ec0, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ee0, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e04, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e24, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e44, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e64, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e84, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ea4, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ec4, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ee4, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e08, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e28, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e48, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e68, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e88, 0x00000002); + nv_mthd(priv, 0xa097, 0x1ea8, 0x00000002); + nv_mthd(priv, 0xa097, 0x1ec8, 0x00000002); + nv_mthd(priv, 0xa097, 0x1ee8, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e0c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e2c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e4c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e6c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e8c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1eac, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ecc, 0x00000001); + nv_mthd(priv, 0xa097, 0x1eec, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e10, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e30, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e50, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e70, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e90, 0x00000001); + nv_mthd(priv, 0xa097, 0x1eb0, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ed0, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ef0, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e14, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e34, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e54, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e74, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e94, 0x00000002); + nv_mthd(priv, 0xa097, 0x1eb4, 0x00000002); + nv_mthd(priv, 0xa097, 0x1ed4, 0x00000002); + nv_mthd(priv, 0xa097, 0x1ef4, 0x00000002); + nv_mthd(priv, 0xa097, 0x1e18, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e38, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e58, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e78, 0x00000001); + nv_mthd(priv, 0xa097, 0x1e98, 0x00000001); + nv_mthd(priv, 0xa097, 0x1eb8, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ed8, 0x00000001); + nv_mthd(priv, 0xa097, 0x1ef8, 0x00000001); + nv_mthd(priv, 0xa097, 0x3400, 0x00000000); + nv_mthd(priv, 0xa097, 0x3404, 0x00000000); + nv_mthd(priv, 0xa097, 0x3408, 0x00000000); + nv_mthd(priv, 0xa097, 0x340c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3410, 0x00000000); + nv_mthd(priv, 0xa097, 0x3414, 0x00000000); + nv_mthd(priv, 0xa097, 0x3418, 0x00000000); + nv_mthd(priv, 0xa097, 0x341c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3420, 0x00000000); + nv_mthd(priv, 0xa097, 0x3424, 0x00000000); + nv_mthd(priv, 0xa097, 0x3428, 0x00000000); + nv_mthd(priv, 0xa097, 0x342c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3430, 0x00000000); + nv_mthd(priv, 0xa097, 0x3434, 0x00000000); + nv_mthd(priv, 0xa097, 0x3438, 0x00000000); + nv_mthd(priv, 0xa097, 0x343c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3440, 0x00000000); + nv_mthd(priv, 0xa097, 0x3444, 0x00000000); + nv_mthd(priv, 0xa097, 0x3448, 0x00000000); + nv_mthd(priv, 0xa097, 0x344c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3450, 0x00000000); + nv_mthd(priv, 0xa097, 0x3454, 0x00000000); + nv_mthd(priv, 0xa097, 0x3458, 0x00000000); + nv_mthd(priv, 0xa097, 0x345c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3460, 0x00000000); + nv_mthd(priv, 0xa097, 0x3464, 0x00000000); + nv_mthd(priv, 0xa097, 0x3468, 0x00000000); + nv_mthd(priv, 0xa097, 0x346c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3470, 0x00000000); + nv_mthd(priv, 0xa097, 0x3474, 0x00000000); + nv_mthd(priv, 0xa097, 0x3478, 0x00000000); + nv_mthd(priv, 0xa097, 0x347c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3480, 0x00000000); + nv_mthd(priv, 0xa097, 0x3484, 0x00000000); + nv_mthd(priv, 0xa097, 0x3488, 0x00000000); + nv_mthd(priv, 0xa097, 0x348c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3490, 0x00000000); + nv_mthd(priv, 0xa097, 0x3494, 0x00000000); + nv_mthd(priv, 0xa097, 0x3498, 0x00000000); + nv_mthd(priv, 0xa097, 0x349c, 0x00000000); + nv_mthd(priv, 0xa097, 0x34a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x34a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x34a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x34ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x34b0, 0x00000000); + nv_mthd(priv, 0xa097, 0x34b4, 0x00000000); + nv_mthd(priv, 0xa097, 0x34b8, 0x00000000); + nv_mthd(priv, 0xa097, 0x34bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x34c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x34c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x34c8, 0x00000000); + nv_mthd(priv, 0xa097, 0x34cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x34d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x34d4, 0x00000000); + nv_mthd(priv, 0xa097, 0x34d8, 0x00000000); + nv_mthd(priv, 0xa097, 0x34dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x34e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x34e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x34e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x34ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x34f0, 0x00000000); + nv_mthd(priv, 0xa097, 0x34f4, 0x00000000); + nv_mthd(priv, 0xa097, 0x34f8, 0x00000000); + nv_mthd(priv, 0xa097, 0x34fc, 0x00000000); + nv_mthd(priv, 0xa097, 0x3500, 0x00000000); + nv_mthd(priv, 0xa097, 0x3504, 0x00000000); + nv_mthd(priv, 0xa097, 0x3508, 0x00000000); + nv_mthd(priv, 0xa097, 0x350c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3510, 0x00000000); + nv_mthd(priv, 0xa097, 0x3514, 0x00000000); + nv_mthd(priv, 0xa097, 0x3518, 0x00000000); + nv_mthd(priv, 0xa097, 0x351c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3520, 0x00000000); + nv_mthd(priv, 0xa097, 0x3524, 0x00000000); + nv_mthd(priv, 0xa097, 0x3528, 0x00000000); + nv_mthd(priv, 0xa097, 0x352c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3530, 0x00000000); + nv_mthd(priv, 0xa097, 0x3534, 0x00000000); + nv_mthd(priv, 0xa097, 0x3538, 0x00000000); + nv_mthd(priv, 0xa097, 0x353c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3540, 0x00000000); + nv_mthd(priv, 0xa097, 0x3544, 0x00000000); + nv_mthd(priv, 0xa097, 0x3548, 0x00000000); + nv_mthd(priv, 0xa097, 0x354c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3550, 0x00000000); + nv_mthd(priv, 0xa097, 0x3554, 0x00000000); + nv_mthd(priv, 0xa097, 0x3558, 0x00000000); + nv_mthd(priv, 0xa097, 0x355c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3560, 0x00000000); + nv_mthd(priv, 0xa097, 0x3564, 0x00000000); + nv_mthd(priv, 0xa097, 0x3568, 0x00000000); + nv_mthd(priv, 0xa097, 0x356c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3570, 0x00000000); + nv_mthd(priv, 0xa097, 0x3574, 0x00000000); + nv_mthd(priv, 0xa097, 0x3578, 0x00000000); + nv_mthd(priv, 0xa097, 0x357c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3580, 0x00000000); + nv_mthd(priv, 0xa097, 0x3584, 0x00000000); + nv_mthd(priv, 0xa097, 0x3588, 0x00000000); + nv_mthd(priv, 0xa097, 0x358c, 0x00000000); + nv_mthd(priv, 0xa097, 0x3590, 0x00000000); + nv_mthd(priv, 0xa097, 0x3594, 0x00000000); + nv_mthd(priv, 0xa097, 0x3598, 0x00000000); + nv_mthd(priv, 0xa097, 0x359c, 0x00000000); + nv_mthd(priv, 0xa097, 0x35a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x35a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x35a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x35ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x35b0, 0x00000000); + nv_mthd(priv, 0xa097, 0x35b4, 0x00000000); + nv_mthd(priv, 0xa097, 0x35b8, 0x00000000); + nv_mthd(priv, 0xa097, 0x35bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x35c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x35c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x35c8, 0x00000000); + nv_mthd(priv, 0xa097, 0x35cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x35d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x35d4, 0x00000000); + nv_mthd(priv, 0xa097, 0x35d8, 0x00000000); + nv_mthd(priv, 0xa097, 0x35dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x35e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x35e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x35e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x35ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x35f0, 0x00000000); + nv_mthd(priv, 0xa097, 0x35f4, 0x00000000); + nv_mthd(priv, 0xa097, 0x35f8, 0x00000000); + nv_mthd(priv, 0xa097, 0x35fc, 0x00000000); + nv_mthd(priv, 0xa097, 0x030c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1944, 0x00000000); + nv_mthd(priv, 0xa097, 0x1514, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d68, 0x0000ffff); + nv_mthd(priv, 0xa097, 0x121c, 0x0fac6881); + nv_mthd(priv, 0xa097, 0x0fac, 0x00000001); + nv_mthd(priv, 0xa097, 0x1538, 0x00000001); + nv_mthd(priv, 0xa097, 0x0fe0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0fe4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0fe8, 0x00000014); + nv_mthd(priv, 0xa097, 0x0fec, 0x00000040); + nv_mthd(priv, 0xa097, 0x0ff0, 0x00000000); + nv_mthd(priv, 0xa097, 0x179c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1228, 0x00000400); + nv_mthd(priv, 0xa097, 0x122c, 0x00000300); + nv_mthd(priv, 0xa097, 0x1230, 0x00010001); + nv_mthd(priv, 0xa097, 0x07f8, 0x00000000); + nv_mthd(priv, 0xa097, 0x15b4, 0x00000001); + nv_mthd(priv, 0xa097, 0x15cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1534, 0x00000000); + nv_mthd(priv, 0xa097, 0x0fb0, 0x00000000); + nv_mthd(priv, 0xa097, 0x15d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x153c, 0x00000000); + nv_mthd(priv, 0xa097, 0x16b4, 0x00000003); + nv_mthd(priv, 0xa097, 0x0fbc, 0x0000ffff); + nv_mthd(priv, 0xa097, 0x0fc0, 0x0000ffff); + nv_mthd(priv, 0xa097, 0x0fc4, 0x0000ffff); + nv_mthd(priv, 0xa097, 0x0fc8, 0x0000ffff); + nv_mthd(priv, 0xa097, 0x0df8, 0x00000000); + nv_mthd(priv, 0xa097, 0x0dfc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1948, 0x00000000); + nv_mthd(priv, 0xa097, 0x1970, 0x00000001); + nv_mthd(priv, 0xa097, 0x161c, 0x000009f0); + nv_mthd(priv, 0xa097, 0x0dcc, 0x00000010); + nv_mthd(priv, 0xa097, 0x163c, 0x00000000); + nv_mthd(priv, 0xa097, 0x15e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1160, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1164, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1168, 0x25e00040); + nv_mthd(priv, 0xa097, 0x116c, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1170, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1174, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1178, 0x25e00040); + nv_mthd(priv, 0xa097, 0x117c, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1180, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1184, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1188, 0x25e00040); + nv_mthd(priv, 0xa097, 0x118c, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1190, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1194, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1198, 0x25e00040); + nv_mthd(priv, 0xa097, 0x119c, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11a0, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11a4, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11a8, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11ac, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11b0, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11b4, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11b8, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11bc, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11c0, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11c4, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11c8, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11cc, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11d0, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11d4, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11d8, 0x25e00040); + nv_mthd(priv, 0xa097, 0x11dc, 0x25e00040); + nv_mthd(priv, 0xa097, 0x1880, 0x00000000); + nv_mthd(priv, 0xa097, 0x1884, 0x00000000); + nv_mthd(priv, 0xa097, 0x1888, 0x00000000); + nv_mthd(priv, 0xa097, 0x188c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1890, 0x00000000); + nv_mthd(priv, 0xa097, 0x1894, 0x00000000); + nv_mthd(priv, 0xa097, 0x1898, 0x00000000); + nv_mthd(priv, 0xa097, 0x189c, 0x00000000); + nv_mthd(priv, 0xa097, 0x18a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x18a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x18a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x18ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x18b0, 0x00000000); + nv_mthd(priv, 0xa097, 0x18b4, 0x00000000); + nv_mthd(priv, 0xa097, 0x18b8, 0x00000000); + nv_mthd(priv, 0xa097, 0x18bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x18c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x18c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x18c8, 0x00000000); + nv_mthd(priv, 0xa097, 0x18cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x18d0, 0x00000000); + nv_mthd(priv, 0xa097, 0x18d4, 0x00000000); + nv_mthd(priv, 0xa097, 0x18d8, 0x00000000); + nv_mthd(priv, 0xa097, 0x18dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x18e0, 0x00000000); + nv_mthd(priv, 0xa097, 0x18e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x18e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x18ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x18f0, 0x00000000); + nv_mthd(priv, 0xa097, 0x18f4, 0x00000000); + nv_mthd(priv, 0xa097, 0x18f8, 0x00000000); + nv_mthd(priv, 0xa097, 0x18fc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f84, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f88, 0x00000000); + nv_mthd(priv, 0xa097, 0x17c8, 0x00000000); + nv_mthd(priv, 0xa097, 0x17cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x17d0, 0x000000ff); + nv_mthd(priv, 0xa097, 0x17d4, 0xffffffff); + nv_mthd(priv, 0xa097, 0x17d8, 0x00000002); + nv_mthd(priv, 0xa097, 0x17dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x15f4, 0x00000000); + nv_mthd(priv, 0xa097, 0x15f8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1434, 0x00000000); + nv_mthd(priv, 0xa097, 0x1438, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d74, 0x00000000); + nv_mthd(priv, 0xa097, 0x0dec, 0x00000001); + nv_mthd(priv, 0xa097, 0x13a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1318, 0x00000001); + nv_mthd(priv, 0xa097, 0x1644, 0x00000000); + nv_mthd(priv, 0xa097, 0x0748, 0x00000000); + nv_mthd(priv, 0xa097, 0x0de8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1648, 0x00000000); + nv_mthd(priv, 0xa097, 0x12a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x1120, 0x00000000); + nv_mthd(priv, 0xa097, 0x1124, 0x00000000); + nv_mthd(priv, 0xa097, 0x1128, 0x00000000); + nv_mthd(priv, 0xa097, 0x112c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1118, 0x00000000); + nv_mthd(priv, 0xa097, 0x164c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1658, 0x00000000); + nv_mthd(priv, 0xa097, 0x1910, 0x00000290); + nv_mthd(priv, 0xa097, 0x1518, 0x00000000); + nv_mthd(priv, 0xa097, 0x165c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1520, 0x00000000); + nv_mthd(priv, 0xa097, 0x1604, 0x00000000); + nv_mthd(priv, 0xa097, 0x1570, 0x00000000); + nv_mthd(priv, 0xa097, 0x13b0, 0x3f800000); + nv_mthd(priv, 0xa097, 0x13b4, 0x3f800000); + nv_mthd(priv, 0xa097, 0x020c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1670, 0x30201000); + nv_mthd(priv, 0xa097, 0x1674, 0x70605040); + nv_mthd(priv, 0xa097, 0x1678, 0xb8a89888); + nv_mthd(priv, 0xa097, 0x167c, 0xf8e8d8c8); + nv_mthd(priv, 0xa097, 0x166c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1680, 0x00ffff00); + nv_mthd(priv, 0xa097, 0x12d0, 0x00000003); + nv_mthd(priv, 0xa097, 0x12d4, 0x00000002); + nv_mthd(priv, 0xa097, 0x1684, 0x00000000); + nv_mthd(priv, 0xa097, 0x1688, 0x00000000); + nv_mthd(priv, 0xa097, 0x0dac, 0x00001b02); + nv_mthd(priv, 0xa097, 0x0db0, 0x00001b02); + nv_mthd(priv, 0xa097, 0x0db4, 0x00000000); + nv_mthd(priv, 0xa097, 0x168c, 0x00000000); + nv_mthd(priv, 0xa097, 0x15bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x156c, 0x00000000); + nv_mthd(priv, 0xa097, 0x187c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1110, 0x00000001); + nv_mthd(priv, 0xa097, 0x0dc0, 0x00000000); + nv_mthd(priv, 0xa097, 0x0dc4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0dc8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1234, 0x00000000); + nv_mthd(priv, 0xa097, 0x1690, 0x00000000); + nv_mthd(priv, 0xa097, 0x12ac, 0x00000001); + nv_mthd(priv, 0xa097, 0x0790, 0x00000000); + nv_mthd(priv, 0xa097, 0x0794, 0x00000000); + nv_mthd(priv, 0xa097, 0x0798, 0x00000000); + nv_mthd(priv, 0xa097, 0x079c, 0x00000000); + nv_mthd(priv, 0xa097, 0x07a0, 0x00000000); + nv_mthd(priv, 0xa097, 0x077c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1000, 0x00000010); + nv_mthd(priv, 0xa097, 0x10fc, 0x00000000); + nv_mthd(priv, 0xa097, 0x1290, 0x00000000); + nv_mthd(priv, 0xa097, 0x0218, 0x00000010); + nv_mthd(priv, 0xa097, 0x12d8, 0x00000000); + nv_mthd(priv, 0xa097, 0x12dc, 0x00000010); + nv_mthd(priv, 0xa097, 0x0d94, 0x00000001); + nv_mthd(priv, 0xa097, 0x155c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1560, 0x00000000); + nv_mthd(priv, 0xa097, 0x1564, 0x00000fff); + nv_mthd(priv, 0xa097, 0x1574, 0x00000000); + nv_mthd(priv, 0xa097, 0x1578, 0x00000000); + nv_mthd(priv, 0xa097, 0x157c, 0x000fffff); + nv_mthd(priv, 0xa097, 0x1354, 0x00000000); + nv_mthd(priv, 0xa097, 0x1610, 0x00000012); + nv_mthd(priv, 0xa097, 0x1608, 0x00000000); + nv_mthd(priv, 0xa097, 0x160c, 0x00000000); + nv_mthd(priv, 0xa097, 0x260c, 0x00000000); + nv_mthd(priv, 0xa097, 0x07ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x162c, 0x00000003); + nv_mthd(priv, 0xa097, 0x0210, 0x00000000); + nv_mthd(priv, 0xa097, 0x0320, 0x00000000); + nv_mthd(priv, 0xa097, 0x0324, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0328, 0x3f800000); + nv_mthd(priv, 0xa097, 0x032c, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0330, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0334, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0338, 0x3f800000); + nv_mthd(priv, 0xa097, 0x0750, 0x00000000); + nv_mthd(priv, 0xa097, 0x0760, 0x39291909); + nv_mthd(priv, 0xa097, 0x0764, 0x79695949); + nv_mthd(priv, 0xa097, 0x0768, 0xb9a99989); + nv_mthd(priv, 0xa097, 0x076c, 0xf9e9d9c9); + nv_mthd(priv, 0xa097, 0x0770, 0x30201000); + nv_mthd(priv, 0xa097, 0x0774, 0x70605040); + nv_mthd(priv, 0xa097, 0x0778, 0x00009080); + nv_mthd(priv, 0xa097, 0x0780, 0x39291909); + nv_mthd(priv, 0xa097, 0x0784, 0x79695949); + nv_mthd(priv, 0xa097, 0x0788, 0xb9a99989); + nv_mthd(priv, 0xa097, 0x078c, 0xf9e9d9c9); + nv_mthd(priv, 0xa097, 0x07d0, 0x30201000); + nv_mthd(priv, 0xa097, 0x07d4, 0x70605040); + nv_mthd(priv, 0xa097, 0x07d8, 0x00009080); + nv_mthd(priv, 0xa097, 0x037c, 0x00000001); + nv_mthd(priv, 0xa097, 0x0740, 0x00000000); + nv_mthd(priv, 0xa097, 0x0744, 0x00000000); + nv_mthd(priv, 0xa097, 0x2600, 0x00000000); + nv_mthd(priv, 0xa097, 0x1918, 0x00000000); + nv_mthd(priv, 0xa097, 0x191c, 0x00000900); + nv_mthd(priv, 0xa097, 0x1920, 0x00000405); + nv_mthd(priv, 0xa097, 0x1308, 0x00000001); + nv_mthd(priv, 0xa097, 0x1924, 0x00000000); + nv_mthd(priv, 0xa097, 0x13ac, 0x00000000); + nv_mthd(priv, 0xa097, 0x192c, 0x00000001); + nv_mthd(priv, 0xa097, 0x193c, 0x00002c1c); + nv_mthd(priv, 0xa097, 0x0d7c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f8c, 0x00000000); + nv_mthd(priv, 0xa097, 0x02c0, 0x00000001); + nv_mthd(priv, 0xa097, 0x1510, 0x00000000); + nv_mthd(priv, 0xa097, 0x1940, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ff4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0ff8, 0x00000000); + nv_mthd(priv, 0xa097, 0x194c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1950, 0x00000000); + nv_mthd(priv, 0xa097, 0x1968, 0x00000000); + nv_mthd(priv, 0xa097, 0x1590, 0x0000003f); + nv_mthd(priv, 0xa097, 0x07e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x07ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x07f0, 0x00000000); + nv_mthd(priv, 0xa097, 0x07f4, 0x00000000); + nv_mthd(priv, 0xa097, 0x196c, 0x00000011); + nv_mthd(priv, 0xa097, 0x02e4, 0x0000b001); + nv_mthd(priv, 0xa097, 0x036c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0370, 0x00000000); + nv_mthd(priv, 0xa097, 0x197c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0fcc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0fd0, 0x00000000); + nv_mthd(priv, 0xa097, 0x02d8, 0x00000040); + nv_mthd(priv, 0xa097, 0x1980, 0x00000080); + nv_mthd(priv, 0xa097, 0x1504, 0x00000080); + nv_mthd(priv, 0xa097, 0x1984, 0x00000000); + nv_mthd(priv, 0xa097, 0x0300, 0x00000001); + nv_mthd(priv, 0xa097, 0x13a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x12ec, 0x00000000); + nv_mthd(priv, 0xa097, 0x1310, 0x00000000); + nv_mthd(priv, 0xa097, 0x1314, 0x00000001); + nv_mthd(priv, 0xa097, 0x1380, 0x00000000); + nv_mthd(priv, 0xa097, 0x1384, 0x00000001); + nv_mthd(priv, 0xa097, 0x1388, 0x00000001); + nv_mthd(priv, 0xa097, 0x138c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1390, 0x00000001); + nv_mthd(priv, 0xa097, 0x1394, 0x00000000); + nv_mthd(priv, 0xa097, 0x139c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1398, 0x00000000); + nv_mthd(priv, 0xa097, 0x1594, 0x00000000); + nv_mthd(priv, 0xa097, 0x1598, 0x00000001); + nv_mthd(priv, 0xa097, 0x159c, 0x00000001); + nv_mthd(priv, 0xa097, 0x15a0, 0x00000001); + nv_mthd(priv, 0xa097, 0x15a4, 0x00000001); + nv_mthd(priv, 0xa097, 0x0f54, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f58, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f5c, 0x00000000); + nv_mthd(priv, 0xa097, 0x19bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f9c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0fa0, 0x00000000); + nv_mthd(priv, 0xa097, 0x12cc, 0x00000000); + nv_mthd(priv, 0xa097, 0x12e8, 0x00000000); + nv_mthd(priv, 0xa097, 0x130c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1360, 0x00000000); + nv_mthd(priv, 0xa097, 0x1364, 0x00000000); + nv_mthd(priv, 0xa097, 0x1368, 0x00000000); + nv_mthd(priv, 0xa097, 0x136c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1370, 0x00000000); + nv_mthd(priv, 0xa097, 0x1374, 0x00000000); + nv_mthd(priv, 0xa097, 0x1378, 0x00000000); + nv_mthd(priv, 0xa097, 0x137c, 0x00000000); + nv_mthd(priv, 0xa097, 0x133c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1340, 0x00000001); + nv_mthd(priv, 0xa097, 0x1344, 0x00000002); + nv_mthd(priv, 0xa097, 0x1348, 0x00000001); + nv_mthd(priv, 0xa097, 0x134c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1350, 0x00000002); + nv_mthd(priv, 0xa097, 0x1358, 0x00000001); + nv_mthd(priv, 0xa097, 0x12e4, 0x00000000); + nv_mthd(priv, 0xa097, 0x131c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1320, 0x00000000); + nv_mthd(priv, 0xa097, 0x1324, 0x00000000); + nv_mthd(priv, 0xa097, 0x1328, 0x00000000); + nv_mthd(priv, 0xa097, 0x19c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x1140, 0x00000000); + nv_mthd(priv, 0xa097, 0x19c4, 0x00000000); + nv_mthd(priv, 0xa097, 0x19c8, 0x00001500); + nv_mthd(priv, 0xa097, 0x135c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f90, 0x00000000); + nv_mthd(priv, 0xa097, 0x19e0, 0x00000001); + nv_mthd(priv, 0xa097, 0x19e4, 0x00000001); + nv_mthd(priv, 0xa097, 0x19e8, 0x00000001); + nv_mthd(priv, 0xa097, 0x19ec, 0x00000001); + nv_mthd(priv, 0xa097, 0x19f0, 0x00000001); + nv_mthd(priv, 0xa097, 0x19f4, 0x00000001); + nv_mthd(priv, 0xa097, 0x19f8, 0x00000001); + nv_mthd(priv, 0xa097, 0x19fc, 0x00000001); + nv_mthd(priv, 0xa097, 0x19cc, 0x00000001); + nv_mthd(priv, 0xa097, 0x15b8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1a00, 0x00001111); + nv_mthd(priv, 0xa097, 0x1a04, 0x00000000); + nv_mthd(priv, 0xa097, 0x1a08, 0x00000000); + nv_mthd(priv, 0xa097, 0x1a0c, 0x00000000); + nv_mthd(priv, 0xa097, 0x1a10, 0x00000000); + nv_mthd(priv, 0xa097, 0x1a14, 0x00000000); + nv_mthd(priv, 0xa097, 0x1a18, 0x00000000); + nv_mthd(priv, 0xa097, 0x1a1c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d6c, 0xffff0000); + nv_mthd(priv, 0xa097, 0x0d70, 0xffff0000); + nv_mthd(priv, 0xa097, 0x10f8, 0x00001010); + nv_mthd(priv, 0xa097, 0x0d80, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d84, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d88, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d8c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0d90, 0x00000000); + nv_mthd(priv, 0xa097, 0x0da0, 0x00000000); + nv_mthd(priv, 0xa097, 0x07a4, 0x00000000); + nv_mthd(priv, 0xa097, 0x07a8, 0x00000000); + nv_mthd(priv, 0xa097, 0x1508, 0x80000000); + nv_mthd(priv, 0xa097, 0x150c, 0x40000000); + nv_mthd(priv, 0xa097, 0x1668, 0x00000000); + nv_mthd(priv, 0xa097, 0x0318, 0x00000008); + nv_mthd(priv, 0xa097, 0x031c, 0x00000008); + nv_mthd(priv, 0xa097, 0x0d9c, 0x00000001); + nv_mthd(priv, 0xa097, 0x0374, 0x00000000); + nv_mthd(priv, 0xa097, 0x0378, 0x00000020); + nv_mthd(priv, 0xa097, 0x07dc, 0x00000000); + nv_mthd(priv, 0xa097, 0x074c, 0x00000055); + nv_mthd(priv, 0xa097, 0x1420, 0x00000003); + nv_mthd(priv, 0xa097, 0x17bc, 0x00000000); + nv_mthd(priv, 0xa097, 0x17c0, 0x00000000); + nv_mthd(priv, 0xa097, 0x17c4, 0x00000001); + nv_mthd(priv, 0xa097, 0x1008, 0x00000008); + nv_mthd(priv, 0xa097, 0x100c, 0x00000040); + nv_mthd(priv, 0xa097, 0x1010, 0x0000012c); + nv_mthd(priv, 0xa097, 0x0d60, 0x00000040); + nv_mthd(priv, 0xa097, 0x075c, 0x00000003); + nv_mthd(priv, 0xa097, 0x1018, 0x00000020); + nv_mthd(priv, 0xa097, 0x101c, 0x00000001); + nv_mthd(priv, 0xa097, 0x1020, 0x00000020); + nv_mthd(priv, 0xa097, 0x1024, 0x00000001); + nv_mthd(priv, 0xa097, 0x1444, 0x00000000); + nv_mthd(priv, 0xa097, 0x1448, 0x00000000); + nv_mthd(priv, 0xa097, 0x144c, 0x00000000); + nv_mthd(priv, 0xa097, 0x0360, 0x20164010); + nv_mthd(priv, 0xa097, 0x0364, 0x00000020); + nv_mthd(priv, 0xa097, 0x0368, 0x00000000); + nv_mthd(priv, 0xa097, 0x0de4, 0x00000000); + nv_mthd(priv, 0xa097, 0x0204, 0x00000006); + nv_mthd(priv, 0xa097, 0x0208, 0x00000000); + nv_mthd(priv, 0xa097, 0x02cc, 0x003fffff); + nv_mthd(priv, 0xa097, 0x02d0, 0x003fffff); + nv_mthd(priv, 0xa097, 0x1220, 0x00000005); + nv_mthd(priv, 0xa097, 0x0fdc, 0x00000000); + nv_mthd(priv, 0xa097, 0x0f98, 0x00400008); + nv_mthd(priv, 0xa097, 0x1284, 0x08000080); + nv_mthd(priv, 0xa097, 0x1450, 0x00400008); + nv_mthd(priv, 0xa097, 0x1454, 0x08000080); + nv_mthd(priv, 0xa097, 0x0214, 0x00000000); +} + +static void +nve0_grctx_generate_902d(struct nvc0_graph_priv *priv) +{ + nv_mthd(priv, 0x902d, 0x0200, 0x000000cf); + nv_mthd(priv, 0x902d, 0x0204, 0x00000001); + nv_mthd(priv, 0x902d, 0x0208, 0x00000020); + nv_mthd(priv, 0x902d, 0x020c, 0x00000001); + nv_mthd(priv, 0x902d, 0x0210, 0x00000000); + nv_mthd(priv, 0x902d, 0x0214, 0x00000080); + nv_mthd(priv, 0x902d, 0x0218, 0x00000100); + nv_mthd(priv, 0x902d, 0x021c, 0x00000100); + nv_mthd(priv, 0x902d, 0x0220, 0x00000000); + nv_mthd(priv, 0x902d, 0x0224, 0x00000000); + nv_mthd(priv, 0x902d, 0x0230, 0x000000cf); + nv_mthd(priv, 0x902d, 0x0234, 0x00000001); + nv_mthd(priv, 0x902d, 0x0238, 0x00000020); + nv_mthd(priv, 0x902d, 0x023c, 0x00000001); + nv_mthd(priv, 0x902d, 0x0244, 0x00000080); + nv_mthd(priv, 0x902d, 0x0248, 0x00000100); + nv_mthd(priv, 0x902d, 0x024c, 0x00000100); + nv_mthd(priv, 0x902d, 0x3410, 0x00000000); +} + +static void +nve0_graph_generate_unk40xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x404010, 0x0); + nv_wr32(priv, 0x404014, 0x0); + nv_wr32(priv, 0x404018, 0x0); + nv_wr32(priv, 0x40401c, 0x0); + nv_wr32(priv, 0x404020, 0x0); + nv_wr32(priv, 0x404024, 0xe000); + nv_wr32(priv, 0x404028, 0x0); + nv_wr32(priv, 0x4040a8, 0x0); + nv_wr32(priv, 0x4040ac, 0x0); + nv_wr32(priv, 0x4040b0, 0x0); + nv_wr32(priv, 0x4040b4, 0x0); + nv_wr32(priv, 0x4040b8, 0x0); + nv_wr32(priv, 0x4040bc, 0x0); + nv_wr32(priv, 0x4040c0, 0x0); + nv_wr32(priv, 0x4040c4, 0x0); + nv_wr32(priv, 0x4040c8, 0xf800008f); + nv_wr32(priv, 0x4040d0, 0x0); + nv_wr32(priv, 0x4040d4, 0x0); + nv_wr32(priv, 0x4040d8, 0x0); + nv_wr32(priv, 0x4040dc, 0x0); + nv_wr32(priv, 0x4040e0, 0x0); + nv_wr32(priv, 0x4040e4, 0x0); + nv_wr32(priv, 0x4040e8, 0x1000); + nv_wr32(priv, 0x4040f8, 0x0); + nv_wr32(priv, 0x404130, 0x0); + nv_wr32(priv, 0x404134, 0x0); + nv_wr32(priv, 0x404138, 0x20000040); + nv_wr32(priv, 0x404150, 0x2e); + nv_wr32(priv, 0x404154, 0x400); + nv_wr32(priv, 0x404158, 0x200); + nv_wr32(priv, 0x404164, 0x55); + nv_wr32(priv, 0x4041a0, 0x0); + nv_wr32(priv, 0x4041a4, 0x0); + nv_wr32(priv, 0x4041a8, 0x0); + nv_wr32(priv, 0x4041ac, 0x0); + nv_wr32(priv, 0x404200, 0x0); + nv_wr32(priv, 0x404204, 0x0); + nv_wr32(priv, 0x404208, 0x0); + nv_wr32(priv, 0x40420c, 0x0); +} + +static void +nve0_graph_generate_unk44xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x404404, 0x0); + nv_wr32(priv, 0x404408, 0x0); + nv_wr32(priv, 0x40440c, 0x0); + nv_wr32(priv, 0x404410, 0x0); + nv_wr32(priv, 0x404414, 0x0); + nv_wr32(priv, 0x404418, 0x0); + nv_wr32(priv, 0x40441c, 0x0); + nv_wr32(priv, 0x404420, 0x0); + nv_wr32(priv, 0x404424, 0x0); + nv_wr32(priv, 0x404428, 0x0); + nv_wr32(priv, 0x40442c, 0x0); + nv_wr32(priv, 0x404430, 0x0); + nv_wr32(priv, 0x404434, 0x0); + nv_wr32(priv, 0x404438, 0x0); + nv_wr32(priv, 0x404460, 0x0); + nv_wr32(priv, 0x404464, 0x0); + nv_wr32(priv, 0x404468, 0xffffff); + nv_wr32(priv, 0x40446c, 0x0); + nv_wr32(priv, 0x404480, 0x1); + nv_wr32(priv, 0x404498, 0x1); +} + +static void +nve0_graph_generate_unk46xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x404604, 0x14); + nv_wr32(priv, 0x404608, 0x0); + nv_wr32(priv, 0x40460c, 0x3fff); + nv_wr32(priv, 0x404610, 0x100); + nv_wr32(priv, 0x404618, 0x0); + nv_wr32(priv, 0x40461c, 0x0); + nv_wr32(priv, 0x404620, 0x0); + nv_wr32(priv, 0x404624, 0x0); + nv_wr32(priv, 0x40462c, 0x0); + nv_wr32(priv, 0x404630, 0x0); + nv_wr32(priv, 0x404640, 0x0); + nv_wr32(priv, 0x404654, 0x0); + nv_wr32(priv, 0x404660, 0x0); + nv_wr32(priv, 0x404678, 0x0); + nv_wr32(priv, 0x40467c, 0x2); + nv_wr32(priv, 0x404680, 0x0); + nv_wr32(priv, 0x404684, 0x0); + nv_wr32(priv, 0x404688, 0x0); + nv_wr32(priv, 0x40468c, 0x0); + nv_wr32(priv, 0x404690, 0x0); + nv_wr32(priv, 0x404694, 0x0); + nv_wr32(priv, 0x404698, 0x0); + nv_wr32(priv, 0x40469c, 0x0); + nv_wr32(priv, 0x4046a0, 0x7f0080); + nv_wr32(priv, 0x4046a4, 0x0); + nv_wr32(priv, 0x4046a8, 0x0); + nv_wr32(priv, 0x4046ac, 0x0); + nv_wr32(priv, 0x4046b0, 0x0); + nv_wr32(priv, 0x4046b4, 0x0); + nv_wr32(priv, 0x4046b8, 0x0); + nv_wr32(priv, 0x4046bc, 0x0); + nv_wr32(priv, 0x4046c0, 0x0); + nv_wr32(priv, 0x4046c8, 0x0); + nv_wr32(priv, 0x4046cc, 0x0); + nv_wr32(priv, 0x4046d0, 0x0); +} + +static void +nve0_graph_generate_unk47xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x404700, 0x0); + nv_wr32(priv, 0x404704, 0x0); + nv_wr32(priv, 0x404708, 0x0); + nv_wr32(priv, 0x404718, 0x0); + nv_wr32(priv, 0x40471c, 0x0); + nv_wr32(priv, 0x404720, 0x0); + nv_wr32(priv, 0x404724, 0x0); + nv_wr32(priv, 0x404728, 0x0); + nv_wr32(priv, 0x40472c, 0x0); + nv_wr32(priv, 0x404730, 0x0); + nv_wr32(priv, 0x404734, 0x100); + nv_wr32(priv, 0x404738, 0x0); + nv_wr32(priv, 0x40473c, 0x0); + nv_wr32(priv, 0x404744, 0x0); + nv_wr32(priv, 0x404748, 0x0); + nv_wr32(priv, 0x404754, 0x0); +} + +static void +nve0_graph_generate_unk58xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x405800, 0xf8000bf); + nv_wr32(priv, 0x405830, 0x2180648); + nv_wr32(priv, 0x405834, 0x8000000); + nv_wr32(priv, 0x405838, 0x0); + nv_wr32(priv, 0x405854, 0x0); + nv_wr32(priv, 0x405870, 0x1); + nv_wr32(priv, 0x405874, 0x1); + nv_wr32(priv, 0x405878, 0x1); + nv_wr32(priv, 0x40587c, 0x1); + nv_wr32(priv, 0x405a00, 0x0); + nv_wr32(priv, 0x405a04, 0x0); + nv_wr32(priv, 0x405a18, 0x0); + nv_wr32(priv, 0x405b00, 0x0); + nv_wr32(priv, 0x405b10, 0x1000); +} + +static void +nve0_graph_generate_unk60xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x406020, 0x4103c1); + nv_wr32(priv, 0x406028, 0x1); + nv_wr32(priv, 0x40602c, 0x1); + nv_wr32(priv, 0x406030, 0x1); + nv_wr32(priv, 0x406034, 0x1); +} + +static void +nve0_graph_generate_unk64xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x4064a8, 0x0); + nv_wr32(priv, 0x4064ac, 0x3fff); + nv_wr32(priv, 0x4064b4, 0x0); + nv_wr32(priv, 0x4064b8, 0x0); + nv_wr32(priv, 0x4064c0, 0x801a00f0); + nv_wr32(priv, 0x4064c4, 0x192ffff); + nv_wr32(priv, 0x4064c8, 0x1800600); + nv_wr32(priv, 0x4064cc, 0x0); + nv_wr32(priv, 0x4064d0, 0x0); + nv_wr32(priv, 0x4064d4, 0x0); + nv_wr32(priv, 0x4064d8, 0x0); + nv_wr32(priv, 0x4064dc, 0x0); + nv_wr32(priv, 0x4064e0, 0x0); + nv_wr32(priv, 0x4064e4, 0x0); + nv_wr32(priv, 0x4064e8, 0x0); + nv_wr32(priv, 0x4064ec, 0x0); + nv_wr32(priv, 0x4064fc, 0x22a); +} + +static void +nve0_graph_generate_unk70xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x407040, 0x0); +} + +static void +nve0_graph_generate_unk78xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x407804, 0x23); + nv_wr32(priv, 0x40780c, 0xa418820); + nv_wr32(priv, 0x407810, 0x62080e6); + nv_wr32(priv, 0x407814, 0x20398a4); + nv_wr32(priv, 0x407818, 0xe629062); + nv_wr32(priv, 0x40781c, 0xa418820); + nv_wr32(priv, 0x407820, 0xe6); + nv_wr32(priv, 0x4078bc, 0x103); +} + +static void +nve0_graph_generate_unk80xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x408000, 0x0); + nv_wr32(priv, 0x408004, 0x0); + nv_wr32(priv, 0x408008, 0x30); + nv_wr32(priv, 0x40800c, 0x0); + nv_wr32(priv, 0x408010, 0x0); + nv_wr32(priv, 0x408014, 0x69); + nv_wr32(priv, 0x408018, 0xe100e100); + nv_wr32(priv, 0x408064, 0x0); +} + +static void +nve0_graph_generate_unk88xx(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x408800, 0x2802a3c); + nv_wr32(priv, 0x408804, 0x40); + nv_wr32(priv, 0x408808, 0x1043e005); + nv_wr32(priv, 0x408840, 0xb); + nv_wr32(priv, 0x408900, 0x3080b801); + nv_wr32(priv, 0x408904, 0x62000001); + nv_wr32(priv, 0x408908, 0xc8102f); + nv_wr32(priv, 0x408980, 0x11d); +} + +static void +nve0_graph_generate_gpc(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x418380, 0x16); + nv_wr32(priv, 0x418400, 0x38004e00); + nv_wr32(priv, 0x418404, 0x71e0ffff); + nv_wr32(priv, 0x41840c, 0x1008); + nv_wr32(priv, 0x418410, 0xfff0fff); + nv_wr32(priv, 0x418414, 0x2200fff); + nv_wr32(priv, 0x418450, 0x0); + nv_wr32(priv, 0x418454, 0x0); + nv_wr32(priv, 0x418458, 0x0); + nv_wr32(priv, 0x41845c, 0x0); + nv_wr32(priv, 0x418460, 0x0); + nv_wr32(priv, 0x418464, 0x0); + nv_wr32(priv, 0x418468, 0x1); + nv_wr32(priv, 0x41846c, 0x0); + nv_wr32(priv, 0x418470, 0x0); + nv_wr32(priv, 0x418600, 0x1f); + nv_wr32(priv, 0x418684, 0xf); + nv_wr32(priv, 0x418700, 0x2); + nv_wr32(priv, 0x418704, 0x80); + nv_wr32(priv, 0x418708, 0x0); + nv_wr32(priv, 0x41870c, 0x0); + nv_wr32(priv, 0x418710, 0x0); + nv_wr32(priv, 0x418800, 0x7006860a); + nv_wr32(priv, 0x418808, 0x0); + nv_wr32(priv, 0x41880c, 0x0); + nv_wr32(priv, 0x418810, 0x0); + nv_wr32(priv, 0x418828, 0x44); + nv_wr32(priv, 0x418830, 0x10000001); + nv_wr32(priv, 0x4188d8, 0x8); + nv_wr32(priv, 0x4188e0, 0x1000000); + nv_wr32(priv, 0x4188e8, 0x0); + nv_wr32(priv, 0x4188ec, 0x0); + nv_wr32(priv, 0x4188f0, 0x0); + nv_wr32(priv, 0x4188f4, 0x0); + nv_wr32(priv, 0x4188f8, 0x0); + nv_wr32(priv, 0x4188fc, 0x20100018); + nv_wr32(priv, 0x41891c, 0xff00ff); + nv_wr32(priv, 0x418924, 0x0); + nv_wr32(priv, 0x418928, 0xffff00); + nv_wr32(priv, 0x41892c, 0xff00); + nv_wr32(priv, 0x418a00, 0x0); + nv_wr32(priv, 0x418a04, 0x0); + nv_wr32(priv, 0x418a08, 0x0); + nv_wr32(priv, 0x418a0c, 0x10000); + nv_wr32(priv, 0x418a10, 0x0); + nv_wr32(priv, 0x418a14, 0x0); + nv_wr32(priv, 0x418a18, 0x0); + nv_wr32(priv, 0x418a20, 0x0); + nv_wr32(priv, 0x418a24, 0x0); + nv_wr32(priv, 0x418a28, 0x0); + nv_wr32(priv, 0x418a2c, 0x10000); + nv_wr32(priv, 0x418a30, 0x0); + nv_wr32(priv, 0x418a34, 0x0); + nv_wr32(priv, 0x418a38, 0x0); + nv_wr32(priv, 0x418a40, 0x0); + nv_wr32(priv, 0x418a44, 0x0); + nv_wr32(priv, 0x418a48, 0x0); + nv_wr32(priv, 0x418a4c, 0x10000); + nv_wr32(priv, 0x418a50, 0x0); + nv_wr32(priv, 0x418a54, 0x0); + nv_wr32(priv, 0x418a58, 0x0); + nv_wr32(priv, 0x418a60, 0x0); + nv_wr32(priv, 0x418a64, 0x0); + nv_wr32(priv, 0x418a68, 0x0); + nv_wr32(priv, 0x418a6c, 0x10000); + nv_wr32(priv, 0x418a70, 0x0); + nv_wr32(priv, 0x418a74, 0x0); + nv_wr32(priv, 0x418a78, 0x0); + nv_wr32(priv, 0x418a80, 0x0); + nv_wr32(priv, 0x418a84, 0x0); + nv_wr32(priv, 0x418a88, 0x0); + nv_wr32(priv, 0x418a8c, 0x10000); + nv_wr32(priv, 0x418a90, 0x0); + nv_wr32(priv, 0x418a94, 0x0); + nv_wr32(priv, 0x418a98, 0x0); + nv_wr32(priv, 0x418aa0, 0x0); + nv_wr32(priv, 0x418aa4, 0x0); + nv_wr32(priv, 0x418aa8, 0x0); + nv_wr32(priv, 0x418aac, 0x10000); + nv_wr32(priv, 0x418ab0, 0x0); + nv_wr32(priv, 0x418ab4, 0x0); + nv_wr32(priv, 0x418ab8, 0x0); + nv_wr32(priv, 0x418ac0, 0x0); + nv_wr32(priv, 0x418ac4, 0x0); + nv_wr32(priv, 0x418ac8, 0x0); + nv_wr32(priv, 0x418acc, 0x10000); + nv_wr32(priv, 0x418ad0, 0x0); + nv_wr32(priv, 0x418ad4, 0x0); + nv_wr32(priv, 0x418ad8, 0x0); + nv_wr32(priv, 0x418ae0, 0x0); + nv_wr32(priv, 0x418ae4, 0x0); + nv_wr32(priv, 0x418ae8, 0x0); + nv_wr32(priv, 0x418aec, 0x10000); + nv_wr32(priv, 0x418af0, 0x0); + nv_wr32(priv, 0x418af4, 0x0); + nv_wr32(priv, 0x418af8, 0x0); + nv_wr32(priv, 0x418b00, 0x6); + nv_wr32(priv, 0x418b08, 0xa418820); + nv_wr32(priv, 0x418b0c, 0x62080e6); + nv_wr32(priv, 0x418b10, 0x20398a4); + nv_wr32(priv, 0x418b14, 0xe629062); + nv_wr32(priv, 0x418b18, 0xa418820); + nv_wr32(priv, 0x418b1c, 0xe6); + nv_wr32(priv, 0x418bb8, 0x103); + nv_wr32(priv, 0x418c08, 0x1); + nv_wr32(priv, 0x418c10, 0x0); + nv_wr32(priv, 0x418c14, 0x0); + nv_wr32(priv, 0x418c18, 0x0); + nv_wr32(priv, 0x418c1c, 0x0); + nv_wr32(priv, 0x418c20, 0x0); + nv_wr32(priv, 0x418c24, 0x0); + nv_wr32(priv, 0x418c28, 0x0); + nv_wr32(priv, 0x418c2c, 0x0); + nv_wr32(priv, 0x418c40, 0xffffffff); + nv_wr32(priv, 0x418c6c, 0x1); + nv_wr32(priv, 0x418c80, 0x20200004); + nv_wr32(priv, 0x418c8c, 0x1); + nv_wr32(priv, 0x419000, 0x780); + nv_wr32(priv, 0x419004, 0x0); + nv_wr32(priv, 0x419008, 0x0); + nv_wr32(priv, 0x419014, 0x4); +} + +static void +nve0_graph_generate_tpc(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x419848, 0x0); + nv_wr32(priv, 0x419864, 0x129); + nv_wr32(priv, 0x419888, 0x0); + nv_wr32(priv, 0x419a00, 0xf0); + nv_wr32(priv, 0x419a04, 0x1); + nv_wr32(priv, 0x419a08, 0x21); + nv_wr32(priv, 0x419a0c, 0x20000); + nv_wr32(priv, 0x419a10, 0x0); + nv_wr32(priv, 0x419a14, 0x200); + nv_wr32(priv, 0x419a1c, 0xc000); + nv_wr32(priv, 0x419a20, 0x800); + nv_wr32(priv, 0x419a30, 0x1); + nv_wr32(priv, 0x419ac4, 0x37f440); + nv_wr32(priv, 0x419c00, 0xa); + nv_wr32(priv, 0x419c04, 0x80000006); + nv_wr32(priv, 0x419c08, 0x2); + nv_wr32(priv, 0x419c20, 0x0); + nv_wr32(priv, 0x419c24, 0x84210); + nv_wr32(priv, 0x419c28, 0x3efbefbe); + nv_wr32(priv, 0x419ce8, 0x0); + nv_wr32(priv, 0x419cf4, 0x3203); + nv_wr32(priv, 0x419e04, 0x0); + nv_wr32(priv, 0x419e08, 0x0); + nv_wr32(priv, 0x419e0c, 0x0); + nv_wr32(priv, 0x419e10, 0x402); + nv_wr32(priv, 0x419e44, 0x13eff2); + nv_wr32(priv, 0x419e48, 0x0); + nv_wr32(priv, 0x419e4c, 0x7f); + nv_wr32(priv, 0x419e50, 0x0); + nv_wr32(priv, 0x419e54, 0x0); + nv_wr32(priv, 0x419e58, 0x0); + nv_wr32(priv, 0x419e5c, 0x0); + nv_wr32(priv, 0x419e60, 0x0); + nv_wr32(priv, 0x419e64, 0x0); + nv_wr32(priv, 0x419e68, 0x0); + nv_wr32(priv, 0x419e6c, 0x0); + nv_wr32(priv, 0x419e70, 0x0); + nv_wr32(priv, 0x419e74, 0x0); + nv_wr32(priv, 0x419e78, 0x0); + nv_wr32(priv, 0x419e7c, 0x0); + nv_wr32(priv, 0x419e80, 0x0); + nv_wr32(priv, 0x419e84, 0x0); + nv_wr32(priv, 0x419e88, 0x0); + nv_wr32(priv, 0x419e8c, 0x0); + nv_wr32(priv, 0x419e90, 0x0); + nv_wr32(priv, 0x419e94, 0x0); + nv_wr32(priv, 0x419e98, 0x0); + nv_wr32(priv, 0x419eac, 0x1fcf); + nv_wr32(priv, 0x419eb0, 0xd3f); + nv_wr32(priv, 0x419ec8, 0x1304f); + nv_wr32(priv, 0x419f30, 0x0); + nv_wr32(priv, 0x419f34, 0x0); + nv_wr32(priv, 0x419f38, 0x0); + nv_wr32(priv, 0x419f3c, 0x0); + nv_wr32(priv, 0x419f40, 0x0); + nv_wr32(priv, 0x419f44, 0x0); + nv_wr32(priv, 0x419f48, 0x0); + nv_wr32(priv, 0x419f4c, 0x0); + nv_wr32(priv, 0x419f58, 0x0); + nv_wr32(priv, 0x419f78, 0xb); +} + +static void +nve0_graph_generate_tpcunk(struct nvc0_graph_priv *priv) +{ + nv_wr32(priv, 0x41be24, 0x6); + nv_wr32(priv, 0x41bec0, 0x12180000); + nv_wr32(priv, 0x41bec4, 0x37f7f); + nv_wr32(priv, 0x41bee4, 0x6480430); + nv_wr32(priv, 0x41bf00, 0xa418820); + nv_wr32(priv, 0x41bf04, 0x62080e6); + nv_wr32(priv, 0x41bf08, 0x20398a4); + nv_wr32(priv, 0x41bf0c, 0xe629062); + nv_wr32(priv, 0x41bf10, 0xa418820); + nv_wr32(priv, 0x41bf14, 0xe6); + nv_wr32(priv, 0x41bfd0, 0x900103); + nv_wr32(priv, 0x41bfe0, 0x400001); + nv_wr32(priv, 0x41bfe4, 0x0); +} + +int +nve0_grctx_generate(struct nvc0_graph_priv *priv) +{ + struct nvc0_grctx info; + int ret, i, gpc, tpc, id; + u32 data[6] = {}, data2[2] = {}, tmp; + u32 tpc_set = 0, tpc_mask = 0; + u32 magic[GPC_MAX][2], offset; + u8 tpcnr[GPC_MAX], a, b; + u8 shift, ntpcv; + + ret = nvc0_grctx_init(priv, &info); + if (ret) + return ret; + + nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nv_wr32(priv, 0x400204, 0x00000000); + nv_wr32(priv, 0x400208, 0x00000000); + + nve0_graph_generate_unk40xx(priv); + nve0_graph_generate_unk44xx(priv); + nve0_graph_generate_unk46xx(priv); + nve0_graph_generate_unk47xx(priv); + nve0_graph_generate_unk58xx(priv); + nve0_graph_generate_unk60xx(priv); + nve0_graph_generate_unk64xx(priv); + nve0_graph_generate_unk70xx(priv); + nve0_graph_generate_unk78xx(priv); + nve0_graph_generate_unk80xx(priv); + nve0_graph_generate_unk88xx(priv); + nve0_graph_generate_gpc(priv); + nve0_graph_generate_tpc(priv); + nve0_graph_generate_tpcunk(priv); + + nv_wr32(priv, 0x404154, 0x0); + + mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); + mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); + mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); + mmio_list(0x40800c, 0x00000000, 8, 1); + mmio_list(0x408010, 0x80000000, 0, 0); + mmio_list(0x419004, 0x00000000, 8, 1); + mmio_list(0x419008, 0x00000000, 0, 0); + mmio_list(0x4064cc, 0x80000000, 0, 0); + mmio_list(0x408004, 0x00000000, 8, 0); + mmio_list(0x408008, 0x80000030, 0, 0); + mmio_list(0x418808, 0x00000000, 8, 0); + mmio_list(0x41880c, 0x80000030, 0, 0); + mmio_list(0x4064c8, 0x01800600, 0, 0); + mmio_list(0x418810, 0x80000000, 12, 2); + mmio_list(0x419848, 0x10000000, 12, 2); + mmio_list(0x405830, 0x02180648, 0, 0); + mmio_list(0x4064c4, 0x0192ffff, 0, 0); + 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 * priv->tpc_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 * priv->tpc_nr[gpc]; + } + mmio_list(0x17e91c, 0x06060609, 0, 0); + mmio_list(0x17e920, 0x00090a05, 0, 0); + + nv_wr32(priv, 0x418c6c, 0x1); + nv_wr32(priv, 0x41980c, 0x10); + nv_wr32(priv, 0x41be08, 0x4); + nv_wr32(priv, 0x4064c0, 0x801a00f0); + nv_wr32(priv, 0x405800, 0xf8000bf); + nv_wr32(priv, 0x419c00, 0xa); + + for (tpc = 0, id = 0; tpc < 4; tpc++) { + 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), priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); + } + } + + tmp = 0; + 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); + + nv_wr32(priv, 0x40602c, 0x0); + nv_wr32(priv, 0x405874, 0x0); + nv_wr32(priv, 0x406030, 0x0); + nv_wr32(priv, 0x405878, 0x0); + nv_wr32(priv, 0x406034, 0x0); + nv_wr32(priv, 0x40587c, 0x0); + + /* calculate first set of magics */ + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + + gpc = -1; + for (tpc = 0; tpc < priv->tpc_total; tpc++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpcnr[gpc]--; + + data[tpc / 6] |= gpc << ((tpc % 6) * 5); + } + + for (; tpc < 32; tpc++) + data[tpc / 6] |= 7 << ((tpc % 6) * 5); + + /* and the second... */ + shift = 0; + ntpcv = priv->tpc_total; + while (!(ntpcv & (1 << 4))) { + ntpcv <<= 1; + shift++; + } + + data2[0] = ntpcv << 16; + data2[0] |= shift << 21; + data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24); + 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, (priv->tpc_total << 8) | priv->magic_not_rop_nr); + for (i = 0; i < 6; i++) + nv_wr32(priv, 0x418b08 + (i * 4), data[i]); + + nv_wr32(priv, 0x41bfd0, data2[0]); + nv_wr32(priv, 0x41bfe4, data2[1]); + for (i = 0; i < 6; i++) + nv_wr32(priv, 0x41bf00 + (i * 4), data[i]); + + 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, 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 * (priv->tpc_total - 1)) / 32; + if (a != b) { + b = a; + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + + tpc_set |= 1 << ((gpc * 8) + tpc); + } + + nv_wr32(priv, 0x406800 + (i * 0x20), tpc_set); + nv_wr32(priv, 0x406c00 + (i * 0x20), tpc_set ^ tpc_mask); + } + + for (i = 0; i < 8; i++) + nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + + nv_wr32(priv, 0x405b00, 0x201); + nv_wr32(priv, 0x408850, 0x2); + nv_wr32(priv, 0x408958, 0x2); + nv_wr32(priv, 0x419f78, 0xa); + + nve0_grctx_generate_icmd(priv); + nve0_grctx_generate_a097(priv); + nve0_grctx_generate_902d(priv); + + nv_mask(priv, 0x000260, 0x00000001, 0x00000001); + nv_wr32(priv, 0x418800, 0x7026860a); //XXX + nv_wr32(priv, 0x41be10, 0x00bb8bc7); //XXX + return nvc0_grctx_fini(&info); +} diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc new file mode 100644 index 00000000000..b86cc60dcd5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc @@ -0,0 +1,539 @@ +/* fuc microcode for nvc0 PGRAPH/GPC + * + * Copyright 2011 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 + */ + +/* To build: + * m4 gpcnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o gpcnvc0.fuc.h + */ + +/* TODO + * - bracket certain functions with scratch writes, useful for debugging + * - watchdog timer around ctx operations + */ + +.section #nvc0_grgpc_data +include(`nvc0.fuc') +gpc_id: .b32 0 +gpc_mmio_list_head: .b32 0 +gpc_mmio_list_tail: .b32 0 + +tpc_count: .b32 0 +tpc_mask: .b32 0 +tpc_mmio_list_head: .b32 0 +tpc_mmio_list_tail: .b32 0 + +cmd_queue: queue_init + +// chipset descriptions +chipsets: +.b8 0xc0 0 0 0 +.b16 #nvc0_gpc_mmio_head +.b16 #nvc0_gpc_mmio_tail +.b16 #nvc0_tpc_mmio_head +.b16 #nvc0_tpc_mmio_tail +.b8 0xc1 0 0 0 +.b16 #nvc0_gpc_mmio_head +.b16 #nvc1_gpc_mmio_tail +.b16 #nvc0_tpc_mmio_head +.b16 #nvc1_tpc_mmio_tail +.b8 0xc3 0 0 0 +.b16 #nvc0_gpc_mmio_head +.b16 #nvc0_gpc_mmio_tail +.b16 #nvc0_tpc_mmio_head +.b16 #nvc3_tpc_mmio_tail +.b8 0xc4 0 0 0 +.b16 #nvc0_gpc_mmio_head +.b16 #nvc0_gpc_mmio_tail +.b16 #nvc0_tpc_mmio_head +.b16 #nvc3_tpc_mmio_tail +.b8 0xc8 0 0 0 +.b16 #nvc0_gpc_mmio_head +.b16 #nvc0_gpc_mmio_tail +.b16 #nvc0_tpc_mmio_head +.b16 #nvc0_tpc_mmio_tail +.b8 0xce 0 0 0 +.b16 #nvc0_gpc_mmio_head +.b16 #nvc0_gpc_mmio_tail +.b16 #nvc0_tpc_mmio_head +.b16 #nvc3_tpc_mmio_tail +.b8 0xcf 0 0 0 +.b16 #nvc0_gpc_mmio_head +.b16 #nvc0_gpc_mmio_tail +.b16 #nvc0_tpc_mmio_head +.b16 #nvcf_tpc_mmio_tail +.b8 0xd9 0 0 0 +.b16 #nvd9_gpc_mmio_head +.b16 #nvd9_gpc_mmio_tail +.b16 #nvd9_tpc_mmio_head +.b16 #nvd9_tpc_mmio_tail +.b8 0 0 0 0 + +// GPC mmio lists +nvc0_gpc_mmio_head: +mmctx_data(0x000380, 1) +mmctx_data(0x000400, 6) +mmctx_data(0x000450, 9) +mmctx_data(0x000600, 1) +mmctx_data(0x000684, 1) +mmctx_data(0x000700, 5) +mmctx_data(0x000800, 1) +mmctx_data(0x000808, 3) +mmctx_data(0x000828, 1) +mmctx_data(0x000830, 1) +mmctx_data(0x0008d8, 1) +mmctx_data(0x0008e0, 1) +mmctx_data(0x0008e8, 6) +mmctx_data(0x00091c, 1) +mmctx_data(0x000924, 3) +mmctx_data(0x000b00, 1) +mmctx_data(0x000b08, 6) +mmctx_data(0x000bb8, 1) +mmctx_data(0x000c08, 1) +mmctx_data(0x000c10, 8) +mmctx_data(0x000c80, 1) +mmctx_data(0x000c8c, 1) +mmctx_data(0x001000, 3) +mmctx_data(0x001014, 1) +nvc0_gpc_mmio_tail: +mmctx_data(0x000c6c, 1); +nvc1_gpc_mmio_tail: + +nvd9_gpc_mmio_head: +mmctx_data(0x000380, 1) +mmctx_data(0x000400, 2) +mmctx_data(0x00040c, 3) +mmctx_data(0x000450, 9) +mmctx_data(0x000600, 1) +mmctx_data(0x000684, 1) +mmctx_data(0x000700, 5) +mmctx_data(0x000800, 1) +mmctx_data(0x000808, 3) +mmctx_data(0x000828, 1) +mmctx_data(0x000830, 1) +mmctx_data(0x0008d8, 1) +mmctx_data(0x0008e0, 1) +mmctx_data(0x0008e8, 6) +mmctx_data(0x00091c, 1) +mmctx_data(0x000924, 3) +mmctx_data(0x000b00, 1) +mmctx_data(0x000b08, 6) +mmctx_data(0x000bb8, 1) +mmctx_data(0x000c08, 1) +mmctx_data(0x000c10, 8) +mmctx_data(0x000c6c, 1) +mmctx_data(0x000c80, 1) +mmctx_data(0x000c8c, 1) +mmctx_data(0x001000, 3) +mmctx_data(0x001014, 1) +nvd9_gpc_mmio_tail: + +// TPC mmio lists +nvc0_tpc_mmio_head: +mmctx_data(0x000018, 1) +mmctx_data(0x00003c, 1) +mmctx_data(0x000048, 1) +mmctx_data(0x000064, 1) +mmctx_data(0x000088, 1) +mmctx_data(0x000200, 6) +mmctx_data(0x00021c, 2) +mmctx_data(0x000300, 6) +mmctx_data(0x0003d0, 1) +mmctx_data(0x0003e0, 2) +mmctx_data(0x000400, 3) +mmctx_data(0x000420, 1) +mmctx_data(0x0004b0, 1) +mmctx_data(0x0004e8, 1) +mmctx_data(0x0004f4, 1) +mmctx_data(0x000520, 2) +mmctx_data(0x000604, 4) +mmctx_data(0x000644, 20) +mmctx_data(0x000698, 1) +mmctx_data(0x000750, 2) +nvc0_tpc_mmio_tail: +mmctx_data(0x000758, 1) +mmctx_data(0x0002c4, 1) +mmctx_data(0x0006e0, 1) +nvcf_tpc_mmio_tail: +mmctx_data(0x0004bc, 1) +nvc3_tpc_mmio_tail: +mmctx_data(0x000544, 1) +nvc1_tpc_mmio_tail: + +nvd9_tpc_mmio_head: +mmctx_data(0x000018, 1) +mmctx_data(0x00003c, 1) +mmctx_data(0x000048, 1) +mmctx_data(0x000064, 1) +mmctx_data(0x000088, 1) +mmctx_data(0x000200, 6) +mmctx_data(0x00021c, 2) +mmctx_data(0x0002c4, 1) +mmctx_data(0x000300, 6) +mmctx_data(0x0003d0, 1) +mmctx_data(0x0003e0, 2) +mmctx_data(0x000400, 3) +mmctx_data(0x000420, 3) +mmctx_data(0x0004b0, 1) +mmctx_data(0x0004e8, 1) +mmctx_data(0x0004f4, 1) +mmctx_data(0x000520, 2) +mmctx_data(0x000544, 1) +mmctx_data(0x000604, 4) +mmctx_data(0x000644, 20) +mmctx_data(0x000698, 1) +mmctx_data(0x0006e0, 1) +mmctx_data(0x000750, 3) +nvd9_tpc_mmio_tail: + +.section #nvc0_grgpc_code +bra #init +define(`include_code') +include(`nvc0.fuc') + +// reports an exception to the host +// +// In: $r15 error code (see nvc0.fuc) +// +error: + push $r14 + mov $r14 -0x67ec // 0x9814 + sethi $r14 0x400000 + call #nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code + add b32 $r14 0x41c + mov $r15 1 + call #nv_wr32 // HUB_CTXCTL_INTR_UP_SET + pop $r14 + ret + +// GPC fuc initialisation, executed by triggering ucode start, will +// fall through to main loop after completion. +// +// Input: +// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh) +// CC_SCRATCH[1]: context base +// +// Output: +// CC_SCRATCH[0]: +// 31:31: set to signal completion +// CC_SCRATCH[1]: +// 31:0: GPC context size +// +init: + clear b32 $r0 + mov $sp $r0 + + // enable fifo access + mov $r1 0x1200 + mov $r2 2 + iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE + + // setup i0 handler, and route all interrupts to it + mov $r1 #ih + mov $iv0 $r1 + mov $r1 0x400 + iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH + + // enable fifo interrupt + mov $r2 4 + iowr I[$r1 + 0x000] $r2 // INTR_EN_SET + + // enable interrupts + bset $flags ie0 + + // figure out which GPC we are, and how many TPCs we have + mov $r1 0x608 + shl b32 $r1 6 + iord $r2 I[$r1 + 0x000] // UNITS + mov $r3 1 + and $r2 0x1f + shl b32 $r3 $r2 + sub b32 $r3 1 + st b32 D[$r0 + #tpc_count] $r2 + st b32 D[$r0 + #tpc_mask] $r3 + add b32 $r1 0x400 + iord $r2 I[$r1 + 0x000] // MYINDEX + st b32 D[$r0 + #gpc_id] $r2 + + // find context data for this chipset + mov $r2 0x800 + shl b32 $r2 6 + iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0] + mov $r1 #chipsets - 12 + init_find_chipset: + add b32 $r1 12 + ld b32 $r3 D[$r1 + 0x00] + cmpu b32 $r3 $r2 + bra e #init_context + cmpu b32 $r3 0 + bra ne #init_find_chipset + // unknown chipset + ret + + // initialise context base, and size tracking + init_context: + mov $r2 0x800 + shl b32 $r2 6 + iord $r2 I[$r2 + 0x100] // CC_SCRATCH[1], initial base + clear b32 $r3 // track GPC context size here + + // set mmctx base addresses now so we don't have to do it later, + // they don't currently ever change + mov $r4 0x700 + shl b32 $r4 6 + shr b32 $r5 $r2 8 + iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE + iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE + + // calculate GPC mmio context size, store the chipset-specific + // mmio list pointers somewhere we can get at them later without + // re-parsing the chipset list + clear b32 $r14 + clear b32 $r15 + ld b16 $r14 D[$r1 + 4] + ld b16 $r15 D[$r1 + 6] + st b16 D[$r0 + #gpc_mmio_list_head] $r14 + st b16 D[$r0 + #gpc_mmio_list_tail] $r15 + call #mmctx_size + add b32 $r2 $r15 + add b32 $r3 $r15 + + // calculate per-TPC mmio context size, store the list pointers + ld b16 $r14 D[$r1 + 8] + ld b16 $r15 D[$r1 + 10] + st b16 D[$r0 + #tpc_mmio_list_head] $r14 + st b16 D[$r0 + #tpc_mmio_list_tail] $r15 + call #mmctx_size + ld b32 $r14 D[$r0 + #tpc_count] + mulu $r14 $r15 + add b32 $r2 $r14 + add b32 $r3 $r14 + + // round up base/size to 256 byte boundary (for strand SWBASE) + add b32 $r4 0x1300 + shr b32 $r3 2 + iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!? + shr b32 $r2 8 + shr b32 $r3 6 + add b32 $r2 1 + add b32 $r3 1 + shl b32 $r2 8 + shl b32 $r3 8 + + // calculate size of strand context data + mov b32 $r15 $r2 + call #strand_ctx_init + add b32 $r3 $r15 + + // save context size, and tell HUB we're done + mov $r1 0x800 + shl b32 $r1 6 + iowr I[$r1 + 0x100] $r3 // CC_SCRATCH[1] = context size + add b32 $r1 0x800 + clear b32 $r2 + bset $r2 31 + iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000 + +// Main program loop, very simple, sleeps until woken up by the interrupt +// handler, pulls a command from the queue and executes its handler +// +main: + bset $flags $p0 + sleep $p0 + mov $r13 #cmd_queue + call #queue_get + bra $p1 #main + + // 0x0000-0x0003 are all context transfers + cmpu b32 $r14 0x04 + bra nc #main_not_ctx_xfer + // fetch $flags and mask off $p1/$p2 + mov $r1 $flags + mov $r2 0x0006 + not b32 $r2 + and $r1 $r2 + // set $p1/$p2 according to transfer type + shl b32 $r14 1 + or $r1 $r14 + mov $flags $r1 + // transfer context data + call #ctx_xfer + bra #main + + main_not_ctx_xfer: + shl b32 $r15 $r14 16 + or $r15 E_BAD_COMMAND + call #error + bra #main + +// interrupt handler +ih: + push $r8 + mov $r8 $flags + push $r8 + push $r9 + push $r10 + push $r11 + push $r13 + push $r14 + push $r15 + + // incoming fifo command? + iord $r10 I[$r0 + 0x200] // INTR + and $r11 $r10 0x00000004 + bra e #ih_no_fifo + // queue incoming fifo command for later processing + mov $r11 0x1900 + mov $r13 #cmd_queue + iord $r14 I[$r11 + 0x100] // FIFO_CMD + iord $r15 I[$r11 + 0x000] // FIFO_DATA + call #queue_put + add b32 $r11 0x400 + mov $r14 1 + iowr I[$r11 + 0x000] $r14 // FIFO_ACK + + // ack, and wake up main() + ih_no_fifo: + iowr I[$r0 + 0x100] $r10 // INTR_ACK + + pop $r15 + pop $r14 + pop $r13 + pop $r11 + pop $r10 + pop $r9 + pop $r8 + mov $flags $r8 + pop $r8 + bclr $flags $p0 + iret + +// Set this GPC's bit in HUB_BAR, used to signal completion of various +// activities to the HUB fuc +// +hub_barrier_done: + mov $r15 1 + ld b32 $r14 D[$r0 + #gpc_id] + shl b32 $r15 $r14 + mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET + sethi $r14 0x400000 + call #nv_wr32 + ret + +// Disables various things, waits a bit, and re-enables them.. +// +// Not sure how exactly this helps, perhaps "ENABLE" is not such a +// good description for the bits we turn off? Anyways, without this, +// funny things happen. +// +ctx_redswitch: + mov $r14 0x614 + shl b32 $r14 6 + mov $r15 0x020 + iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER + mov $r15 8 + ctx_redswitch_delay: + sub b32 $r15 1 + bra ne #ctx_redswitch_delay + mov $r15 0xa20 + iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER + ret + +// Transfer GPC context data between GPU and storage area +// +// In: $r15 context base address +// $p1 clear on save, set on load +// $p2 set if opposite direction done/will be done, so: +// on save it means: "a load will follow this save" +// on load it means: "a save preceeded this load" +// +ctx_xfer: + // set context base address + mov $r1 0xa04 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r15// MEM_BASE + bra not $p1 #ctx_xfer_not_load + call #ctx_redswitch + ctx_xfer_not_load: + + // strands + mov $r1 0x4afc + sethi $r1 0x20000 + mov $r2 0xc + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c + call #strand_wait + mov $r2 0x47fc + sethi $r2 0x20000 + iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 + xbit $r2 $flags $p1 + add b32 $r2 3 + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) + + // mmio context + xbit $r10 $flags $p1 // direction + or $r10 2 // first + mov $r11 0x0000 + sethi $r11 0x500000 + ld b32 $r12 D[$r0 + #gpc_id] + shl b32 $r12 15 + add b32 $r11 $r12 // base = NV_PGRAPH_GPCn + ld b32 $r12 D[$r0 + #gpc_mmio_list_head] + ld b32 $r13 D[$r0 + #gpc_mmio_list_tail] + mov $r14 0 // not multi + call #mmctx_xfer + + // per-TPC mmio context + xbit $r10 $flags $p1 // direction + or $r10 4 // last + mov $r11 0x4000 + sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0 + ld b32 $r12 D[$r0 + #gpc_id] + shl b32 $r12 15 + add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0 + ld b32 $r12 D[$r0 + #tpc_mmio_list_head] + ld b32 $r13 D[$r0 + #tpc_mmio_list_tail] + ld b32 $r15 D[$r0 + #tpc_mask] + mov $r14 0x800 // stride = 0x800 + call #mmctx_xfer + + // wait for strands to finish + call #strand_wait + + // if load, or a save without a load following, do some + // unknown stuff that's done after finishing a block of + // strand commands + bra $p1 #ctx_xfer_post + bra not $p2 #ctx_xfer_done + ctx_xfer_post: + mov $r1 0x4afc + sethi $r1 0x20000 + mov $r2 0xd + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d + call #strand_wait + + // mark completion in HUB's barrier + ctx_xfer_done: + call #hub_barrier_done + ret + +.align 256 diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h new file mode 100644 index 00000000000..96050ddb22c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h @@ -0,0 +1,604 @@ +uint32_t nvc0_grgpc_data[] = { +/* 0x0000: gpc_id */ + 0x00000000, +/* 0x0004: gpc_mmio_list_head */ + 0x00000000, +/* 0x0008: gpc_mmio_list_tail */ + 0x00000000, +/* 0x000c: tpc_count */ + 0x00000000, +/* 0x0010: tpc_mask */ + 0x00000000, +/* 0x0014: tpc_mmio_list_head */ + 0x00000000, +/* 0x0018: tpc_mmio_list_tail */ + 0x00000000, +/* 0x001c: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0064: chipsets */ + 0x000000c0, + 0x012800c8, + 0x01e40194, + 0x000000c1, + 0x012c00c8, + 0x01f80194, + 0x000000c3, + 0x012800c8, + 0x01f40194, + 0x000000c4, + 0x012800c8, + 0x01f40194, + 0x000000c8, + 0x012800c8, + 0x01e40194, + 0x000000ce, + 0x012800c8, + 0x01f40194, + 0x000000cf, + 0x012800c8, + 0x01f00194, + 0x000000d9, + 0x0194012c, + 0x025401f8, + 0x00000000, +/* 0x00c8: nvc0_gpc_mmio_head */ + 0x00000380, + 0x14000400, + 0x20000450, + 0x00000600, + 0x00000684, + 0x10000700, + 0x00000800, + 0x08000808, + 0x00000828, + 0x00000830, + 0x000008d8, + 0x000008e0, + 0x140008e8, + 0x0000091c, + 0x08000924, + 0x00000b00, + 0x14000b08, + 0x00000bb8, + 0x00000c08, + 0x1c000c10, + 0x00000c80, + 0x00000c8c, + 0x08001000, + 0x00001014, +/* 0x0128: nvc0_gpc_mmio_tail */ + 0x00000c6c, +/* 0x012c: nvc1_gpc_mmio_tail */ +/* 0x012c: nvd9_gpc_mmio_head */ + 0x00000380, + 0x04000400, + 0x0800040c, + 0x20000450, + 0x00000600, + 0x00000684, + 0x10000700, + 0x00000800, + 0x08000808, + 0x00000828, + 0x00000830, + 0x000008d8, + 0x000008e0, + 0x140008e8, + 0x0000091c, + 0x08000924, + 0x00000b00, + 0x14000b08, + 0x00000bb8, + 0x00000c08, + 0x1c000c10, + 0x00000c6c, + 0x00000c80, + 0x00000c8c, + 0x08001000, + 0x00001014, +/* 0x0194: nvd9_gpc_mmio_tail */ +/* 0x0194: nvc0_tpc_mmio_head */ + 0x00000018, + 0x0000003c, + 0x00000048, + 0x00000064, + 0x00000088, + 0x14000200, + 0x0400021c, + 0x14000300, + 0x000003d0, + 0x040003e0, + 0x08000400, + 0x00000420, + 0x000004b0, + 0x000004e8, + 0x000004f4, + 0x04000520, + 0x0c000604, + 0x4c000644, + 0x00000698, + 0x04000750, +/* 0x01e4: nvc0_tpc_mmio_tail */ + 0x00000758, + 0x000002c4, + 0x000006e0, +/* 0x01f0: nvcf_tpc_mmio_tail */ + 0x000004bc, +/* 0x01f4: nvc3_tpc_mmio_tail */ + 0x00000544, +/* 0x01f8: nvc1_tpc_mmio_tail */ +/* 0x01f8: nvd9_tpc_mmio_head */ + 0x00000018, + 0x0000003c, + 0x00000048, + 0x00000064, + 0x00000088, + 0x14000200, + 0x0400021c, + 0x000002c4, + 0x14000300, + 0x000003d0, + 0x040003e0, + 0x08000400, + 0x08000420, + 0x000004b0, + 0x000004e8, + 0x000004f4, + 0x04000520, + 0x00000544, + 0x0c000604, + 0x4c000644, + 0x00000698, + 0x000006e0, + 0x08000750, +}; + +uint32_t nvc0_grgpc_code[] = { + 0x03060ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0x0489b808, + 0xf00c1bf4, + 0x21f502f7, + 0x00f802ec, +/* 0x001c: queue_put_next */ + 0xb60798c4, + 0x8dbb0384, + 0x0880b600, + 0x80008e80, + 0x90b6018f, + 0x0f94f001, + 0xf801d980, +/* 0x0039: queue_get */ + 0x0131f400, + 0x9800d898, + 0x89b801d9, + 0x210bf404, + 0xb60789c4, + 0x9dbb0394, + 0x0890b600, + 0x98009e98, + 0x80b6019f, + 0x0f84f001, + 0xf400d880, +/* 0x0066: queue_get_done */ + 0x00f80132, +/* 0x0068: nv_rd32 */ + 0x0728b7f1, + 0xb906b4b6, + 0xc9f002ec, + 0x00bcd01f, +/* 0x0078: nv_rd32_wait */ + 0xc800bccf, + 0x1bf41fcc, + 0x06a7f0fa, + 0x010321f5, + 0xf840bfcf, +/* 0x008d: nv_wr32 */ + 0x28b7f100, + 0x06b4b607, + 0xb980bfd0, + 0xc9f002ec, + 0x1ec9f01f, +/* 0x00a3: nv_wr32_wait */ + 0xcf00bcd0, + 0xccc800bc, + 0xfa1bf41f, +/* 0x00ae: watchdog_reset */ + 0x87f100f8, + 0x84b60430, + 0x1ff9f006, + 0xf8008fd0, +/* 0x00bd: watchdog_clear */ + 0x3087f100, + 0x0684b604, + 0xf80080d0, +/* 0x00c9: wait_donez */ + 0x3c87f100, + 0x0684b608, + 0x99f094bd, + 0x0089d000, + 0x081887f1, + 0xd00684b6, +/* 0x00e2: wait_done_wait_donez */ + 0x87f1008a, + 0x84b60400, + 0x0088cf06, + 0xf4888aff, + 0x87f1f31b, + 0x84b6085c, + 0xf094bd06, + 0x89d00099, +/* 0x0103: wait_doneo */ + 0xf100f800, + 0xb6083c87, + 0x94bd0684, + 0xd00099f0, + 0x87f10089, + 0x84b60818, + 0x008ad006, +/* 0x011c: wait_done_wait_doneo */ + 0x040087f1, + 0xcf0684b6, + 0x8aff0088, + 0xf30bf488, + 0x085c87f1, + 0xbd0684b6, + 0x0099f094, + 0xf80089d0, +/* 0x013d: mmctx_size */ +/* 0x013f: nv_mmctx_size_loop */ + 0x9894bd00, + 0x85b600e8, + 0x0180b61a, + 0xbb0284b6, + 0xe0b60098, + 0x04efb804, + 0xb9eb1bf4, + 0x00f8029f, +/* 0x015c: mmctx_xfer */ + 0x083c87f1, + 0xbd0684b6, + 0x0199f094, + 0xf10089d0, + 0xb6071087, + 0x94bd0684, + 0xf405bbfd, + 0x8bd0090b, + 0x0099f000, +/* 0x0180: mmctx_base_disabled */ + 0xf405eefd, + 0x8ed00c0b, + 0xc08fd080, +/* 0x018f: mmctx_multi_disabled */ + 0xb70199f0, + 0xc8010080, + 0xb4b600ab, + 0x0cb9f010, + 0xb601aec8, + 0xbefd11e4, + 0x008bd005, +/* 0x01a8: mmctx_exec_loop */ +/* 0x01a8: mmctx_wait_free */ + 0xf0008ecf, + 0x0bf41fe4, + 0x00ce98fa, + 0xd005e9fd, + 0xc0b6c08e, + 0x04cdb804, + 0xc8e81bf4, + 0x1bf402ab, +/* 0x01c9: mmctx_fini_wait */ + 0x008bcf18, + 0xb01fb4f0, + 0x1bf410b4, + 0x02a7f0f7, + 0xf4c921f4, +/* 0x01de: mmctx_stop */ + 0xabc81b0e, + 0x10b4b600, + 0xf00cb9f0, + 0x8bd012b9, +/* 0x01ed: mmctx_stop_wait */ + 0x008bcf00, + 0xf412bbc8, +/* 0x01f6: mmctx_done */ + 0x87f1fa1b, + 0x84b6085c, + 0xf094bd06, + 0x89d00199, +/* 0x0207: strand_wait */ + 0xf900f800, + 0x02a7f0a0, + 0xfcc921f4, +/* 0x0213: strand_pre */ + 0xf100f8a0, + 0xf04afc87, + 0x97f00283, + 0x0089d00c, + 0x020721f5, +/* 0x0226: strand_post */ + 0x87f100f8, + 0x83f04afc, + 0x0d97f002, + 0xf50089d0, + 0xf8020721, +/* 0x0239: strand_set */ + 0xfca7f100, + 0x02a3f04f, + 0x0500aba2, + 0xd00fc7f0, + 0xc7f000ac, + 0x00bcd00b, + 0x020721f5, + 0xf000aed0, + 0xbcd00ac7, + 0x0721f500, +/* 0x0263: strand_ctx_init */ + 0xf100f802, + 0xb6083c87, + 0x94bd0684, + 0xd00399f0, + 0x21f50089, + 0xe7f00213, + 0x3921f503, + 0xfca7f102, + 0x02a3f046, + 0x0400aba0, + 0xf040a0d0, + 0xbcd001c7, + 0x0721f500, + 0x010c9202, + 0xf000acd0, + 0xbcd002c7, + 0x0721f500, + 0x2621f502, + 0x8087f102, + 0x0684b608, + 0xb70089cf, + 0x95220080, +/* 0x02ba: ctx_init_strand_loop */ + 0x8ed008fe, + 0x408ed000, + 0xb6808acf, + 0xa0b606a5, + 0x00eabb01, + 0xb60480b6, + 0x1bf40192, + 0x08e4b6e8, + 0xf1f2efbc, + 0xb6085c87, + 0x94bd0684, + 0xd00399f0, + 0x00f80089, +/* 0x02ec: error */ + 0xe7f1e0f9, + 0xe3f09814, + 0x8d21f440, + 0x041ce0b7, + 0xf401f7f0, + 0xe0fc8d21, +/* 0x0306: init */ + 0x04bd00f8, + 0xf10004fe, + 0xf0120017, + 0x12d00227, + 0x3e17f100, + 0x0010fe04, + 0x040017f1, + 0xf0c010d0, + 0x12d00427, + 0x1031f400, + 0x060817f1, + 0xcf0614b6, + 0x37f00012, + 0x1f24f001, + 0xb60432bb, + 0x02800132, + 0x04038003, + 0x040010b7, + 0x800012cf, + 0x27f10002, + 0x24b60800, + 0x0022cf06, +/* 0x035f: init_find_chipset */ + 0xb65817f0, + 0x13980c10, + 0x0432b800, + 0xb00b0bf4, + 0x1bf40034, +/* 0x0373: init_context */ + 0xf100f8f1, + 0xb6080027, + 0x22cf0624, + 0xf134bd40, + 0xb6070047, + 0x25950644, + 0x0045d008, + 0xbd4045d0, + 0x58f4bde4, + 0x1f58021e, + 0x020e4003, + 0xf5040f40, + 0xbb013d21, + 0x3fbb002f, + 0x041e5800, + 0x40051f58, + 0x0f400a0e, + 0x3d21f50c, + 0x030e9801, + 0xbb00effd, + 0x3ebb002e, + 0x0040b700, + 0x0235b613, + 0xb60043d0, + 0x35b60825, + 0x0120b606, + 0xb60130b6, + 0x34b60824, + 0x022fb908, + 0x026321f5, + 0xf1003fbb, + 0xb6080017, + 0x13d00614, + 0x0010b740, + 0xf024bd08, + 0x12d01f29, +/* 0x0401: main */ + 0x0031f400, + 0xf00028f4, + 0x21f41cd7, + 0xf401f439, + 0xf404e4b0, + 0x81fe1e18, + 0x0627f001, + 0x12fd20bd, + 0x01e4b604, + 0xfe051efd, + 0x21f50018, + 0x0ef404c3, +/* 0x0431: main_not_ctx_xfer */ + 0x10ef94d3, + 0xf501f5f0, + 0xf402ec21, +/* 0x043e: ih */ + 0x80f9c60e, + 0xf90188fe, + 0xf990f980, + 0xf9b0f9a0, + 0xf9e0f9d0, + 0x800acff0, + 0xf404abc4, + 0xb7f11d0b, + 0xd7f01900, + 0x40becf1c, + 0xf400bfcf, + 0xb0b70421, + 0xe7f00400, + 0x00bed001, +/* 0x0474: ih_no_fifo */ + 0xfc400ad0, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x048f: hub_barrier_done */ + 0xf001f800, + 0x0e9801f7, + 0x04febb00, + 0x9418e7f1, + 0xf440e3f0, + 0x00f88d21, +/* 0x04a4: ctx_redswitch */ + 0x0614e7f1, + 0xf006e4b6, + 0xefd020f7, + 0x08f7f000, +/* 0x04b4: ctx_redswitch_delay */ + 0xf401f2b6, + 0xf7f1fd1b, + 0xefd00a20, +/* 0x04c3: ctx_xfer */ + 0xf100f800, + 0xb60a0417, + 0x1fd00614, + 0x0711f400, + 0x04a421f5, +/* 0x04d4: ctx_xfer_not_load */ + 0x4afc17f1, + 0xf00213f0, + 0x12d00c27, + 0x0721f500, + 0xfc27f102, + 0x0223f047, + 0xf00020d0, + 0x20b6012c, + 0x0012d003, + 0xf001acf0, + 0xb7f002a5, + 0x50b3f000, + 0xb6000c98, + 0xbcbb0fc4, + 0x010c9800, + 0xf0020d98, + 0x21f500e7, + 0xacf0015c, + 0x04a5f001, + 0x4000b7f1, + 0x9850b3f0, + 0xc4b6000c, + 0x00bcbb0f, + 0x98050c98, + 0x0f98060d, + 0x00e7f104, + 0x5c21f508, + 0x0721f501, + 0x0601f402, +/* 0x054b: ctx_xfer_post */ + 0xf11412f4, + 0xf04afc17, + 0x27f00213, + 0x0012d00d, + 0x020721f5, +/* 0x055c: ctx_xfer_done */ + 0x048f21f5, + 0x000000f8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc new file mode 100644 index 00000000000..7b715fda276 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc @@ -0,0 +1,451 @@ +/* fuc microcode for nve0 PGRAPH/GPC + * + * Copyright 2011 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 + */ + +/* To build: + * m4 nve0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grgpc.fuc.h + */ + +/* TODO + * - bracket certain functions with scratch writes, useful for debugging + * - watchdog timer around ctx operations + */ + +.section #nve0_grgpc_data +include(`nve0.fuc') +gpc_id: .b32 0 +gpc_mmio_list_head: .b32 0 +gpc_mmio_list_tail: .b32 0 + +tpc_count: .b32 0 +tpc_mask: .b32 0 +tpc_mmio_list_head: .b32 0 +tpc_mmio_list_tail: .b32 0 + +cmd_queue: queue_init + +// chipset descriptions +chipsets: +.b8 0xe4 0 0 0 +.b16 #nve4_gpc_mmio_head +.b16 #nve4_gpc_mmio_tail +.b16 #nve4_tpc_mmio_head +.b16 #nve4_tpc_mmio_tail +.b8 0xe7 0 0 0 +.b16 #nve4_gpc_mmio_head +.b16 #nve4_gpc_mmio_tail +.b16 #nve4_tpc_mmio_head +.b16 #nve4_tpc_mmio_tail +.b8 0 0 0 0 + +// GPC mmio lists +nve4_gpc_mmio_head: +mmctx_data(0x000380, 1) +mmctx_data(0x000400, 2) +mmctx_data(0x00040c, 3) +mmctx_data(0x000450, 9) +mmctx_data(0x000600, 1) +mmctx_data(0x000684, 1) +mmctx_data(0x000700, 5) +mmctx_data(0x000800, 1) +mmctx_data(0x000808, 3) +mmctx_data(0x000828, 1) +mmctx_data(0x000830, 1) +mmctx_data(0x0008d8, 1) +mmctx_data(0x0008e0, 1) +mmctx_data(0x0008e8, 6) +mmctx_data(0x00091c, 1) +mmctx_data(0x000924, 3) +mmctx_data(0x000b00, 1) +mmctx_data(0x000b08, 6) +mmctx_data(0x000bb8, 1) +mmctx_data(0x000c08, 1) +mmctx_data(0x000c10, 8) +mmctx_data(0x000c40, 1) +mmctx_data(0x000c6c, 1) +mmctx_data(0x000c80, 1) +mmctx_data(0x000c8c, 1) +mmctx_data(0x001000, 3) +mmctx_data(0x001014, 1) +mmctx_data(0x003024, 1) +mmctx_data(0x0030c0, 2) +mmctx_data(0x0030e4, 1) +mmctx_data(0x003100, 6) +mmctx_data(0x0031d0, 1) +mmctx_data(0x0031e0, 2) +nve4_gpc_mmio_tail: + +// TPC mmio lists +nve4_tpc_mmio_head: +mmctx_data(0x000048, 1) +mmctx_data(0x000064, 1) +mmctx_data(0x000088, 1) +mmctx_data(0x000200, 6) +mmctx_data(0x00021c, 2) +mmctx_data(0x000230, 1) +mmctx_data(0x0002c4, 1) +mmctx_data(0x000400, 3) +mmctx_data(0x000420, 3) +mmctx_data(0x0004e8, 1) +mmctx_data(0x0004f4, 1) +mmctx_data(0x000604, 4) +mmctx_data(0x000644, 22) +mmctx_data(0x0006ac, 2) +mmctx_data(0x0006c8, 1) +mmctx_data(0x000730, 8) +mmctx_data(0x000758, 1) +mmctx_data(0x000778, 1) +nve4_tpc_mmio_tail: + +.section #nve0_grgpc_code +bra #init +define(`include_code') +include(`nve0.fuc') + +// reports an exception to the host +// +// In: $r15 error code (see nve0.fuc) +// +error: + push $r14 + mov $r14 -0x67ec // 0x9814 + sethi $r14 0x400000 + call #nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code + add b32 $r14 0x41c + mov $r15 1 + call #nv_wr32 // HUB_CTXCTL_INTR_UP_SET + pop $r14 + ret + +// GPC fuc initialisation, executed by triggering ucode start, will +// fall through to main loop after completion. +// +// Input: +// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh) +// CC_SCRATCH[1]: context base +// +// Output: +// CC_SCRATCH[0]: +// 31:31: set to signal completion +// CC_SCRATCH[1]: +// 31:0: GPC context size +// +init: + clear b32 $r0 + mov $sp $r0 + + // enable fifo access + mov $r1 0x1200 + mov $r2 2 + iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE + + // setup i0 handler, and route all interrupts to it + mov $r1 #ih + mov $iv0 $r1 + mov $r1 0x400 + iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH + + // enable fifo interrupt + mov $r2 4 + iowr I[$r1 + 0x000] $r2 // INTR_EN_SET + + // enable interrupts + bset $flags ie0 + + // figure out which GPC we are, and how many TPCs we have + mov $r1 0x608 + shl b32 $r1 6 + iord $r2 I[$r1 + 0x000] // UNITS + mov $r3 1 + and $r2 0x1f + shl b32 $r3 $r2 + sub b32 $r3 1 + st b32 D[$r0 + #tpc_count] $r2 + st b32 D[$r0 + #tpc_mask] $r3 + add b32 $r1 0x400 + iord $r2 I[$r1 + 0x000] // MYINDEX + st b32 D[$r0 + #gpc_id] $r2 + + // find context data for this chipset + mov $r2 0x800 + shl b32 $r2 6 + iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0] + mov $r1 #chipsets - 12 + init_find_chipset: + add b32 $r1 12 + ld b32 $r3 D[$r1 + 0x00] + cmpu b32 $r3 $r2 + bra e #init_context + cmpu b32 $r3 0 + bra ne #init_find_chipset + // unknown chipset + ret + + // initialise context base, and size tracking + init_context: + mov $r2 0x800 + shl b32 $r2 6 + iord $r2 I[$r2 + 0x100] // CC_SCRATCH[1], initial base + clear b32 $r3 // track GPC context size here + + // set mmctx base addresses now so we don't have to do it later, + // they don't currently ever change + mov $r4 0x700 + shl b32 $r4 6 + shr b32 $r5 $r2 8 + iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE + iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE + + // calculate GPC mmio context size, store the chipset-specific + // mmio list pointers somewhere we can get at them later without + // re-parsing the chipset list + clear b32 $r14 + clear b32 $r15 + ld b16 $r14 D[$r1 + 4] + ld b16 $r15 D[$r1 + 6] + st b16 D[$r0 + #gpc_mmio_list_head] $r14 + st b16 D[$r0 + #gpc_mmio_list_tail] $r15 + call #mmctx_size + add b32 $r2 $r15 + add b32 $r3 $r15 + + // calculate per-TPC mmio context size, store the list pointers + ld b16 $r14 D[$r1 + 8] + ld b16 $r15 D[$r1 + 10] + st b16 D[$r0 + #tpc_mmio_list_head] $r14 + st b16 D[$r0 + #tpc_mmio_list_tail] $r15 + call #mmctx_size + ld b32 $r14 D[$r0 + #tpc_count] + mulu $r14 $r15 + add b32 $r2 $r14 + add b32 $r3 $r14 + + // round up base/size to 256 byte boundary (for strand SWBASE) + add b32 $r4 0x1300 + shr b32 $r3 2 + iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!? + shr b32 $r2 8 + shr b32 $r3 6 + add b32 $r2 1 + add b32 $r3 1 + shl b32 $r2 8 + shl b32 $r3 8 + + // calculate size of strand context data + mov b32 $r15 $r2 + call #strand_ctx_init + add b32 $r3 $r15 + + // save context size, and tell HUB we're done + mov $r1 0x800 + shl b32 $r1 6 + iowr I[$r1 + 0x100] $r3 // CC_SCRATCH[1] = context size + add b32 $r1 0x800 + clear b32 $r2 + bset $r2 31 + iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000 + +// Main program loop, very simple, sleeps until woken up by the interrupt +// handler, pulls a command from the queue and executes its handler +// +main: + bset $flags $p0 + sleep $p0 + mov $r13 #cmd_queue + call #queue_get + bra $p1 #main + + // 0x0000-0x0003 are all context transfers + cmpu b32 $r14 0x04 + bra nc #main_not_ctx_xfer + // fetch $flags and mask off $p1/$p2 + mov $r1 $flags + mov $r2 0x0006 + not b32 $r2 + and $r1 $r2 + // set $p1/$p2 according to transfer type + shl b32 $r14 1 + or $r1 $r14 + mov $flags $r1 + // transfer context data + call #ctx_xfer + bra #main + + main_not_ctx_xfer: + shl b32 $r15 $r14 16 + or $r15 E_BAD_COMMAND + call #error + bra #main + +// interrupt handler +ih: + push $r8 + mov $r8 $flags + push $r8 + push $r9 + push $r10 + push $r11 + push $r13 + push $r14 + push $r15 + + // incoming fifo command? + iord $r10 I[$r0 + 0x200] // INTR + and $r11 $r10 0x00000004 + bra e #ih_no_fifo + // queue incoming fifo command for later processing + mov $r11 0x1900 + mov $r13 #cmd_queue + iord $r14 I[$r11 + 0x100] // FIFO_CMD + iord $r15 I[$r11 + 0x000] // FIFO_DATA + call #queue_put + add b32 $r11 0x400 + mov $r14 1 + iowr I[$r11 + 0x000] $r14 // FIFO_ACK + + // ack, and wake up main() + ih_no_fifo: + iowr I[$r0 + 0x100] $r10 // INTR_ACK + + pop $r15 + pop $r14 + pop $r13 + pop $r11 + pop $r10 + pop $r9 + pop $r8 + mov $flags $r8 + pop $r8 + bclr $flags $p0 + iret + +// Set this GPC's bit in HUB_BAR, used to signal completion of various +// activities to the HUB fuc +// +hub_barrier_done: + mov $r15 1 + ld b32 $r14 D[$r0 + #gpc_id] + shl b32 $r15 $r14 + mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET + sethi $r14 0x400000 + call #nv_wr32 + ret + +// Disables various things, waits a bit, and re-enables them.. +// +// Not sure how exactly this helps, perhaps "ENABLE" is not such a +// good description for the bits we turn off? Anyways, without this, +// funny things happen. +// +ctx_redswitch: + mov $r14 0x614 + shl b32 $r14 6 + mov $r15 0x020 + iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER + mov $r15 8 + ctx_redswitch_delay: + sub b32 $r15 1 + bra ne #ctx_redswitch_delay + mov $r15 0xa20 + iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER + ret + +// Transfer GPC context data between GPU and storage area +// +// In: $r15 context base address +// $p1 clear on save, set on load +// $p2 set if opposite direction done/will be done, so: +// on save it means: "a load will follow this save" +// on load it means: "a save preceeded this load" +// +ctx_xfer: + // set context base address + mov $r1 0xa04 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r15// MEM_BASE + bra not $p1 #ctx_xfer_not_load + call #ctx_redswitch + ctx_xfer_not_load: + + // strands + mov $r1 0x4afc + sethi $r1 0x20000 + mov $r2 0xc + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c + call #strand_wait + mov $r2 0x47fc + sethi $r2 0x20000 + iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 + xbit $r2 $flags $p1 + add b32 $r2 3 + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) + + // mmio context + xbit $r10 $flags $p1 // direction + or $r10 2 // first + mov $r11 0x0000 + sethi $r11 0x500000 + ld b32 $r12 D[$r0 + #gpc_id] + shl b32 $r12 15 + add b32 $r11 $r12 // base = NV_PGRAPH_GPCn + ld b32 $r12 D[$r0 + #gpc_mmio_list_head] + ld b32 $r13 D[$r0 + #gpc_mmio_list_tail] + mov $r14 0 // not multi + call #mmctx_xfer + + // per-TPC mmio context + xbit $r10 $flags $p1 // direction + or $r10 4 // last + mov $r11 0x4000 + sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0 + ld b32 $r12 D[$r0 + #gpc_id] + shl b32 $r12 15 + add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0 + ld b32 $r12 D[$r0 + #tpc_mmio_list_head] + ld b32 $r13 D[$r0 + #tpc_mmio_list_tail] + ld b32 $r15 D[$r0 + #tpc_mask] + mov $r14 0x800 // stride = 0x800 + call #mmctx_xfer + + // wait for strands to finish + call #strand_wait + + // if load, or a save without a load following, do some + // unknown stuff that's done after finishing a block of + // strand commands + bra $p1 #ctx_xfer_post + bra not $p2 #ctx_xfer_done + ctx_xfer_post: + mov $r1 0x4afc + sethi $r1 0x20000 + mov $r2 0xd + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d + call #strand_wait + + // mark completion in HUB's barrier + ctx_xfer_done: + call #hub_barrier_done + ret + +.align 256 diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h new file mode 100644 index 00000000000..26c2165bad0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h @@ -0,0 +1,530 @@ +uint32_t nve0_grgpc_data[] = { +/* 0x0000: gpc_id */ + 0x00000000, +/* 0x0004: gpc_mmio_list_head */ + 0x00000000, +/* 0x0008: gpc_mmio_list_tail */ + 0x00000000, +/* 0x000c: tpc_count */ + 0x00000000, +/* 0x0010: tpc_mask */ + 0x00000000, +/* 0x0014: tpc_mmio_list_head */ + 0x00000000, +/* 0x0018: tpc_mmio_list_tail */ + 0x00000000, +/* 0x001c: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0064: chipsets */ + 0x000000e4, + 0x01040080, + 0x014c0104, + 0x000000e7, + 0x01040080, + 0x014c0104, + 0x00000000, +/* 0x0080: nve4_gpc_mmio_head */ + 0x00000380, + 0x04000400, + 0x0800040c, + 0x20000450, + 0x00000600, + 0x00000684, + 0x10000700, + 0x00000800, + 0x08000808, + 0x00000828, + 0x00000830, + 0x000008d8, + 0x000008e0, + 0x140008e8, + 0x0000091c, + 0x08000924, + 0x00000b00, + 0x14000b08, + 0x00000bb8, + 0x00000c08, + 0x1c000c10, + 0x00000c40, + 0x00000c6c, + 0x00000c80, + 0x00000c8c, + 0x08001000, + 0x00001014, + 0x00003024, + 0x040030c0, + 0x000030e4, + 0x14003100, + 0x000031d0, + 0x040031e0, +/* 0x0104: nve4_gpc_mmio_tail */ +/* 0x0104: nve4_tpc_mmio_head */ + 0x00000048, + 0x00000064, + 0x00000088, + 0x14000200, + 0x0400021c, + 0x00000230, + 0x000002c4, + 0x08000400, + 0x08000420, + 0x000004e8, + 0x000004f4, + 0x0c000604, + 0x54000644, + 0x040006ac, + 0x000006c8, + 0x1c000730, + 0x00000758, + 0x00000778, +}; + +uint32_t nve0_grgpc_code[] = { + 0x03060ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0x0489b808, + 0xf00c1bf4, + 0x21f502f7, + 0x00f802ec, +/* 0x001c: queue_put_next */ + 0xb60798c4, + 0x8dbb0384, + 0x0880b600, + 0x80008e80, + 0x90b6018f, + 0x0f94f001, + 0xf801d980, +/* 0x0039: queue_get */ + 0x0131f400, + 0x9800d898, + 0x89b801d9, + 0x210bf404, + 0xb60789c4, + 0x9dbb0394, + 0x0890b600, + 0x98009e98, + 0x80b6019f, + 0x0f84f001, + 0xf400d880, +/* 0x0066: queue_get_done */ + 0x00f80132, +/* 0x0068: nv_rd32 */ + 0x0728b7f1, + 0xb906b4b6, + 0xc9f002ec, + 0x00bcd01f, +/* 0x0078: nv_rd32_wait */ + 0xc800bccf, + 0x1bf41fcc, + 0x06a7f0fa, + 0x010321f5, + 0xf840bfcf, +/* 0x008d: nv_wr32 */ + 0x28b7f100, + 0x06b4b607, + 0xb980bfd0, + 0xc9f002ec, + 0x1ec9f01f, +/* 0x00a3: nv_wr32_wait */ + 0xcf00bcd0, + 0xccc800bc, + 0xfa1bf41f, +/* 0x00ae: watchdog_reset */ + 0x87f100f8, + 0x84b60430, + 0x1ff9f006, + 0xf8008fd0, +/* 0x00bd: watchdog_clear */ + 0x3087f100, + 0x0684b604, + 0xf80080d0, +/* 0x00c9: wait_donez */ + 0x3c87f100, + 0x0684b608, + 0x99f094bd, + 0x0089d000, + 0x081887f1, + 0xd00684b6, +/* 0x00e2: wait_done_wait_donez */ + 0x87f1008a, + 0x84b60400, + 0x0088cf06, + 0xf4888aff, + 0x87f1f31b, + 0x84b6085c, + 0xf094bd06, + 0x89d00099, +/* 0x0103: wait_doneo */ + 0xf100f800, + 0xb6083c87, + 0x94bd0684, + 0xd00099f0, + 0x87f10089, + 0x84b60818, + 0x008ad006, +/* 0x011c: wait_done_wait_doneo */ + 0x040087f1, + 0xcf0684b6, + 0x8aff0088, + 0xf30bf488, + 0x085c87f1, + 0xbd0684b6, + 0x0099f094, + 0xf80089d0, +/* 0x013d: mmctx_size */ +/* 0x013f: nv_mmctx_size_loop */ + 0x9894bd00, + 0x85b600e8, + 0x0180b61a, + 0xbb0284b6, + 0xe0b60098, + 0x04efb804, + 0xb9eb1bf4, + 0x00f8029f, +/* 0x015c: mmctx_xfer */ + 0x083c87f1, + 0xbd0684b6, + 0x0199f094, + 0xf10089d0, + 0xb6071087, + 0x94bd0684, + 0xf405bbfd, + 0x8bd0090b, + 0x0099f000, +/* 0x0180: mmctx_base_disabled */ + 0xf405eefd, + 0x8ed00c0b, + 0xc08fd080, +/* 0x018f: mmctx_multi_disabled */ + 0xb70199f0, + 0xc8010080, + 0xb4b600ab, + 0x0cb9f010, + 0xb601aec8, + 0xbefd11e4, + 0x008bd005, +/* 0x01a8: mmctx_exec_loop */ +/* 0x01a8: mmctx_wait_free */ + 0xf0008ecf, + 0x0bf41fe4, + 0x00ce98fa, + 0xd005e9fd, + 0xc0b6c08e, + 0x04cdb804, + 0xc8e81bf4, + 0x1bf402ab, +/* 0x01c9: mmctx_fini_wait */ + 0x008bcf18, + 0xb01fb4f0, + 0x1bf410b4, + 0x02a7f0f7, + 0xf4c921f4, +/* 0x01de: mmctx_stop */ + 0xabc81b0e, + 0x10b4b600, + 0xf00cb9f0, + 0x8bd012b9, +/* 0x01ed: mmctx_stop_wait */ + 0x008bcf00, + 0xf412bbc8, +/* 0x01f6: mmctx_done */ + 0x87f1fa1b, + 0x84b6085c, + 0xf094bd06, + 0x89d00199, +/* 0x0207: strand_wait */ + 0xf900f800, + 0x02a7f0a0, + 0xfcc921f4, +/* 0x0213: strand_pre */ + 0xf100f8a0, + 0xf04afc87, + 0x97f00283, + 0x0089d00c, + 0x020721f5, +/* 0x0226: strand_post */ + 0x87f100f8, + 0x83f04afc, + 0x0d97f002, + 0xf50089d0, + 0xf8020721, +/* 0x0239: strand_set */ + 0xfca7f100, + 0x02a3f04f, + 0x0500aba2, + 0xd00fc7f0, + 0xc7f000ac, + 0x00bcd00b, + 0x020721f5, + 0xf000aed0, + 0xbcd00ac7, + 0x0721f500, +/* 0x0263: strand_ctx_init */ + 0xf100f802, + 0xb6083c87, + 0x94bd0684, + 0xd00399f0, + 0x21f50089, + 0xe7f00213, + 0x3921f503, + 0xfca7f102, + 0x02a3f046, + 0x0400aba0, + 0xf040a0d0, + 0xbcd001c7, + 0x0721f500, + 0x010c9202, + 0xf000acd0, + 0xbcd002c7, + 0x0721f500, + 0x2621f502, + 0x8087f102, + 0x0684b608, + 0xb70089cf, + 0x95220080, +/* 0x02ba: ctx_init_strand_loop */ + 0x8ed008fe, + 0x408ed000, + 0xb6808acf, + 0xa0b606a5, + 0x00eabb01, + 0xb60480b6, + 0x1bf40192, + 0x08e4b6e8, + 0xf1f2efbc, + 0xb6085c87, + 0x94bd0684, + 0xd00399f0, + 0x00f80089, +/* 0x02ec: error */ + 0xe7f1e0f9, + 0xe3f09814, + 0x8d21f440, + 0x041ce0b7, + 0xf401f7f0, + 0xe0fc8d21, +/* 0x0306: init */ + 0x04bd00f8, + 0xf10004fe, + 0xf0120017, + 0x12d00227, + 0x3e17f100, + 0x0010fe04, + 0x040017f1, + 0xf0c010d0, + 0x12d00427, + 0x1031f400, + 0x060817f1, + 0xcf0614b6, + 0x37f00012, + 0x1f24f001, + 0xb60432bb, + 0x02800132, + 0x04038003, + 0x040010b7, + 0x800012cf, + 0x27f10002, + 0x24b60800, + 0x0022cf06, +/* 0x035f: init_find_chipset */ + 0xb65817f0, + 0x13980c10, + 0x0432b800, + 0xb00b0bf4, + 0x1bf40034, +/* 0x0373: init_context */ + 0xf100f8f1, + 0xb6080027, + 0x22cf0624, + 0xf134bd40, + 0xb6070047, + 0x25950644, + 0x0045d008, + 0xbd4045d0, + 0x58f4bde4, + 0x1f58021e, + 0x020e4003, + 0xf5040f40, + 0xbb013d21, + 0x3fbb002f, + 0x041e5800, + 0x40051f58, + 0x0f400a0e, + 0x3d21f50c, + 0x030e9801, + 0xbb00effd, + 0x3ebb002e, + 0x0040b700, + 0x0235b613, + 0xb60043d0, + 0x35b60825, + 0x0120b606, + 0xb60130b6, + 0x34b60824, + 0x022fb908, + 0x026321f5, + 0xf1003fbb, + 0xb6080017, + 0x13d00614, + 0x0010b740, + 0xf024bd08, + 0x12d01f29, +/* 0x0401: main */ + 0x0031f400, + 0xf00028f4, + 0x21f41cd7, + 0xf401f439, + 0xf404e4b0, + 0x81fe1e18, + 0x0627f001, + 0x12fd20bd, + 0x01e4b604, + 0xfe051efd, + 0x21f50018, + 0x0ef404c3, +/* 0x0431: main_not_ctx_xfer */ + 0x10ef94d3, + 0xf501f5f0, + 0xf402ec21, +/* 0x043e: ih */ + 0x80f9c60e, + 0xf90188fe, + 0xf990f980, + 0xf9b0f9a0, + 0xf9e0f9d0, + 0x800acff0, + 0xf404abc4, + 0xb7f11d0b, + 0xd7f01900, + 0x40becf1c, + 0xf400bfcf, + 0xb0b70421, + 0xe7f00400, + 0x00bed001, +/* 0x0474: ih_no_fifo */ + 0xfc400ad0, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x048f: hub_barrier_done */ + 0xf001f800, + 0x0e9801f7, + 0x04febb00, + 0x9418e7f1, + 0xf440e3f0, + 0x00f88d21, +/* 0x04a4: ctx_redswitch */ + 0x0614e7f1, + 0xf006e4b6, + 0xefd020f7, + 0x08f7f000, +/* 0x04b4: ctx_redswitch_delay */ + 0xf401f2b6, + 0xf7f1fd1b, + 0xefd00a20, +/* 0x04c3: ctx_xfer */ + 0xf100f800, + 0xb60a0417, + 0x1fd00614, + 0x0711f400, + 0x04a421f5, +/* 0x04d4: ctx_xfer_not_load */ + 0x4afc17f1, + 0xf00213f0, + 0x12d00c27, + 0x0721f500, + 0xfc27f102, + 0x0223f047, + 0xf00020d0, + 0x20b6012c, + 0x0012d003, + 0xf001acf0, + 0xb7f002a5, + 0x50b3f000, + 0xb6000c98, + 0xbcbb0fc4, + 0x010c9800, + 0xf0020d98, + 0x21f500e7, + 0xacf0015c, + 0x04a5f001, + 0x4000b7f1, + 0x9850b3f0, + 0xc4b6000c, + 0x00bcbb0f, + 0x98050c98, + 0x0f98060d, + 0x00e7f104, + 0x5c21f508, + 0x0721f501, + 0x0601f402, +/* 0x054b: ctx_xfer_post */ + 0xf11412f4, + 0xf04afc17, + 0x27f00213, + 0x0012d00d, + 0x020721f5, +/* 0x055c: ctx_xfer_done */ + 0x048f21f5, + 0x000000f8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc new file mode 100644 index 00000000000..acfc457654b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc @@ -0,0 +1,856 @@ +/* fuc microcode for nvc0 PGRAPH/HUB + * + * Copyright 2011 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 + */ + +/* To build: + * m4 hubnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o hubnvc0.fuc.h + */ + +.section #nvc0_grhub_data +include(`nvc0.fuc') +gpc_count: .b32 0 +rop_count: .b32 0 +cmd_queue: queue_init +hub_mmio_list_head: .b32 0 +hub_mmio_list_tail: .b32 0 + +ctx_current: .b32 0 + +chipsets: +.b8 0xc0 0 0 0 +.b16 #nvc0_hub_mmio_head +.b16 #nvc0_hub_mmio_tail +.b8 0xc1 0 0 0 +.b16 #nvc0_hub_mmio_head +.b16 #nvc1_hub_mmio_tail +.b8 0xc3 0 0 0 +.b16 #nvc0_hub_mmio_head +.b16 #nvc0_hub_mmio_tail +.b8 0xc4 0 0 0 +.b16 #nvc0_hub_mmio_head +.b16 #nvc0_hub_mmio_tail +.b8 0xc8 0 0 0 +.b16 #nvc0_hub_mmio_head +.b16 #nvc0_hub_mmio_tail +.b8 0xce 0 0 0 +.b16 #nvc0_hub_mmio_head +.b16 #nvc0_hub_mmio_tail +.b8 0xcf 0 0 0 +.b16 #nvc0_hub_mmio_head +.b16 #nvc0_hub_mmio_tail +.b8 0xd9 0 0 0 +.b16 #nvd9_hub_mmio_head +.b16 #nvd9_hub_mmio_tail +.b8 0 0 0 0 + +nvc0_hub_mmio_head: +mmctx_data(0x17e91c, 2) +mmctx_data(0x400204, 2) +mmctx_data(0x404004, 11) +mmctx_data(0x404044, 1) +mmctx_data(0x404094, 14) +mmctx_data(0x4040d0, 7) +mmctx_data(0x4040f8, 1) +mmctx_data(0x404130, 3) +mmctx_data(0x404150, 3) +mmctx_data(0x404164, 2) +mmctx_data(0x404174, 3) +mmctx_data(0x404200, 8) +mmctx_data(0x404404, 14) +mmctx_data(0x404460, 4) +mmctx_data(0x404480, 1) +mmctx_data(0x404498, 1) +mmctx_data(0x404604, 4) +mmctx_data(0x404618, 32) +mmctx_data(0x404698, 21) +mmctx_data(0x4046f0, 2) +mmctx_data(0x404700, 22) +mmctx_data(0x405800, 1) +mmctx_data(0x405830, 3) +mmctx_data(0x405854, 1) +mmctx_data(0x405870, 4) +mmctx_data(0x405a00, 2) +mmctx_data(0x405a18, 1) +mmctx_data(0x406020, 1) +mmctx_data(0x406028, 4) +mmctx_data(0x4064a8, 2) +mmctx_data(0x4064b4, 2) +mmctx_data(0x407804, 1) +mmctx_data(0x40780c, 6) +mmctx_data(0x4078bc, 1) +mmctx_data(0x408000, 7) +mmctx_data(0x408064, 1) +mmctx_data(0x408800, 3) +mmctx_data(0x408900, 4) +mmctx_data(0x408980, 1) +nvc0_hub_mmio_tail: +mmctx_data(0x4064c0, 2) +nvc1_hub_mmio_tail: + +nvd9_hub_mmio_head: +mmctx_data(0x17e91c, 2) +mmctx_data(0x400204, 2) +mmctx_data(0x404004, 10) +mmctx_data(0x404044, 1) +mmctx_data(0x404094, 14) +mmctx_data(0x4040d0, 7) +mmctx_data(0x4040f8, 1) +mmctx_data(0x404130, 3) +mmctx_data(0x404150, 3) +mmctx_data(0x404164, 2) +mmctx_data(0x404178, 2) +mmctx_data(0x404200, 8) +mmctx_data(0x404404, 14) +mmctx_data(0x404460, 4) +mmctx_data(0x404480, 1) +mmctx_data(0x404498, 1) +mmctx_data(0x404604, 4) +mmctx_data(0x404618, 32) +mmctx_data(0x404698, 21) +mmctx_data(0x4046f0, 2) +mmctx_data(0x404700, 22) +mmctx_data(0x405800, 1) +mmctx_data(0x405830, 3) +mmctx_data(0x405854, 1) +mmctx_data(0x405870, 4) +mmctx_data(0x405a00, 2) +mmctx_data(0x405a18, 1) +mmctx_data(0x406020, 1) +mmctx_data(0x406028, 4) +mmctx_data(0x4064a8, 2) +mmctx_data(0x4064b4, 5) +mmctx_data(0x407804, 1) +mmctx_data(0x40780c, 6) +mmctx_data(0x4078bc, 1) +mmctx_data(0x408000, 7) +mmctx_data(0x408064, 1) +mmctx_data(0x408800, 3) +mmctx_data(0x408900, 4) +mmctx_data(0x408980, 1) +nvd9_hub_mmio_tail: + +.align 256 +chan_data: +chan_mmio_count: .b32 0 +chan_mmio_address: .b32 0 + +.align 256 +xfer_data: .b32 0 + +.section #nvc0_grhub_code +bra #init +define(`include_code') +include(`nvc0.fuc') + +// reports an exception to the host +// +// In: $r15 error code (see nvc0.fuc) +// +error: + push $r14 + mov $r14 0x814 + shl b32 $r14 6 + iowr I[$r14 + 0x000] $r15 // CC_SCRATCH[5] = error code + mov $r14 0xc1c + shl b32 $r14 6 + mov $r15 1 + iowr I[$r14 + 0x000] $r15 // INTR_UP_SET + pop $r14 + ret + +// HUB fuc initialisation, executed by triggering ucode start, will +// fall through to main loop after completion. +// +// Input: +// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh) +// +// Output: +// CC_SCRATCH[0]: +// 31:31: set to signal completion +// CC_SCRATCH[1]: +// 31:0: total PGRAPH context size +// +init: + clear b32 $r0 + mov $sp $r0 + mov $xdbase $r0 + + // enable fifo access + mov $r1 0x1200 + mov $r2 2 + iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE + + // setup i0 handler, and route all interrupts to it + mov $r1 #ih + mov $iv0 $r1 + mov $r1 0x400 + iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH + + // route HUB_CHANNEL_SWITCH to fuc interrupt 8 + mov $r3 0x404 + shl b32 $r3 6 + mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8 + iowr I[$r3 + 0x000] $r2 + + // not sure what these are, route them because NVIDIA does, and + // the IRQ handler will signal the host if we ever get one.. we + // may find out if/why we need to handle these if so.. + // + mov $r2 0x2004 + iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9 + mov $r2 0x200b + iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10 + mov $r2 0x200c + iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15 + + // enable all INTR_UP interrupts + mov $r2 0xc24 + shl b32 $r2 6 + not b32 $r3 $r0 + iowr I[$r2] $r3 + + // enable fifo, ctxsw, 9, 10, 15 interrupts + mov $r2 -0x78fc // 0x8704 + sethi $r2 0 + iowr I[$r1 + 0x000] $r2 // INTR_EN_SET + + // fifo level triggered, rest edge + sub b32 $r1 0x100 + mov $r2 4 + iowr I[$r1] $r2 + + // enable interrupts + bset $flags ie0 + + // fetch enabled GPC/ROP counts + mov $r14 -0x69fc // 0x409604 + sethi $r14 0x400000 + call #nv_rd32 + extr $r1 $r15 16:20 + st b32 D[$r0 + #rop_count] $r1 + and $r15 0x1f + st b32 D[$r0 + #gpc_count] $r15 + + // set BAR_REQMASK to GPC mask + mov $r1 1 + shl b32 $r1 $r15 + sub b32 $r1 1 + mov $r2 0x40c + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r1 + iowr I[$r2 + 0x100] $r1 + + // find context data for this chipset + mov $r2 0x800 + shl b32 $r2 6 + iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0] + mov $r15 #chipsets - 8 + init_find_chipset: + add b32 $r15 8 + ld b32 $r3 D[$r15 + 0x00] + cmpu b32 $r3 $r2 + bra e #init_context + cmpu b32 $r3 0 + bra ne #init_find_chipset + // unknown chipset + ret + + // context size calculation, reserve first 256 bytes for use by fuc + init_context: + mov $r1 256 + + // calculate size of mmio context data + ld b16 $r14 D[$r15 + 4] + ld b16 $r15 D[$r15 + 6] + sethi $r14 0 + st b32 D[$r0 + #hub_mmio_list_head] $r14 + st b32 D[$r0 + #hub_mmio_list_tail] $r15 + call #mmctx_size + + // set mmctx base addresses now so we don't have to do it later, + // they don't (currently) ever change + mov $r3 0x700 + shl b32 $r3 6 + shr b32 $r4 $r1 8 + iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE + iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE + add b32 $r3 0x1300 + add b32 $r1 $r15 + shr b32 $r15 2 + iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!? + + // strands, base offset needs to be aligned to 256 bytes + shr b32 $r1 8 + add b32 $r1 1 + shl b32 $r1 8 + mov b32 $r15 $r1 + call #strand_ctx_init + add b32 $r1 $r15 + + // initialise each GPC in sequence by passing in the offset of its + // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which + // has previously been uploaded by the host) running. + // + // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31 + // when it has completed, and return the size of its context data + // in GPCn_CC_SCRATCH[1] + // + ld b32 $r3 D[$r0 + #gpc_count] + mov $r4 0x2000 + sethi $r4 0x500000 + init_gpc: + // setup, and start GPC ucode running + add b32 $r14 $r4 0x804 + mov b32 $r15 $r1 + call #nv_wr32 // CC_SCRATCH[1] = ctx offset + add b32 $r14 $r4 0x800 + mov b32 $r15 $r2 + call #nv_wr32 // CC_SCRATCH[0] = chipset + add b32 $r14 $r4 0x10c + clear b32 $r15 + call #nv_wr32 + add b32 $r14 $r4 0x104 + call #nv_wr32 // ENTRY + add b32 $r14 $r4 0x100 + mov $r15 2 // CTRL_START_TRIGGER + call #nv_wr32 // CTRL + + // wait for it to complete, and adjust context size + add b32 $r14 $r4 0x800 + init_gpc_wait: + call #nv_rd32 + xbit $r15 $r15 31 + bra e #init_gpc_wait + add b32 $r14 $r4 0x804 + call #nv_rd32 + add b32 $r1 $r15 + + // next! + add b32 $r4 0x8000 + sub b32 $r3 1 + bra ne #init_gpc + + // save context size, and tell host we're ready + mov $r2 0x800 + shl b32 $r2 6 + iowr I[$r2 + 0x100] $r1 // CC_SCRATCH[1] = context size + add b32 $r2 0x800 + clear b32 $r1 + bset $r1 31 + iowr I[$r2 + 0x000] $r1 // CC_SCRATCH[0] |= 0x80000000 + +// Main program loop, very simple, sleeps until woken up by the interrupt +// handler, pulls a command from the queue and executes its handler +// +main: + // sleep until we have something to do + bset $flags $p0 + sleep $p0 + mov $r13 #cmd_queue + call #queue_get + bra $p1 #main + + // context switch, requested by GPU? + cmpu b32 $r14 0x4001 + bra ne #main_not_ctx_switch + trace_set(T_AUTO) + mov $r1 0xb00 + shl b32 $r1 6 + iord $r2 I[$r1 + 0x100] // CHAN_NEXT + iord $r1 I[$r1 + 0x000] // CHAN_CUR + + xbit $r3 $r1 31 + bra e #chsw_no_prev + xbit $r3 $r2 31 + bra e #chsw_prev_no_next + push $r2 + mov b32 $r2 $r1 + trace_set(T_SAVE) + bclr $flags $p1 + bset $flags $p2 + call #ctx_xfer + trace_clr(T_SAVE); + pop $r2 + trace_set(T_LOAD); + bset $flags $p1 + call #ctx_xfer + trace_clr(T_LOAD); + bra #chsw_done + chsw_prev_no_next: + push $r2 + mov b32 $r2 $r1 + bclr $flags $p1 + bclr $flags $p2 + call #ctx_xfer + pop $r2 + mov $r1 0xb00 + shl b32 $r1 6 + iowr I[$r1] $r2 + bra #chsw_done + chsw_no_prev: + xbit $r3 $r2 31 + bra e #chsw_done + bset $flags $p1 + bclr $flags $p2 + call #ctx_xfer + + // ack the context switch request + chsw_done: + mov $r1 0xb0c + shl b32 $r1 6 + mov $r2 1 + iowr I[$r1 + 0x000] $r2 // 0x409b0c + trace_clr(T_AUTO) + bra #main + + // request to set current channel? (*not* a context switch) + main_not_ctx_switch: + cmpu b32 $r14 0x0001 + bra ne #main_not_ctx_chan + mov b32 $r2 $r15 + call #ctx_chan + bra #main_done + + // request to store current channel context? + main_not_ctx_chan: + cmpu b32 $r14 0x0002 + bra ne #main_not_ctx_save + trace_set(T_SAVE) + bclr $flags $p1 + bclr $flags $p2 + call #ctx_xfer + trace_clr(T_SAVE) + bra #main_done + + main_not_ctx_save: + shl b32 $r15 $r14 16 + or $r15 E_BAD_COMMAND + call #error + bra #main + + main_done: + mov $r1 0x820 + shl b32 $r1 6 + clear b32 $r2 + bset $r2 31 + iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000 + bra #main + +// interrupt handler +ih: + push $r8 + mov $r8 $flags + push $r8 + push $r9 + push $r10 + push $r11 + push $r13 + push $r14 + push $r15 + + // incoming fifo command? + iord $r10 I[$r0 + 0x200] // INTR + and $r11 $r10 0x00000004 + bra e #ih_no_fifo + // queue incoming fifo command for later processing + mov $r11 0x1900 + mov $r13 #cmd_queue + iord $r14 I[$r11 + 0x100] // FIFO_CMD + iord $r15 I[$r11 + 0x000] // FIFO_DATA + call #queue_put + add b32 $r11 0x400 + mov $r14 1 + iowr I[$r11 + 0x000] $r14 // FIFO_ACK + + // context switch request? + ih_no_fifo: + and $r11 $r10 0x00000100 + bra e #ih_no_ctxsw + // enqueue a context switch for later processing + mov $r13 #cmd_queue + mov $r14 0x4001 + call #queue_put + + // anything we didn't handle, bring it to the host's attention + ih_no_ctxsw: + mov $r11 0x104 + not b32 $r11 + and $r11 $r10 $r11 + bra e #ih_no_other + mov $r10 0xc1c + shl b32 $r10 6 + iowr I[$r10] $r11 // INTR_UP_SET + + // ack, and wake up main() + ih_no_other: + iowr I[$r0 + 0x100] $r10 // INTR_ACK + + pop $r15 + pop $r14 + pop $r13 + pop $r11 + pop $r10 + pop $r9 + pop $r8 + mov $flags $r8 + pop $r8 + bclr $flags $p0 + iret + +// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done +ctx_4160s: + mov $r14 0x4160 + sethi $r14 0x400000 + mov $r15 1 + call #nv_wr32 + ctx_4160s_wait: + call #nv_rd32 + xbit $r15 $r15 4 + bra e #ctx_4160s_wait + ret + +// Without clearing again at end of xfer, some things cause PGRAPH +// to hang with STATUS=0x00000007 until it's cleared.. fbcon can +// still function with it set however... +ctx_4160c: + mov $r14 0x4160 + sethi $r14 0x400000 + clear b32 $r15 + call #nv_wr32 + ret + +// Again, not real sure +// +// In: $r15 value to set 0x404170 to +// +ctx_4170s: + mov $r14 0x4170 + sethi $r14 0x400000 + or $r15 0x10 + call #nv_wr32 + ret + +// Waits for a ctx_4170s() call to complete +// +ctx_4170w: + mov $r14 0x4170 + sethi $r14 0x400000 + call #nv_rd32 + and $r15 0x10 + bra ne #ctx_4170w + ret + +// Disables various things, waits a bit, and re-enables them.. +// +// Not sure how exactly this helps, perhaps "ENABLE" is not such a +// good description for the bits we turn off? Anyways, without this, +// funny things happen. +// +ctx_redswitch: + mov $r14 0x614 + shl b32 $r14 6 + mov $r15 0x270 + iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL + mov $r15 8 + ctx_redswitch_delay: + sub b32 $r15 1 + bra ne #ctx_redswitch_delay + mov $r15 0x770 + iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL + ret + +// Not a clue what this is for, except that unless the value is 0x10, the +// strand context is saved (and presumably restored) incorrectly.. +// +// In: $r15 value to set to (0x00/0x10 are used) +// +ctx_86c: + mov $r14 0x86c + shl b32 $r14 6 + iowr I[$r14] $r15 // HUB(0x86c) = val + mov $r14 -0x75ec + sethi $r14 0x400000 + call #nv_wr32 // ROP(0xa14) = val + mov $r14 -0x5794 + sethi $r14 0x410000 + call #nv_wr32 // GPC(0x86c) = val + ret + +// ctx_load - load's a channel's ctxctl data, and selects its vm +// +// In: $r2 channel address +// +ctx_load: + trace_set(T_CHAN) + + // switch to channel, somewhat magic in parts.. + mov $r10 12 // DONE_UNK12 + call #wait_donez + mov $r1 0xa24 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r0 // 0x409a24 + mov $r3 0xb00 + shl b32 $r3 6 + iowr I[$r3 + 0x100] $r2 // CHAN_NEXT + mov $r1 0xa0c + shl b32 $r1 6 + mov $r4 7 + iowr I[$r1 + 0x000] $r2 // MEM_CHAN + iowr I[$r1 + 0x100] $r4 // MEM_CMD + ctx_chan_wait_0: + iord $r4 I[$r1 + 0x100] + and $r4 0x1f + bra ne #ctx_chan_wait_0 + iowr I[$r3 + 0x000] $r2 // CHAN_CUR + + // load channel header, fetch PGRAPH context pointer + mov $xtargets $r0 + bclr $r2 31 + shl b32 $r2 4 + add b32 $r2 2 + + trace_set(T_LCHAN) + mov $r1 0xa04 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r2 // MEM_BASE + mov $r1 0xa20 + shl b32 $r1 6 + mov $r2 0x0002 + sethi $r2 0x80000000 + iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram + mov $r1 0x10 // chan + 0x0210 + mov $r2 #xfer_data + sethi $r2 0x00020000 // 16 bytes + xdld $r1 $r2 + xdwait + trace_clr(T_LCHAN) + + // update current context + ld b32 $r1 D[$r0 + #xfer_data + 4] + shl b32 $r1 24 + ld b32 $r2 D[$r0 + #xfer_data + 0] + shr b32 $r2 8 + or $r1 $r2 + st b32 D[$r0 + #ctx_current] $r1 + + // set transfer base to start of context, and fetch context header + trace_set(T_LCTXH) + mov $r2 0xa04 + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r1 // MEM_BASE + mov $r2 1 + mov $r1 0xa20 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm + mov $r1 #chan_data + sethi $r1 0x00060000 // 256 bytes + xdld $r0 $r1 + xdwait + trace_clr(T_LCTXH) + + trace_clr(T_CHAN) + ret + +// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as +// the active channel for ctxctl, but not actually transfer +// any context data. intended for use only during initial +// context construction. +// +// In: $r2 channel address +// +ctx_chan: + call #ctx_4160s + call #ctx_load + mov $r10 12 // DONE_UNK12 + call #wait_donez + mov $r1 0xa10 + shl b32 $r1 6 + mov $r2 5 + iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???) + ctx_chan_wait: + iord $r2 I[$r1 + 0x000] + or $r2 $r2 + bra ne #ctx_chan_wait + call #ctx_4160c + ret + +// Execute per-context state overrides list +// +// Only executed on the first load of a channel. Might want to look into +// removing this and having the host directly modify the channel's context +// to change this state... The nouveau DRM already builds this list as +// it's definitely needed for NVIDIA's, so we may as well use it for now +// +// Input: $r1 mmio list length +// +ctx_mmio_exec: + // set transfer base to be the mmio list + ld b32 $r3 D[$r0 + #chan_mmio_address] + mov $r2 0xa04 + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r3 // MEM_BASE + + clear b32 $r3 + ctx_mmio_loop: + // fetch next 256 bytes of mmio list if necessary + and $r4 $r3 0xff + bra ne #ctx_mmio_pull + mov $r5 #xfer_data + sethi $r5 0x00060000 // 256 bytes + xdld $r3 $r5 + xdwait + + // execute a single list entry + ctx_mmio_pull: + ld b32 $r14 D[$r4 + #xfer_data + 0x00] + ld b32 $r15 D[$r4 + #xfer_data + 0x04] + call #nv_wr32 + + // next! + add b32 $r3 8 + sub b32 $r1 1 + bra ne #ctx_mmio_loop + + // set transfer base back to the current context + ctx_mmio_done: + ld b32 $r3 D[$r0 + #ctx_current] + iowr I[$r2 + 0x000] $r3 // MEM_BASE + + // disable the mmio list now, we don't need/want to execute it again + st b32 D[$r0 + #chan_mmio_count] $r0 + mov $r1 #chan_data + sethi $r1 0x00060000 // 256 bytes + xdst $r0 $r1 + xdwait + ret + +// Transfer HUB context data between GPU and storage area +// +// In: $r2 channel address +// $p1 clear on save, set on load +// $p2 set if opposite direction done/will be done, so: +// on save it means: "a load will follow this save" +// on load it means: "a save preceeded this load" +// +ctx_xfer: + bra not $p1 #ctx_xfer_pre + bra $p2 #ctx_xfer_pre_load + ctx_xfer_pre: + mov $r15 0x10 + call #ctx_86c + call #ctx_4160s + bra not $p1 #ctx_xfer_exec + + ctx_xfer_pre_load: + mov $r15 2 + call #ctx_4170s + call #ctx_4170w + call #ctx_redswitch + clear b32 $r15 + call #ctx_4170s + call #ctx_load + + // fetch context pointer, and initiate xfer on all GPCs + ctx_xfer_exec: + ld b32 $r1 D[$r0 + #ctx_current] + mov $r2 0x414 + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset + mov $r14 -0x5b00 + sethi $r14 0x410000 + mov b32 $r15 $r1 + call #nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer + add b32 $r14 4 + xbit $r15 $flags $p1 + xbit $r2 $flags $p2 + shl b32 $r2 1 + or $r15 $r2 + call #nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type) + + // strands + mov $r1 0x4afc + sethi $r1 0x20000 + mov $r2 0xc + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c + call #strand_wait + mov $r2 0x47fc + sethi $r2 0x20000 + iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 + xbit $r2 $flags $p1 + add b32 $r2 3 + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) + + // mmio context + xbit $r10 $flags $p1 // direction + or $r10 6 // first, last + mov $r11 0 // base = 0 + ld b32 $r12 D[$r0 + #hub_mmio_list_head] + ld b32 $r13 D[$r0 + #hub_mmio_list_tail] + mov $r14 0 // not multi + call #mmctx_xfer + + // wait for GPCs to all complete + mov $r10 8 // DONE_BAR + call #wait_doneo + + // wait for strand xfer to complete + call #strand_wait + + // post-op + bra $p1 #ctx_xfer_post + mov $r10 12 // DONE_UNK12 + call #wait_donez + mov $r1 0xa10 + shl b32 $r1 6 + mov $r2 5 + iowr I[$r1] $r2 // MEM_CMD + ctx_xfer_post_save_wait: + iord $r2 I[$r1] + or $r2 $r2 + bra ne #ctx_xfer_post_save_wait + + bra $p2 #ctx_xfer_done + ctx_xfer_post: + mov $r15 2 + call #ctx_4170s + clear b32 $r15 + call #ctx_86c + call #strand_post + call #ctx_4170w + clear b32 $r15 + call #ctx_4170s + + bra not $p1 #ctx_xfer_no_post_mmio + ld b32 $r1 D[$r0 + #chan_mmio_count] + or $r1 $r1 + bra e #ctx_xfer_no_post_mmio + call #ctx_mmio_exec + + ctx_xfer_no_post_mmio: + call #ctx_4160c + + ctx_xfer_done: + ret + +.align 256 diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h new file mode 100644 index 00000000000..85a8d556f48 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h @@ -0,0 +1,927 @@ +uint32_t nvc0_grhub_data[] = { +/* 0x0000: gpc_count */ + 0x00000000, +/* 0x0004: rop_count */ + 0x00000000, +/* 0x0008: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0050: hub_mmio_list_head */ + 0x00000000, +/* 0x0054: hub_mmio_list_tail */ + 0x00000000, +/* 0x0058: ctx_current */ + 0x00000000, +/* 0x005c: chipsets */ + 0x000000c0, + 0x013c00a0, + 0x000000c1, + 0x014000a0, + 0x000000c3, + 0x013c00a0, + 0x000000c4, + 0x013c00a0, + 0x000000c8, + 0x013c00a0, + 0x000000ce, + 0x013c00a0, + 0x000000cf, + 0x013c00a0, + 0x000000d9, + 0x01dc0140, + 0x00000000, +/* 0x00a0: nvc0_hub_mmio_head */ + 0x0417e91c, + 0x04400204, + 0x28404004, + 0x00404044, + 0x34404094, + 0x184040d0, + 0x004040f8, + 0x08404130, + 0x08404150, + 0x04404164, + 0x08404174, + 0x1c404200, + 0x34404404, + 0x0c404460, + 0x00404480, + 0x00404498, + 0x0c404604, + 0x7c404618, + 0x50404698, + 0x044046f0, + 0x54404700, + 0x00405800, + 0x08405830, + 0x00405854, + 0x0c405870, + 0x04405a00, + 0x00405a18, + 0x00406020, + 0x0c406028, + 0x044064a8, + 0x044064b4, + 0x00407804, + 0x1440780c, + 0x004078bc, + 0x18408000, + 0x00408064, + 0x08408800, + 0x0c408900, + 0x00408980, +/* 0x013c: nvc0_hub_mmio_tail */ + 0x044064c0, +/* 0x0140: nvc1_hub_mmio_tail */ +/* 0x0140: nvd9_hub_mmio_head */ + 0x0417e91c, + 0x04400204, + 0x24404004, + 0x00404044, + 0x34404094, + 0x184040d0, + 0x004040f8, + 0x08404130, + 0x08404150, + 0x04404164, + 0x04404178, + 0x1c404200, + 0x34404404, + 0x0c404460, + 0x00404480, + 0x00404498, + 0x0c404604, + 0x7c404618, + 0x50404698, + 0x044046f0, + 0x54404700, + 0x00405800, + 0x08405830, + 0x00405854, + 0x0c405870, + 0x04405a00, + 0x00405a18, + 0x00406020, + 0x0c406028, + 0x044064a8, + 0x104064b4, + 0x00407804, + 0x1440780c, + 0x004078bc, + 0x18408000, + 0x00408064, + 0x08408800, + 0x0c408900, + 0x00408980, +/* 0x01dc: nvd9_hub_mmio_tail */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0200: chan_data */ +/* 0x0200: chan_mmio_count */ + 0x00000000, +/* 0x0204: chan_mmio_address */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0300: xfer_data */ + 0x00000000, +}; + +uint32_t nvc0_grhub_code[] = { + 0x03090ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0x0489b808, + 0xf00c1bf4, + 0x21f502f7, + 0x00f802ec, +/* 0x001c: queue_put_next */ + 0xb60798c4, + 0x8dbb0384, + 0x0880b600, + 0x80008e80, + 0x90b6018f, + 0x0f94f001, + 0xf801d980, +/* 0x0039: queue_get */ + 0x0131f400, + 0x9800d898, + 0x89b801d9, + 0x210bf404, + 0xb60789c4, + 0x9dbb0394, + 0x0890b600, + 0x98009e98, + 0x80b6019f, + 0x0f84f001, + 0xf400d880, +/* 0x0066: queue_get_done */ + 0x00f80132, +/* 0x0068: nv_rd32 */ + 0x0728b7f1, + 0xb906b4b6, + 0xc9f002ec, + 0x00bcd01f, +/* 0x0078: nv_rd32_wait */ + 0xc800bccf, + 0x1bf41fcc, + 0x06a7f0fa, + 0x010321f5, + 0xf840bfcf, +/* 0x008d: nv_wr32 */ + 0x28b7f100, + 0x06b4b607, + 0xb980bfd0, + 0xc9f002ec, + 0x1ec9f01f, +/* 0x00a3: nv_wr32_wait */ + 0xcf00bcd0, + 0xccc800bc, + 0xfa1bf41f, +/* 0x00ae: watchdog_reset */ + 0x87f100f8, + 0x84b60430, + 0x1ff9f006, + 0xf8008fd0, +/* 0x00bd: watchdog_clear */ + 0x3087f100, + 0x0684b604, + 0xf80080d0, +/* 0x00c9: wait_donez */ + 0x3c87f100, + 0x0684b608, + 0x99f094bd, + 0x0089d000, + 0x081887f1, + 0xd00684b6, +/* 0x00e2: wait_done_wait_donez */ + 0x87f1008a, + 0x84b60400, + 0x0088cf06, + 0xf4888aff, + 0x87f1f31b, + 0x84b6085c, + 0xf094bd06, + 0x89d00099, +/* 0x0103: wait_doneo */ + 0xf100f800, + 0xb6083c87, + 0x94bd0684, + 0xd00099f0, + 0x87f10089, + 0x84b60818, + 0x008ad006, +/* 0x011c: wait_done_wait_doneo */ + 0x040087f1, + 0xcf0684b6, + 0x8aff0088, + 0xf30bf488, + 0x085c87f1, + 0xbd0684b6, + 0x0099f094, + 0xf80089d0, +/* 0x013d: mmctx_size */ +/* 0x013f: nv_mmctx_size_loop */ + 0x9894bd00, + 0x85b600e8, + 0x0180b61a, + 0xbb0284b6, + 0xe0b60098, + 0x04efb804, + 0xb9eb1bf4, + 0x00f8029f, +/* 0x015c: mmctx_xfer */ + 0x083c87f1, + 0xbd0684b6, + 0x0199f094, + 0xf10089d0, + 0xb6071087, + 0x94bd0684, + 0xf405bbfd, + 0x8bd0090b, + 0x0099f000, +/* 0x0180: mmctx_base_disabled */ + 0xf405eefd, + 0x8ed00c0b, + 0xc08fd080, +/* 0x018f: mmctx_multi_disabled */ + 0xb70199f0, + 0xc8010080, + 0xb4b600ab, + 0x0cb9f010, + 0xb601aec8, + 0xbefd11e4, + 0x008bd005, +/* 0x01a8: mmctx_exec_loop */ +/* 0x01a8: mmctx_wait_free */ + 0xf0008ecf, + 0x0bf41fe4, + 0x00ce98fa, + 0xd005e9fd, + 0xc0b6c08e, + 0x04cdb804, + 0xc8e81bf4, + 0x1bf402ab, +/* 0x01c9: mmctx_fini_wait */ + 0x008bcf18, + 0xb01fb4f0, + 0x1bf410b4, + 0x02a7f0f7, + 0xf4c921f4, +/* 0x01de: mmctx_stop */ + 0xabc81b0e, + 0x10b4b600, + 0xf00cb9f0, + 0x8bd012b9, +/* 0x01ed: mmctx_stop_wait */ + 0x008bcf00, + 0xf412bbc8, +/* 0x01f6: mmctx_done */ + 0x87f1fa1b, + 0x84b6085c, + 0xf094bd06, + 0x89d00199, +/* 0x0207: strand_wait */ + 0xf900f800, + 0x02a7f0a0, + 0xfcc921f4, +/* 0x0213: strand_pre */ + 0xf100f8a0, + 0xf04afc87, + 0x97f00283, + 0x0089d00c, + 0x020721f5, +/* 0x0226: strand_post */ + 0x87f100f8, + 0x83f04afc, + 0x0d97f002, + 0xf50089d0, + 0xf8020721, +/* 0x0239: strand_set */ + 0xfca7f100, + 0x02a3f04f, + 0x0500aba2, + 0xd00fc7f0, + 0xc7f000ac, + 0x00bcd00b, + 0x020721f5, + 0xf000aed0, + 0xbcd00ac7, + 0x0721f500, +/* 0x0263: strand_ctx_init */ + 0xf100f802, + 0xb6083c87, + 0x94bd0684, + 0xd00399f0, + 0x21f50089, + 0xe7f00213, + 0x3921f503, + 0xfca7f102, + 0x02a3f046, + 0x0400aba0, + 0xf040a0d0, + 0xbcd001c7, + 0x0721f500, + 0x010c9202, + 0xf000acd0, + 0xbcd002c7, + 0x0721f500, + 0x2621f502, + 0x8087f102, + 0x0684b608, + 0xb70089cf, + 0x95220080, +/* 0x02ba: ctx_init_strand_loop */ + 0x8ed008fe, + 0x408ed000, + 0xb6808acf, + 0xa0b606a5, + 0x00eabb01, + 0xb60480b6, + 0x1bf40192, + 0x08e4b6e8, + 0xf1f2efbc, + 0xb6085c87, + 0x94bd0684, + 0xd00399f0, + 0x00f80089, +/* 0x02ec: error */ + 0xe7f1e0f9, + 0xe4b60814, + 0x00efd006, + 0x0c1ce7f1, + 0xf006e4b6, + 0xefd001f7, + 0xf8e0fc00, +/* 0x0309: init */ + 0xfe04bd00, + 0x07fe0004, + 0x0017f100, + 0x0227f012, + 0xf10012d0, + 0xfe05b917, + 0x17f10010, + 0x10d00400, + 0x0437f1c0, + 0x0634b604, + 0x200327f1, + 0xf10032d0, + 0xd0200427, + 0x27f10132, + 0x32d0200b, + 0x0c27f102, + 0x0732d020, + 0x0c2427f1, + 0xb90624b6, + 0x23d00003, + 0x0427f100, + 0x0023f087, + 0xb70012d0, + 0xf0010012, + 0x12d00427, + 0x1031f400, + 0x9604e7f1, + 0xf440e3f0, + 0xf1c76821, + 0x01018090, + 0x801ff4f0, + 0x17f0000f, + 0x041fbb01, + 0xf10112b6, + 0xb6040c27, + 0x21d00624, + 0x4021d000, + 0x080027f1, + 0xcf0624b6, + 0xf7f00022, +/* 0x03a9: init_find_chipset */ + 0x08f0b654, + 0xb800f398, + 0x0bf40432, + 0x0034b00b, + 0xf8f11bf4, +/* 0x03bd: init_context */ + 0x0017f100, + 0x02fe5801, + 0xf003ff58, + 0x0e8000e3, + 0x150f8014, + 0x013d21f5, + 0x070037f1, + 0x950634b6, + 0x34d00814, + 0x4034d000, + 0x130030b7, + 0xb6001fbb, + 0x3fd002f5, + 0x0815b600, + 0xb60110b6, + 0x1fb90814, + 0x6321f502, + 0x001fbb02, + 0xf1000398, + 0xf0200047, +/* 0x040e: init_gpc */ + 0x4ea05043, + 0x1fb90804, + 0x8d21f402, + 0x08004ea0, + 0xf4022fb9, + 0x4ea08d21, + 0xf4bd010c, + 0xa08d21f4, + 0xf401044e, + 0x4ea08d21, + 0xf7f00100, + 0x8d21f402, + 0x08004ea0, +/* 0x0440: init_gpc_wait */ + 0xc86821f4, + 0x0bf41fff, + 0x044ea0fa, + 0x6821f408, + 0xb7001fbb, + 0xb6800040, + 0x1bf40132, + 0x0027f1b4, + 0x0624b608, + 0xb74021d0, + 0xbd080020, + 0x1f19f014, +/* 0x0473: main */ + 0xf40021d0, + 0x28f40031, + 0x08d7f000, + 0xf43921f4, + 0xe4b1f401, + 0x1bf54001, + 0x87f100d1, + 0x84b6083c, + 0xf094bd06, + 0x89d00499, + 0x0017f100, + 0x0614b60b, + 0xcf4012cf, + 0x13c80011, + 0x7e0bf41f, + 0xf41f23c8, + 0x20f95a0b, + 0xf10212b9, + 0xb6083c87, + 0x94bd0684, + 0xd00799f0, + 0x32f40089, + 0x0231f401, + 0x082921f5, + 0x085c87f1, + 0xbd0684b6, + 0x0799f094, + 0xfc0089d0, + 0x3c87f120, + 0x0684b608, + 0x99f094bd, + 0x0089d006, + 0xf50131f4, + 0xf1082921, + 0xb6085c87, + 0x94bd0684, + 0xd00699f0, + 0x0ef40089, +/* 0x0509: chsw_prev_no_next */ + 0xb920f931, + 0x32f40212, + 0x0232f401, + 0x082921f5, + 0x17f120fc, + 0x14b60b00, + 0x0012d006, +/* 0x0527: chsw_no_prev */ + 0xc8130ef4, + 0x0bf41f23, + 0x0131f40d, + 0xf50232f4, +/* 0x0537: chsw_done */ + 0xf1082921, + 0xb60b0c17, + 0x27f00614, + 0x0012d001, + 0x085c87f1, + 0xbd0684b6, + 0x0499f094, + 0xf50089d0, +/* 0x0557: main_not_ctx_switch */ + 0xb0ff200e, + 0x1bf401e4, + 0x02f2b90d, + 0x07b521f5, +/* 0x0567: main_not_ctx_chan */ + 0xb0420ef4, + 0x1bf402e4, + 0x3c87f12e, + 0x0684b608, + 0x99f094bd, + 0x0089d007, + 0xf40132f4, + 0x21f50232, + 0x87f10829, + 0x84b6085c, + 0xf094bd06, + 0x89d00799, + 0x110ef400, +/* 0x0598: main_not_ctx_save */ + 0xf010ef94, + 0x21f501f5, + 0x0ef502ec, +/* 0x05a6: main_done */ + 0x17f1fed1, + 0x14b60820, + 0xf024bd06, + 0x12d01f29, + 0xbe0ef500, +/* 0x05b9: ih */ + 0xfe80f9fe, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0xc4800acf, + 0x0bf404ab, + 0x00b7f11d, + 0x08d7f019, + 0xcf40becf, + 0x21f400bf, + 0x00b0b704, + 0x01e7f004, +/* 0x05ef: ih_no_fifo */ + 0xe400bed0, + 0xf40100ab, + 0xd7f00d0b, + 0x01e7f108, + 0x0421f440, +/* 0x0600: ih_no_ctxsw */ + 0x0104b7f1, + 0xabffb0bd, + 0x0d0bf4b4, + 0x0c1ca7f1, + 0xd006a4b6, +/* 0x0616: ih_no_other */ + 0x0ad000ab, + 0xfcf0fc40, + 0xfcd0fce0, + 0xfca0fcb0, + 0xfe80fc90, + 0x80fc0088, + 0xf80032f4, +/* 0x0631: ctx_4160s */ + 0x60e7f101, + 0x40e3f041, + 0xf401f7f0, +/* 0x063e: ctx_4160s_wait */ + 0x21f48d21, + 0x04ffc868, + 0xf8fa0bf4, +/* 0x0649: ctx_4160c */ + 0x60e7f100, + 0x40e3f041, + 0x21f4f4bd, +/* 0x0657: ctx_4170s */ + 0xf100f88d, + 0xf04170e7, + 0xf5f040e3, + 0x8d21f410, +/* 0x0666: ctx_4170w */ + 0xe7f100f8, + 0xe3f04170, + 0x6821f440, + 0xf410f4f0, + 0x00f8f31b, +/* 0x0678: ctx_redswitch */ + 0x0614e7f1, + 0xf106e4b6, + 0xd00270f7, + 0xf7f000ef, +/* 0x0689: ctx_redswitch_delay */ + 0x01f2b608, + 0xf1fd1bf4, + 0xd00770f7, + 0x00f800ef, +/* 0x0698: ctx_86c */ + 0x086ce7f1, + 0xd006e4b6, + 0xe7f100ef, + 0xe3f08a14, + 0x8d21f440, + 0xa86ce7f1, + 0xf441e3f0, + 0x00f88d21, +/* 0x06b8: ctx_load */ + 0x083c87f1, + 0xbd0684b6, + 0x0599f094, + 0xf00089d0, + 0x21f40ca7, + 0x2417f1c9, + 0x0614b60a, + 0xf10010d0, + 0xb60b0037, + 0x32d00634, + 0x0c17f140, + 0x0614b60a, + 0xd00747f0, + 0x14d00012, +/* 0x06f1: ctx_chan_wait_0 */ + 0x4014cf40, + 0xf41f44f0, + 0x32d0fa1b, + 0x000bfe00, + 0xb61f2af0, + 0x20b60424, + 0x3c87f102, + 0x0684b608, + 0x99f094bd, + 0x0089d008, + 0x0a0417f1, + 0xd00614b6, + 0x17f10012, + 0x14b60a20, + 0x0227f006, + 0x800023f1, + 0xf00012d0, + 0x27f11017, + 0x23f00300, + 0x0512fa02, + 0x87f103f8, + 0x84b6085c, + 0xf094bd06, + 0x89d00899, + 0xc1019800, + 0x981814b6, + 0x25b6c002, + 0x0512fd08, + 0xf1160180, + 0xb6083c87, + 0x94bd0684, + 0xd00999f0, + 0x27f10089, + 0x24b60a04, + 0x0021d006, + 0xf10127f0, + 0xb60a2017, + 0x12d00614, + 0x0017f100, + 0x0613f002, + 0xf80501fa, + 0x5c87f103, + 0x0684b608, + 0x99f094bd, + 0x0089d009, + 0x085c87f1, + 0xbd0684b6, + 0x0599f094, + 0xf80089d0, +/* 0x07b5: ctx_chan */ + 0x3121f500, + 0xb821f506, + 0x0ca7f006, + 0xf1c921f4, + 0xb60a1017, + 0x27f00614, + 0x0012d005, +/* 0x07d0: ctx_chan_wait */ + 0xfd0012cf, + 0x1bf40522, + 0x4921f5fa, +/* 0x07df: ctx_mmio_exec */ + 0x9800f806, + 0x27f18103, + 0x24b60a04, + 0x0023d006, +/* 0x07ee: ctx_mmio_loop */ + 0x34c434bd, + 0x0f1bf4ff, + 0x030057f1, + 0xfa0653f0, + 0x03f80535, +/* 0x0800: ctx_mmio_pull */ + 0x98c04e98, + 0x21f4c14f, + 0x0830b68d, + 0xf40112b6, +/* 0x0812: ctx_mmio_done */ + 0x0398df1b, + 0x0023d016, + 0xf1800080, + 0xf0020017, + 0x01fa0613, + 0xf803f806, +/* 0x0829: ctx_xfer */ + 0x0611f400, +/* 0x082f: ctx_xfer_pre */ + 0xf01102f4, + 0x21f510f7, + 0x21f50698, + 0x11f40631, +/* 0x083d: ctx_xfer_pre_load */ + 0x02f7f01c, + 0x065721f5, + 0x066621f5, + 0x067821f5, + 0x21f5f4bd, + 0x21f50657, +/* 0x0856: ctx_xfer_exec */ + 0x019806b8, + 0x1427f116, + 0x0624b604, + 0xf10020d0, + 0xf0a500e7, + 0x1fb941e3, + 0x8d21f402, + 0xf004e0b6, + 0x2cf001fc, + 0x0124b602, + 0xf405f2fd, + 0x17f18d21, + 0x13f04afc, + 0x0c27f002, + 0xf50012d0, + 0xf1020721, + 0xf047fc27, + 0x20d00223, + 0x012cf000, + 0xd00320b6, + 0xacf00012, + 0x06a5f001, + 0x9800b7f0, + 0x0d98140c, + 0x00e7f015, + 0x015c21f5, + 0xf508a7f0, + 0xf5010321, + 0xf4020721, + 0xa7f02201, + 0xc921f40c, + 0x0a1017f1, + 0xf00614b6, + 0x12d00527, +/* 0x08dd: ctx_xfer_post_save_wait */ + 0x0012cf00, + 0xf40522fd, + 0x02f4fa1b, +/* 0x08e9: ctx_xfer_post */ + 0x02f7f032, + 0x065721f5, + 0x21f5f4bd, + 0x21f50698, + 0x21f50226, + 0xf4bd0666, + 0x065721f5, + 0x981011f4, + 0x11fd8001, + 0x070bf405, + 0x07df21f5, +/* 0x0914: ctx_xfer_no_post_mmio */ + 0x064921f5, +/* 0x0918: ctx_xfer_done */ + 0x000000f8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc new file mode 100644 index 00000000000..138eeaa2866 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc @@ -0,0 +1,780 @@ +/* fuc microcode for nve0 PGRAPH/HUB + * + * Copyright 2011 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 + */ + +/* To build: + * m4 nve0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grhub.fuc.h + */ + +.section #nve0_grhub_data +include(`nve0.fuc') +gpc_count: .b32 0 +rop_count: .b32 0 +cmd_queue: queue_init +hub_mmio_list_head: .b32 0 +hub_mmio_list_tail: .b32 0 + +ctx_current: .b32 0 + +chipsets: +.b8 0xe4 0 0 0 +.b16 #nve4_hub_mmio_head +.b16 #nve4_hub_mmio_tail +.b8 0xe7 0 0 0 +.b16 #nve4_hub_mmio_head +.b16 #nve4_hub_mmio_tail +.b8 0 0 0 0 + +nve4_hub_mmio_head: +mmctx_data(0x17e91c, 2) +mmctx_data(0x400204, 2) +mmctx_data(0x404010, 7) +mmctx_data(0x4040a8, 9) +mmctx_data(0x4040d0, 7) +mmctx_data(0x4040f8, 1) +mmctx_data(0x404130, 3) +mmctx_data(0x404150, 3) +mmctx_data(0x404164, 1) +mmctx_data(0x4041a0, 4) +mmctx_data(0x404200, 4) +mmctx_data(0x404404, 14) +mmctx_data(0x404460, 4) +mmctx_data(0x404480, 1) +mmctx_data(0x404498, 1) +mmctx_data(0x404604, 4) +mmctx_data(0x404618, 4) +mmctx_data(0x40462c, 2) +mmctx_data(0x404640, 1) +mmctx_data(0x404654, 1) +mmctx_data(0x404660, 1) +mmctx_data(0x404678, 19) +mmctx_data(0x4046c8, 3) +mmctx_data(0x404700, 3) +mmctx_data(0x404718, 10) +mmctx_data(0x404744, 2) +mmctx_data(0x404754, 1) +mmctx_data(0x405800, 1) +mmctx_data(0x405830, 3) +mmctx_data(0x405854, 1) +mmctx_data(0x405870, 4) +mmctx_data(0x405a00, 2) +mmctx_data(0x405a18, 1) +mmctx_data(0x405b00, 1) +mmctx_data(0x405b10, 1) +mmctx_data(0x406020, 1) +mmctx_data(0x406028, 4) +mmctx_data(0x4064a8, 2) +mmctx_data(0x4064b4, 2) +mmctx_data(0x4064c0, 12) +mmctx_data(0x4064fc, 1) +mmctx_data(0x407040, 1) +mmctx_data(0x407804, 1) +mmctx_data(0x40780c, 6) +mmctx_data(0x4078bc, 1) +mmctx_data(0x408000, 7) +mmctx_data(0x408064, 1) +mmctx_data(0x408800, 3) +mmctx_data(0x408840, 1) +mmctx_data(0x408900, 3) +mmctx_data(0x408980, 1) +nve4_hub_mmio_tail: + +.align 256 +chan_data: +chan_mmio_count: .b32 0 +chan_mmio_address: .b32 0 + +.align 256 +xfer_data: .b32 0 + +.section #nve0_grhub_code +bra #init +define(`include_code') +include(`nve0.fuc') + +// reports an exception to the host +// +// In: $r15 error code (see nve0.fuc) +// +error: + push $r14 + mov $r14 0x814 + shl b32 $r14 6 + iowr I[$r14 + 0x000] $r15 // CC_SCRATCH[5] = error code + mov $r14 0xc1c + shl b32 $r14 6 + mov $r15 1 + iowr I[$r14 + 0x000] $r15 // INTR_UP_SET + pop $r14 + ret + +// HUB fuc initialisation, executed by triggering ucode start, will +// fall through to main loop after completion. +// +// Input: +// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh) +// +// Output: +// CC_SCRATCH[0]: +// 31:31: set to signal completion +// CC_SCRATCH[1]: +// 31:0: total PGRAPH context size +// +init: + clear b32 $r0 + mov $sp $r0 + mov $xdbase $r0 + + // enable fifo access + mov $r1 0x1200 + mov $r2 2 + iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE + + // setup i0 handler, and route all interrupts to it + mov $r1 #ih + mov $iv0 $r1 + mov $r1 0x400 + iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH + + // route HUB_CHANNEL_SWITCH to fuc interrupt 8 + mov $r3 0x404 + shl b32 $r3 6 + mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8 + iowr I[$r3 + 0x000] $r2 + + // not sure what these are, route them because NVIDIA does, and + // the IRQ handler will signal the host if we ever get one.. we + // may find out if/why we need to handle these if so.. + // + mov $r2 0x2004 + iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9 + mov $r2 0x200b + iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10 + mov $r2 0x200c + iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15 + + // enable all INTR_UP interrupts + mov $r2 0xc24 + shl b32 $r2 6 + not b32 $r3 $r0 + iowr I[$r2] $r3 + + // enable fifo, ctxsw, 9, 10, 15 interrupts + mov $r2 -0x78fc // 0x8704 + sethi $r2 0 + iowr I[$r1 + 0x000] $r2 // INTR_EN_SET + + // fifo level triggered, rest edge + sub b32 $r1 0x100 + mov $r2 4 + iowr I[$r1] $r2 + + // enable interrupts + bset $flags ie0 + + // fetch enabled GPC/ROP counts + mov $r14 -0x69fc // 0x409604 + sethi $r14 0x400000 + call #nv_rd32 + extr $r1 $r15 16:20 + st b32 D[$r0 + #rop_count] $r1 + and $r15 0x1f + st b32 D[$r0 + #gpc_count] $r15 + + // set BAR_REQMASK to GPC mask + mov $r1 1 + shl b32 $r1 $r15 + sub b32 $r1 1 + mov $r2 0x40c + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r1 + iowr I[$r2 + 0x100] $r1 + + // find context data for this chipset + mov $r2 0x800 + shl b32 $r2 6 + iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0] + mov $r15 #chipsets - 8 + init_find_chipset: + add b32 $r15 8 + ld b32 $r3 D[$r15 + 0x00] + cmpu b32 $r3 $r2 + bra e #init_context + cmpu b32 $r3 0 + bra ne #init_find_chipset + // unknown chipset + ret + + // context size calculation, reserve first 256 bytes for use by fuc + init_context: + mov $r1 256 + + // calculate size of mmio context data + ld b16 $r14 D[$r15 + 4] + ld b16 $r15 D[$r15 + 6] + sethi $r14 0 + st b32 D[$r0 + #hub_mmio_list_head] $r14 + st b32 D[$r0 + #hub_mmio_list_tail] $r15 + call #mmctx_size + + // set mmctx base addresses now so we don't have to do it later, + // they don't (currently) ever change + mov $r3 0x700 + shl b32 $r3 6 + shr b32 $r4 $r1 8 + iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE + iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE + add b32 $r3 0x1300 + add b32 $r1 $r15 + shr b32 $r15 2 + iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!? + + // strands, base offset needs to be aligned to 256 bytes + shr b32 $r1 8 + add b32 $r1 1 + shl b32 $r1 8 + mov b32 $r15 $r1 + call #strand_ctx_init + add b32 $r1 $r15 + + // initialise each GPC in sequence by passing in the offset of its + // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which + // has previously been uploaded by the host) running. + // + // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31 + // when it has completed, and return the size of its context data + // in GPCn_CC_SCRATCH[1] + // + ld b32 $r3 D[$r0 + #gpc_count] + mov $r4 0x2000 + sethi $r4 0x500000 + init_gpc: + // setup, and start GPC ucode running + add b32 $r14 $r4 0x804 + mov b32 $r15 $r1 + call #nv_wr32 // CC_SCRATCH[1] = ctx offset + add b32 $r14 $r4 0x800 + mov b32 $r15 $r2 + call #nv_wr32 // CC_SCRATCH[0] = chipset + add b32 $r14 $r4 0x10c + clear b32 $r15 + call #nv_wr32 + add b32 $r14 $r4 0x104 + call #nv_wr32 // ENTRY + add b32 $r14 $r4 0x100 + mov $r15 2 // CTRL_START_TRIGGER + call #nv_wr32 // CTRL + + // wait for it to complete, and adjust context size + add b32 $r14 $r4 0x800 + init_gpc_wait: + call #nv_rd32 + xbit $r15 $r15 31 + bra e #init_gpc_wait + add b32 $r14 $r4 0x804 + call #nv_rd32 + add b32 $r1 $r15 + + // next! + add b32 $r4 0x8000 + sub b32 $r3 1 + bra ne #init_gpc + + // save context size, and tell host we're ready + mov $r2 0x800 + shl b32 $r2 6 + iowr I[$r2 + 0x100] $r1 // CC_SCRATCH[1] = context size + add b32 $r2 0x800 + clear b32 $r1 + bset $r1 31 + iowr I[$r2 + 0x000] $r1 // CC_SCRATCH[0] |= 0x80000000 + +// Main program loop, very simple, sleeps until woken up by the interrupt +// handler, pulls a command from the queue and executes its handler +// +main: + // sleep until we have something to do + bset $flags $p0 + sleep $p0 + mov $r13 #cmd_queue + call #queue_get + bra $p1 #main + + // context switch, requested by GPU? + cmpu b32 $r14 0x4001 + bra ne #main_not_ctx_switch + trace_set(T_AUTO) + mov $r1 0xb00 + shl b32 $r1 6 + iord $r2 I[$r1 + 0x100] // CHAN_NEXT + iord $r1 I[$r1 + 0x000] // CHAN_CUR + + xbit $r3 $r1 31 + bra e #chsw_no_prev + xbit $r3 $r2 31 + bra e #chsw_prev_no_next + push $r2 + mov b32 $r2 $r1 + trace_set(T_SAVE) + bclr $flags $p1 + bset $flags $p2 + call #ctx_xfer + trace_clr(T_SAVE); + pop $r2 + trace_set(T_LOAD); + bset $flags $p1 + call #ctx_xfer + trace_clr(T_LOAD); + bra #chsw_done + chsw_prev_no_next: + push $r2 + mov b32 $r2 $r1 + bclr $flags $p1 + bclr $flags $p2 + call #ctx_xfer + pop $r2 + mov $r1 0xb00 + shl b32 $r1 6 + iowr I[$r1] $r2 + bra #chsw_done + chsw_no_prev: + xbit $r3 $r2 31 + bra e #chsw_done + bset $flags $p1 + bclr $flags $p2 + call #ctx_xfer + + // ack the context switch request + chsw_done: + mov $r1 0xb0c + shl b32 $r1 6 + mov $r2 1 + iowr I[$r1 + 0x000] $r2 // 0x409b0c + trace_clr(T_AUTO) + bra #main + + // request to set current channel? (*not* a context switch) + main_not_ctx_switch: + cmpu b32 $r14 0x0001 + bra ne #main_not_ctx_chan + mov b32 $r2 $r15 + call #ctx_chan + bra #main_done + + // request to store current channel context? + main_not_ctx_chan: + cmpu b32 $r14 0x0002 + bra ne #main_not_ctx_save + trace_set(T_SAVE) + bclr $flags $p1 + bclr $flags $p2 + call #ctx_xfer + trace_clr(T_SAVE) + bra #main_done + + main_not_ctx_save: + shl b32 $r15 $r14 16 + or $r15 E_BAD_COMMAND + call #error + bra #main + + main_done: + mov $r1 0x820 + shl b32 $r1 6 + clear b32 $r2 + bset $r2 31 + iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000 + bra #main + +// interrupt handler +ih: + push $r8 + mov $r8 $flags + push $r8 + push $r9 + push $r10 + push $r11 + push $r13 + push $r14 + push $r15 + + // incoming fifo command? + iord $r10 I[$r0 + 0x200] // INTR + and $r11 $r10 0x00000004 + bra e #ih_no_fifo + // queue incoming fifo command for later processing + mov $r11 0x1900 + mov $r13 #cmd_queue + iord $r14 I[$r11 + 0x100] // FIFO_CMD + iord $r15 I[$r11 + 0x000] // FIFO_DATA + call #queue_put + add b32 $r11 0x400 + mov $r14 1 + iowr I[$r11 + 0x000] $r14 // FIFO_ACK + + // context switch request? + ih_no_fifo: + and $r11 $r10 0x00000100 + bra e #ih_no_ctxsw + // enqueue a context switch for later processing + mov $r13 #cmd_queue + mov $r14 0x4001 + call #queue_put + + // anything we didn't handle, bring it to the host's attention + ih_no_ctxsw: + mov $r11 0x104 + not b32 $r11 + and $r11 $r10 $r11 + bra e #ih_no_other + mov $r10 0xc1c + shl b32 $r10 6 + iowr I[$r10] $r11 // INTR_UP_SET + + // ack, and wake up main() + ih_no_other: + iowr I[$r0 + 0x100] $r10 // INTR_ACK + + pop $r15 + pop $r14 + pop $r13 + pop $r11 + pop $r10 + pop $r9 + pop $r8 + mov $flags $r8 + pop $r8 + bclr $flags $p0 + iret + +// Again, not real sure +// +// In: $r15 value to set 0x404170 to +// +ctx_4170s: + mov $r14 0x4170 + sethi $r14 0x400000 + or $r15 0x10 + call #nv_wr32 + ret + +// Waits for a ctx_4170s() call to complete +// +ctx_4170w: + mov $r14 0x4170 + sethi $r14 0x400000 + call #nv_rd32 + and $r15 0x10 + bra ne #ctx_4170w + ret + +// Disables various things, waits a bit, and re-enables them.. +// +// Not sure how exactly this helps, perhaps "ENABLE" is not such a +// good description for the bits we turn off? Anyways, without this, +// funny things happen. +// +ctx_redswitch: + mov $r14 0x614 + shl b32 $r14 6 + mov $r15 0x270 + iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL + mov $r15 8 + ctx_redswitch_delay: + sub b32 $r15 1 + bra ne #ctx_redswitch_delay + mov $r15 0x770 + iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL + ret + +// Not a clue what this is for, except that unless the value is 0x10, the +// strand context is saved (and presumably restored) incorrectly.. +// +// In: $r15 value to set to (0x00/0x10 are used) +// +ctx_86c: + mov $r14 0x86c + shl b32 $r14 6 + iowr I[$r14] $r15 // HUB(0x86c) = val + mov $r14 -0x75ec + sethi $r14 0x400000 + call #nv_wr32 // ROP(0xa14) = val + mov $r14 -0x5794 + sethi $r14 0x410000 + call #nv_wr32 // GPC(0x86c) = val + ret + +// ctx_load - load's a channel's ctxctl data, and selects its vm +// +// In: $r2 channel address +// +ctx_load: + trace_set(T_CHAN) + + // switch to channel, somewhat magic in parts.. + mov $r10 12 // DONE_UNK12 + call #wait_donez + mov $r1 0xa24 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r0 // 0x409a24 + mov $r3 0xb00 + shl b32 $r3 6 + iowr I[$r3 + 0x100] $r2 // CHAN_NEXT + mov $r1 0xa0c + shl b32 $r1 6 + mov $r4 7 + iowr I[$r1 + 0x000] $r2 // MEM_CHAN + iowr I[$r1 + 0x100] $r4 // MEM_CMD + ctx_chan_wait_0: + iord $r4 I[$r1 + 0x100] + and $r4 0x1f + bra ne #ctx_chan_wait_0 + iowr I[$r3 + 0x000] $r2 // CHAN_CUR + + // load channel header, fetch PGRAPH context pointer + mov $xtargets $r0 + bclr $r2 31 + shl b32 $r2 4 + add b32 $r2 2 + + trace_set(T_LCHAN) + mov $r1 0xa04 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r2 // MEM_BASE + mov $r1 0xa20 + shl b32 $r1 6 + mov $r2 0x0002 + sethi $r2 0x80000000 + iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram + mov $r1 0x10 // chan + 0x0210 + mov $r2 #xfer_data + sethi $r2 0x00020000 // 16 bytes + xdld $r1 $r2 + xdwait + trace_clr(T_LCHAN) + + // update current context + ld b32 $r1 D[$r0 + #xfer_data + 4] + shl b32 $r1 24 + ld b32 $r2 D[$r0 + #xfer_data + 0] + shr b32 $r2 8 + or $r1 $r2 + st b32 D[$r0 + #ctx_current] $r1 + + // set transfer base to start of context, and fetch context header + trace_set(T_LCTXH) + mov $r2 0xa04 + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r1 // MEM_BASE + mov $r2 1 + mov $r1 0xa20 + shl b32 $r1 6 + iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm + mov $r1 #chan_data + sethi $r1 0x00060000 // 256 bytes + xdld $r0 $r1 + xdwait + trace_clr(T_LCTXH) + + trace_clr(T_CHAN) + ret + +// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as +// the active channel for ctxctl, but not actually transfer +// any context data. intended for use only during initial +// context construction. +// +// In: $r2 channel address +// +ctx_chan: + call #ctx_load + mov $r10 12 // DONE_UNK12 + call #wait_donez + mov $r1 0xa10 + shl b32 $r1 6 + mov $r2 5 + iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???) + ctx_chan_wait: + iord $r2 I[$r1 + 0x000] + or $r2 $r2 + bra ne #ctx_chan_wait + ret + +// Execute per-context state overrides list +// +// Only executed on the first load of a channel. Might want to look into +// removing this and having the host directly modify the channel's context +// to change this state... The nouveau DRM already builds this list as +// it's definitely needed for NVIDIA's, so we may as well use it for now +// +// Input: $r1 mmio list length +// +ctx_mmio_exec: + // set transfer base to be the mmio list + ld b32 $r3 D[$r0 + #chan_mmio_address] + mov $r2 0xa04 + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r3 // MEM_BASE + + clear b32 $r3 + ctx_mmio_loop: + // fetch next 256 bytes of mmio list if necessary + and $r4 $r3 0xff + bra ne #ctx_mmio_pull + mov $r5 #xfer_data + sethi $r5 0x00060000 // 256 bytes + xdld $r3 $r5 + xdwait + + // execute a single list entry + ctx_mmio_pull: + ld b32 $r14 D[$r4 + #xfer_data + 0x00] + ld b32 $r15 D[$r4 + #xfer_data + 0x04] + call #nv_wr32 + + // next! + add b32 $r3 8 + sub b32 $r1 1 + bra ne #ctx_mmio_loop + + // set transfer base back to the current context + ctx_mmio_done: + ld b32 $r3 D[$r0 + #ctx_current] + iowr I[$r2 + 0x000] $r3 // MEM_BASE + + // disable the mmio list now, we don't need/want to execute it again + st b32 D[$r0 + #chan_mmio_count] $r0 + mov $r1 #chan_data + sethi $r1 0x00060000 // 256 bytes + xdst $r0 $r1 + xdwait + ret + +// Transfer HUB context data between GPU and storage area +// +// In: $r2 channel address +// $p1 clear on save, set on load +// $p2 set if opposite direction done/will be done, so: +// on save it means: "a load will follow this save" +// on load it means: "a save preceeded this load" +// +ctx_xfer: + bra not $p1 #ctx_xfer_pre + bra $p2 #ctx_xfer_pre_load + ctx_xfer_pre: + mov $r15 0x10 + call #ctx_86c + bra not $p1 #ctx_xfer_exec + + ctx_xfer_pre_load: + mov $r15 2 + call #ctx_4170s + call #ctx_4170w + call #ctx_redswitch + clear b32 $r15 + call #ctx_4170s + call #ctx_load + + // fetch context pointer, and initiate xfer on all GPCs + ctx_xfer_exec: + ld b32 $r1 D[$r0 + #ctx_current] + mov $r2 0x414 + shl b32 $r2 6 + iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset + mov $r14 -0x5b00 + sethi $r14 0x410000 + mov b32 $r15 $r1 + call #nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer + add b32 $r14 4 + xbit $r15 $flags $p1 + xbit $r2 $flags $p2 + shl b32 $r2 1 + or $r15 $r2 + call #nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type) + + // strands + mov $r1 0x4afc + sethi $r1 0x20000 + mov $r2 0xc + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c + call #strand_wait + mov $r2 0x47fc + sethi $r2 0x20000 + iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 + xbit $r2 $flags $p1 + add b32 $r2 3 + iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) + + // mmio context + xbit $r10 $flags $p1 // direction + or $r10 6 // first, last + mov $r11 0 // base = 0 + ld b32 $r12 D[$r0 + #hub_mmio_list_head] + ld b32 $r13 D[$r0 + #hub_mmio_list_tail] + mov $r14 0 // not multi + call #mmctx_xfer + + // wait for GPCs to all complete + mov $r10 8 // DONE_BAR + call #wait_doneo + + // wait for strand xfer to complete + call #strand_wait + + // post-op + bra $p1 #ctx_xfer_post + mov $r10 12 // DONE_UNK12 + call #wait_donez + mov $r1 0xa10 + shl b32 $r1 6 + mov $r2 5 + iowr I[$r1] $r2 // MEM_CMD + ctx_xfer_post_save_wait: + iord $r2 I[$r1] + or $r2 $r2 + bra ne #ctx_xfer_post_save_wait + + bra $p2 #ctx_xfer_done + ctx_xfer_post: + mov $r15 2 + call #ctx_4170s + clear b32 $r15 + call #ctx_86c + call #strand_post + call #ctx_4170w + clear b32 $r15 + call #ctx_4170s + + bra not $p1 #ctx_xfer_no_post_mmio + ld b32 $r1 D[$r0 + #chan_mmio_count] + or $r1 $r1 + bra e #ctx_xfer_no_post_mmio + call #ctx_mmio_exec + + ctx_xfer_no_post_mmio: + + ctx_xfer_done: + ret + +.align 256 diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h new file mode 100644 index 00000000000..decf0c60ca3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h @@ -0,0 +1,857 @@ +uint32_t nve0_grhub_data[] = { +/* 0x0000: gpc_count */ + 0x00000000, +/* 0x0004: rop_count */ + 0x00000000, +/* 0x0008: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0050: hub_mmio_list_head */ + 0x00000000, +/* 0x0054: hub_mmio_list_tail */ + 0x00000000, +/* 0x0058: ctx_current */ + 0x00000000, +/* 0x005c: chipsets */ + 0x000000e4, + 0x013c0070, + 0x000000e7, + 0x013c0070, + 0x00000000, +/* 0x0070: nve4_hub_mmio_head */ + 0x0417e91c, + 0x04400204, + 0x18404010, + 0x204040a8, + 0x184040d0, + 0x004040f8, + 0x08404130, + 0x08404150, + 0x00404164, + 0x0c4041a0, + 0x0c404200, + 0x34404404, + 0x0c404460, + 0x00404480, + 0x00404498, + 0x0c404604, + 0x0c404618, + 0x0440462c, + 0x00404640, + 0x00404654, + 0x00404660, + 0x48404678, + 0x084046c8, + 0x08404700, + 0x24404718, + 0x04404744, + 0x00404754, + 0x00405800, + 0x08405830, + 0x00405854, + 0x0c405870, + 0x04405a00, + 0x00405a18, + 0x00405b00, + 0x00405b10, + 0x00406020, + 0x0c406028, + 0x044064a8, + 0x044064b4, + 0x2c4064c0, + 0x004064fc, + 0x00407040, + 0x00407804, + 0x1440780c, + 0x004078bc, + 0x18408000, + 0x00408064, + 0x08408800, + 0x00408840, + 0x08408900, + 0x00408980, +/* 0x013c: nve4_hub_mmio_tail */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0200: chan_data */ +/* 0x0200: chan_mmio_count */ + 0x00000000, +/* 0x0204: chan_mmio_address */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0300: xfer_data */ + 0x00000000, +}; + +uint32_t nve0_grhub_code[] = { + 0x03090ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0x0489b808, + 0xf00c1bf4, + 0x21f502f7, + 0x00f802ec, +/* 0x001c: queue_put_next */ + 0xb60798c4, + 0x8dbb0384, + 0x0880b600, + 0x80008e80, + 0x90b6018f, + 0x0f94f001, + 0xf801d980, +/* 0x0039: queue_get */ + 0x0131f400, + 0x9800d898, + 0x89b801d9, + 0x210bf404, + 0xb60789c4, + 0x9dbb0394, + 0x0890b600, + 0x98009e98, + 0x80b6019f, + 0x0f84f001, + 0xf400d880, +/* 0x0066: queue_get_done */ + 0x00f80132, +/* 0x0068: nv_rd32 */ + 0x0728b7f1, + 0xb906b4b6, + 0xc9f002ec, + 0x00bcd01f, +/* 0x0078: nv_rd32_wait */ + 0xc800bccf, + 0x1bf41fcc, + 0x06a7f0fa, + 0x010321f5, + 0xf840bfcf, +/* 0x008d: nv_wr32 */ + 0x28b7f100, + 0x06b4b607, + 0xb980bfd0, + 0xc9f002ec, + 0x1ec9f01f, +/* 0x00a3: nv_wr32_wait */ + 0xcf00bcd0, + 0xccc800bc, + 0xfa1bf41f, +/* 0x00ae: watchdog_reset */ + 0x87f100f8, + 0x84b60430, + 0x1ff9f006, + 0xf8008fd0, +/* 0x00bd: watchdog_clear */ + 0x3087f100, + 0x0684b604, + 0xf80080d0, +/* 0x00c9: wait_donez */ + 0x3c87f100, + 0x0684b608, + 0x99f094bd, + 0x0089d000, + 0x081887f1, + 0xd00684b6, +/* 0x00e2: wait_done_wait_donez */ + 0x87f1008a, + 0x84b60400, + 0x0088cf06, + 0xf4888aff, + 0x87f1f31b, + 0x84b6085c, + 0xf094bd06, + 0x89d00099, +/* 0x0103: wait_doneo */ + 0xf100f800, + 0xb6083c87, + 0x94bd0684, + 0xd00099f0, + 0x87f10089, + 0x84b60818, + 0x008ad006, +/* 0x011c: wait_done_wait_doneo */ + 0x040087f1, + 0xcf0684b6, + 0x8aff0088, + 0xf30bf488, + 0x085c87f1, + 0xbd0684b6, + 0x0099f094, + 0xf80089d0, +/* 0x013d: mmctx_size */ +/* 0x013f: nv_mmctx_size_loop */ + 0x9894bd00, + 0x85b600e8, + 0x0180b61a, + 0xbb0284b6, + 0xe0b60098, + 0x04efb804, + 0xb9eb1bf4, + 0x00f8029f, +/* 0x015c: mmctx_xfer */ + 0x083c87f1, + 0xbd0684b6, + 0x0199f094, + 0xf10089d0, + 0xb6071087, + 0x94bd0684, + 0xf405bbfd, + 0x8bd0090b, + 0x0099f000, +/* 0x0180: mmctx_base_disabled */ + 0xf405eefd, + 0x8ed00c0b, + 0xc08fd080, +/* 0x018f: mmctx_multi_disabled */ + 0xb70199f0, + 0xc8010080, + 0xb4b600ab, + 0x0cb9f010, + 0xb601aec8, + 0xbefd11e4, + 0x008bd005, +/* 0x01a8: mmctx_exec_loop */ +/* 0x01a8: mmctx_wait_free */ + 0xf0008ecf, + 0x0bf41fe4, + 0x00ce98fa, + 0xd005e9fd, + 0xc0b6c08e, + 0x04cdb804, + 0xc8e81bf4, + 0x1bf402ab, +/* 0x01c9: mmctx_fini_wait */ + 0x008bcf18, + 0xb01fb4f0, + 0x1bf410b4, + 0x02a7f0f7, + 0xf4c921f4, +/* 0x01de: mmctx_stop */ + 0xabc81b0e, + 0x10b4b600, + 0xf00cb9f0, + 0x8bd012b9, +/* 0x01ed: mmctx_stop_wait */ + 0x008bcf00, + 0xf412bbc8, +/* 0x01f6: mmctx_done */ + 0x87f1fa1b, + 0x84b6085c, + 0xf094bd06, + 0x89d00199, +/* 0x0207: strand_wait */ + 0xf900f800, + 0x02a7f0a0, + 0xfcc921f4, +/* 0x0213: strand_pre */ + 0xf100f8a0, + 0xf04afc87, + 0x97f00283, + 0x0089d00c, + 0x020721f5, +/* 0x0226: strand_post */ + 0x87f100f8, + 0x83f04afc, + 0x0d97f002, + 0xf50089d0, + 0xf8020721, +/* 0x0239: strand_set */ + 0xfca7f100, + 0x02a3f04f, + 0x0500aba2, + 0xd00fc7f0, + 0xc7f000ac, + 0x00bcd00b, + 0x020721f5, + 0xf000aed0, + 0xbcd00ac7, + 0x0721f500, +/* 0x0263: strand_ctx_init */ + 0xf100f802, + 0xb6083c87, + 0x94bd0684, + 0xd00399f0, + 0x21f50089, + 0xe7f00213, + 0x3921f503, + 0xfca7f102, + 0x02a3f046, + 0x0400aba0, + 0xf040a0d0, + 0xbcd001c7, + 0x0721f500, + 0x010c9202, + 0xf000acd0, + 0xbcd002c7, + 0x0721f500, + 0x2621f502, + 0x8087f102, + 0x0684b608, + 0xb70089cf, + 0x95220080, +/* 0x02ba: ctx_init_strand_loop */ + 0x8ed008fe, + 0x408ed000, + 0xb6808acf, + 0xa0b606a5, + 0x00eabb01, + 0xb60480b6, + 0x1bf40192, + 0x08e4b6e8, + 0xf1f2efbc, + 0xb6085c87, + 0x94bd0684, + 0xd00399f0, + 0x00f80089, +/* 0x02ec: error */ + 0xe7f1e0f9, + 0xe4b60814, + 0x00efd006, + 0x0c1ce7f1, + 0xf006e4b6, + 0xefd001f7, + 0xf8e0fc00, +/* 0x0309: init */ + 0xfe04bd00, + 0x07fe0004, + 0x0017f100, + 0x0227f012, + 0xf10012d0, + 0xfe05b917, + 0x17f10010, + 0x10d00400, + 0x0437f1c0, + 0x0634b604, + 0x200327f1, + 0xf10032d0, + 0xd0200427, + 0x27f10132, + 0x32d0200b, + 0x0c27f102, + 0x0732d020, + 0x0c2427f1, + 0xb90624b6, + 0x23d00003, + 0x0427f100, + 0x0023f087, + 0xb70012d0, + 0xf0010012, + 0x12d00427, + 0x1031f400, + 0x9604e7f1, + 0xf440e3f0, + 0xf1c76821, + 0x01018090, + 0x801ff4f0, + 0x17f0000f, + 0x041fbb01, + 0xf10112b6, + 0xb6040c27, + 0x21d00624, + 0x4021d000, + 0x080027f1, + 0xcf0624b6, + 0xf7f00022, +/* 0x03a9: init_find_chipset */ + 0x08f0b654, + 0xb800f398, + 0x0bf40432, + 0x0034b00b, + 0xf8f11bf4, +/* 0x03bd: init_context */ + 0x0017f100, + 0x02fe5801, + 0xf003ff58, + 0x0e8000e3, + 0x150f8014, + 0x013d21f5, + 0x070037f1, + 0x950634b6, + 0x34d00814, + 0x4034d000, + 0x130030b7, + 0xb6001fbb, + 0x3fd002f5, + 0x0815b600, + 0xb60110b6, + 0x1fb90814, + 0x6321f502, + 0x001fbb02, + 0xf1000398, + 0xf0200047, +/* 0x040e: init_gpc */ + 0x4ea05043, + 0x1fb90804, + 0x8d21f402, + 0x08004ea0, + 0xf4022fb9, + 0x4ea08d21, + 0xf4bd010c, + 0xa08d21f4, + 0xf401044e, + 0x4ea08d21, + 0xf7f00100, + 0x8d21f402, + 0x08004ea0, +/* 0x0440: init_gpc_wait */ + 0xc86821f4, + 0x0bf41fff, + 0x044ea0fa, + 0x6821f408, + 0xb7001fbb, + 0xb6800040, + 0x1bf40132, + 0x0027f1b4, + 0x0624b608, + 0xb74021d0, + 0xbd080020, + 0x1f19f014, +/* 0x0473: main */ + 0xf40021d0, + 0x28f40031, + 0x08d7f000, + 0xf43921f4, + 0xe4b1f401, + 0x1bf54001, + 0x87f100d1, + 0x84b6083c, + 0xf094bd06, + 0x89d00499, + 0x0017f100, + 0x0614b60b, + 0xcf4012cf, + 0x13c80011, + 0x7e0bf41f, + 0xf41f23c8, + 0x20f95a0b, + 0xf10212b9, + 0xb6083c87, + 0x94bd0684, + 0xd00799f0, + 0x32f40089, + 0x0231f401, + 0x07fb21f5, + 0x085c87f1, + 0xbd0684b6, + 0x0799f094, + 0xfc0089d0, + 0x3c87f120, + 0x0684b608, + 0x99f094bd, + 0x0089d006, + 0xf50131f4, + 0xf107fb21, + 0xb6085c87, + 0x94bd0684, + 0xd00699f0, + 0x0ef40089, +/* 0x0509: chsw_prev_no_next */ + 0xb920f931, + 0x32f40212, + 0x0232f401, + 0x07fb21f5, + 0x17f120fc, + 0x14b60b00, + 0x0012d006, +/* 0x0527: chsw_no_prev */ + 0xc8130ef4, + 0x0bf41f23, + 0x0131f40d, + 0xf50232f4, +/* 0x0537: chsw_done */ + 0xf107fb21, + 0xb60b0c17, + 0x27f00614, + 0x0012d001, + 0x085c87f1, + 0xbd0684b6, + 0x0499f094, + 0xf50089d0, +/* 0x0557: main_not_ctx_switch */ + 0xb0ff200e, + 0x1bf401e4, + 0x02f2b90d, + 0x078f21f5, +/* 0x0567: main_not_ctx_chan */ + 0xb0420ef4, + 0x1bf402e4, + 0x3c87f12e, + 0x0684b608, + 0x99f094bd, + 0x0089d007, + 0xf40132f4, + 0x21f50232, + 0x87f107fb, + 0x84b6085c, + 0xf094bd06, + 0x89d00799, + 0x110ef400, +/* 0x0598: main_not_ctx_save */ + 0xf010ef94, + 0x21f501f5, + 0x0ef502ec, +/* 0x05a6: main_done */ + 0x17f1fed1, + 0x14b60820, + 0xf024bd06, + 0x12d01f29, + 0xbe0ef500, +/* 0x05b9: ih */ + 0xfe80f9fe, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0xc4800acf, + 0x0bf404ab, + 0x00b7f11d, + 0x08d7f019, + 0xcf40becf, + 0x21f400bf, + 0x00b0b704, + 0x01e7f004, +/* 0x05ef: ih_no_fifo */ + 0xe400bed0, + 0xf40100ab, + 0xd7f00d0b, + 0x01e7f108, + 0x0421f440, +/* 0x0600: ih_no_ctxsw */ + 0x0104b7f1, + 0xabffb0bd, + 0x0d0bf4b4, + 0x0c1ca7f1, + 0xd006a4b6, +/* 0x0616: ih_no_other */ + 0x0ad000ab, + 0xfcf0fc40, + 0xfcd0fce0, + 0xfca0fcb0, + 0xfe80fc90, + 0x80fc0088, + 0xf80032f4, +/* 0x0631: ctx_4170s */ + 0x70e7f101, + 0x40e3f041, + 0xf410f5f0, + 0x00f88d21, +/* 0x0640: ctx_4170w */ + 0x4170e7f1, + 0xf440e3f0, + 0xf4f06821, + 0xf31bf410, +/* 0x0652: ctx_redswitch */ + 0xe7f100f8, + 0xe4b60614, + 0x70f7f106, + 0x00efd002, +/* 0x0663: ctx_redswitch_delay */ + 0xb608f7f0, + 0x1bf401f2, + 0x70f7f1fd, + 0x00efd007, +/* 0x0672: ctx_86c */ + 0xe7f100f8, + 0xe4b6086c, + 0x00efd006, + 0x8a14e7f1, + 0xf440e3f0, + 0xe7f18d21, + 0xe3f0a86c, + 0x8d21f441, +/* 0x0692: ctx_load */ + 0x87f100f8, + 0x84b6083c, + 0xf094bd06, + 0x89d00599, + 0x0ca7f000, + 0xf1c921f4, + 0xb60a2417, + 0x10d00614, + 0x0037f100, + 0x0634b60b, + 0xf14032d0, + 0xb60a0c17, + 0x47f00614, + 0x0012d007, +/* 0x06cb: ctx_chan_wait_0 */ + 0xcf4014d0, + 0x44f04014, + 0xfa1bf41f, + 0xfe0032d0, + 0x2af0000b, + 0x0424b61f, + 0xf10220b6, + 0xb6083c87, + 0x94bd0684, + 0xd00899f0, + 0x17f10089, + 0x14b60a04, + 0x0012d006, + 0x0a2017f1, + 0xf00614b6, + 0x23f10227, + 0x12d08000, + 0x1017f000, + 0x030027f1, + 0xfa0223f0, + 0x03f80512, + 0x085c87f1, + 0xbd0684b6, + 0x0899f094, + 0x980089d0, + 0x14b6c101, + 0xc0029818, + 0xfd0825b6, + 0x01800512, + 0x3c87f116, + 0x0684b608, + 0x99f094bd, + 0x0089d009, + 0x0a0427f1, + 0xd00624b6, + 0x27f00021, + 0x2017f101, + 0x0614b60a, + 0xf10012d0, + 0xf0020017, + 0x01fa0613, + 0xf103f805, + 0xb6085c87, + 0x94bd0684, + 0xd00999f0, + 0x87f10089, + 0x84b6085c, + 0xf094bd06, + 0x89d00599, +/* 0x078f: ctx_chan */ + 0xf500f800, + 0xf0069221, + 0x21f40ca7, + 0x1017f1c9, + 0x0614b60a, + 0xd00527f0, +/* 0x07a6: ctx_chan_wait */ + 0x12cf0012, + 0x0522fd00, + 0xf8fa1bf4, +/* 0x07b1: ctx_mmio_exec */ + 0x81039800, + 0x0a0427f1, + 0xd00624b6, + 0x34bd0023, +/* 0x07c0: ctx_mmio_loop */ + 0xf4ff34c4, + 0x57f10f1b, + 0x53f00300, + 0x0535fa06, +/* 0x07d2: ctx_mmio_pull */ + 0x4e9803f8, + 0xc14f98c0, + 0xb68d21f4, + 0x12b60830, + 0xdf1bf401, +/* 0x07e4: ctx_mmio_done */ + 0xd0160398, + 0x00800023, + 0x0017f180, + 0x0613f002, + 0xf80601fa, +/* 0x07fb: ctx_xfer */ + 0xf400f803, + 0x02f40611, +/* 0x0801: ctx_xfer_pre */ + 0x10f7f00d, + 0x067221f5, +/* 0x080b: ctx_xfer_pre_load */ + 0xf01c11f4, + 0x21f502f7, + 0x21f50631, + 0x21f50640, + 0xf4bd0652, + 0x063121f5, + 0x069221f5, +/* 0x0824: ctx_xfer_exec */ + 0xf1160198, + 0xb6041427, + 0x20d00624, + 0x00e7f100, + 0x41e3f0a5, + 0xf4021fb9, + 0xe0b68d21, + 0x01fcf004, + 0xb6022cf0, + 0xf2fd0124, + 0x8d21f405, + 0x4afc17f1, + 0xf00213f0, + 0x12d00c27, + 0x0721f500, + 0xfc27f102, + 0x0223f047, + 0xf00020d0, + 0x20b6012c, + 0x0012d003, + 0xf001acf0, + 0xb7f006a5, + 0x140c9800, + 0xf0150d98, + 0x21f500e7, + 0xa7f0015c, + 0x0321f508, + 0x0721f501, + 0x2201f402, + 0xf40ca7f0, + 0x17f1c921, + 0x14b60a10, + 0x0527f006, +/* 0x08ab: ctx_xfer_post_save_wait */ + 0xcf0012d0, + 0x22fd0012, + 0xfa1bf405, +/* 0x08b7: ctx_xfer_post */ + 0xf02e02f4, + 0x21f502f7, + 0xf4bd0631, + 0x067221f5, + 0x022621f5, + 0x064021f5, + 0x21f5f4bd, + 0x11f40631, + 0x80019810, + 0xf40511fd, + 0x21f5070b, +/* 0x08e2: ctx_xfer_no_post_mmio */ +/* 0x08e2: ctx_xfer_done */ + 0x00f807b1, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc new file mode 100644 index 00000000000..e6b228844a3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc @@ -0,0 +1,400 @@ +/* fuc microcode util functions for nvc0 PGRAPH + * + * Copyright 2011 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)') +define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))') + +ifdef(`include_code', ` +// Error codes +define(`E_BAD_COMMAND', 0x01) +define(`E_CMD_OVERFLOW', 0x02) + +// Util macros to help with debugging ucode hangs etc +define(`T_WAIT', 0) +define(`T_MMCTX', 1) +define(`T_STRWAIT', 2) +define(`T_STRINIT', 3) +define(`T_AUTO', 4) +define(`T_CHAN', 5) +define(`T_LOAD', 6) +define(`T_SAVE', 7) +define(`T_LCHAN', 8) +define(`T_LCTXH', 9) + +define(`trace_set', ` + mov $r8 0x83c + shl b32 $r8 6 + clear b32 $r9 + bset $r9 $1 + iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7] +') + +define(`trace_clr', ` + mov $r8 0x85c + shl b32 $r8 6 + clear b32 $r9 + bset $r9 $1 + iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7] +') + +// queue_put - add request to queue +// +// In : $r13 queue pointer +// $r14 command +// $r15 data +// +queue_put: + // make sure we have space.. + ld b32 $r8 D[$r13 + 0x0] // GET + ld b32 $r9 D[$r13 + 0x4] // PUT + xor $r8 8 + cmpu b32 $r8 $r9 + bra ne #queue_put_next + mov $r15 E_CMD_OVERFLOW + call #error + ret + + // store cmd/data on queue + queue_put_next: + and $r8 $r9 7 + shl b32 $r8 3 + add b32 $r8 $r13 + add b32 $r8 8 + st b32 D[$r8 + 0x0] $r14 + st b32 D[$r8 + 0x4] $r15 + + // update PUT + add b32 $r9 1 + and $r9 0xf + st b32 D[$r13 + 0x4] $r9 + ret + +// queue_get - fetch request from queue +// +// In : $r13 queue pointer +// +// Out: $p1 clear on success (data available) +// $r14 command +// $r15 data +// +queue_get: + bset $flags $p1 + ld b32 $r8 D[$r13 + 0x0] // GET + ld b32 $r9 D[$r13 + 0x4] // PUT + cmpu b32 $r8 $r9 + bra e #queue_get_done + // fetch first cmd/data pair + and $r9 $r8 7 + shl b32 $r9 3 + add b32 $r9 $r13 + add b32 $r9 8 + ld b32 $r14 D[$r9 + 0x0] + ld b32 $r15 D[$r9 + 0x4] + + // update GET + add b32 $r8 1 + and $r8 0xf + st b32 D[$r13 + 0x0] $r8 + bclr $flags $p1 +queue_get_done: + ret + +// nv_rd32 - read 32-bit value from nv register +// +// In : $r14 register +// Out: $r15 value +// +nv_rd32: + mov $r11 0x728 + shl b32 $r11 6 + mov b32 $r12 $r14 + bset $r12 31 // MMIO_CTRL_PENDING + iowr I[$r11 + 0x000] $r12 // MMIO_CTRL + nv_rd32_wait: + iord $r12 I[$r11 + 0x000] + xbit $r12 $r12 31 + bra ne #nv_rd32_wait + mov $r10 6 // DONE_MMIO_RD + call #wait_doneo + iord $r15 I[$r11 + 0x100] // MMIO_RDVAL + ret + +// nv_wr32 - write 32-bit value to nv register +// +// In : $r14 register +// $r15 value +// +nv_wr32: + mov $r11 0x728 + shl b32 $r11 6 + iowr I[$r11 + 0x200] $r15 // MMIO_WRVAL + mov b32 $r12 $r14 + bset $r12 31 // MMIO_CTRL_PENDING + bset $r12 30 // MMIO_CTRL_WRITE + iowr I[$r11 + 0x000] $r12 // MMIO_CTRL + nv_wr32_wait: + iord $r12 I[$r11 + 0x000] + xbit $r12 $r12 31 + bra ne #nv_wr32_wait + ret + +// (re)set watchdog timer +// +// In : $r15 timeout +// +watchdog_reset: + mov $r8 0x430 + shl b32 $r8 6 + bset $r15 31 + iowr I[$r8 + 0x000] $r15 + ret + +// clear watchdog timer +watchdog_clear: + mov $r8 0x430 + shl b32 $r8 6 + iowr I[$r8 + 0x000] $r0 + ret + +// wait_done{z,o} - wait on FUC_DONE bit to become clear/set +// +// In : $r10 bit to wait on +// +define(`wait_done', ` +$1: + trace_set(T_WAIT); + mov $r8 0x818 + shl b32 $r8 6 + iowr I[$r8 + 0x000] $r10 // CC_SCRATCH[6] = wait bit + wait_done_$1: + mov $r8 0x400 + shl b32 $r8 6 + iord $r8 I[$r8 + 0x000] // DONE + xbit $r8 $r8 $r10 + bra $2 #wait_done_$1 + trace_clr(T_WAIT) + ret +') +wait_done(wait_donez, ne) +wait_done(wait_doneo, e) + +// mmctx_size - determine size of a mmio list transfer +// +// In : $r14 mmio list head +// $r15 mmio list tail +// Out: $r15 transfer size (in bytes) +// +mmctx_size: + clear b32 $r9 + nv_mmctx_size_loop: + ld b32 $r8 D[$r14] + shr b32 $r8 26 + add b32 $r8 1 + shl b32 $r8 2 + add b32 $r9 $r8 + add b32 $r14 4 + cmpu b32 $r14 $r15 + bra ne #nv_mmctx_size_loop + mov b32 $r15 $r9 + ret + +// mmctx_xfer - execute a list of mmio transfers +// +// In : $r10 flags +// bit 0: direction (0 = save, 1 = load) +// bit 1: set if first transfer +// bit 2: set if last transfer +// $r11 base +// $r12 mmio list head +// $r13 mmio list tail +// $r14 multi_stride +// $r15 multi_mask +// +mmctx_xfer: + trace_set(T_MMCTX) + mov $r8 0x710 + shl b32 $r8 6 + clear b32 $r9 + or $r11 $r11 + bra e #mmctx_base_disabled + iowr I[$r8 + 0x000] $r11 // MMCTX_BASE + bset $r9 0 // BASE_EN + mmctx_base_disabled: + or $r14 $r14 + bra e #mmctx_multi_disabled + iowr I[$r8 + 0x200] $r14 // MMCTX_MULTI_STRIDE + iowr I[$r8 + 0x300] $r15 // MMCTX_MULTI_MASK + bset $r9 1 // MULTI_EN + mmctx_multi_disabled: + add b32 $r8 0x100 + + xbit $r11 $r10 0 + shl b32 $r11 16 // DIR + bset $r11 12 // QLIMIT = 0x10 + xbit $r14 $r10 1 + shl b32 $r14 17 + or $r11 $r14 // START_TRIGGER + iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL + + // loop over the mmio list, and send requests to the hw + mmctx_exec_loop: + // wait for space in mmctx queue + mmctx_wait_free: + iord $r14 I[$r8 + 0x000] // MMCTX_CTRL + and $r14 0x1f + bra e #mmctx_wait_free + + // queue up an entry + ld b32 $r14 D[$r12] + or $r14 $r9 + iowr I[$r8 + 0x300] $r14 + add b32 $r12 4 + cmpu b32 $r12 $r13 + bra ne #mmctx_exec_loop + + xbit $r11 $r10 2 + bra ne #mmctx_stop + // wait for queue to empty + mmctx_fini_wait: + iord $r11 I[$r8 + 0x000] // MMCTX_CTRL + and $r11 0x1f + cmpu b32 $r11 0x10 + bra ne #mmctx_fini_wait + mov $r10 2 // DONE_MMCTX + call #wait_donez + bra #mmctx_done + mmctx_stop: + xbit $r11 $r10 0 + shl b32 $r11 16 // DIR + bset $r11 12 // QLIMIT = 0x10 + bset $r11 18 // STOP_TRIGGER + iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL + mmctx_stop_wait: + // wait for STOP_TRIGGER to clear + iord $r11 I[$r8 + 0x000] // MMCTX_CTRL + xbit $r11 $r11 18 + bra ne #mmctx_stop_wait + mmctx_done: + trace_clr(T_MMCTX) + ret + +// Wait for DONE_STRAND +// +strand_wait: + push $r10 + mov $r10 2 + call #wait_donez + pop $r10 + ret + +// unknown - call before issuing strand commands +// +strand_pre: + mov $r8 0x4afc + sethi $r8 0x20000 + mov $r9 0xc + iowr I[$r8] $r9 + call #strand_wait + ret + +// unknown - call after issuing strand commands +// +strand_post: + mov $r8 0x4afc + sethi $r8 0x20000 + mov $r9 0xd + iowr I[$r8] $r9 + call #strand_wait + ret + +// Selects strand set?! +// +// In: $r14 id +// +strand_set: + mov $r10 0x4ffc + sethi $r10 0x20000 + sub b32 $r11 $r10 0x500 + mov $r12 0xf + iowr I[$r10 + 0x000] $r12 // 0x93c = 0xf + mov $r12 0xb + iowr I[$r11 + 0x000] $r12 // 0x928 = 0xb + call #strand_wait + iowr I[$r10 + 0x000] $r14 // 0x93c = <id> + mov $r12 0xa + iowr I[$r11 + 0x000] $r12 // 0x928 = 0xa + call #strand_wait + ret + +// Initialise strand context data +// +// In : $r15 context base +// Out: $r15 context size (in bytes) +// +// Strandset(?) 3 hardcoded currently +// +strand_ctx_init: + trace_set(T_STRINIT) + call #strand_pre + mov $r14 3 + call #strand_set + mov $r10 0x46fc + sethi $r10 0x20000 + add b32 $r11 $r10 0x400 + iowr I[$r10 + 0x100] $r0 // STRAND_FIRST_GENE = 0 + mov $r12 1 + iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_FIRST_GENE + call #strand_wait + sub b32 $r12 $r0 1 + iowr I[$r10 + 0x000] $r12 // STRAND_GENE_CNT = 0xffffffff + mov $r12 2 + iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_GENE_CNT + call #strand_wait + call #strand_post + + // read the size of each strand, poke the context offset of + // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry + // about it later then. + mov $r8 0x880 + shl b32 $r8 6 + iord $r9 I[$r8 + 0x000] // STRANDS + add b32 $r8 0x2200 + shr b32 $r14 $r15 8 + ctx_init_strand_loop: + iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE + iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE + iord $r10 I[$r8 + 0x200] // STRAND_SIZE + shr b32 $r10 6 + add b32 $r10 1 + add b32 $r14 $r10 + add b32 $r8 4 + sub b32 $r9 1 + bra ne #ctx_init_strand_loop + + shl b32 $r14 8 + sub b32 $r15 $r14 $r15 + trace_clr(T_STRINIT) + ret +') diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc new file mode 100644 index 00000000000..f16a5d53319 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc @@ -0,0 +1,400 @@ +/* fuc microcode util functions for nve0 PGRAPH + * + * Copyright 2011 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)') +define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))') + +ifdef(`include_code', ` +// Error codes +define(`E_BAD_COMMAND', 0x01) +define(`E_CMD_OVERFLOW', 0x02) + +// Util macros to help with debugging ucode hangs etc +define(`T_WAIT', 0) +define(`T_MMCTX', 1) +define(`T_STRWAIT', 2) +define(`T_STRINIT', 3) +define(`T_AUTO', 4) +define(`T_CHAN', 5) +define(`T_LOAD', 6) +define(`T_SAVE', 7) +define(`T_LCHAN', 8) +define(`T_LCTXH', 9) + +define(`trace_set', ` + mov $r8 0x83c + shl b32 $r8 6 + clear b32 $r9 + bset $r9 $1 + iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7] +') + +define(`trace_clr', ` + mov $r8 0x85c + shl b32 $r8 6 + clear b32 $r9 + bset $r9 $1 + iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7] +') + +// queue_put - add request to queue +// +// In : $r13 queue pointer +// $r14 command +// $r15 data +// +queue_put: + // make sure we have space.. + ld b32 $r8 D[$r13 + 0x0] // GET + ld b32 $r9 D[$r13 + 0x4] // PUT + xor $r8 8 + cmpu b32 $r8 $r9 + bra ne #queue_put_next + mov $r15 E_CMD_OVERFLOW + call #error + ret + + // store cmd/data on queue + queue_put_next: + and $r8 $r9 7 + shl b32 $r8 3 + add b32 $r8 $r13 + add b32 $r8 8 + st b32 D[$r8 + 0x0] $r14 + st b32 D[$r8 + 0x4] $r15 + + // update PUT + add b32 $r9 1 + and $r9 0xf + st b32 D[$r13 + 0x4] $r9 + ret + +// queue_get - fetch request from queue +// +// In : $r13 queue pointer +// +// Out: $p1 clear on success (data available) +// $r14 command +// $r15 data +// +queue_get: + bset $flags $p1 + ld b32 $r8 D[$r13 + 0x0] // GET + ld b32 $r9 D[$r13 + 0x4] // PUT + cmpu b32 $r8 $r9 + bra e #queue_get_done + // fetch first cmd/data pair + and $r9 $r8 7 + shl b32 $r9 3 + add b32 $r9 $r13 + add b32 $r9 8 + ld b32 $r14 D[$r9 + 0x0] + ld b32 $r15 D[$r9 + 0x4] + + // update GET + add b32 $r8 1 + and $r8 0xf + st b32 D[$r13 + 0x0] $r8 + bclr $flags $p1 +queue_get_done: + ret + +// nv_rd32 - read 32-bit value from nv register +// +// In : $r14 register +// Out: $r15 value +// +nv_rd32: + mov $r11 0x728 + shl b32 $r11 6 + mov b32 $r12 $r14 + bset $r12 31 // MMIO_CTRL_PENDING + iowr I[$r11 + 0x000] $r12 // MMIO_CTRL + nv_rd32_wait: + iord $r12 I[$r11 + 0x000] + xbit $r12 $r12 31 + bra ne #nv_rd32_wait + mov $r10 6 // DONE_MMIO_RD + call #wait_doneo + iord $r15 I[$r11 + 0x100] // MMIO_RDVAL + ret + +// nv_wr32 - write 32-bit value to nv register +// +// In : $r14 register +// $r15 value +// +nv_wr32: + mov $r11 0x728 + shl b32 $r11 6 + iowr I[$r11 + 0x200] $r15 // MMIO_WRVAL + mov b32 $r12 $r14 + bset $r12 31 // MMIO_CTRL_PENDING + bset $r12 30 // MMIO_CTRL_WRITE + iowr I[$r11 + 0x000] $r12 // MMIO_CTRL + nv_wr32_wait: + iord $r12 I[$r11 + 0x000] + xbit $r12 $r12 31 + bra ne #nv_wr32_wait + ret + +// (re)set watchdog timer +// +// In : $r15 timeout +// +watchdog_reset: + mov $r8 0x430 + shl b32 $r8 6 + bset $r15 31 + iowr I[$r8 + 0x000] $r15 + ret + +// clear watchdog timer +watchdog_clear: + mov $r8 0x430 + shl b32 $r8 6 + iowr I[$r8 + 0x000] $r0 + ret + +// wait_done{z,o} - wait on FUC_DONE bit to become clear/set +// +// In : $r10 bit to wait on +// +define(`wait_done', ` +$1: + trace_set(T_WAIT); + mov $r8 0x818 + shl b32 $r8 6 + iowr I[$r8 + 0x000] $r10 // CC_SCRATCH[6] = wait bit + wait_done_$1: + mov $r8 0x400 + shl b32 $r8 6 + iord $r8 I[$r8 + 0x000] // DONE + xbit $r8 $r8 $r10 + bra $2 #wait_done_$1 + trace_clr(T_WAIT) + ret +') +wait_done(wait_donez, ne) +wait_done(wait_doneo, e) + +// mmctx_size - determine size of a mmio list transfer +// +// In : $r14 mmio list head +// $r15 mmio list tail +// Out: $r15 transfer size (in bytes) +// +mmctx_size: + clear b32 $r9 + nv_mmctx_size_loop: + ld b32 $r8 D[$r14] + shr b32 $r8 26 + add b32 $r8 1 + shl b32 $r8 2 + add b32 $r9 $r8 + add b32 $r14 4 + cmpu b32 $r14 $r15 + bra ne #nv_mmctx_size_loop + mov b32 $r15 $r9 + ret + +// mmctx_xfer - execute a list of mmio transfers +// +// In : $r10 flags +// bit 0: direction (0 = save, 1 = load) +// bit 1: set if first transfer +// bit 2: set if last transfer +// $r11 base +// $r12 mmio list head +// $r13 mmio list tail +// $r14 multi_stride +// $r15 multi_mask +// +mmctx_xfer: + trace_set(T_MMCTX) + mov $r8 0x710 + shl b32 $r8 6 + clear b32 $r9 + or $r11 $r11 + bra e #mmctx_base_disabled + iowr I[$r8 + 0x000] $r11 // MMCTX_BASE + bset $r9 0 // BASE_EN + mmctx_base_disabled: + or $r14 $r14 + bra e #mmctx_multi_disabled + iowr I[$r8 + 0x200] $r14 // MMCTX_MULTI_STRIDE + iowr I[$r8 + 0x300] $r15 // MMCTX_MULTI_MASK + bset $r9 1 // MULTI_EN + mmctx_multi_disabled: + add b32 $r8 0x100 + + xbit $r11 $r10 0 + shl b32 $r11 16 // DIR + bset $r11 12 // QLIMIT = 0x10 + xbit $r14 $r10 1 + shl b32 $r14 17 + or $r11 $r14 // START_TRIGGER + iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL + + // loop over the mmio list, and send requests to the hw + mmctx_exec_loop: + // wait for space in mmctx queue + mmctx_wait_free: + iord $r14 I[$r8 + 0x000] // MMCTX_CTRL + and $r14 0x1f + bra e #mmctx_wait_free + + // queue up an entry + ld b32 $r14 D[$r12] + or $r14 $r9 + iowr I[$r8 + 0x300] $r14 + add b32 $r12 4 + cmpu b32 $r12 $r13 + bra ne #mmctx_exec_loop + + xbit $r11 $r10 2 + bra ne #mmctx_stop + // wait for queue to empty + mmctx_fini_wait: + iord $r11 I[$r8 + 0x000] // MMCTX_CTRL + and $r11 0x1f + cmpu b32 $r11 0x10 + bra ne #mmctx_fini_wait + mov $r10 2 // DONE_MMCTX + call #wait_donez + bra #mmctx_done + mmctx_stop: + xbit $r11 $r10 0 + shl b32 $r11 16 // DIR + bset $r11 12 // QLIMIT = 0x10 + bset $r11 18 // STOP_TRIGGER + iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL + mmctx_stop_wait: + // wait for STOP_TRIGGER to clear + iord $r11 I[$r8 + 0x000] // MMCTX_CTRL + xbit $r11 $r11 18 + bra ne #mmctx_stop_wait + mmctx_done: + trace_clr(T_MMCTX) + ret + +// Wait for DONE_STRAND +// +strand_wait: + push $r10 + mov $r10 2 + call #wait_donez + pop $r10 + ret + +// unknown - call before issuing strand commands +// +strand_pre: + mov $r8 0x4afc + sethi $r8 0x20000 + mov $r9 0xc + iowr I[$r8] $r9 + call #strand_wait + ret + +// unknown - call after issuing strand commands +// +strand_post: + mov $r8 0x4afc + sethi $r8 0x20000 + mov $r9 0xd + iowr I[$r8] $r9 + call #strand_wait + ret + +// Selects strand set?! +// +// In: $r14 id +// +strand_set: + mov $r10 0x4ffc + sethi $r10 0x20000 + sub b32 $r11 $r10 0x500 + mov $r12 0xf + iowr I[$r10 + 0x000] $r12 // 0x93c = 0xf + mov $r12 0xb + iowr I[$r11 + 0x000] $r12 // 0x928 = 0xb + call #strand_wait + iowr I[$r10 + 0x000] $r14 // 0x93c = <id> + mov $r12 0xa + iowr I[$r11 + 0x000] $r12 // 0x928 = 0xa + call #strand_wait + ret + +// Initialise strand context data +// +// In : $r15 context base +// Out: $r15 context size (in bytes) +// +// Strandset(?) 3 hardcoded currently +// +strand_ctx_init: + trace_set(T_STRINIT) + call #strand_pre + mov $r14 3 + call #strand_set + mov $r10 0x46fc + sethi $r10 0x20000 + add b32 $r11 $r10 0x400 + iowr I[$r10 + 0x100] $r0 // STRAND_FIRST_GENE = 0 + mov $r12 1 + iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_FIRST_GENE + call #strand_wait + sub b32 $r12 $r0 1 + iowr I[$r10 + 0x000] $r12 // STRAND_GENE_CNT = 0xffffffff + mov $r12 2 + iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_GENE_CNT + call #strand_wait + call #strand_post + + // read the size of each strand, poke the context offset of + // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry + // about it later then. + mov $r8 0x880 + shl b32 $r8 6 + iord $r9 I[$r8 + 0x000] // STRANDS + add b32 $r8 0x2200 + shr b32 $r14 $r15 8 + ctx_init_strand_loop: + iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE + iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE + iord $r10 I[$r8 + 0x200] // STRAND_SIZE + shr b32 $r10 6 + add b32 $r10 1 + add b32 $r14 $r10 + add b32 $r8 4 + sub b32 $r9 1 + bra ne #ctx_init_strand_loop + + shl b32 $r14 8 + sub b32 $r15 $r14 $r15 + trace_clr(T_STRINIT) + ret +') diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c new file mode 100644 index 00000000000..61852824845 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c @@ -0,0 +1,1387 @@ +/* + * Copyright 2007 Stephane Marchesin + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <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> + +#include "regs.h" + +static u32 +nv04_graph_ctx_regs[] = { + 0x0040053c, + 0x00400544, + 0x00400540, + 0x00400548, + NV04_PGRAPH_CTX_SWITCH1, + NV04_PGRAPH_CTX_SWITCH2, + NV04_PGRAPH_CTX_SWITCH3, + NV04_PGRAPH_CTX_SWITCH4, + NV04_PGRAPH_CTX_CACHE1, + NV04_PGRAPH_CTX_CACHE2, + NV04_PGRAPH_CTX_CACHE3, + NV04_PGRAPH_CTX_CACHE4, + 0x00400184, + 0x004001a4, + 0x004001c4, + 0x004001e4, + 0x00400188, + 0x004001a8, + 0x004001c8, + 0x004001e8, + 0x0040018c, + 0x004001ac, + 0x004001cc, + 0x004001ec, + 0x00400190, + 0x004001b0, + 0x004001d0, + 0x004001f0, + 0x00400194, + 0x004001b4, + 0x004001d4, + 0x004001f4, + 0x00400198, + 0x004001b8, + 0x004001d8, + 0x004001f8, + 0x0040019c, + 0x004001bc, + 0x004001dc, + 0x004001fc, + 0x00400174, + NV04_PGRAPH_DMA_START_0, + NV04_PGRAPH_DMA_START_1, + NV04_PGRAPH_DMA_LENGTH, + NV04_PGRAPH_DMA_MISC, + NV04_PGRAPH_DMA_PITCH, + NV04_PGRAPH_BOFFSET0, + NV04_PGRAPH_BBASE0, + NV04_PGRAPH_BLIMIT0, + NV04_PGRAPH_BOFFSET1, + NV04_PGRAPH_BBASE1, + NV04_PGRAPH_BLIMIT1, + NV04_PGRAPH_BOFFSET2, + NV04_PGRAPH_BBASE2, + NV04_PGRAPH_BLIMIT2, + NV04_PGRAPH_BOFFSET3, + NV04_PGRAPH_BBASE3, + NV04_PGRAPH_BLIMIT3, + NV04_PGRAPH_BOFFSET4, + NV04_PGRAPH_BBASE4, + NV04_PGRAPH_BLIMIT4, + NV04_PGRAPH_BOFFSET5, + NV04_PGRAPH_BBASE5, + NV04_PGRAPH_BLIMIT5, + NV04_PGRAPH_BPITCH0, + NV04_PGRAPH_BPITCH1, + NV04_PGRAPH_BPITCH2, + NV04_PGRAPH_BPITCH3, + NV04_PGRAPH_BPITCH4, + NV04_PGRAPH_SURFACE, + NV04_PGRAPH_STATE, + NV04_PGRAPH_BSWIZZLE2, + NV04_PGRAPH_BSWIZZLE5, + NV04_PGRAPH_BPIXEL, + NV04_PGRAPH_NOTIFY, + NV04_PGRAPH_PATT_COLOR0, + NV04_PGRAPH_PATT_COLOR1, + NV04_PGRAPH_PATT_COLORRAM+0x00, + NV04_PGRAPH_PATT_COLORRAM+0x04, + NV04_PGRAPH_PATT_COLORRAM+0x08, + NV04_PGRAPH_PATT_COLORRAM+0x0c, + NV04_PGRAPH_PATT_COLORRAM+0x10, + NV04_PGRAPH_PATT_COLORRAM+0x14, + NV04_PGRAPH_PATT_COLORRAM+0x18, + NV04_PGRAPH_PATT_COLORRAM+0x1c, + NV04_PGRAPH_PATT_COLORRAM+0x20, + NV04_PGRAPH_PATT_COLORRAM+0x24, + NV04_PGRAPH_PATT_COLORRAM+0x28, + NV04_PGRAPH_PATT_COLORRAM+0x2c, + NV04_PGRAPH_PATT_COLORRAM+0x30, + NV04_PGRAPH_PATT_COLORRAM+0x34, + NV04_PGRAPH_PATT_COLORRAM+0x38, + NV04_PGRAPH_PATT_COLORRAM+0x3c, + NV04_PGRAPH_PATT_COLORRAM+0x40, + NV04_PGRAPH_PATT_COLORRAM+0x44, + NV04_PGRAPH_PATT_COLORRAM+0x48, + NV04_PGRAPH_PATT_COLORRAM+0x4c, + NV04_PGRAPH_PATT_COLORRAM+0x50, + NV04_PGRAPH_PATT_COLORRAM+0x54, + NV04_PGRAPH_PATT_COLORRAM+0x58, + NV04_PGRAPH_PATT_COLORRAM+0x5c, + NV04_PGRAPH_PATT_COLORRAM+0x60, + NV04_PGRAPH_PATT_COLORRAM+0x64, + NV04_PGRAPH_PATT_COLORRAM+0x68, + NV04_PGRAPH_PATT_COLORRAM+0x6c, + NV04_PGRAPH_PATT_COLORRAM+0x70, + NV04_PGRAPH_PATT_COLORRAM+0x74, + NV04_PGRAPH_PATT_COLORRAM+0x78, + NV04_PGRAPH_PATT_COLORRAM+0x7c, + NV04_PGRAPH_PATT_COLORRAM+0x80, + NV04_PGRAPH_PATT_COLORRAM+0x84, + NV04_PGRAPH_PATT_COLORRAM+0x88, + NV04_PGRAPH_PATT_COLORRAM+0x8c, + NV04_PGRAPH_PATT_COLORRAM+0x90, + NV04_PGRAPH_PATT_COLORRAM+0x94, + NV04_PGRAPH_PATT_COLORRAM+0x98, + NV04_PGRAPH_PATT_COLORRAM+0x9c, + NV04_PGRAPH_PATT_COLORRAM+0xa0, + NV04_PGRAPH_PATT_COLORRAM+0xa4, + NV04_PGRAPH_PATT_COLORRAM+0xa8, + NV04_PGRAPH_PATT_COLORRAM+0xac, + NV04_PGRAPH_PATT_COLORRAM+0xb0, + NV04_PGRAPH_PATT_COLORRAM+0xb4, + NV04_PGRAPH_PATT_COLORRAM+0xb8, + NV04_PGRAPH_PATT_COLORRAM+0xbc, + NV04_PGRAPH_PATT_COLORRAM+0xc0, + NV04_PGRAPH_PATT_COLORRAM+0xc4, + NV04_PGRAPH_PATT_COLORRAM+0xc8, + NV04_PGRAPH_PATT_COLORRAM+0xcc, + NV04_PGRAPH_PATT_COLORRAM+0xd0, + NV04_PGRAPH_PATT_COLORRAM+0xd4, + NV04_PGRAPH_PATT_COLORRAM+0xd8, + NV04_PGRAPH_PATT_COLORRAM+0xdc, + NV04_PGRAPH_PATT_COLORRAM+0xe0, + NV04_PGRAPH_PATT_COLORRAM+0xe4, + NV04_PGRAPH_PATT_COLORRAM+0xe8, + NV04_PGRAPH_PATT_COLORRAM+0xec, + NV04_PGRAPH_PATT_COLORRAM+0xf0, + NV04_PGRAPH_PATT_COLORRAM+0xf4, + NV04_PGRAPH_PATT_COLORRAM+0xf8, + NV04_PGRAPH_PATT_COLORRAM+0xfc, + NV04_PGRAPH_PATTERN, + 0x0040080c, + NV04_PGRAPH_PATTERN_SHAPE, + 0x00400600, + NV04_PGRAPH_ROP3, + NV04_PGRAPH_CHROMA, + NV04_PGRAPH_BETA_AND, + NV04_PGRAPH_BETA_PREMULT, + NV04_PGRAPH_CONTROL0, + NV04_PGRAPH_CONTROL1, + NV04_PGRAPH_CONTROL2, + NV04_PGRAPH_BLEND, + NV04_PGRAPH_STORED_FMT, + NV04_PGRAPH_SOURCE_COLOR, + 0x00400560, + 0x00400568, + 0x00400564, + 0x0040056c, + 0x00400400, + 0x00400480, + 0x00400404, + 0x00400484, + 0x00400408, + 0x00400488, + 0x0040040c, + 0x0040048c, + 0x00400410, + 0x00400490, + 0x00400414, + 0x00400494, + 0x00400418, + 0x00400498, + 0x0040041c, + 0x0040049c, + 0x00400420, + 0x004004a0, + 0x00400424, + 0x004004a4, + 0x00400428, + 0x004004a8, + 0x0040042c, + 0x004004ac, + 0x00400430, + 0x004004b0, + 0x00400434, + 0x004004b4, + 0x00400438, + 0x004004b8, + 0x0040043c, + 0x004004bc, + 0x00400440, + 0x004004c0, + 0x00400444, + 0x004004c4, + 0x00400448, + 0x004004c8, + 0x0040044c, + 0x004004cc, + 0x00400450, + 0x004004d0, + 0x00400454, + 0x004004d4, + 0x00400458, + 0x004004d8, + 0x0040045c, + 0x004004dc, + 0x00400460, + 0x004004e0, + 0x00400464, + 0x004004e4, + 0x00400468, + 0x004004e8, + 0x0040046c, + 0x004004ec, + 0x00400470, + 0x004004f0, + 0x00400474, + 0x004004f4, + 0x00400478, + 0x004004f8, + 0x0040047c, + 0x004004fc, + 0x00400534, + 0x00400538, + 0x00400514, + 0x00400518, + 0x0040051c, + 0x00400520, + 0x00400524, + 0x00400528, + 0x0040052c, + 0x00400530, + 0x00400d00, + 0x00400d40, + 0x00400d80, + 0x00400d04, + 0x00400d44, + 0x00400d84, + 0x00400d08, + 0x00400d48, + 0x00400d88, + 0x00400d0c, + 0x00400d4c, + 0x00400d8c, + 0x00400d10, + 0x00400d50, + 0x00400d90, + 0x00400d14, + 0x00400d54, + 0x00400d94, + 0x00400d18, + 0x00400d58, + 0x00400d98, + 0x00400d1c, + 0x00400d5c, + 0x00400d9c, + 0x00400d20, + 0x00400d60, + 0x00400da0, + 0x00400d24, + 0x00400d64, + 0x00400da4, + 0x00400d28, + 0x00400d68, + 0x00400da8, + 0x00400d2c, + 0x00400d6c, + 0x00400dac, + 0x00400d30, + 0x00400d70, + 0x00400db0, + 0x00400d34, + 0x00400d74, + 0x00400db4, + 0x00400d38, + 0x00400d78, + 0x00400db8, + 0x00400d3c, + 0x00400d7c, + 0x00400dbc, + 0x00400590, + 0x00400594, + 0x00400598, + 0x0040059c, + 0x004005a8, + 0x004005ac, + 0x004005b0, + 0x004005b4, + 0x004005c0, + 0x004005c4, + 0x004005c8, + 0x004005cc, + 0x004005d0, + 0x004005d4, + 0x004005d8, + 0x004005dc, + 0x004005e0, + NV04_PGRAPH_PASSTHRU_0, + NV04_PGRAPH_PASSTHRU_1, + NV04_PGRAPH_PASSTHRU_2, + NV04_PGRAPH_DVD_COLORFMT, + NV04_PGRAPH_SCALED_FORMAT, + NV04_PGRAPH_MISC24_0, + NV04_PGRAPH_MISC24_1, + NV04_PGRAPH_MISC24_2, + 0x00400500, + 0x00400504, + NV04_PGRAPH_VALID1, + NV04_PGRAPH_VALID2, + NV04_PGRAPH_DEBUG_3 +}; + +struct nv04_graph_priv { + struct nouveau_graph base; + struct nv04_graph_chan *chan[16]; + spinlock_t lock; +}; + +struct nv04_graph_chan { + struct nouveau_object base; + int chid; + u32 nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; +}; + + +static inline struct nv04_graph_priv * +nv04_graph_priv(struct nv04_graph_chan *chan) +{ + return (void *)nv_object(chan)->engine; +} + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +/* + * Software methods, why they are needed, and how they all work: + * + * NV04 and NV05 keep most of the state in PGRAPH context itself, but some + * 2d engine settings are kept inside the grobjs themselves. The grobjs are + * 3 words long on both. grobj format on NV04 is: + * + * word 0: + * - bits 0-7: class + * - bit 12: color key active + * - bit 13: clip rect active + * - bit 14: if set, destination surface is swizzled and taken from buffer 5 + * [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken + * from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or + * NV03_CONTEXT_SURFACE_DST]. + * - bits 15-17: 2d operation [aka patch config] + * - bit 24: patch valid [enables rendering using this object] + * - bit 25: surf3d valid [for tex_tri and multitex_tri only] + * word 1: + * - bits 0-1: mono format + * - bits 8-13: color format + * - bits 16-31: DMA_NOTIFY instance + * word 2: + * - bits 0-15: DMA_A instance + * - bits 16-31: DMA_B instance + * + * On NV05 it's: + * + * word 0: + * - bits 0-7: class + * - bit 12: color key active + * - bit 13: clip rect active + * - bit 14: if set, destination surface is swizzled and taken from buffer 5 + * [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken + * from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or + * NV03_CONTEXT_SURFACE_DST]. + * - bits 15-17: 2d operation [aka patch config] + * - bits 20-22: dither mode + * - bit 24: patch valid [enables rendering using this object] + * - bit 25: surface_dst/surface_color/surf2d/surf3d valid + * - bit 26: surface_src/surface_zeta valid + * - bit 27: pattern valid + * - bit 28: rop valid + * - bit 29: beta1 valid + * - bit 30: beta4 valid + * word 1: + * - bits 0-1: mono format + * - bits 8-13: color format + * - bits 16-31: DMA_NOTIFY instance + * word 2: + * - bits 0-15: DMA_A instance + * - bits 16-31: DMA_B instance + * + * NV05 will set/unset the relevant valid bits when you poke the relevant + * object-binding methods with object of the proper type, or with the NULL + * type. It'll only allow rendering using the grobj if all needed objects + * are bound. The needed set of objects depends on selected operation: for + * example rop object is needed by ROP_AND, but not by SRCCOPY_AND. + * + * NV04 doesn't have these methods implemented at all, and doesn't have the + * relevant bits in grobj. Instead, it'll allow rendering whenever bit 24 + * is set. So we have to emulate them in software, internally keeping the + * same bits as NV05 does. Since grobjs are aligned to 16 bytes on nv04, + * but the last word isn't actually used for anything, we abuse it for this + * purpose. + * + * Actually, NV05 can optionally check bit 24 too, but we disable this since + * there's no use for it. + * + * For unknown reasons, NV04 implements surf3d binding in hardware as an + * exception. Also for unknown reasons, NV04 doesn't implement the clipping + * methods on the surf3d object, so we have to emulate them too. + */ + +static void +nv04_graph_set_ctx1(struct nouveau_object *object, u32 mask, u32 value) +{ + struct nv04_graph_priv *priv = (void *)object->engine; + int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; + u32 tmp; + + tmp = nv_ro32(object, 0x00); + tmp &= ~mask; + tmp |= value; + nv_wo32(object, 0x00, 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_object *object, u32 mask, u32 value) +{ + int class, op, valid = 1; + u32 tmp, ctx1; + + ctx1 = nv_ro32(object, 0x00); + class = ctx1 & 0xff; + op = (ctx1 >> 15) & 7; + + tmp = nv_ro32(object, 0x0c); + tmp &= ~mask; + tmp |= value; + nv_wo32(object, 0x0c, tmp); + + /* check for valid surf2d/surf_dst/surf_color */ + if (!(tmp & 0x02000000)) + valid = 0; + /* check for valid surf_src/surf_zeta */ + if ((class == 0x1f || class == 0x48) && !(tmp & 0x04000000)) + valid = 0; + + switch (op) { + /* SRCCOPY_AND, SRCCOPY: no extra objects required */ + case 0: + case 3: + break; + /* ROP_AND: requires pattern and rop */ + case 1: + if (!(tmp & 0x18000000)) + valid = 0; + break; + /* BLEND_AND: requires beta1 */ + case 2: + if (!(tmp & 0x20000000)) + valid = 0; + break; + /* SRCCOPY_PREMULT, BLEND_PREMULT: beta4 required */ + case 4: + case 5: + if (!(tmp & 0x40000000)) + valid = 0; + break; + } + + nv04_graph_set_ctx1(object, 0x01000000, valid << 24); +} + +static int +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(object, 0x00038000, data << 15); + /* changing operation changes set of objects needed for validation */ + nv04_graph_set_ctx_val(object, 0, 0); + return 0; +} + +static int +nv04_graph_mthd_surf3d_clip_h(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + 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; + if (w & 0x8000) + /* yes, it accepts negative for some reason. */ + w |= 0xffff0000; + max = min + w; + max &= 0x3ffff; + nv_wr32(priv, 0x40053c, min); + nv_wr32(priv, 0x400544, max); + return 0; +} + +static int +nv04_graph_mthd_surf3d_clip_v(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + 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; + if (w & 0x8000) + /* yes, it accepts negative for some reason. */ + w |= 0xffff0000; + max = min + w; + max &= 0x3ffff; + 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_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx1(object, 0x00004000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0); + return 0; + case 0x42: + 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_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx1(object, 0x00004000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0); + return 0; + case 0x42: + nv04_graph_set_ctx1(object, 0x00004000, 0); + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); + return 0; + case 0x52: + nv04_graph_set_ctx1(object, 0x00004000, 0x00004000); + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); + return 0; + } + return 1; +} + +static int +nv01_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x08000000, 0); + return 0; + case 0x18: + nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x08000000, 0); + return 0; + case 0x44: + nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_rop(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x10000000, 0); + return 0; + case 0x43: + nv04_graph_set_ctx_val(object, 0x10000000, 0x10000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_beta1(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x20000000, 0); + return 0; + case 0x12: + nv04_graph_set_ctx_val(object, 0x20000000, 0x20000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_beta4(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x40000000, 0); + return 0; + case 0x72: + nv04_graph_set_ctx_val(object, 0x40000000, 0x40000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_surf_dst(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x02000000, 0); + return 0; + case 0x58: + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_surf_src(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x04000000, 0); + return 0; + case 0x59: + nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_surf_color(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x02000000, 0); + return 0; + case 0x5a: + nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000); + return 0; + } + return 1; +} + +static int +nv04_graph_mthd_bind_surf_zeta(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx_val(object, 0x04000000, 0); + return 0; + case 0x5b: + nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000); + return 0; + } + return 1; +} + +static int +nv01_graph_mthd_bind_clip(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + nv04_graph_set_ctx1(object, 0x2000, 0); + return 0; + case 0x19: + nv04_graph_set_ctx1(object, 0x2000, 0x2000); + return 0; + } + return 1; +} + +static int +nv01_graph_mthd_bind_chroma(struct nouveau_object *object, u32 mthd, + void *args, u32 size) +{ + switch (nv04_graph_mthd_bind_class(object, args, size)) { + case 0x30: + 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(object, 0x1000, 0x1000); + return 0; + } + return 1; +} + +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 const struct nouveau_bitfield +nv04_graph_intr_name[] = { + { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, + {} +}; + +static const 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" }, + { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, + {} +}; + +const 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" }, + { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" }, + { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" }, + { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" }, + { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" }, + { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" }, + { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" }, + { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" }, + { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" }, + { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" }, + { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" }, + { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" }, + { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" }, + { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" }, + { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" }, + { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" }, + { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" }, + {} +}; + +static void +nv04_graph_intr(struct nouveau_subdev *subdev) +{ + 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; + + 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_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(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(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 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_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 = nv04_graph_intr; + nv_engine(priv)->cclass = &nv04_graph_cclass; + nv_engine(priv)->sclass = nv04_graph_sclass; + spin_lock_init(&priv->lock); + return 0; +} + +static int +nv04_graph_init(struct nouveau_object *object) +{ + 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 new file mode 100644 index 00000000000..92521c89e77 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c @@ -0,0 +1,1314 @@ +/* + * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <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 { + 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[] = { + NV10_PGRAPH_CTX_SWITCH(0), + NV10_PGRAPH_CTX_SWITCH(1), + NV10_PGRAPH_CTX_SWITCH(2), + NV10_PGRAPH_CTX_SWITCH(3), + NV10_PGRAPH_CTX_SWITCH(4), + NV10_PGRAPH_CTX_CACHE(0, 0), + NV10_PGRAPH_CTX_CACHE(0, 1), + NV10_PGRAPH_CTX_CACHE(0, 2), + NV10_PGRAPH_CTX_CACHE(0, 3), + NV10_PGRAPH_CTX_CACHE(0, 4), + NV10_PGRAPH_CTX_CACHE(1, 0), + NV10_PGRAPH_CTX_CACHE(1, 1), + NV10_PGRAPH_CTX_CACHE(1, 2), + NV10_PGRAPH_CTX_CACHE(1, 3), + NV10_PGRAPH_CTX_CACHE(1, 4), + NV10_PGRAPH_CTX_CACHE(2, 0), + NV10_PGRAPH_CTX_CACHE(2, 1), + NV10_PGRAPH_CTX_CACHE(2, 2), + NV10_PGRAPH_CTX_CACHE(2, 3), + NV10_PGRAPH_CTX_CACHE(2, 4), + NV10_PGRAPH_CTX_CACHE(3, 0), + NV10_PGRAPH_CTX_CACHE(3, 1), + NV10_PGRAPH_CTX_CACHE(3, 2), + NV10_PGRAPH_CTX_CACHE(3, 3), + NV10_PGRAPH_CTX_CACHE(3, 4), + NV10_PGRAPH_CTX_CACHE(4, 0), + NV10_PGRAPH_CTX_CACHE(4, 1), + NV10_PGRAPH_CTX_CACHE(4, 2), + NV10_PGRAPH_CTX_CACHE(4, 3), + NV10_PGRAPH_CTX_CACHE(4, 4), + NV10_PGRAPH_CTX_CACHE(5, 0), + NV10_PGRAPH_CTX_CACHE(5, 1), + NV10_PGRAPH_CTX_CACHE(5, 2), + NV10_PGRAPH_CTX_CACHE(5, 3), + NV10_PGRAPH_CTX_CACHE(5, 4), + NV10_PGRAPH_CTX_CACHE(6, 0), + NV10_PGRAPH_CTX_CACHE(6, 1), + NV10_PGRAPH_CTX_CACHE(6, 2), + NV10_PGRAPH_CTX_CACHE(6, 3), + NV10_PGRAPH_CTX_CACHE(6, 4), + NV10_PGRAPH_CTX_CACHE(7, 0), + NV10_PGRAPH_CTX_CACHE(7, 1), + NV10_PGRAPH_CTX_CACHE(7, 2), + NV10_PGRAPH_CTX_CACHE(7, 3), + NV10_PGRAPH_CTX_CACHE(7, 4), + NV10_PGRAPH_CTX_USER, + NV04_PGRAPH_DMA_START_0, + NV04_PGRAPH_DMA_START_1, + NV04_PGRAPH_DMA_LENGTH, + NV04_PGRAPH_DMA_MISC, + NV10_PGRAPH_DMA_PITCH, + NV04_PGRAPH_BOFFSET0, + NV04_PGRAPH_BBASE0, + NV04_PGRAPH_BLIMIT0, + NV04_PGRAPH_BOFFSET1, + NV04_PGRAPH_BBASE1, + NV04_PGRAPH_BLIMIT1, + NV04_PGRAPH_BOFFSET2, + NV04_PGRAPH_BBASE2, + NV04_PGRAPH_BLIMIT2, + NV04_PGRAPH_BOFFSET3, + NV04_PGRAPH_BBASE3, + NV04_PGRAPH_BLIMIT3, + NV04_PGRAPH_BOFFSET4, + NV04_PGRAPH_BBASE4, + NV04_PGRAPH_BLIMIT4, + NV04_PGRAPH_BOFFSET5, + NV04_PGRAPH_BBASE5, + NV04_PGRAPH_BLIMIT5, + NV04_PGRAPH_BPITCH0, + NV04_PGRAPH_BPITCH1, + NV04_PGRAPH_BPITCH2, + NV04_PGRAPH_BPITCH3, + NV04_PGRAPH_BPITCH4, + NV10_PGRAPH_SURFACE, + NV10_PGRAPH_STATE, + NV04_PGRAPH_BSWIZZLE2, + NV04_PGRAPH_BSWIZZLE5, + NV04_PGRAPH_BPIXEL, + NV10_PGRAPH_NOTIFY, + NV04_PGRAPH_PATT_COLOR0, + NV04_PGRAPH_PATT_COLOR1, + NV04_PGRAPH_PATT_COLORRAM, /* 64 values from 0x400900 to 0x4009fc */ + 0x00400904, + 0x00400908, + 0x0040090c, + 0x00400910, + 0x00400914, + 0x00400918, + 0x0040091c, + 0x00400920, + 0x00400924, + 0x00400928, + 0x0040092c, + 0x00400930, + 0x00400934, + 0x00400938, + 0x0040093c, + 0x00400940, + 0x00400944, + 0x00400948, + 0x0040094c, + 0x00400950, + 0x00400954, + 0x00400958, + 0x0040095c, + 0x00400960, + 0x00400964, + 0x00400968, + 0x0040096c, + 0x00400970, + 0x00400974, + 0x00400978, + 0x0040097c, + 0x00400980, + 0x00400984, + 0x00400988, + 0x0040098c, + 0x00400990, + 0x00400994, + 0x00400998, + 0x0040099c, + 0x004009a0, + 0x004009a4, + 0x004009a8, + 0x004009ac, + 0x004009b0, + 0x004009b4, + 0x004009b8, + 0x004009bc, + 0x004009c0, + 0x004009c4, + 0x004009c8, + 0x004009cc, + 0x004009d0, + 0x004009d4, + 0x004009d8, + 0x004009dc, + 0x004009e0, + 0x004009e4, + 0x004009e8, + 0x004009ec, + 0x004009f0, + 0x004009f4, + 0x004009f8, + 0x004009fc, + NV04_PGRAPH_PATTERN, /* 2 values from 0x400808 to 0x40080c */ + 0x0040080c, + NV04_PGRAPH_PATTERN_SHAPE, + NV03_PGRAPH_MONO_COLOR0, + NV04_PGRAPH_ROP3, + NV04_PGRAPH_CHROMA, + NV04_PGRAPH_BETA_AND, + NV04_PGRAPH_BETA_PREMULT, + 0x00400e70, + 0x00400e74, + 0x00400e78, + 0x00400e7c, + 0x00400e80, + 0x00400e84, + 0x00400e88, + 0x00400e8c, + 0x00400ea0, + 0x00400ea4, + 0x00400ea8, + 0x00400e90, + 0x00400e94, + 0x00400e98, + 0x00400e9c, + NV10_PGRAPH_WINDOWCLIP_HORIZONTAL, /* 8 values from 0x400f00-0x400f1c */ + NV10_PGRAPH_WINDOWCLIP_VERTICAL, /* 8 values from 0x400f20-0x400f3c */ + 0x00400f04, + 0x00400f24, + 0x00400f08, + 0x00400f28, + 0x00400f0c, + 0x00400f2c, + 0x00400f10, + 0x00400f30, + 0x00400f14, + 0x00400f34, + 0x00400f18, + 0x00400f38, + 0x00400f1c, + 0x00400f3c, + NV10_PGRAPH_XFMODE0, + NV10_PGRAPH_XFMODE1, + NV10_PGRAPH_GLOBALSTATE0, + NV10_PGRAPH_GLOBALSTATE1, + NV04_PGRAPH_STORED_FMT, + NV04_PGRAPH_SOURCE_COLOR, + NV03_PGRAPH_ABS_X_RAM, /* 32 values from 0x400400 to 0x40047c */ + NV03_PGRAPH_ABS_Y_RAM, /* 32 values from 0x400480 to 0x4004fc */ + 0x00400404, + 0x00400484, + 0x00400408, + 0x00400488, + 0x0040040c, + 0x0040048c, + 0x00400410, + 0x00400490, + 0x00400414, + 0x00400494, + 0x00400418, + 0x00400498, + 0x0040041c, + 0x0040049c, + 0x00400420, + 0x004004a0, + 0x00400424, + 0x004004a4, + 0x00400428, + 0x004004a8, + 0x0040042c, + 0x004004ac, + 0x00400430, + 0x004004b0, + 0x00400434, + 0x004004b4, + 0x00400438, + 0x004004b8, + 0x0040043c, + 0x004004bc, + 0x00400440, + 0x004004c0, + 0x00400444, + 0x004004c4, + 0x00400448, + 0x004004c8, + 0x0040044c, + 0x004004cc, + 0x00400450, + 0x004004d0, + 0x00400454, + 0x004004d4, + 0x00400458, + 0x004004d8, + 0x0040045c, + 0x004004dc, + 0x00400460, + 0x004004e0, + 0x00400464, + 0x004004e4, + 0x00400468, + 0x004004e8, + 0x0040046c, + 0x004004ec, + 0x00400470, + 0x004004f0, + 0x00400474, + 0x004004f4, + 0x00400478, + 0x004004f8, + 0x0040047c, + 0x004004fc, + NV03_PGRAPH_ABS_UCLIP_XMIN, + NV03_PGRAPH_ABS_UCLIP_XMAX, + NV03_PGRAPH_ABS_UCLIP_YMIN, + NV03_PGRAPH_ABS_UCLIP_YMAX, + 0x00400550, + 0x00400558, + 0x00400554, + 0x0040055c, + NV03_PGRAPH_ABS_UCLIPA_XMIN, + NV03_PGRAPH_ABS_UCLIPA_XMAX, + NV03_PGRAPH_ABS_UCLIPA_YMIN, + NV03_PGRAPH_ABS_UCLIPA_YMAX, + NV03_PGRAPH_ABS_ICLIP_XMAX, + NV03_PGRAPH_ABS_ICLIP_YMAX, + NV03_PGRAPH_XY_LOGIC_MISC0, + NV03_PGRAPH_XY_LOGIC_MISC1, + NV03_PGRAPH_XY_LOGIC_MISC2, + NV03_PGRAPH_XY_LOGIC_MISC3, + NV03_PGRAPH_CLIPX_0, + NV03_PGRAPH_CLIPX_1, + NV03_PGRAPH_CLIPY_0, + NV03_PGRAPH_CLIPY_1, + NV10_PGRAPH_COMBINER0_IN_ALPHA, + NV10_PGRAPH_COMBINER1_IN_ALPHA, + NV10_PGRAPH_COMBINER0_IN_RGB, + NV10_PGRAPH_COMBINER1_IN_RGB, + NV10_PGRAPH_COMBINER_COLOR0, + NV10_PGRAPH_COMBINER_COLOR1, + NV10_PGRAPH_COMBINER0_OUT_ALPHA, + NV10_PGRAPH_COMBINER1_OUT_ALPHA, + NV10_PGRAPH_COMBINER0_OUT_RGB, + NV10_PGRAPH_COMBINER1_OUT_RGB, + NV10_PGRAPH_COMBINER_FINAL0, + NV10_PGRAPH_COMBINER_FINAL1, + 0x00400e00, + 0x00400e04, + 0x00400e08, + 0x00400e0c, + 0x00400e10, + 0x00400e14, + 0x00400e18, + 0x00400e1c, + 0x00400e20, + 0x00400e24, + 0x00400e28, + 0x00400e2c, + 0x00400e30, + 0x00400e34, + 0x00400e38, + 0x00400e3c, + NV04_PGRAPH_PASSTHRU_0, + NV04_PGRAPH_PASSTHRU_1, + NV04_PGRAPH_PASSTHRU_2, + NV10_PGRAPH_DIMX_TEXTURE, + NV10_PGRAPH_WDIMX_TEXTURE, + NV10_PGRAPH_DVD_COLORFMT, + NV10_PGRAPH_SCALED_FORMAT, + NV04_PGRAPH_MISC24_0, + NV04_PGRAPH_MISC24_1, + NV04_PGRAPH_MISC24_2, + NV03_PGRAPH_X_MISC, + NV03_PGRAPH_Y_MISC, + NV04_PGRAPH_VALID1, + NV04_PGRAPH_VALID2, +}; + +static int nv17_graph_ctx_regs[] = { + NV10_PGRAPH_DEBUG_4, + 0x004006b0, + 0x00400eac, + 0x00400eb0, + 0x00400eb4, + 0x00400eb8, + 0x00400ebc, + 0x00400ec0, + 0x00400ec4, + 0x00400ec8, + 0x00400ecc, + 0x00400ed0, + 0x00400ed4, + 0x00400ed8, + 0x00400edc, + 0x00400ee0, + 0x00400a00, + 0x00400a04, +}; + +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; + u32 lma_window[4]; +}; + + +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(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ + state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \ + } while (0) + +#define PIPE_RESTORE(priv, state, addr) \ + do { \ + int __i; \ + nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ + nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \ + } while (0) + +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 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 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 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; + + nv04_graph_idle(priv); + /* XXX check haiku comments */ + 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(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); + + /* restore XFMODE */ + 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 nv10_graph_chan *chan) +{ + 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 { \ + pipe_state_addr = pipe_state->pipe_##addr; \ + } while (0) +#define PIPE_INIT_END(addr) \ + do { \ + 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) *(pipe_state_addr++) = value + + PIPE_INIT(0x0200); + for (i = 0; i < 48; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x0200); + + PIPE_INIT(0x6400); + for (i = 0; i < 211; i++) + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x3f800000); + NV_WRITE_PIPE_INIT(0x40000000); + NV_WRITE_PIPE_INIT(0x40000000); + NV_WRITE_PIPE_INIT(0x40000000); + NV_WRITE_PIPE_INIT(0x40000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x3f800000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x3f000000); + NV_WRITE_PIPE_INIT(0x3f000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x3f800000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x3f800000); + NV_WRITE_PIPE_INIT(0x3f800000); + NV_WRITE_PIPE_INIT(0x3f800000); + NV_WRITE_PIPE_INIT(0x3f800000); + PIPE_INIT_END(0x6400); + + PIPE_INIT(0x6800); + for (i = 0; i < 162; i++) + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x3f800000); + for (i = 0; i < 25; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x6800); + + PIPE_INIT(0x6c00); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0xbf800000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x6c00); + + PIPE_INIT(0x7000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x00000000); + NV_WRITE_PIPE_INIT(0x7149f2ca); + for (i = 0; i < 35; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x7000); + + PIPE_INIT(0x7400); + for (i = 0; i < 48; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x7400); + + PIPE_INIT(0x7800); + for (i = 0; i < 48; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x7800); + + PIPE_INIT(0x4400); + for (i = 0; i < 32; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x4400); + + PIPE_INIT(0x0000); + for (i = 0; i < 16; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x0000); + + PIPE_INIT(0x0040); + for (i = 0; i < 4; i++) + NV_WRITE_PIPE_INIT(0x00000000); + PIPE_INIT_END(0x0040); + +#undef PIPE_INIT +#undef PIPE_INIT_END +#undef NV_WRITE_PIPE_INIT +} + +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(priv, "unknow offset nv10_ctx_regs %d\n", reg); + return -1; +} + +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(priv, "unknow offset nv17_ctx_regs %d\n", reg); + return -1; +} + +static void +nv10_graph_load_dma_vtxbuf(struct nv10_graph_chan *chan, int chid, u32 inst) +{ + 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 + * that cannot be restored via MMIO. Do it through the FIFO + * instead. + */ + + /* Look for a celsius object */ + for (i = 0; i < 8; i++) { + int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; + + if (class == 0x56 || class == 0x96 || class == 0x99) { + subchan = i; + break; + } + } + + if (subchan < 0 || !inst) + return; + + /* Save the current ctx object */ + ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER); + for (i = 0; i < 5; i++) + ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i)); + + /* Save the FIFO state */ + 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(priv, 0x4007a0 + 4 * i); + + /* Switch to the celsius subchannel */ + for (i = 0; i < 5; i++) + 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(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(priv, 0x4007a0 + 4 * i, fifo[i]); + + 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(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 nv10_graph_chan *chan, int chid) +{ + 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(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(priv, nv17_graph_ctx_regs[i], chan->nv17[i]); + } + + nv10_graph_load_pipe(chan); + + 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 nv10_graph_chan *chan) +{ + struct nv10_graph_priv *priv = nv10_graph_priv(chan); + int i; + + for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) + chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]); + + if (nv_device(priv)->chipset >= 0x17) { + for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) + chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]); + } + + nv10_graph_save_pipe(chan); + + 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 nv10_graph_priv *priv) +{ + struct nv10_graph_chan *prev = NULL; + struct nv10_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 = 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); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +#define NV_WRITE_CTX(reg, val) do { \ + int offset = nv10_graph_ctx_regs_find_offset(priv, reg); \ + if (offset > 0) \ + chan->nv10[offset] = val; \ + } while (0) + +#define NV17_WRITE_CTX(reg, val) do { \ + int offset = nv17_graph_ctx_regs_find_offset(priv, reg); \ + if (offset > 0) \ + chan->nv17[offset] = val; \ + } while (0) + +static int +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 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); + NV_WRITE_CTX(NV03_PGRAPH_XY_LOGIC_MISC0, 0x0001ffff); + NV_WRITE_CTX(0x00400e10, 0x00001000); + NV_WRITE_CTX(0x00400e14, 0x00001000); + NV_WRITE_CTX(0x00400e30, 0x00080008); + NV_WRITE_CTX(0x00400e34, 0x00080008); + if (nv_device(priv)->chipset >= 0x17) { + /* is it really needed ??? */ + NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4, + 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->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_dtor(struct nouveau_object *object) +{ + struct nv10_graph_priv *priv = (void *)object->engine; + struct nv10_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 +nv10_graph_context_fini(struct nouveau_object *object, bool suspend) +{ + struct nv10_graph_priv *priv = (void *)object->engine; + struct nv10_graph_chan *chan = (void *)object; + unsigned long flags; + + 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 nouveau_object_fini(&chan->base, suspend); +} + +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, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static void +nv10_graph_tile_prog(struct nouveau_engine *engine, int i) +{ + 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; + + pfifo->pause(pfifo, &flags); + nv04_graph_idle(priv); + + 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); + + pfifo->start(pfifo, &flags); +} + +const struct nouveau_bitfield nv10_graph_intr_name[] = { + { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, + { NV_PGRAPH_INTR_ERROR, "ERROR" }, + {} +}; + +const struct nouveau_bitfield nv10_graph_nstatus[] = { + { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, + { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, + { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, + { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, + {} +}; + +static void +nv10_graph_intr(struct nouveau_subdev *subdev) +{ + 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; + + 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; + } + } + + 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 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_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; +} + +static void +nv10_graph_dtor(struct nouveau_object *object) +{ + struct nv10_graph_priv *priv = (void *)object; + nouveau_graph_destroy(&priv->base); +} + +static int +nv10_graph_init(struct nouveau_object *object) +{ + 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 { + 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 new file mode 100644 index 00000000000..8f3f619c4a7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c @@ -0,0 +1,381 @@ +#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 */ + {}, +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +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 nv20_graph_chan *chan; + int ret, i; + + ret = nouveau_graph_context_create(parent, engine, oclass, NULL, + 0x37f0, 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 = 0x1c1c; i <= 0x248c; i += 16) { + nv_wo32(chan, (i + 0), 0x10700ff9); + nv_wo32(chan, (i + 4), 0x0436086c); + nv_wo32(chan, (i + 8), 0x000c001b); + } + 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(chan, i, 0x001c527c); + return 0; +} + +int +nv20_graph_context_init(struct nouveau_object *object) +{ + struct nv20_graph_priv *priv = (void *)object->engine; + struct nv20_graph_chan *chan = (void *)object; + int ret; + + ret = nouveau_graph_context_init(&chan->base); + if (ret) + return ret; + + nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); + return 0; +} + +int +nv20_graph_context_fini(struct nouveau_object *object, bool suspend) +{ + 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); + } + nv_mask(priv, 0x400720, 0x00000001, 0x00000001); + + nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000); + return nouveau_graph_context_fini(&chan->base, suspend); +} + +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, + }, +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +void +nv20_graph_tile_prog(struct nouveau_engine *engine, int i) +{ + 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; + + pfifo->pause(pfifo, &flags); + nv04_graph_idle(priv); + + 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_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); + + 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); + } + + pfifo->start(pfifo, &flags); +} + +void +nv20_graph_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nouveau_handle *handle; + struct nv20_graph_priv *priv = (void *)subdev; + 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; + + engctx = nouveau_engctx_get(engine, chid); + if (stat & NV_PGRAPH_INTR_ERROR) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + handle = nouveau_handle_get_class(engctx, class); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; + nouveau_handle_put(handle); + } + } + + 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); + } + + nouveau_engctx_put(engctx); +} + +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; + + 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 = &nv20_graph_cclass; + nv_engine(priv)->sclass = nv20_graph_sclass; + nv_engine(priv)->tile_prog = nv20_graph_tile_prog; + return 0; +} + +void +nv20_graph_dtor(struct nouveau_object *object) +{ + struct nv20_graph_priv *priv = (void *)object; + nouveau_gpuobj_ref(NULL, &priv->ctxtab); + nouveau_graph_destroy(&priv->base); +} + +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; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4); + + 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); + } + + 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_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ + nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000); + nv_wr32(priv, 0x40009C , 0x00000040); + + 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); + + } 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); + } + + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->tile.regions; i++) + engine->tile_prog(engine, i); + + 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)); + + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); + + 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); + + /* 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); + + /* 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 00000000000..2bea7313e03 --- /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 00000000000..b2b650dd8b2 --- /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 00000000000..700462fa0ae --- /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 00000000000..cedadaa92d3 --- /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 00000000000..273f6320027 --- /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 00000000000..f40ee2116ee --- /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 new file mode 100644 index 00000000000..8d0021049ec --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -0,0 +1,495 @@ +/* + * 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/handle.h> +#include <core/engctx.h> + +#include <subdev/fb.h> +#include <subdev/timer.h> + +#include <engine/graph.h> +#include <engine/fifo.h> + +#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_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, + 20, 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); +#ifdef __BIG_ENDIAN + nv_mo32(obj, 0x08, 0x01000000, 0x01000000); +#endif + nv_wo32(obj, 0x0c, 0x00000000); + nv_wo32(obj, 0x10, 0x00000000); + return 0; +} + +static 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, +}; + +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 + ******************************************************************************/ + +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 nv40_graph_priv *priv = (void *)engine; + struct nv40_graph_chan *chan; + int ret; + + 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; + + 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; + } + } + + 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_tile_prog(struct nouveau_engine *engine, int 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 (nv_device(priv)->chipset) { + case 0x40: + case 0x41: /* guess */ + case 0x42: + case 0x43: + case 0x45: /* guess */ + case 0x4e: + 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(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: + case 0x49: + case 0x4b: + case 0x4c: + case 0x67: + default: + 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); +} + +static void +nv40_graph_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nouveau_handle *handle = NULL; + struct nv40_graph_priv *priv = (void *)subdev; + 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; + 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; + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & NV_PGRAPH_INTR_ERROR) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + handle = nouveau_handle_get_class(engctx, class); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; + nouveau_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 %d [0x%08x] subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, inst << 4, subc, class, mthd, data); + } + + nouveau_engctx_put(engctx); +} + +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_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 = 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(nv_device(priv), &priv->size); + + /* No context present currently */ + nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); + + nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(priv, NV40_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, NV04_PGRAPH_DEBUG_3, 0xe0de8055); + nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000); + nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); + + nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); + + j = nv_rd32(priv, 0x1540) & 0xff; + if (j) { + for (i = 0; !(j & 1); j >>= 1, i++) + ; + nv_wr32(priv, 0x405000, i); + } + + if (nv_device(priv)->chipset == 0x40) { + nv_wr32(priv, 0x4009b0, 0x83280fff); + nv_wr32(priv, 0x4009b4, 0x000000a0); + } else { + nv_wr32(priv, 0x400820, 0x83280eff); + nv_wr32(priv, 0x400824, 0x000000a0); + } + + switch (nv_device(priv)->chipset) { + case 0x40: + case 0x45: + nv_wr32(priv, 0x4009b8, 0x0078e366); + nv_wr32(priv, 0x4009bc, 0x0000014c); + break; + case 0x41: + case 0x42: /* pciid also 0x00Cx */ + /* case 0x0120: XXX (pciid) */ + nv_wr32(priv, 0x400828, 0x007596ff); + nv_wr32(priv, 0x40082c, 0x00000108); + break; + case 0x43: + 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(priv, 0x400860, 0); + nv_wr32(priv, 0x400864, 0); + break; + case 0x47: /* G70 */ + case 0x49: /* G71 */ + case 0x4b: /* G73 */ + nv_wr32(priv, 0x400828, 0x07830610); + nv_wr32(priv, 0x40082c, 0x0000016A); + break; + default: + break; + } + + nv_wr32(priv, 0x400b38, 0x2ffff800); + nv_wr32(priv, 0x400b3c, 0x00006000); + + /* Tiling related stuff. */ + switch (nv_device(priv)->chipset) { + case 0x44: + case 0x4a: + nv_wr32(priv, 0x400bc4, 0x1003d888); + nv_wr32(priv, 0x400bbc, 0xb7a7b500); + break; + case 0x46: + nv_wr32(priv, 0x400bc4, 0x0000e024); + nv_wr32(priv, 0x400bbc, 0xb7a7b520); + break; + case 0x4c: + case 0x4e: + case 0x67: + nv_wr32(priv, 0x400bc4, 0x1003d888); + nv_wr32(priv, 0x400bbc, 0xb7a7b540); + break; + default: + break; + } + + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->tile.regions; i++) + engine->tile_prog(engine, i); + + /* begin RAM config */ + vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1; + switch (nv_device(priv)->chipset) { + case 0x40: + 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 (nv_device(priv)->chipset) { + case 0x41: + case 0x42: + case 0x43: + case 0x45: + case 0x4e: + case 0x44: + case 0x4a: + nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204)); + break; + default: + nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200)); + nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204)); + break; + } + 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; +} + +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 00000000000..d2ac975afc2 --- /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 new file mode 100644 index 00000000000..ab3b9dcaf47 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c @@ -0,0 +1,888 @@ +/* + * 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/handle.h> +#include <core/engctx.h> +#include <core/enum.h> + +#include <subdev/fb.h> +#include <subdev/vm.h> +#include <subdev/timer.h> + +#include <engine/fifo.h> +#include <engine/graph.h> + +#include "nv50.h" + +struct nv50_graph_priv { + struct nouveau_graph base; + spinlock_t lock; + u32 size; +}; + +struct nv50_graph_chan { + struct nouveau_graph_chan base; +}; + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +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; + + 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 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 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 }, + {} +}; + +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 }, + {} +}; + +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 }, + {} +}; + +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 }, + {} +}; + +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 }, + {} +}; + +/******************************************************************************* + * PGRAPH context + ******************************************************************************/ + +static int +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 nv50_graph_priv *priv = (void *)engine; + struct nv50_graph_chan *chan; + int ret; + + 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; + + nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan)); + return 0; +} + +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(&engine->base, 0x00); + return 0; +} + +static int +nv84_graph_tlb_flush(struct nouveau_engine *engine) +{ + 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(&priv->lock, flags); + nv_mask(priv, 0x400500, 0x00000001, 0x00000000); + + start = ptimer->read(ptimer); + do { + idle = true; + + for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + } while (!idle && + !(timeout = ptimer->read(ptimer) - start > 2000000000)); + + if (timeout) { + nv_error(priv, "PGRAPH TLB flush idle timeout fail: " + "0x%08x 0x%08x 0x%08x 0x%08x\n", + nv_rd32(priv, 0x400700), nv_rd32(priv, 0x400380), + nv_rd32(priv, 0x400384), nv_rd32(priv, 0x400388)); + } + + nv50_vm_flush_engine(&engine->base, 0x00); + + nv_mask(priv, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&priv->lock, flags); + return timeout ? -EBUSY : 0; +} + +static const struct nouveau_enum nv50_mp_exec_error_names[] = { + { 3, "STACK_UNDERFLOW", NULL }, + { 4, "QUADON_ACTIVE", NULL }, + { 8, "TIMEOUT", NULL }, + { 0x10, "INVALID_OPCODE", NULL }, + { 0x40, "BREAKPOINT", NULL }, + {} +}; + +static const struct nouveau_bitfield nv50_graph_trap_m2mf[] = { + { 0x00000001, "NOTIFY" }, + { 0x00000002, "IN" }, + { 0x00000004, "OUT" }, + {} +}; + +static const struct nouveau_bitfield nv50_graph_trap_vfetch[] = { + { 0x00000001, "FAULT" }, + {} +}; + +static const struct nouveau_bitfield nv50_graph_trap_strmout[] = { + { 0x00000001, "FAULT" }, + {} +}; + +static const struct nouveau_bitfield nv50_graph_trap_ccache[] = { + { 0x00000001, "FAULT" }, + {} +}; + +/* There must be a *lot* of these. Will take some time to gather them up. */ +const struct nouveau_enum nv50_data_error_names[] = { + { 0x00000003, "INVALID_OPERATION", NULL }, + { 0x00000004, "INVALID_VALUE", NULL }, + { 0x00000005, "INVALID_ENUM", NULL }, + { 0x00000008, "INVALID_OBJECT", NULL }, + { 0x00000009, "READ_ONLY_OBJECT", NULL }, + { 0x0000000a, "SUPERVISOR_OBJECT", NULL }, + { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL }, + { 0x0000000c, "INVALID_BITFIELD", NULL }, + { 0x0000000d, "BEGIN_END_ACTIVE", NULL }, + { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL }, + { 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL }, + { 0x00000010, "RT_DOUBLE_BIND", NULL }, + { 0x00000011, "RT_TYPES_MISMATCH", NULL }, + { 0x00000012, "RT_LINEAR_WITH_ZETA", NULL }, + { 0x00000015, "FP_TOO_FEW_REGS", NULL }, + { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL }, + { 0x00000017, "RT_LINEAR_WITH_MSAA", NULL }, + { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL }, + { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL }, + { 0x0000001a, "RT_INVALID_ALIGNMENT", NULL }, + { 0x0000001b, "SAMPLER_OVER_LIMIT", NULL }, + { 0x0000001c, "TEXTURE_OVER_LIMIT", NULL }, + { 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL }, + { 0x0000001f, "RT_BPP128_WITH_MS8", NULL }, + { 0x00000021, "Z_OUT_OF_BOUNDS", NULL }, + { 0x00000023, "XY_OUT_OF_BOUNDS", NULL }, + { 0x00000024, "VP_ZERO_INPUTS", NULL }, + { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL }, + { 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL }, + { 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL }, + { 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL }, + { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL }, + { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL }, + { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL }, + { 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL }, + { 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL }, + { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL }, + { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL }, + { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL }, + { 0x00000046, "LAYER_ID_NEEDS_GP", NULL }, + { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL }, + { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL }, + {} +}; + +static const struct nouveau_bitfield nv50_graph_intr_name[] = { + { 0x00000001, "NOTIFY" }, + { 0x00000002, "COMPUTE_QUERY" }, + { 0x00000010, "ILLEGAL_MTHD" }, + { 0x00000020, "ILLEGAL_CLASS" }, + { 0x00000040, "DOUBLE_NOTIFY" }, + { 0x00001000, "CONTEXT_SWITCH" }, + { 0x00010000, "BUFFER_NOTIFY" }, + { 0x00100000, "DATA_ERROR" }, + { 0x00200000, "TRAP" }, + { 0x01000000, "SINGLE_STEP" }, + {} +}; + +static void +nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display) +{ + 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 (nv_device(priv)->chipset < 0xa0) + addr = 0x408200 + (tpid << 12) + (i << 7); + else + addr = 0x408100 + (tpid << 11) + (i << 7); + mp10 = nv_rd32(priv, addr + 0x10); + status = nv_rd32(priv, addr + 0x14); + if (!status) + continue; + if (display) { + 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(priv, addr + 0x10, mp10); + nv_wr32(priv, addr + 0x14, 0); + mps++; + } + if (!mps && display) + nv_error(priv, "TRAP_MP_EXEC - TP %d: " + "No MPs claiming errors?\n", tpid); +} + +static void +nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old, + u32 ustatus_new, int display, const char *name) +{ + int tps = 0; + u32 units = nv_rd32(priv, 0x1540); + int i, r; + u32 ustatus_addr, ustatus; + for (i = 0; i < 16; i++) { + if (!(units & (1 << i))) + continue; + if (nv_device(priv)->chipset < 0xa0) + ustatus_addr = ustatus_old + (i << 12); + else + ustatus_addr = ustatus_new + (i << 11); + ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff; + if (!ustatus) + continue; + tps++; + switch (type) { + case 6: /* texture error... unknown for now */ + if (display) { + nv_error(priv, "magic set %d:\n", i); + for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) + nv_error(priv, "\t0x%08x: 0x%08x\n", r, + nv_rd32(priv, r)); + } + break; + case 7: /* MP error */ + if (ustatus & 0x04030000) { + nv50_priv_mp_trap(priv, i, display); + ustatus &= ~0x04030000; + } + break; + case 8: /* TPDMA error */ + { + 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_error(priv, "TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", + i, e14, e10); + 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; + } + /* Render target */ + if (ustatus & 0x00000040) { + if (display) { + nv_error(priv, "TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", + i, e14, e10); + 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; + } + /* CUDA memory: l[], g[] or stack. */ + if (ustatus & 0x00000080) { + if (display) { + if (e18 & 0x80000000) { + /* g[] read fault? */ + 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_error(priv, "TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", + i, e14, e10 | ((e18 >> 7) & 0x1f)); + e18 &= ~0x00000f80; + } else { + nv_error(priv, "TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", + i, e14, e10); + } + 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; + } + } + break; + } + if (ustatus) { + if (display) + nv_info(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); + } + nv_wr32(priv, ustatus_addr, 0xc0000000); + } + + if (!tps && display) + nv_info(priv, "%s - No TPs claiming errors?\n", name); +} + +static int +nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, + int chid, u64 inst) +{ + u32 status = nv_rd32(priv, 0x400108); + u32 ustatus; + + if (!status && display) { + nv_error(priv, "TRAP: no units reporting traps?\n"); + return 1; + } + + /* DISPATCH: Relays commands to other units and handles NOTIFY, + * 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(priv, 0x400804) & 0x7fffffff; + if (!ustatus && display) { + nv_error(priv, "TRAP_DISPATCH - no ustatus?\n"); + } + + nv_wr32(priv, 0x400500, 0x00000000); + + /* Known to be triggered by screwed up NOTIFY and COND... */ + if (ustatus & 0x00000001) { + u32 addr = nv_rd32(priv, 0x400808); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + 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_error(priv, "TRAP DISPATCH_FAULT\n"); + if (display && (addr & 0x80000000)) { + nv_error(priv, "ch %d [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, + datal, addr, r848); + } else + if (display) { + nv_error(priv, "no stuck command?\n"); + } + + 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(priv, 0x40084c); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(priv, 0x40085c); + u32 class = nv_rd32(priv, 0x400814); + + nv_error(priv, "TRAP DISPATCH_QUERY\n"); + if (display && (addr & 0x80000000)) { + nv_error(priv, "ch %d [0x%010llx] " + "subc %d class 0x%04x mthd 0x%04x " + "data 0x%08x 40084c 0x%08x\n", + chid, inst, subc, class, mthd, + data, addr); + } else + if (display) { + nv_error(priv, "no stuck command?\n"); + } + + nv_wr32(priv, 0x40084c, 0); + ustatus &= ~0x00000002; + } + + if (ustatus && display) { + nv_error(priv, "TRAP_DISPATCH (unknown " + "0x%08x)\n", ustatus); + } + + nv_wr32(priv, 0x400804, 0xc0000000); + nv_wr32(priv, 0x400108, 0x001); + status &= ~0x001; + if (!status) + return 0; + } + + /* M2MF: Memory to memory copy engine. */ + if (status & 0x002) { + u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff; + if (display) { + nv_error(priv, "TRAP_M2MF"); + nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); + printk("\n"); + 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(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(priv, 0x400c04) & 0x7fffffff; + if (display) { + nv_error(priv, "TRAP_VFETCH"); + nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); + printk("\n"); + 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(priv, 0x400c04, 0xc0000000); + nv_wr32(priv, 0x400108, 0x004); + status &= ~0x004; + } + + /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ + if (status & 0x008) { + ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff; + if (display) { + nv_error(priv, "TRAP_STRMOUT"); + nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); + printk("\n"); + 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(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(priv, 0x405018) & 0x7fffffff; + if (display) { + nv_error(priv, "TRAP_CCACHE"); + nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); + printk("\n"); + nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x" + " %08x %08x %08x\n", + 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(priv, 0x405018, 0xc0000000); + nv_wr32(priv, 0x400108, 0x010); + status &= ~0x010; + } + + /* Unknown, not seen yet... 0x402000 is the only trap status reg + * remaining, so try to handle it anyway. Perhaps related to that + * unknown DMA slot on tesla? */ + if (status & 0x20) { + ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff; + if (display) + 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_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_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_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display, + "TRAP_TPDMA"); + nv_wr32(priv, 0x400108, 0x100); + status &= ~0x100; + } + + if (status) { + if (display) + nv_error(priv, "TRAP: unknown 0x%08x\n", status); + nv_wr32(priv, 0x400108, status); + } + + return 1; +} + +static void +nv50_graph_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nouveau_handle *handle = NULL; + struct nv50_graph_priv *priv = (void *)subdev; + u32 stat = nv_rd32(priv, 0x400100); + u32 inst = nv_rd32(priv, 0x40032c) & 0x0fffffff; + 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; + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x00000010) { + handle = nouveau_handle_get_class(engctx, class); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~0x00000010; + nouveau_handle_put(handle); + } + + 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 (stat & 0x00200000) { + if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12)) + 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 %d [0x%010llx] subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, (u64)inst << 12, subc, class, mthd, data); + nv50_fb_trap(nouveau_fb(priv), 1); + } + + if (nv_rd32(priv, 0x400824) & (1 << 31)) + nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31)); + + nouveau_engctx_put(engctx); +} + +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) +{ + struct nv50_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 = 0x00201000; + nv_subdev(priv)->intr = nv50_graph_intr; + nv_engine(priv)->cclass = &nv50_graph_cclass; + + 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; + + }; + + 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; + + spin_lock_init(&priv->lock); + return 0; +} + +static int +nv50_graph_init(struct nouveau_object *object) +{ + struct nv50_graph_priv *priv = (void *)object; + int ret, units, i; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */ + nv_wr32(priv, 0x40008c, 0x00000004); + + /* 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; + + 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); + } + } + + 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); + + /* upload context program, initialise ctxctl defaults */ + ret = nv50_grctx_init(nv_device(priv), &priv->size); + if (ret) + return ret; + + 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 */ + + /* 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); + } + + 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 00000000000..0505fb419bd --- /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 new file mode 100644 index 00000000000..c62f2d0f5f0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -0,0 +1,955 @@ +/* + * 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 "nvc0.h" +#include "fuc/hubnvc0.fuc.h" +#include "fuc/gpcnvc0.fuc.h" + +/******************************************************************************* + * 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_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *args, u32 size, + struct nouveau_object **pobject) +{ + 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 *chan; + int ret, i; + + /* 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; + + /* 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(parent, NULL, 0x1000, 0x100, 0, &chan->mmio); + if (ret) + return ret; + + ret = nouveau_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm, + NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, + &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(parent, NULL, data->size, data->align, + 0, &chan->data[i].mem); + if (ret) + return ret; + + ret = nouveau_gpuobj_map_vm(chan->data[i].mem, vm, data->access, + &chan->data[i].vma); + if (ret) + return ret; + + data++; + } + + /* finally, fill in the mmio list and point the context at it */ + for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) { + u32 addr = mmio->addr; + u32 data = mmio->data; + + if (mmio->shift) { + u64 info = chan->data[mmio->buffer].vma.offset; + data |= info >> mmio->shift; + } + + 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(chan, i, priv->data[i / 4]); + + if (!priv->firmware) { + nv_wo32(chan, 0x00, chan->mmio_nr / 2); + nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8); + } else { + 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); + } + + return 0; +} + +void +nvc0_graph_context_dtor(struct nouveau_object *object) +{ + struct nvc0_graph_chan *chan = (void *)object; + int i; + + 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(&chan->mmio_vma); + nouveau_gpuobj_ref(NULL, &chan->mmio); + + nouveau_graph_context_destroy(&chan->base); +} + +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) +{ + 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_trap_tpc(struct nvc0_graph_priv *priv, int gpc, int tpc) +{ + u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508)); + + if (stat & 0x00000001) { + u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224)); + nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000001); + stat &= ~0x00000001; + } + + if (stat & 0x00000002) { + u32 trap0 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0644)); + u32 trap1 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x064c)); + nv_error(priv, "GPC%d/TPC%d/MP: 0x%08x 0x%08x\n", + gpc, tpc, trap0, trap1); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0644), 0x001ffffe); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x064c), 0x0000000f); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000002); + stat &= ~0x00000002; + } + + if (stat & 0x00000004) { + u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084)); + nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000004); + stat &= ~0x00000004; + } + + if (stat & 0x00000008) { + u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c)); + nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000008); + stat &= ~0x00000008; + } + + if (stat) { + nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), stat); + } +} + +static void +nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc) +{ + u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90)); + int tpc; + + if (stat & 0x00000001) { + u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0420)); + nv_error(priv, "GPC%d/PROP: 0x%08x\n", gpc, trap); + nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000001); + stat &= ~0x00000001; + } + + if (stat & 0x00000002) { + u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900)); + nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap); + nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000002); + stat &= ~0x00000002; + } + + if (stat & 0x00000004) { + u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028)); + nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap); + nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000004); + stat &= ~0x00000004; + } + + if (stat & 0x00000008) { + u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824)); + nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap); + nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000008); + stat &= ~0x00000009; + } + + for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + u32 mask = 0x00010000 << tpc; + if (stat & mask) { + nvc0_graph_trap_tpc(priv, gpc, tpc); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask); + stat &= ~mask; + } + } + + if (stat) { + nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), stat); + } +} + +static void +nvc0_graph_trap_intr(struct nvc0_graph_priv *priv) +{ + u32 trap = nv_rd32(priv, 0x400108); + int rop, gpc; + + if (trap & 0x00000001) { + u32 stat = nv_rd32(priv, 0x404000); + nv_error(priv, "DISPATCH 0x%08x\n", stat); + nv_wr32(priv, 0x404000, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000001); + trap &= ~0x00000001; + } + + if (trap & 0x00000002) { + u32 stat = nv_rd32(priv, 0x404600); + nv_error(priv, "M2MF 0x%08x\n", stat); + nv_wr32(priv, 0x404600, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000002); + trap &= ~0x00000002; + } + + if (trap & 0x00000008) { + u32 stat = nv_rd32(priv, 0x408030); + nv_error(priv, "CCACHE 0x%08x\n", stat); + nv_wr32(priv, 0x408030, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000008); + trap &= ~0x00000008; + } + + if (trap & 0x00000010) { + u32 stat = nv_rd32(priv, 0x405840); + nv_error(priv, "SHADER 0x%08x\n", stat); + nv_wr32(priv, 0x405840, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000010); + trap &= ~0x00000010; + } + + if (trap & 0x00000040) { + u32 stat = nv_rd32(priv, 0x40601c); + nv_error(priv, "UNK6 0x%08x\n", stat); + nv_wr32(priv, 0x40601c, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000040); + trap &= ~0x00000040; + } + + if (trap & 0x00000080) { + u32 stat = nv_rd32(priv, 0x404490); + nv_error(priv, "MACRO 0x%08x\n", stat); + nv_wr32(priv, 0x404490, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000080); + trap &= ~0x00000080; + } + + if (trap & 0x01000000) { + u32 stat = nv_rd32(priv, 0x400118); + for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) { + u32 mask = 0x00000001 << gpc; + if (stat & mask) { + nvc0_graph_trap_gpc(priv, gpc); + nv_wr32(priv, 0x400118, mask); + stat &= ~mask; + } + } + nv_wr32(priv, 0x400108, 0x01000000); + trap &= ~0x01000000; + } + + 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 0x%08x 0x%08x\n", + rop, 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 UNHANDLED 0x%08x\n", trap); + nv_wr32(priv, 0x400108, trap); + } +} + +static void +nvc0_graph_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nouveau_handle *handle; + struct nvc0_graph_priv *priv = (void *)subdev; + u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff; + 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)); + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x00000010) { + handle = nouveau_handle_get_class(engctx, class); + if (!handle || nv_call(handle->object, mthd, data)) { + nv_error(priv, "ILLEGAL_MTHD ch %d [0x%010llx] " + "subc %d class 0x%04x mthd 0x%04x " + "data 0x%08x\n", + chid, inst << 12, subc, class, mthd, data); + } + nouveau_handle_put(handle); + nv_wr32(priv, 0x400100, 0x00000010); + stat &= ~0x00000010; + } + + if (stat & 0x00000020) { + nv_error(priv, "ILLEGAL_CLASS ch %d [0x%010llx] subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + chid, inst << 12, 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 %d [0x%010llx] subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, inst << 12, subc, class, mthd, data); + nv_wr32(priv, 0x400100, 0x00100000); + stat &= ~0x00100000; + } + + if (stat & 0x00200000) { + nv_error(priv, "TRAP ch %d [0x%010llx]\n", chid, inst << 12); + nvc0_graph_trap_intr(priv); + 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); + nouveau_engctx_put(engctx); +} + +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_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_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) +{ + int i; + + nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); + for (i = 0; i < 4; i++) + 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 nvc0_graph_priv *priv) +{ + 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 nvc0_graph_priv *priv) +{ + 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(priv, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */ + + /* + * TP ROP UNKVAL(magic_not_rop_nr) + * 450: 4/0/0/0 2 3 + * 460: 3/4/0/0 4 1 + * 465: 3/4/4/0 4 7 + * 470: 3/3/4/4 5 5 + * 480: 3/4/4/4 6 6 + */ + + memset(data, 0x00, sizeof(data)); + 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 (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + + data[i / 8] |= tpc << ((i % 8) * 4); + } + + 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(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | + priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + } + + nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918); + nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); +} + +static void +nvc0_graph_init_units(struct nvc0_graph_priv *priv) +{ + 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 nvc0_graph_priv *priv) +{ + int gpc, tpc; + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + 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(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + } +} + +static void +nvc0_graph_init_rop(struct nvc0_graph_priv *priv) +{ + int rop; + + for (rop = 0; rop < priv->rop_nr; rop++) { + 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); + } +} + +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(priv, fuc_base + 0x01c0, 0x01000000); + for (i = 0; i < data->size / 4; i++) + nv_wr32(priv, fuc_base + 0x01c4, data->data[i]); + + nv_wr32(priv, fuc_base + 0x0180, 0x01000000); + for (i = 0; i < code->size / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(priv, fuc_base + 0x0188, i >> 6); + nv_wr32(priv, fuc_base + 0x0184, code->data[i]); + } +} + +static int +nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) +{ + u32 r000260; + int i; + + if (priv->firmware) { + /* load fuc microcode */ + 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(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(priv, 0x409800); + + 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(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; + } + + 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(priv, 0x000260, 0x00000001, 0x00000000); + nv_wr32(priv, 0x4091c0, 0x01000000); + for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++) + nv_wr32(priv, 0x4091c4, nvc0_grhub_data[i]); + + nv_wr32(priv, 0x409180, 0x01000000); + for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(priv, 0x409188, i >> 6); + nv_wr32(priv, 0x409184, nvc0_grhub_code[i]); + } + + /* load GPC microcode */ + nv_wr32(priv, 0x41a1c0, 0x01000000); + for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++) + nv_wr32(priv, 0x41a1c4, nvc0_grgpc_data[i]); + + nv_wr32(priv, 0x41a180, 0x01000000); + for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(priv, 0x41a188, i >> 6); + nv_wr32(priv, 0x41a184, nvc0_grgpc_code[i]); + } + nv_wr32(priv, 0x000260, r000260); + + /* start HUB ucode running, it'll init the GPCs */ + 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(priv, 0x409804); + if (priv->data == NULL) { + int ret = nvc0_grctx_generate(priv); + if (ret) { + nv_error(priv, "failed to construct context\n"); + return ret; + } + } + + return 0; +} + +static int +nvc0_graph_init(struct nouveau_object *object) +{ + struct nvc0_graph_priv *priv = (void *)object; + int ret; + + 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) + return ret; + + return 0; +} + +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 new file mode 100644 index 00000000000..18d2210e12e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h @@ -0,0 +1,171 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#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/fifo.h> +#include <engine/graph.h> + +#define GPC_MAX 4 +#define TPC_MAX 32 + +#define ROP_BCAST(r) (0x408800 + (r)) +#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r)) +#define GPC_BCAST(r) (0x418000 + (r)) +#define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r)) +#define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) + +struct nvc0_graph_data { + u32 size; + u32 align; + u32 access; +}; + +struct nvc0_graph_mmio { + u32 addr; + u32 data; + u32 shift; + u32 buffer; +}; + +struct nvc0_graph_fuc { + u32 *data; + u32 size; +}; + +struct nvc0_graph_priv { + struct nouveau_graph base; + + struct nvc0_graph_fuc fuc409c; + struct nvc0_graph_fuc fuc409d; + struct nvc0_graph_fuc fuc41ac; + struct nvc0_graph_fuc fuc41ad; + bool firmware; + + u8 rop_nr; + u8 gpc_nr; + u8 tpc_nr[GPC_MAX]; + u8 tpc_total; + + struct nouveau_gpuobj *unk4188b4; + struct nouveau_gpuobj *unk4188b8; + + struct nvc0_graph_data mmio_data[4]; + struct nvc0_graph_mmio mmio_list[4096/8]; + u32 size; + u32 *data; + + u8 magic_not_rop_nr; +}; + +struct nvc0_graph_chan { + struct nouveau_graph_chan base; + + struct nouveau_gpuobj *mmio; + struct nouveau_vma mmio_vma; + int mmio_nr; + struct { + struct nouveau_gpuobj *mem; + struct nouveau_vma vma; + } data[4]; +}; + +static inline u32 +nvc0_graph_class(void *obj) +{ + struct nouveau_device *device = nv_device(obj); + + switch (device->chipset) { + case 0xc0: + case 0xc3: + case 0xc4: + case 0xce: /* guess, mmio trace shows only 0x9097 state */ + case 0xcf: /* guess, mmio trace shows only 0x9097 state */ + return 0x9097; + case 0xc1: + return 0x9197; + case 0xc8: + case 0xd9: + return 0x9297; + case 0xe4: + case 0xe7: + return 0xa097; + default: + return 0; + } +} + +void nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data); + +static inline void +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 nvc0_graph_priv *priv; + struct nvc0_graph_data *data; + struct nvc0_graph_mmio *mmio; + struct nouveau_gpuobj *chan; + int buffer_nr; + u64 buffer[4]; + u64 addr; +}; + +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 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 *); +void nvc0_graph_init_fw(struct nvc0_graph_priv *, u32 base, + struct nvc0_graph_fuc *, struct nvc0_graph_fuc *); +int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nvc0_graph_context_dtor(struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c new file mode 100644 index 00000000000..539d4c72f19 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c @@ -0,0 +1,576 @@ +/* + * 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 "nvc0.h" +#include "fuc/hubnve0.fuc.h" +#include "fuc/gpcnve0.fuc.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_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 +nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst) +{ + u32 trap = nv_rd32(priv, 0x400108); + int rop; + + if (trap & 0x00000001) { + u32 stat = nv_rd32(priv, 0x404000); + nv_error(priv, "DISPATCH ch %d [0x%010llx] 0x%08x\n", + chid, inst, stat); + nv_wr32(priv, 0x404000, 0xc0000000); + nv_wr32(priv, 0x400108, 0x00000001); + trap &= ~0x00000001; + } + + if (trap & 0x00000010) { + u32 stat = nv_rd32(priv, 0x405840); + nv_error(priv, "SHADER ch %d [0x%010llx] 0x%08x\n", + chid, 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 %d [0x%010llx] 0x%08x 0x%08x\n", + rop, chid, 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 %d [0x%010llx] 0x%08x\n", + chid, inst, trap); + nv_wr32(priv, 0x400108, trap); + } +} + +static void +nve0_graph_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nouveau_handle *handle; + struct nvc0_graph_priv *priv = (void *)subdev; + u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff; + 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)); + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x00000010) { + handle = nouveau_handle_get_class(engctx, class); + if (!handle || nv_call(handle->object, mthd, data)) { + nv_error(priv, "ILLEGAL_MTHD ch %d [0x%010llx] " + "subc %d class 0x%04x mthd 0x%04x " + "data 0x%08x\n", + chid, inst, subc, class, mthd, data); + } + nouveau_handle_put(handle); + nv_wr32(priv, 0x400100, 0x00000010); + stat &= ~0x00000010; + } + + if (stat & 0x00000020) { + nv_error(priv, "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(priv, 0x400100, 0x00000020); + stat &= ~0x00000020; + } + + if (stat & 0x00100000) { + nv_error(priv, "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(priv, 0x400100, 0x00100000); + stat &= ~0x00100000; + } + + if (stat & 0x00200000) { + nve0_graph_trap_isr(priv, chid, 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); + nouveau_engctx_put(engctx); +} + +static int +nve0_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; + 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; + + 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; + } + + 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 nvc0_graph_priv *priv) +{ + int i; + + nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); + for (i = 0; i < 4; i++) + 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 nvc0_graph_priv *priv) +{ + 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 nvc0_graph_priv *priv) +{ + 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 nvc0_graph_priv *priv) +{ + 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(priv, GPC_UNIT(0, 0x3018), 0x00000001); + + memset(data, 0x00, sizeof(data)); + 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 (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + + data[i / 8] |= tpc << ((i % 8) * 4); + } + + 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(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | + priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + } + + 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 nvc0_graph_priv *priv) +{ + int gpc, tpc; + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + 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(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(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + } +} + +static void +nve0_graph_init_rop(struct nvc0_graph_priv *priv) +{ + int rop; + + for (rop = 0; rop < priv->rop_nr; rop++) { + 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 nvc0_graph_priv *priv) +{ + u32 r000260; + int i; + + if (priv->firmware) { + /* load fuc microcode */ + 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(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(priv, 0x409800); + + 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(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(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(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(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(priv, 0x409614, 0x00000070); + nv_wr32(priv, 0x409614, 0x00000770); + nv_wr32(priv, 0x40802c, 0x00000001); + + if (priv->data == NULL) { + int ret = nve0_grctx_generate(priv); + if (ret) { + nv_error(priv, "failed to construct context\n"); + return ret; + } + } + + return 0; + } + + /* load HUB microcode */ + r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nv_wr32(priv, 0x4091c0, 0x01000000); + for (i = 0; i < sizeof(nve0_grhub_data) / 4; i++) + nv_wr32(priv, 0x4091c4, nve0_grhub_data[i]); + + nv_wr32(priv, 0x409180, 0x01000000); + for (i = 0; i < sizeof(nve0_grhub_code) / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(priv, 0x409188, i >> 6); + nv_wr32(priv, 0x409184, nve0_grhub_code[i]); + } + + /* load GPC microcode */ + nv_wr32(priv, 0x41a1c0, 0x01000000); + for (i = 0; i < sizeof(nve0_grgpc_data) / 4; i++) + nv_wr32(priv, 0x41a1c4, nve0_grgpc_data[i]); + + nv_wr32(priv, 0x41a180, 0x01000000); + for (i = 0; i < sizeof(nve0_grgpc_code) / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(priv, 0x41a188, i >> 6); + nv_wr32(priv, 0x41a184, nve0_grgpc_code[i]); + } + nv_wr32(priv, 0x000260, r000260); + + /* start HUB ucode running, it'll init the GPCs */ + 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(priv, 0x409804); + if (priv->data == NULL) { + int ret = nve0_grctx_generate(priv); + if (ret) { + nv_error(priv, "failed to construct context\n"); + return ret; + } + } + + return 0; +} + +static int +nve0_graph_init(struct nouveau_object *object) +{ + struct nvc0_graph_priv *priv = (void *)object; + int ret; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + nve0_graph_init_obj418880(priv); + nve0_graph_init_regs(priv); + nve0_graph_init_gpc_0(priv); + + nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); + + nve0_graph_init_units(priv); + nve0_graph_init_gpc_1(priv); + nve0_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 = nve0_graph_init_ctxctl(priv); + if (ret) + return ret; + + return 0; +} + +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 00000000000..9c715a25cec --- /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 new file mode 100644 index 00000000000..1f394a2629e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c @@ -0,0 +1,308 @@ +/* + * 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/handle.h> + +#include <subdev/fb.h> +#include <subdev/timer.h> +#include <subdev/instmem.h> + +#include <engine/fifo.h> +#include <engine/mpeg.h> +#include <engine/graph/nv40.h> + +struct nv31_mpeg_priv { + struct nouveau_mpeg base; + atomic_t refcount; +}; + +struct nv31_mpeg_chan { + struct nouveau_object base; +}; + +/******************************************************************************* + * MPEG object classes + ******************************************************************************/ + +static int +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 nouveau_gpuobj *obj; + int ret; + + ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent, + 20, 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 +nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len) +{ + 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; + + /* only allow linear DMA objects */ + if (!(dma0 & 0x00002000)) + return -EINVAL; + + if (mthd == 0x0190) { + /* DMA_CMD */ + 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(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(priv, 0x00b370, base); + nv_wr32(priv, 0x00b374, size); + } + + return 0; +} + +static 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, +}; + +static 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_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + 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_mpeg_context_dtor(struct nouveau_object *object) +{ + 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 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) +{ + 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 nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nouveau_handle *handle; + struct nv31_mpeg_priv *priv = (void *)subdev; + u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff; + 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; + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x01000000) { + /* happens on initial binding of the object */ + if (type == 0x00000020 && mthd == 0x0000) { + nv_mask(priv, 0x00b308, 0x00000000, 0x00000000); + show &= ~0x01000000; + } + + if (type == 0x00000010) { + handle = nouveau_handle_get_class(engctx, 0x3174); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~0x01000000; + nouveau_handle_put(handle); + } + } + + nv_wr32(priv, 0x00b100, stat); + nv_wr32(priv, 0x00b230, 0x00000001); + + if (show) { + nv_error(priv, "ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", + chid, inst << 4, stat, type, mthd, data); + } + + nouveau_engctx_put(engctx); +} + +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) +{ + struct nv31_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 = 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; +} + +int +nv31_mpeg_init(struct nouveau_object *object) +{ + 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; + + ret = nouveau_mpeg_init(&priv->base); + if (ret) + return ret; + + /* VPE init */ + nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + + 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; + } + + 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 00000000000..12418574efe --- /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 new file mode 100644 index 00000000000..8678a9996d5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c @@ -0,0 +1,240 @@ +/* + * 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 nv50_mpeg_priv { + struct nouveau_mpeg base; +}; + +struct nv50_mpeg_chan { + struct nouveau_mpeg_chan base; +}; + +/******************************************************************************* + * MPEG object classes + ******************************************************************************/ + +static int +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 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)); + nv_wo32(obj, 0x04, 0x00000000); + nv_wo32(obj, 0x08, 0x00000000); + nv_wo32(obj, 0x0c, 0x00000000); + return 0; +} + +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, +}; + +static struct nouveau_oclass +nv50_mpeg_sclass[] = { + { 0x3174, &nv50_mpeg_ofuncs }, + {} +}; + +/******************************************************************************* + * PMPEG context + ******************************************************************************/ + +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 nouveau_bar *bar = nouveau_bar(parent); + struct nv50_mpeg_chan *chan; + int ret; + + 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; + + nv_wo32(chan, 0x0070, 0x00801ec1); + nv_wo32(chan, 0x007c, 0x0000037c); + bar->flush(bar); + return 0; +} + +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, + }, +}; + +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ + +int +nv50_mpeg_tlb_flush(struct nouveau_engine *engine) +{ + nv50_vm_flush_engine(&engine->base, 0x08); + return 0; +} + +void +nv50_mpeg_intr(struct nouveau_subdev *subdev) +{ + 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(priv, 0x00b308, 0x00000100); + show &= ~0x01000000; + } + } + + if (show) { + nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n", + stat, type, mthd, data); + } + + nv_wr32(priv, 0x00b100, stat); + nv_wr32(priv, 0x00b230, 0x00000001); + nv50_fb_trap(nouveau_fb(priv), 1); +} + +static void +nv50_vpe_intr(struct nouveau_subdev *subdev) +{ + struct nv50_mpeg_priv *priv = (void *)subdev; + + 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 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_priv *priv; + int ret; + + ret = nouveau_mpeg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + 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_init(struct nouveau_object *object) +{ + 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 00000000000..8f805b44d59 --- /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 new file mode 100644 index 00000000000..50e7e0da198 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c @@ -0,0 +1,175 @@ +/* + * 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/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_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + 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; + + 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_context_init(struct nouveau_object *object) +{ + 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_intr(struct nouveau_subdev *subdev) +{ +} + +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; + + 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; +} + +static void +nv98_ppp_dtor(struct nouveau_object *object) +{ + struct nv98_ppp_priv *priv = (void *)object; + nouveau_ppp_destroy(&priv->base); +} + +static int +nv98_ppp_init(struct nouveau_object *object) +{ + struct nv98_ppp_priv *priv = (void *)object; + int ret; + + ret = nouveau_ppp_init(&priv->base); + if (ret) + return ret; + + 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 00000000000..3ca4c3aa90b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c @@ -0,0 +1,147 @@ +/* + * 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 + ******************************************************************************/ + +void +nv04_software_intr(struct nouveau_subdev *subdev) +{ + nv_mask(subdev, 0x000100, 0x80000000, 0x00000000); +} + +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; + nv_subdev(priv)->intr = nv04_software_intr; + 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 00000000000..6e699afbfdb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c @@ -0,0 +1,129 @@ +/* + * 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; + nv_subdev(priv)->intr = nv04_software_intr; + 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 00000000000..a2edcd38544 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c @@ -0,0 +1,199 @@ +/* + * 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; + nv_subdev(priv)->intr = nv04_software_intr; + 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 00000000000..b7b0d7e330d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c @@ -0,0 +1,181 @@ +/* + * 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; + nv_subdev(priv)->intr = nv04_software_intr; + 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 new file mode 100644 index 00000000000..dd23c80e540 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c @@ -0,0 +1,175 @@ +/* + * 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/vp.h> + +struct nv84_vp_priv { + struct nouveau_vp 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_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + 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; + + 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_context_init(struct nouveau_object *object) +{ + 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_intr(struct nouveau_subdev *subdev) +{ +} + +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; + + 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; +} + +static void +nv84_vp_dtor(struct nouveau_object *object) +{ + struct nv84_vp_priv *priv = (void *)object; + nouveau_vp_destroy(&priv->base); +} + +static int +nv84_vp_init(struct nouveau_object *object) +{ + struct nv84_vp_priv *priv = (void *)object; + int ret; + + ret = nouveau_vp_init(&priv->base); + if (ret) + return ret; + + 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, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h new file mode 100644 index 00000000000..6180ae9800f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -0,0 +1,118 @@ +#ifndef __NOUVEAU_CLASS_H__ +#define __NOUVEAU_CLASS_H__ + +/* Device class + * + * 0080: NV_DEVICE + */ +#define NV_DEVICE_CLASS 0x00000080 + +#define NV_DEVICE_DISABLE_IDENTIFY 0x0000000000000001ULL +#define NV_DEVICE_DISABLE_MMIO 0x0000000000000002ULL +#define NV_DEVICE_DISABLE_VBIOS 0x0000000000000004ULL +#define NV_DEVICE_DISABLE_CORE 0x0000000000000008ULL +#define NV_DEVICE_DISABLE_DISP 0x0000000000010000ULL +#define NV_DEVICE_DISABLE_FIFO 0x0000000000020000ULL +#define NV_DEVICE_DISABLE_GRAPH 0x0000000100000000ULL +#define NV_DEVICE_DISABLE_MPEG 0x0000000200000000ULL +#define NV_DEVICE_DISABLE_ME 0x0000000400000000ULL +#define NV_DEVICE_DISABLE_VP 0x0000000800000000ULL +#define NV_DEVICE_DISABLE_CRYPT 0x0000001000000000ULL +#define NV_DEVICE_DISABLE_BSP 0x0000002000000000ULL +#define NV_DEVICE_DISABLE_PPP 0x0000004000000000ULL +#define NV_DEVICE_DISABLE_COPY0 0x0000008000000000ULL +#define NV_DEVICE_DISABLE_COPY1 0x0000010000000000ULL +#define NV_DEVICE_DISABLE_UNK1C1 0x0000020000000000ULL + +struct nv_device_class { + u64 device; /* device identifier, ~0 for client default */ + u64 disable; /* disable particular subsystems */ + u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */ +}; + +/* DMA object classes + * + * 0002: NV_DMA_FROM_MEMORY + * 0003: NV_DMA_TO_MEMORY + * 003d: NV_DMA_IN_MEMORY + */ +#define NV_DMA_FROM_MEMORY_CLASS 0x00000002 +#define NV_DMA_TO_MEMORY_CLASS 0x00000003 +#define NV_DMA_IN_MEMORY_CLASS 0x0000003d + +#define NV_DMA_TARGET_MASK 0x000000ff +#define NV_DMA_TARGET_VM 0x00000000 +#define NV_DMA_TARGET_VRAM 0x00000001 +#define NV_DMA_TARGET_PCI 0x00000002 +#define NV_DMA_TARGET_PCI_US 0x00000003 +#define NV_DMA_TARGET_AGP 0x00000004 +#define NV_DMA_ACCESS_MASK 0x00000f00 +#define NV_DMA_ACCESS_VM 0x00000000 +#define NV_DMA_ACCESS_RD 0x00000100 +#define NV_DMA_ACCESS_WR 0x00000200 +#define NV_DMA_ACCESS_RDWR 0x00000300 + +struct nv_dma_class { + u32 flags; + u32 pad0; + u64 start; + u64 limit; +}; + +/* DMA FIFO channel classes + * + * 006b: NV03_CHANNEL_DMA + * 006e: NV10_CHANNEL_DMA + * 176e: NV17_CHANNEL_DMA + * 406e: NV40_CHANNEL_DMA + * 506e: NV50_CHANNEL_DMA + * 826e: NV84_CHANNEL_DMA + */ +#define NV03_CHANNEL_DMA_CLASS 0x0000006b +#define NV10_CHANNEL_DMA_CLASS 0x0000006e +#define NV17_CHANNEL_DMA_CLASS 0x0000176e +#define NV40_CHANNEL_DMA_CLASS 0x0000406e +#define NV50_CHANNEL_DMA_CLASS 0x0000506e +#define NV84_CHANNEL_DMA_CLASS 0x0000826e + +struct nv03_channel_dma_class { + u32 pushbuf; + u32 pad0; + u64 offset; +}; + +/* Indirect FIFO channel classes + * + * 506f: NV50_CHANNEL_IND + * 826f: NV84_CHANNEL_IND + * 906f: NVC0_CHANNEL_IND + * a06f: NVE0_CHANNEL_IND + */ + +#define NV50_CHANNEL_IND_CLASS 0x0000506f +#define NV84_CHANNEL_IND_CLASS 0x0000826f +#define NVC0_CHANNEL_IND_CLASS 0x0000906f +#define NVE0_CHANNEL_IND_CLASS 0x0000a06f + +struct nv50_channel_ind_class { + u32 pushbuf; + u32 ilength; + u64 ioffset; +}; + +#define NVE0_CHANNEL_IND_ENGINE_GR 0x00000001 +#define NVE0_CHANNEL_IND_ENGINE_VP 0x00000002 +#define NVE0_CHANNEL_IND_ENGINE_PPP 0x00000004 +#define NVE0_CHANNEL_IND_ENGINE_BSP 0x00000008 +#define NVE0_CHANNEL_IND_ENGINE_CE0 0x00000010 +#define NVE0_CHANNEL_IND_ENGINE_CE1 0x00000020 +#define NVE0_CHANNEL_IND_ENGINE_ENC 0x00000040 + +struct nve0_channel_ind_class { + u32 pushbuf; + u32 ilength; + u64 ioffset; + u32 engine; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h new file mode 100644 index 00000000000..0193532ceac --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/client.h @@ -0,0 +1,42 @@ +#ifndef __NOUVEAU_CLIENT_H__ +#define __NOUVEAU_CLIENT_H__ + +#include <core/namedb.h> + +struct nouveau_client { + struct nouveau_namedb base; + struct nouveau_handle *root; + struct nouveau_object *device; + char name[16]; + u32 debug; + struct nouveau_vm *vm; +}; + +static inline struct nouveau_client * +nv_client(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(obj, NV_CLIENT_CLASS))) + nv_assert("BAD CAST -> NvClient, %08x", nv_hclass(obj)); +#endif + return obj; +} + +static inline struct nouveau_client * +nouveau_client(void *obj) +{ + struct nouveau_object *client = nv_object(obj); + while (client && !(nv_iclass(client, NV_CLIENT_CLASS))) + client = client->parent; + return (void *)client; +} + +#define nouveau_client_create(n,c,oc,od,d) \ + nouveau_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d) + +int nouveau_client_create_(const char *name, u64 device, const char *cfg, + const char *dbg, int, void **); +int nouveau_client_init(struct nouveau_client *); +int nouveau_client_fini(struct nouveau_client *, bool suspend); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/debug.h b/drivers/gpu/drm/nouveau/core/include/core/debug.h new file mode 100644 index 00000000000..9ea18dfcb4d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/debug.h @@ -0,0 +1,13 @@ +#ifndef __NOUVEAU_DEBUG_H__ +#define __NOUVEAU_DEBUG_H__ + +#define NV_DBG_FATAL 0 +#define NV_DBG_ERROR 1 +#define NV_DBG_WARN 2 +#define NV_DBG_INFO 3 +#define NV_DBG_DEBUG 4 +#define NV_DBG_TRACE 5 +#define NV_DBG_PARANOIA 6 +#define NV_DBG_SPAM 7 + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h new file mode 100644 index 00000000000..e58b6f0984c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/device.h @@ -0,0 +1,136 @@ +#ifndef __NOUVEAU_DEVICE_H__ +#define __NOUVEAU_DEVICE_H__ + +#include <core/object.h> +#include <core/subdev.h> +#include <core/engine.h> + +enum nv_subdev_type { + NVDEV_SUBDEV_DEVICE, + NVDEV_SUBDEV_VBIOS, + + /* All subdevs from DEVINIT to DEVINIT_LAST will be created before + * *any* of them are initialised. This subdev category is used + * for any subdevs that the VBIOS init table parsing may call out + * to during POST. + */ + NVDEV_SUBDEV_DEVINIT, + NVDEV_SUBDEV_GPIO, + NVDEV_SUBDEV_I2C, + NVDEV_SUBDEV_CLOCK, + NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_CLOCK, + + /* This grouping of subdevs are initialised right after they've + * been created, and are allowed to assume any subdevs in the + * list above them exist and have been initialised. + */ + NVDEV_SUBDEV_MXM, + NVDEV_SUBDEV_MC, + NVDEV_SUBDEV_TIMER, + NVDEV_SUBDEV_FB, + NVDEV_SUBDEV_LTCG, + NVDEV_SUBDEV_IBUS, + NVDEV_SUBDEV_INSTMEM, + NVDEV_SUBDEV_VM, + NVDEV_SUBDEV_BAR, + NVDEV_SUBDEV_VOLT, + NVDEV_SUBDEV_THERM, + + NVDEV_ENGINE_DMAOBJ, + NVDEV_ENGINE_FIFO, + NVDEV_ENGINE_SW, + NVDEV_ENGINE_GR, + NVDEV_ENGINE_MPEG, + NVDEV_ENGINE_ME, + NVDEV_ENGINE_VP, + NVDEV_ENGINE_CRYPT, + NVDEV_ENGINE_BSP, + NVDEV_ENGINE_PPP, + NVDEV_ENGINE_COPY0, + NVDEV_ENGINE_COPY1, + NVDEV_ENGINE_UNK1C1, + NVDEV_ENGINE_VENC, + NVDEV_ENGINE_DISP, + + NVDEV_SUBDEV_NR, +}; + +struct nouveau_device { + struct nouveau_subdev base; + struct list_head head; + + struct pci_dev *pdev; + u64 handle; + + const char *cfgopt; + const char *dbgopt; + const char *name; + const char *cname; + + enum { + NV_04 = 0x04, + NV_10 = 0x10, + NV_20 = 0x20, + NV_30 = 0x30, + NV_40 = 0x40, + NV_50 = 0x50, + NV_C0 = 0xc0, + NV_D0 = 0xd0, + NV_E0 = 0xe0, + } card_type; + u32 chipset; + u32 crystal; + + struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR]; + struct nouveau_object *subdev[NVDEV_SUBDEV_NR]; +}; + +static inline struct nouveau_device * +nv_device(void *obj) +{ + struct nouveau_object *object = nv_object(obj); + struct nouveau_object *device = object; + + if (device->engine) + device = device->engine; + if (device->parent) + device = device->parent; + +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(device, NV_SUBDEV_CLASS) || + (nv_hclass(device) & 0xff) != NVDEV_SUBDEV_DEVICE)) { + nv_assert("BAD CAST -> NvDevice, 0x%08x 0x%08x", + nv_hclass(object), nv_hclass(device)); + } +#endif + + return (void *)device; +} + +static inline struct nouveau_subdev * +nouveau_subdev(void *obj, int sub) +{ + if (nv_device(obj)->subdev[sub]) + return nv_subdev(nv_device(obj)->subdev[sub]); + return NULL; +} + +static inline struct nouveau_engine * +nouveau_engine(void *obj, int sub) +{ + struct nouveau_subdev *subdev = nouveau_subdev(obj, sub); + if (subdev && nv_iclass(subdev, NV_ENGINE_CLASS)) + return nv_engine(subdev); + return NULL; +} + +static inline bool +nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub) +{ + struct nouveau_device *device = nv_device(object); + return device->pdev->device == dev && + device->pdev->subsystem_vendor == ven && + device->pdev->subsystem_device == sub; +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/engctx.h b/drivers/gpu/drm/nouveau/core/include/core/engctx.h new file mode 100644 index 00000000000..8a947b6872e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/engctx.h @@ -0,0 +1,51 @@ +#ifndef __NOUVEAU_ENGCTX_H__ +#define __NOUVEAU_ENGCTX_H__ + +#include <core/object.h> +#include <core/gpuobj.h> + +#include <subdev/vm.h> + +#define NV_ENGCTX_(eng,var) (NV_ENGCTX_CLASS | ((var) << 8) | (eng)) +#define NV_ENGCTX(name,var) NV_ENGCTX_(NVDEV_ENGINE_##name, (var)) + +struct nouveau_engctx { + struct nouveau_gpuobj base; + struct nouveau_vma vma; + struct list_head head; + unsigned long save; + u64 addr; +}; + +static inline struct nouveau_engctx * +nv_engctx(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(obj, NV_ENGCTX_CLASS))) + nv_assert("BAD CAST -> NvEngCtx, %08x", nv_hclass(obj)); +#endif + return obj; +} + +#define nouveau_engctx_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create_((p), (e), (c), (g), (s), (a), (f), \ + sizeof(**d), (void **)d) + +int nouveau_engctx_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, struct nouveau_object *, + u32 size, u32 align, u32 flags, + int length, void **data); +void nouveau_engctx_destroy(struct nouveau_engctx *); +int nouveau_engctx_init(struct nouveau_engctx *); +int nouveau_engctx_fini(struct nouveau_engctx *, bool suspend); + +void _nouveau_engctx_dtor(struct nouveau_object *); +int _nouveau_engctx_init(struct nouveau_object *); +int _nouveau_engctx_fini(struct nouveau_object *, bool suspend); +#define _nouveau_engctx_rd32 _nouveau_gpuobj_rd32 +#define _nouveau_engctx_wr32 _nouveau_gpuobj_wr32 + +struct nouveau_object *nouveau_engctx_get(struct nouveau_engine *, u64 addr); +void nouveau_engctx_put(struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/engine.h b/drivers/gpu/drm/nouveau/core/include/core/engine.h new file mode 100644 index 00000000000..666d06de77e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/engine.h @@ -0,0 +1,57 @@ +#ifndef __NOUVEAU_ENGINE_H__ +#define __NOUVEAU_ENGINE_H__ + +#include <core/object.h> +#include <core/subdev.h> + +#define NV_ENGINE_(eng,var) (NV_ENGINE_CLASS | ((var) << 8) | (eng)) +#define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var)) + +struct nouveau_engine { + struct nouveau_subdev base; + struct nouveau_oclass *cclass; + struct nouveau_oclass *sclass; + + struct list_head contexts; + spinlock_t lock; + + void (*tile_prog)(struct nouveau_engine *, int region); + int (*tlb_flush)(struct nouveau_engine *); +}; + +static inline struct nouveau_engine * +nv_engine(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(obj, NV_ENGINE_CLASS))) + nv_assert("BAD CAST -> NvEngine, %08x", nv_hclass(obj)); +#endif + return obj; +} + +static inline int +nv_engidx(struct nouveau_object *object) +{ + return nv_subidx(object); +} + +#define nouveau_engine_create(p,e,c,d,i,f,r) \ + nouveau_engine_create_((p), (e), (c), (d), (i), (f), \ + sizeof(**r),(void **)r) + +#define nouveau_engine_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_engine_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_engine_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +int nouveau_engine_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, bool, const char *, + const char *, int, void **); + +#define _nouveau_engine_dtor _nouveau_subdev_dtor +#define _nouveau_engine_init _nouveau_subdev_init +#define _nouveau_engine_fini _nouveau_subdev_fini + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/enum.h b/drivers/gpu/drm/nouveau/core/include/core/enum.h new file mode 100644 index 00000000000..e7b1e181943 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/enum.h @@ -0,0 +1,23 @@ +#ifndef __NOUVEAU_ENUM_H__ +#define __NOUVEAU_ENUM_H__ + +struct nouveau_enum { + u32 value; + const char *name; + const void *data; +}; + +const struct nouveau_enum * +nouveau_enum_find(const struct nouveau_enum *, u32 value); + +void +nouveau_enum_print(const struct nouveau_enum *en, u32 value); + +struct nouveau_bitfield { + u32 mask; + const char *name; +}; + +void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h b/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h new file mode 100644 index 00000000000..6eaff79377a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h @@ -0,0 +1,71 @@ +#ifndef __NOUVEAU_GPUOBJ_H__ +#define __NOUVEAU_GPUOBJ_H__ + +#include <core/object.h> +#include <core/device.h> +#include <core/parent.h> +#include <core/mm.h> + +struct nouveau_vma; +struct nouveau_vm; + +#define NVOBJ_FLAG_ZERO_ALLOC 0x00000001 +#define NVOBJ_FLAG_ZERO_FREE 0x00000002 +#define NVOBJ_FLAG_HEAP 0x00000004 + +struct nouveau_gpuobj { + struct nouveau_object base; + struct nouveau_object *parent; + struct nouveau_mm_node *node; + struct nouveau_mm heap; + + u32 flags; + u64 addr; + u32 size; +}; + +static inline struct nouveau_gpuobj * +nv_gpuobj(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(obj, NV_GPUOBJ_CLASS))) + nv_assert("BAD CAST -> NvGpuObj, %08x", nv_hclass(obj)); +#endif + return obj; +} + +#define nouveau_gpuobj_create(p,e,c,v,g,s,a,f,d) \ + nouveau_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f), \ + sizeof(**d), (void **)d) +#define nouveau_gpuobj_init(p) nouveau_object_init(&(p)->base) +#define nouveau_gpuobj_fini(p,s) nouveau_object_fini(&(p)->base, (s)) +int nouveau_gpuobj_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u32 pclass, + struct nouveau_object *, u32 size, u32 align, + u32 flags, int length, void **); +void nouveau_gpuobj_destroy(struct nouveau_gpuobj *); + +int nouveau_gpuobj_new(struct nouveau_object *, struct nouveau_object *, + u32 size, u32 align, u32 flags, + struct nouveau_gpuobj **); +int nouveau_gpuobj_dup(struct nouveau_object *, struct nouveau_gpuobj *, + struct nouveau_gpuobj **); + +int nouveau_gpuobj_map(struct nouveau_gpuobj *, u32 acc, struct nouveau_vma *); +int nouveau_gpuobj_map_vm(struct nouveau_gpuobj *, struct nouveau_vm *, + u32 access, struct nouveau_vma *); +void nouveau_gpuobj_unmap(struct nouveau_vma *); + +static inline void +nouveau_gpuobj_ref(struct nouveau_gpuobj *obj, struct nouveau_gpuobj **ref) +{ + nouveau_object_ref(&obj->base, (struct nouveau_object **)ref); +} + +void _nouveau_gpuobj_dtor(struct nouveau_object *); +int _nouveau_gpuobj_init(struct nouveau_object *); +int _nouveau_gpuobj_fini(struct nouveau_object *, bool); +u32 _nouveau_gpuobj_rd32(struct nouveau_object *, u32); +void _nouveau_gpuobj_wr32(struct nouveau_object *, u32, u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/handle.h b/drivers/gpu/drm/nouveau/core/include/core/handle.h new file mode 100644 index 00000000000..363674cdf8a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/handle.h @@ -0,0 +1,31 @@ +#ifndef __NOUVEAU_HANDLE_H__ +#define __NOUVEAU_HANDLE_H__ + +struct nouveau_handle { + struct nouveau_namedb *namedb; + struct list_head node; + + struct list_head head; + struct list_head tree; + u32 name; + u32 priv; + + struct nouveau_handle *parent; + struct nouveau_object *object; +}; + +int nouveau_handle_create(struct nouveau_object *, u32 parent, u32 handle, + struct nouveau_object *, struct nouveau_handle **); +void nouveau_handle_destroy(struct nouveau_handle *); +int nouveau_handle_init(struct nouveau_handle *); +int nouveau_handle_fini(struct nouveau_handle *, bool suspend); + +struct nouveau_object * +nouveau_handle_ref(struct nouveau_object *, u32 name); + +struct nouveau_handle *nouveau_handle_get_class(struct nouveau_object *, u16); +struct nouveau_handle *nouveau_handle_get_vinst(struct nouveau_object *, u64); +struct nouveau_handle *nouveau_handle_get_cinst(struct nouveau_object *, u32); +void nouveau_handle_put(struct nouveau_handle *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/math.h b/drivers/gpu/drm/nouveau/core/include/core/math.h new file mode 100644 index 00000000000..f808131c5cd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/math.h @@ -0,0 +1,16 @@ +#ifndef __NOUVEAU_MATH_H__ +#define __NOUVEAU_MATH_H__ + +static inline int +log2i(u64 base) +{ + u64 temp = base >> 1; + int log2; + + for (log2 = 0; temp; log2++, temp >>= 1) { + } + + return (base & (base - 1)) ? log2 + 1: log2; +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h new file mode 100644 index 00000000000..9ee9bf4028c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/mm.h @@ -0,0 +1,33 @@ +#ifndef __NOUVEAU_MM_H__ +#define __NOUVEAU_MM_H__ + +struct nouveau_mm_node { + struct list_head nl_entry; + struct list_head fl_entry; + struct list_head rl_entry; + + u8 type; + u32 offset; + u32 length; +}; + +struct nouveau_mm { + struct list_head nodes; + struct list_head free; + + struct mutex mutex; + + u32 block_size; + int heap_nodes; + u32 heap_size; +}; + +int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block); +int nouveau_mm_fini(struct nouveau_mm *); +int nouveau_mm_head(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min, + u32 align, struct nouveau_mm_node **); +int nouveau_mm_tail(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min, + u32 align, struct nouveau_mm_node **); +void nouveau_mm_free(struct nouveau_mm *, struct nouveau_mm_node **); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/namedb.h b/drivers/gpu/drm/nouveau/core/include/core/namedb.h new file mode 100644 index 00000000000..8897e088608 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/namedb.h @@ -0,0 +1,56 @@ +#ifndef __NOUVEAU_NAMEDB_H__ +#define __NOUVEAU_NAMEDB_H__ + +#include <core/parent.h> + +struct nouveau_handle; + +struct nouveau_namedb { + struct nouveau_parent base; + rwlock_t lock; + struct list_head list; +}; + +static inline struct nouveau_namedb * +nv_namedb(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(obj, NV_NAMEDB_CLASS))) + nv_assert("BAD CAST -> NvNameDB, %08x", nv_hclass(obj)); +#endif + return obj; +} + +#define nouveau_namedb_create(p,e,c,v,s,m,d) \ + nouveau_namedb_create_((p), (e), (c), (v), (s), (m), \ + sizeof(**d), (void **)d) +#define nouveau_namedb_init(p) \ + nouveau_parent_init(&(p)->base) +#define nouveau_namedb_fini(p,s) \ + nouveau_parent_fini(&(p)->base, (s)) +#define nouveau_namedb_destroy(p) \ + nouveau_parent_destroy(&(p)->base) + +int nouveau_namedb_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u32 pclass, + struct nouveau_oclass *, u32 engcls, + int size, void **); + +int _nouveau_namedb_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +#define _nouveau_namedb_dtor _nouveau_parent_dtor +#define _nouveau_namedb_init _nouveau_parent_init +#define _nouveau_namedb_fini _nouveau_parent_fini + +int nouveau_namedb_insert(struct nouveau_namedb *, u32 name, + struct nouveau_object *, struct nouveau_handle *); +void nouveau_namedb_remove(struct nouveau_handle *); + +struct nouveau_handle *nouveau_namedb_get(struct nouveau_namedb *, u32); +struct nouveau_handle *nouveau_namedb_get_class(struct nouveau_namedb *, u16); +struct nouveau_handle *nouveau_namedb_get_vinst(struct nouveau_namedb *, u64); +struct nouveau_handle *nouveau_namedb_get_cinst(struct nouveau_namedb *, u32); +void nouveau_namedb_put(struct nouveau_handle *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h new file mode 100644 index 00000000000..818feabbf4a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h @@ -0,0 +1,188 @@ +#ifndef __NOUVEAU_OBJECT_H__ +#define __NOUVEAU_OBJECT_H__ + +#include <core/os.h> +#include <core/printk.h> + +#define NV_PARENT_CLASS 0x80000000 +#define NV_NAMEDB_CLASS 0x40000000 +#define NV_CLIENT_CLASS 0x20000000 +#define NV_SUBDEV_CLASS 0x10000000 +#define NV_ENGINE_CLASS 0x08000000 +#define NV_MEMOBJ_CLASS 0x04000000 +#define NV_GPUOBJ_CLASS 0x02000000 +#define NV_ENGCTX_CLASS 0x01000000 +#define NV_OBJECT_CLASS 0x0000ffff + +struct nouveau_object { + struct nouveau_oclass *oclass; + struct nouveau_object *parent; + struct nouveau_object *engine; + atomic_t refcount; + atomic_t usecount; +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA +#define NOUVEAU_OBJECT_MAGIC 0x75ef0bad + struct list_head list; + u32 _magic; +#endif +}; + +static inline struct nouveau_object * +nv_object(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (likely(obj)) { + struct nouveau_object *object = obj; + if (unlikely(object->_magic != NOUVEAU_OBJECT_MAGIC)) + nv_assert("BAD CAST -> NvObject, invalid magic"); + } +#endif + return obj; +} + +#define nouveau_object_create(p,e,c,s,d) \ + nouveau_object_create_((p), (e), (c), (s), sizeof(**d), (void **)d) +int nouveau_object_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u32, int size, void **); +void nouveau_object_destroy(struct nouveau_object *); +int nouveau_object_init(struct nouveau_object *); +int nouveau_object_fini(struct nouveau_object *, bool suspend); + +extern struct nouveau_ofuncs nouveau_object_ofuncs; + +struct nouveau_oclass { + u32 handle; + struct nouveau_ofuncs *ofuncs; + struct nouveau_omthds *omthds; +}; + +#define nv_oclass(o) nv_object(o)->oclass +#define nv_hclass(o) nv_oclass(o)->handle +#define nv_iclass(o,i) (nv_hclass(o) & (i)) +#define nv_mclass(o) nv_iclass(o, NV_OBJECT_CLASS) + +static inline struct nouveau_object * +nv_pclass(struct nouveau_object *parent, u32 oclass) +{ + while (parent && !nv_iclass(parent, oclass)) + parent = parent->parent; + return parent; +} + +struct nouveau_omthds { + u32 method; + int (*call)(struct nouveau_object *, u32, void *, u32); +}; + +struct nouveau_ofuncs { + int (*ctor)(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *data, u32 size, + struct nouveau_object **); + void (*dtor)(struct nouveau_object *); + int (*init)(struct nouveau_object *); + int (*fini)(struct nouveau_object *, bool suspend); + u8 (*rd08)(struct nouveau_object *, u32 offset); + u16 (*rd16)(struct nouveau_object *, u32 offset); + u32 (*rd32)(struct nouveau_object *, u32 offset); + void (*wr08)(struct nouveau_object *, u32 offset, u8 data); + void (*wr16)(struct nouveau_object *, u32 offset, u16 data); + void (*wr32)(struct nouveau_object *, u32 offset, u32 data); +}; + +static inline struct nouveau_ofuncs * +nv_ofuncs(void *obj) +{ + return nv_oclass(obj)->ofuncs; +} + +int nouveau_object_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nouveau_object_ref(struct nouveau_object *, struct nouveau_object **); +int nouveau_object_inc(struct nouveau_object *); +int nouveau_object_dec(struct nouveau_object *, bool suspend); + +int nouveau_object_new(struct nouveau_object *, u32 parent, u32 handle, + u16 oclass, void *data, u32 size, + struct nouveau_object **); +int nouveau_object_del(struct nouveau_object *, u32 parent, u32 handle); +void nouveau_object_debug(void); + +static inline int +nv_call(void *obj, u32 mthd, u32 data) +{ + struct nouveau_omthds *method = nv_oclass(obj)->omthds; + + while (method && method->call) { + if (method->method == mthd) + return method->call(obj, mthd, &data, sizeof(data)); + method++; + } + + return -EINVAL; +} + +static inline u8 +nv_ro08(void *obj, u32 addr) +{ + u8 data = nv_ofuncs(obj)->rd08(obj, addr); + nv_spam(obj, "nv_ro08 0x%08x 0x%02x\n", addr, data); + return data; +} + +static inline u16 +nv_ro16(void *obj, u32 addr) +{ + u16 data = nv_ofuncs(obj)->rd16(obj, addr); + nv_spam(obj, "nv_ro16 0x%08x 0x%04x\n", addr, data); + return data; +} + +static inline u32 +nv_ro32(void *obj, u32 addr) +{ + u32 data = nv_ofuncs(obj)->rd32(obj, addr); + nv_spam(obj, "nv_ro32 0x%08x 0x%08x\n", addr, data); + return data; +} + +static inline void +nv_wo08(void *obj, u32 addr, u8 data) +{ + nv_spam(obj, "nv_wo08 0x%08x 0x%02x\n", addr, data); + nv_ofuncs(obj)->wr08(obj, addr, data); +} + +static inline void +nv_wo16(void *obj, u32 addr, u16 data) +{ + nv_spam(obj, "nv_wo16 0x%08x 0x%04x\n", addr, data); + nv_ofuncs(obj)->wr16(obj, addr, data); +} + +static inline void +nv_wo32(void *obj, u32 addr, u32 data) +{ + nv_spam(obj, "nv_wo32 0x%08x 0x%08x\n", addr, data); + nv_ofuncs(obj)->wr32(obj, addr, data); +} + +static inline u32 +nv_mo32(void *obj, u32 addr, u32 mask, u32 data) +{ + u32 temp = nv_ro32(obj, addr); + nv_wo32(obj, addr, (temp & ~mask) | data); + return temp; +} + +static inline bool +nv_strncmp(void *obj, u32 addr, u32 len, const char *str) +{ + while (len--) { + if (nv_ro08(obj, addr++) != *(str++)) + return false; + } + return true; +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/option.h b/drivers/gpu/drm/nouveau/core/include/core/option.h new file mode 100644 index 00000000000..27074957fd2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/option.h @@ -0,0 +1,11 @@ +#ifndef __NOUVEAU_OPTION_H__ +#define __NOUVEAU_OPTION_H__ + +#include <core/os.h> + +const char *nouveau_stropt(const char *optstr, const char *opt, int *len); +bool nouveau_boolopt(const char *optstr, const char *opt, bool value); + +int nouveau_dbgopt(const char *optstr, const char *sub); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h new file mode 100644 index 00000000000..d3aa251a5eb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/parent.h @@ -0,0 +1,64 @@ +#ifndef __NOUVEAU_PARENT_H__ +#define __NOUVEAU_PARENT_H__ + +#include <core/device.h> +#include <core/object.h> + +struct nouveau_sclass { + struct nouveau_sclass *sclass; + struct nouveau_engine *engine; + struct nouveau_oclass *oclass; +}; + +struct nouveau_parent { + struct nouveau_object base; + + struct nouveau_sclass *sclass; + u32 engine; + + int (*context_attach)(struct nouveau_object *, + struct nouveau_object *); + int (*context_detach)(struct nouveau_object *, bool suspend, + struct nouveau_object *); + + int (*object_attach)(struct nouveau_object *parent, + struct nouveau_object *object, u32 name); + void (*object_detach)(struct nouveau_object *parent, int cookie); +}; + +static inline struct nouveau_parent * +nv_parent(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!(nv_iclass(obj, NV_PARENT_CLASS)))) + nv_assert("BAD CAST -> NvParent, %08x", nv_hclass(obj)); +#endif + return obj; +} + +#define nouveau_parent_create(p,e,c,v,s,m,d) \ + nouveau_parent_create_((p), (e), (c), (v), (s), (m), \ + sizeof(**d), (void **)d) +#define nouveau_parent_init(p) \ + nouveau_object_init(&(p)->base) +#define nouveau_parent_fini(p,s) \ + nouveau_object_fini(&(p)->base, (s)) + +int nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u32 pclass, + struct nouveau_oclass *, u64 engcls, + int size, void **); +void nouveau_parent_destroy(struct nouveau_parent *); + +int _nouveau_parent_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nouveau_parent_dtor(struct nouveau_object *); +#define _nouveau_parent_init _nouveau_object_init +#define _nouveau_parent_fini _nouveau_object_fini + +int nouveau_parent_sclass(struct nouveau_object *, u16 handle, + struct nouveau_object **pengine, + struct nouveau_oclass **poclass); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/printk.h b/drivers/gpu/drm/nouveau/core/include/core/printk.h new file mode 100644 index 00000000000..1d629664f32 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/printk.h @@ -0,0 +1,39 @@ +#ifndef __NOUVEAU_PRINTK_H__ +#define __NOUVEAU_PRINTK_H__ + +#include <core/os.h> +#include <core/debug.h> + +struct nouveau_object; + +#define NV_PRINTK_FATAL KERN_CRIT +#define NV_PRINTK_ERROR KERN_ERR +#define NV_PRINTK_WARN KERN_WARNING +#define NV_PRINTK_INFO KERN_INFO +#define NV_PRINTK_DEBUG KERN_DEBUG +#define NV_PRINTK_PARANOIA KERN_DEBUG +#define NV_PRINTK_TRACE KERN_DEBUG +#define NV_PRINTK_SPAM KERN_DEBUG + +void nv_printk_(struct nouveau_object *, const char *, int, const char *, ...); + +#define nv_printk(o,l,f,a...) do { \ + if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \ + nv_printk_(nv_object(o), NV_PRINTK_##l, NV_DBG_##l, f, ##a); \ +} while(0) + +#define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a) +#define nv_error(o,f,a...) nv_printk((o), ERROR, f, ##a) +#define nv_warn(o,f,a...) nv_printk((o), WARN, f, ##a) +#define nv_info(o,f,a...) nv_printk((o), INFO, f, ##a) +#define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a) +#define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a) +#define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a) + +#define nv_assert(f,a...) do { \ + if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG) \ + nv_printk_(NULL, NV_PRINTK_FATAL, NV_DBG_FATAL, f "\n", ##a); \ + BUG_ON(1); \ +} while(0) + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/ramht.h b/drivers/gpu/drm/nouveau/core/include/core/ramht.h new file mode 100644 index 00000000000..47e4cacbca3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/ramht.h @@ -0,0 +1,23 @@ +#ifndef __NOUVEAU_RAMHT_H__ +#define __NOUVEAU_RAMHT_H__ + +#include <core/gpuobj.h> + +struct nouveau_ramht { + struct nouveau_gpuobj base; + int bits; +}; + +int nouveau_ramht_insert(struct nouveau_ramht *, int chid, + u32 handle, u32 context); +void nouveau_ramht_remove(struct nouveau_ramht *, int cookie); +int nouveau_ramht_new(struct nouveau_object *, struct nouveau_object *, + u32 size, u32 align, struct nouveau_ramht **); + +static inline void +nouveau_ramht_ref(struct nouveau_ramht *obj, struct nouveau_ramht **ref) +{ + nouveau_gpuobj_ref(&obj->base, (struct nouveau_gpuobj **)ref); +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/subdev.h b/drivers/gpu/drm/nouveau/core/include/core/subdev.h new file mode 100644 index 00000000000..e9632e93161 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/subdev.h @@ -0,0 +1,118 @@ +#ifndef __NOUVEAU_SUBDEV_H__ +#define __NOUVEAU_SUBDEV_H__ + +#include <core/object.h> + +#define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub)) +#define NV_SUBDEV(name,var) NV_SUBDEV_(NVDEV_SUBDEV_##name, (var)) + +struct nouveau_subdev { + struct nouveau_object base; + struct mutex mutex; + const char *name; + void __iomem *mmio; + u32 debug; + u32 unit; + + void (*intr)(struct nouveau_subdev *); +}; + +static inline struct nouveau_subdev * +nv_subdev(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(obj, NV_SUBDEV_CLASS))) + nv_assert("BAD CAST -> NvSubDev, %08x", nv_hclass(obj)); +#endif + return obj; +} + +static inline int +nv_subidx(struct nouveau_object *object) +{ + return nv_hclass(nv_subdev(object)) & 0xff; +} + +#define nouveau_subdev_create(p,e,o,v,s,f,d) \ + nouveau_subdev_create_((p), (e), (o), (v), (s), (f), \ + sizeof(**d),(void **)d) + +int nouveau_subdev_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u32 pclass, + const char *sname, const char *fname, + int size, void **); +void nouveau_subdev_destroy(struct nouveau_subdev *); +int nouveau_subdev_init(struct nouveau_subdev *); +int nouveau_subdev_fini(struct nouveau_subdev *, bool suspend); +void nouveau_subdev_reset(struct nouveau_object *); + +void _nouveau_subdev_dtor(struct nouveau_object *); +int _nouveau_subdev_init(struct nouveau_object *); +int _nouveau_subdev_fini(struct nouveau_object *, bool suspend); + +#define s_printk(s,l,f,a...) do { \ + if ((s)->debug >= OS_DBG_##l) { \ + nv_printk((s)->base.parent, (s)->name, l, f, ##a); \ + } \ +} while(0) + +static inline u8 +nv_rd08(void *obj, u32 addr) +{ + struct nouveau_subdev *subdev = nv_subdev(obj); + u8 data = ioread8(subdev->mmio + addr); + nv_spam(subdev, "nv_rd08 0x%06x 0x%02x\n", addr, data); + return data; +} + +static inline u16 +nv_rd16(void *obj, u32 addr) +{ + struct nouveau_subdev *subdev = nv_subdev(obj); + u16 data = ioread16_native(subdev->mmio + addr); + nv_spam(subdev, "nv_rd16 0x%06x 0x%04x\n", addr, data); + return data; +} + +static inline u32 +nv_rd32(void *obj, u32 addr) +{ + struct nouveau_subdev *subdev = nv_subdev(obj); + u32 data = ioread32_native(subdev->mmio + addr); + nv_spam(subdev, "nv_rd32 0x%06x 0x%08x\n", addr, data); + return data; +} + +static inline void +nv_wr08(void *obj, u32 addr, u8 data) +{ + struct nouveau_subdev *subdev = nv_subdev(obj); + nv_spam(subdev, "nv_wr08 0x%06x 0x%02x\n", addr, data); + iowrite8(data, subdev->mmio + addr); +} + +static inline void +nv_wr16(void *obj, u32 addr, u16 data) +{ + struct nouveau_subdev *subdev = nv_subdev(obj); + nv_spam(subdev, "nv_wr16 0x%06x 0x%04x\n", addr, data); + iowrite16_native(data, subdev->mmio + addr); +} + +static inline void +nv_wr32(void *obj, u32 addr, u32 data) +{ + struct nouveau_subdev *subdev = nv_subdev(obj); + nv_spam(subdev, "nv_wr32 0x%06x 0x%08x\n", addr, data); + iowrite32_native(data, subdev->mmio + addr); +} + +static inline u32 +nv_mask(void *obj, u32 addr, u32 mask, u32 data) +{ + u32 temp = nv_rd32(obj, addr); + nv_wr32(obj, addr, (temp & ~mask) | data); + return temp; +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h new file mode 100644 index 00000000000..75d1ed5f85f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h @@ -0,0 +1,45 @@ +#ifndef __NOUVEAU_BSP_H__ +#define __NOUVEAU_BSP_H__ + +#include <core/engine.h> +#include <core/engctx.h> + +struct nouveau_bsp_chan { + struct nouveau_engctx base; +}; + +#define nouveau_bsp_context_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) +#define nouveau_bsp_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_bsp_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_bsp_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_bsp_context_dtor _nouveau_engctx_dtor +#define _nouveau_bsp_context_init _nouveau_engctx_init +#define _nouveau_bsp_context_fini _nouveau_engctx_fini +#define _nouveau_bsp_context_rd32 _nouveau_engctx_rd32 +#define _nouveau_bsp_context_wr32 _nouveau_engctx_wr32 + +struct nouveau_bsp { + struct nouveau_engine base; +}; + +#define nouveau_bsp_create(p,e,c,d) \ + nouveau_engine_create((p), (e), (c), true, "PBSP", "bsp", (d)) +#define nouveau_bsp_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_bsp_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_bsp_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_bsp_dtor _nouveau_engine_dtor +#define _nouveau_bsp_init _nouveau_engine_init +#define _nouveau_bsp_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv84_bsp_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/copy.h b/drivers/gpu/drm/nouveau/core/include/engine/copy.h new file mode 100644 index 00000000000..70b9d8c5fcf --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/copy.h @@ -0,0 +1,49 @@ +#ifndef __NOUVEAU_COPY_H__ +#define __NOUVEAU_COPY_H__ + +#include <core/engine.h> +#include <core/engctx.h> + +struct nouveau_copy_chan { + struct nouveau_engctx base; +}; + +#define nouveau_copy_context_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) +#define nouveau_copy_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_copy_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_copy_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_copy_context_dtor _nouveau_engctx_dtor +#define _nouveau_copy_context_init _nouveau_engctx_init +#define _nouveau_copy_context_fini _nouveau_engctx_fini +#define _nouveau_copy_context_rd32 _nouveau_engctx_rd32 +#define _nouveau_copy_context_wr32 _nouveau_engctx_wr32 + +struct nouveau_copy { + struct nouveau_engine base; +}; + +#define nouveau_copy_create(p,e,c,y,i,d) \ + nouveau_engine_create((p), (e), (c), (y), "PCE"#i, "copy"#i, (d)) +#define nouveau_copy_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_copy_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_copy_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_copy_dtor _nouveau_engine_dtor +#define _nouveau_copy_init _nouveau_engine_init +#define _nouveau_copy_fini _nouveau_engine_fini + +extern struct nouveau_oclass nva3_copy_oclass; +extern struct nouveau_oclass nvc0_copy0_oclass; +extern struct nouveau_oclass nvc0_copy1_oclass; +extern struct nouveau_oclass nve0_copy0_oclass; +extern struct nouveau_oclass nve0_copy1_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/crypt.h b/drivers/gpu/drm/nouveau/core/include/engine/crypt.h new file mode 100644 index 00000000000..e3674743baa --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/crypt.h @@ -0,0 +1,46 @@ +#ifndef __NOUVEAU_CRYPT_H__ +#define __NOUVEAU_CRYPT_H__ + +#include <core/engine.h> +#include <core/engctx.h> + +struct nouveau_crypt_chan { + struct nouveau_engctx base; +}; + +#define nouveau_crypt_context_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) +#define nouveau_crypt_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_crypt_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_crypt_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_crypt_context_dtor _nouveau_engctx_dtor +#define _nouveau_crypt_context_init _nouveau_engctx_init +#define _nouveau_crypt_context_fini _nouveau_engctx_fini +#define _nouveau_crypt_context_rd32 _nouveau_engctx_rd32 +#define _nouveau_crypt_context_wr32 _nouveau_engctx_wr32 + +struct nouveau_crypt { + struct nouveau_engine base; +}; + +#define nouveau_crypt_create(p,e,c,d) \ + nouveau_engine_create((p), (e), (c), true, "PCRYPT", "crypt", (d)) +#define nouveau_crypt_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_crypt_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_crypt_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_crypt_dtor _nouveau_engine_dtor +#define _nouveau_crypt_init _nouveau_engine_init +#define _nouveau_crypt_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv84_crypt_oclass; +extern struct nouveau_oclass nv98_crypt_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h new file mode 100644 index 00000000000..38ec1252cba --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h @@ -0,0 +1,44 @@ +#ifndef __NOUVEAU_DISP_H__ +#define __NOUVEAU_DISP_H__ + +#include <core/object.h> +#include <core/engine.h> +#include <core/device.h> + +struct nouveau_disp { + struct nouveau_engine base; + + struct { + struct list_head list; + spinlock_t lock; + void (*notify)(void *, int); + void (*get)(void *, int); + void (*put)(void *, int); + void *data; + } vblank; +}; + +static inline struct nouveau_disp * +nouveau_disp(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP]; +} + +#define nouveau_disp_create(p,e,c,i,x,d) \ + nouveau_engine_create((p), (e), (c), true, (i), (x), (d)) +#define nouveau_disp_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_disp_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_disp_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_disp_dtor _nouveau_engine_dtor +#define _nouveau_disp_init _nouveau_engine_init +#define _nouveau_disp_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv04_disp_oclass; +extern struct nouveau_oclass nv50_disp_oclass; +extern struct nouveau_oclass nvd0_disp_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h new file mode 100644 index 00000000000..700ccbb1941 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h @@ -0,0 +1,57 @@ +#ifndef __NOUVEAU_DMAOBJ_H__ +#define __NOUVEAU_DMAOBJ_H__ + +#include <core/object.h> +#include <core/engine.h> + +struct nouveau_gpuobj; + +struct nouveau_dmaobj { + struct nouveau_object base; + u32 target; + u32 access; + u64 start; + u64 limit; +}; + +#define nouveau_dmaobj_create(p,e,c,a,s,d) \ + nouveau_dmaobj_create_((p), (e), (c), (a), (s), sizeof(**d), (void **)d) +#define nouveau_dmaobj_destroy(p) \ + nouveau_object_destroy(&(p)->base) +#define nouveau_dmaobj_init(p) \ + nouveau_object_init(&(p)->base) +#define nouveau_dmaobj_fini(p,s) \ + nouveau_object_fini(&(p)->base, (s)) + +int nouveau_dmaobj_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *data, u32 size, + int length, void **); + +#define _nouveau_dmaobj_dtor nouveau_object_destroy +#define _nouveau_dmaobj_init nouveau_object_init +#define _nouveau_dmaobj_fini nouveau_object_fini + +struct nouveau_dmaeng { + struct nouveau_engine base; + int (*bind)(struct nouveau_dmaeng *, struct nouveau_object *parent, + struct nouveau_dmaobj *, struct nouveau_gpuobj **); +}; + +#define nouveau_dmaeng_create(p,e,c,d) \ + nouveau_engine_create((p), (e), (c), true, "DMAOBJ", "dmaobj", (d)) +#define nouveau_dmaeng_destroy(p) \ + nouveau_engine_destroy(&(p)->base) +#define nouveau_dmaeng_init(p) \ + nouveau_engine_init(&(p)->base) +#define nouveau_dmaeng_fini(p,s) \ + nouveau_engine_fini(&(p)->base, (s)) + +#define _nouveau_dmaeng_dtor _nouveau_engine_dtor +#define _nouveau_dmaeng_init _nouveau_engine_init +#define _nouveau_dmaeng_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv04_dmaeng_oclass; +extern struct nouveau_oclass nv50_dmaeng_oclass; +extern struct nouveau_oclass nvc0_dmaeng_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h new file mode 100644 index 00000000000..d67fed1e397 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h @@ -0,0 +1,111 @@ +#ifndef __NOUVEAU_FIFO_H__ +#define __NOUVEAU_FIFO_H__ + +#include <core/namedb.h> +#include <core/gpuobj.h> +#include <core/engine.h> + +struct nouveau_fifo_chan { + struct nouveau_namedb base; + struct nouveau_dmaobj *pushdma; + struct nouveau_gpuobj *pushgpu; + void __iomem *user; + u32 size; + u16 chid; + atomic_t refcnt; /* NV04_NVSW_SET_REF */ +}; + +static inline struct nouveau_fifo_chan * +nouveau_fifo_chan(void *obj) +{ + return (void *)nv_namedb(obj); +} + +#define nouveau_fifo_channel_create(p,e,c,b,a,s,n,m,d) \ + nouveau_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n), \ + (m), sizeof(**d), (void **)d) +#define nouveau_fifo_channel_init(p) \ + nouveau_namedb_init(&(p)->base) +#define nouveau_fifo_channel_fini(p,s) \ + nouveau_namedb_fini(&(p)->base, (s)) + +int nouveau_fifo_channel_create_(struct nouveau_object *, + struct nouveau_object *, + struct nouveau_oclass *, + int bar, u32 addr, u32 size, u32 push, + u32 engmask, int len, void **); +void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *); + +#define _nouveau_fifo_channel_init _nouveau_namedb_init +#define _nouveau_fifo_channel_fini _nouveau_namedb_fini + +void _nouveau_fifo_channel_dtor(struct nouveau_object *); +u32 _nouveau_fifo_channel_rd32(struct nouveau_object *, u32); +void _nouveau_fifo_channel_wr32(struct nouveau_object *, u32, u32); + +struct nouveau_fifo_base { + struct nouveau_gpuobj base; +}; + +#define nouveau_fifo_context_create(p,e,c,g,s,a,f,d) \ + nouveau_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d)) +#define nouveau_fifo_context_destroy(p) \ + nouveau_gpuobj_destroy(&(p)->base) +#define nouveau_fifo_context_init(p) \ + nouveau_gpuobj_init(&(p)->base) +#define nouveau_fifo_context_fini(p,s) \ + nouveau_gpuobj_fini(&(p)->base, (s)) + +#define _nouveau_fifo_context_dtor _nouveau_gpuobj_dtor +#define _nouveau_fifo_context_init _nouveau_gpuobj_init +#define _nouveau_fifo_context_fini _nouveau_gpuobj_fini +#define _nouveau_fifo_context_rd32 _nouveau_gpuobj_rd32 +#define _nouveau_fifo_context_wr32 _nouveau_gpuobj_wr32 + +struct nouveau_fifo { + struct nouveau_engine base; + + struct nouveau_object **channel; + spinlock_t lock; + u16 min; + u16 max; + + int (*chid)(struct nouveau_fifo *, struct nouveau_object *); + void (*pause)(struct nouveau_fifo *, unsigned long *); + void (*start)(struct nouveau_fifo *, unsigned long *); +}; + +static inline struct nouveau_fifo * +nouveau_fifo(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_FIFO]; +} + +#define nouveau_fifo_create(o,e,c,fc,lc,d) \ + nouveau_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d) +#define nouveau_fifo_init(p) \ + nouveau_engine_init(&(p)->base) +#define nouveau_fifo_fini(p,s) \ + nouveau_engine_fini(&(p)->base, (s)) + +int nouveau_fifo_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int min, int max, + int size, void **); +void nouveau_fifo_destroy(struct nouveau_fifo *); + +#define _nouveau_fifo_init _nouveau_engine_init +#define _nouveau_fifo_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv04_fifo_oclass; +extern struct nouveau_oclass nv10_fifo_oclass; +extern struct nouveau_oclass nv17_fifo_oclass; +extern struct nouveau_oclass nv40_fifo_oclass; +extern struct nouveau_oclass nv50_fifo_oclass; +extern struct nouveau_oclass nv84_fifo_oclass; +extern struct nouveau_oclass nvc0_fifo_oclass; +extern struct nouveau_oclass nve0_fifo_oclass; + +void nv04_fifo_intr(struct nouveau_subdev *); +int nv04_fifo_context_attach(struct nouveau_object *, struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h new file mode 100644 index 00000000000..6943b40d081 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/graph.h @@ -0,0 +1,72 @@ +#ifndef __NOUVEAU_GRAPH_H__ +#define __NOUVEAU_GRAPH_H__ + +#include <core/engine.h> +#include <core/engctx.h> +#include <core/enum.h> + +struct nouveau_graph_chan { + struct nouveau_engctx base; +}; + +#define nouveau_graph_context_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) +#define nouveau_graph_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_graph_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_graph_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_graph_context_dtor _nouveau_engctx_dtor +#define _nouveau_graph_context_init _nouveau_engctx_init +#define _nouveau_graph_context_fini _nouveau_engctx_fini +#define _nouveau_graph_context_rd32 _nouveau_engctx_rd32 +#define _nouveau_graph_context_wr32 _nouveau_engctx_wr32 + +struct nouveau_graph { + struct nouveau_engine base; +}; + +static inline struct nouveau_graph * +nouveau_graph(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_GR]; +} + +#define nouveau_graph_create(p,e,c,y,d) \ + nouveau_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d)) +#define nouveau_graph_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_graph_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_graph_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_graph_dtor _nouveau_engine_dtor +#define _nouveau_graph_init _nouveau_engine_init +#define _nouveau_graph_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv04_graph_oclass; +extern struct nouveau_oclass nv10_graph_oclass; +extern struct nouveau_oclass nv20_graph_oclass; +extern struct nouveau_oclass nv25_graph_oclass; +extern struct nouveau_oclass nv2a_graph_oclass; +extern struct nouveau_oclass nv30_graph_oclass; +extern struct nouveau_oclass nv34_graph_oclass; +extern struct nouveau_oclass nv35_graph_oclass; +extern struct nouveau_oclass nv40_graph_oclass; +extern struct nouveau_oclass nv50_graph_oclass; +extern struct nouveau_oclass nvc0_graph_oclass; +extern struct nouveau_oclass nve0_graph_oclass; + +extern const struct nouveau_bitfield nv04_graph_nsource[]; +extern struct nouveau_ofuncs nv04_graph_ofuncs; +bool nv04_graph_idle(void *obj); + +extern const struct nouveau_bitfield nv10_graph_intr_name[]; +extern const struct nouveau_bitfield nv10_graph_nstatus[]; + +extern const struct nouveau_enum nv50_data_error_names[]; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h new file mode 100644 index 00000000000..bbf0d4a5bbd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h @@ -0,0 +1,61 @@ +#ifndef __NOUVEAU_MPEG_H__ +#define __NOUVEAU_MPEG_H__ + +#include <core/engine.h> +#include <core/engctx.h> + +struct nouveau_mpeg_chan { + struct nouveau_engctx base; +}; + +#define nouveau_mpeg_context_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) +#define nouveau_mpeg_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_mpeg_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_mpeg_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_mpeg_context_dtor _nouveau_engctx_dtor +#define _nouveau_mpeg_context_init _nouveau_engctx_init +#define _nouveau_mpeg_context_fini _nouveau_engctx_fini +#define _nouveau_mpeg_context_rd32 _nouveau_engctx_rd32 +#define _nouveau_mpeg_context_wr32 _nouveau_engctx_wr32 + +struct nouveau_mpeg { + struct nouveau_engine base; +}; + +#define nouveau_mpeg_create(p,e,c,d) \ + nouveau_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d)) +#define nouveau_mpeg_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_mpeg_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_mpeg_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_mpeg_dtor _nouveau_engine_dtor +#define _nouveau_mpeg_init _nouveau_engine_init +#define _nouveau_mpeg_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv31_mpeg_oclass; +extern struct nouveau_oclass nv40_mpeg_oclass; +extern struct nouveau_oclass nv50_mpeg_oclass; +extern struct nouveau_oclass nv84_mpeg_oclass; + +extern struct nouveau_oclass nv31_mpeg_sclass[]; +void nv31_mpeg_intr(struct nouveau_subdev *); +void nv31_mpeg_tile_prog(struct nouveau_engine *, int); +int nv31_mpeg_init(struct nouveau_object *); + +extern struct nouveau_ofuncs nv50_mpeg_ofuncs; +int nv50_mpeg_context_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +int nv50_mpeg_tlb_flush(struct nouveau_engine *); +void nv50_mpeg_intr(struct nouveau_subdev *); +int nv50_mpeg_init(struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/ppp.h b/drivers/gpu/drm/nouveau/core/include/engine/ppp.h new file mode 100644 index 00000000000..74d554fb328 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/ppp.h @@ -0,0 +1,45 @@ +#ifndef __NOUVEAU_PPP_H__ +#define __NOUVEAU_PPP_H__ + +#include <core/engine.h> +#include <core/engctx.h> + +struct nouveau_ppp_chan { + struct nouveau_engctx base; +}; + +#define nouveau_ppp_context_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) +#define nouveau_ppp_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_ppp_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_ppp_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_ppp_context_dtor _nouveau_engctx_dtor +#define _nouveau_ppp_context_init _nouveau_engctx_init +#define _nouveau_ppp_context_fini _nouveau_engctx_fini +#define _nouveau_ppp_context_rd32 _nouveau_engctx_rd32 +#define _nouveau_ppp_context_wr32 _nouveau_engctx_wr32 + +struct nouveau_ppp { + struct nouveau_engine base; +}; + +#define nouveau_ppp_create(p,e,c,d) \ + nouveau_engine_create((p), (e), (c), true, "PPPP", "ppp", (d)) +#define nouveau_ppp_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_ppp_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_ppp_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_ppp_dtor _nouveau_engine_dtor +#define _nouveau_ppp_init _nouveau_engine_init +#define _nouveau_ppp_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv98_ppp_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h new file mode 100644 index 00000000000..c945691c856 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/software.h @@ -0,0 +1,60 @@ +#ifndef __NOUVEAU_SOFTWARE_H__ +#define __NOUVEAU_SOFTWARE_H__ + +#include <core/engine.h> +#include <core/engctx.h> + +struct nouveau_software_chan { + struct nouveau_engctx base; + + struct { + struct list_head head; + u32 channel; + u32 ctxdma; + u64 offset; + u32 value; + u32 crtc; + } vblank; + + int (*flip)(void *); + void *flip_data; +}; + +#define nouveau_software_context_create(p,e,c,d) \ + nouveau_engctx_create((p), (e), (c), (p), 0, 0, 0, (d)) +#define nouveau_software_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_software_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_software_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_software_context_dtor _nouveau_engctx_dtor +#define _nouveau_software_context_init _nouveau_engctx_init +#define _nouveau_software_context_fini _nouveau_engctx_fini + +struct nouveau_software { + struct nouveau_engine base; +}; + +#define nouveau_software_create(p,e,c,d) \ + nouveau_engine_create((p), (e), (c), true, "SW", "software", (d)) +#define nouveau_software_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_software_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_software_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_software_dtor _nouveau_engine_dtor +#define _nouveau_software_init _nouveau_engine_init +#define _nouveau_software_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv04_software_oclass; +extern struct nouveau_oclass nv10_software_oclass; +extern struct nouveau_oclass nv50_software_oclass; +extern struct nouveau_oclass nvc0_software_oclass; + +void nv04_software_intr(struct nouveau_subdev *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/vp.h b/drivers/gpu/drm/nouveau/core/include/engine/vp.h new file mode 100644 index 00000000000..05cd08fba37 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/vp.h @@ -0,0 +1,45 @@ +#ifndef __NOUVEAU_VP_H__ +#define __NOUVEAU_VP_H__ + +#include <core/engine.h> +#include <core/engctx.h> + +struct nouveau_vp_chan { + struct nouveau_engctx base; +}; + +#define nouveau_vp_context_create(p,e,c,g,s,a,f,d) \ + nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) +#define nouveau_vp_context_destroy(d) \ + nouveau_engctx_destroy(&(d)->base) +#define nouveau_vp_context_init(d) \ + nouveau_engctx_init(&(d)->base) +#define nouveau_vp_context_fini(d,s) \ + nouveau_engctx_fini(&(d)->base, (s)) + +#define _nouveau_vp_context_dtor _nouveau_engctx_dtor +#define _nouveau_vp_context_init _nouveau_engctx_init +#define _nouveau_vp_context_fini _nouveau_engctx_fini +#define _nouveau_vp_context_rd32 _nouveau_engctx_rd32 +#define _nouveau_vp_context_wr32 _nouveau_engctx_wr32 + +struct nouveau_vp { + struct nouveau_engine base; +}; + +#define nouveau_vp_create(p,e,c,d) \ + nouveau_engine_create((p), (e), (c), true, "PVP", "vp", (d)) +#define nouveau_vp_destroy(d) \ + nouveau_engine_destroy(&(d)->base) +#define nouveau_vp_init(d) \ + nouveau_engine_init(&(d)->base) +#define nouveau_vp_fini(d,s) \ + nouveau_engine_fini(&(d)->base, (s)) + +#define _nouveau_vp_dtor _nouveau_engine_dtor +#define _nouveau_vp_init _nouveau_engine_init +#define _nouveau_vp_fini _nouveau_engine_fini + +extern struct nouveau_oclass nv84_vp_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h new file mode 100644 index 00000000000..4f4ff4502c3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h @@ -0,0 +1,55 @@ +#ifndef __NOUVEAU_BAR_H__ +#define __NOUVEAU_BAR_H__ + +#include <core/subdev.h> +#include <core/device.h> + +#include <subdev/fb.h> + +struct nouveau_vma; + +struct nouveau_bar { + struct nouveau_subdev base; + + int (*alloc)(struct nouveau_bar *, struct nouveau_object *, + struct nouveau_mem *, struct nouveau_object **); + void __iomem *iomem; + + int (*kmap)(struct nouveau_bar *, struct nouveau_mem *, + u32 flags, struct nouveau_vma *); + int (*umap)(struct nouveau_bar *, struct nouveau_mem *, + u32 flags, struct nouveau_vma *); + void (*unmap)(struct nouveau_bar *, struct nouveau_vma *); + void (*flush)(struct nouveau_bar *); +}; + +static inline struct nouveau_bar * +nouveau_bar(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BAR]; +} + +#define nouveau_bar_create(p,e,o,d) \ + nouveau_bar_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_bar_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_bar_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +int nouveau_bar_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void nouveau_bar_destroy(struct nouveau_bar *); + +void _nouveau_bar_dtor(struct nouveau_object *); +#define _nouveau_bar_init _nouveau_subdev_init +#define _nouveau_bar_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv50_bar_oclass; +extern struct nouveau_oclass nvc0_bar_oclass; + +int nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *, + struct nouveau_mem *, struct nouveau_object **); + +void nv84_bar_flush(struct nouveau_bar *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios.h new file mode 100644 index 00000000000..d145b25e6be --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios.h @@ -0,0 +1,34 @@ +#ifndef __NOUVEAU_BIOS_H__ +#define __NOUVEAU_BIOS_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_bios { + struct nouveau_subdev base; + u32 size; + u8 *data; + + u32 bmp_offset; + u32 bit_offset; + + struct { + u8 major; + u8 chip; + u8 minor; + u8 micro; + } version; +}; + +static inline struct nouveau_bios * +nouveau_bios(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VBIOS]; +} + +u8 nvbios_checksum(const u8 *data, int size); +u16 nvbios_findstr(const u8 *data, int size, const char *str, int len); + +extern struct nouveau_oclass nouveau_bios_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h new file mode 100644 index 00000000000..73f060b0798 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h @@ -0,0 +1,13 @@ +#ifndef __NVBIOS_BIT_H__ +#define __NVBIOS_BIT_H__ + +struct bit_entry { + u8 id; + u8 version; + u16 length; + u16 offset; +}; + +int bit_entry(struct nouveau_bios *, u8 id, struct bit_entry *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h new file mode 100644 index 00000000000..10e4dbca649 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h @@ -0,0 +1,39 @@ +#ifndef __NVBIOS_BMP_H__ +#define __NVBIOS_BMP_H__ + +static inline u16 +bmp_version(struct nouveau_bios *bios) +{ + if (bios->bmp_offset) { + return nv_ro08(bios, bios->bmp_offset + 5) << 8 | + nv_ro08(bios, bios->bmp_offset + 6); + } + + return 0x0000; +} + +static inline u16 +bmp_mem_init_table(struct nouveau_bios *bios) +{ + if (bmp_version(bios) >= 0x0300) + return nv_ro16(bios, bios->bmp_offset + 24); + return 0x0000; +} + +static inline u16 +bmp_sdr_seq_table(struct nouveau_bios *bios) +{ + if (bmp_version(bios) >= 0x0300) + return nv_ro16(bios, bios->bmp_offset + 26); + return 0x0000; +} + +static inline u16 +bmp_ddr_seq_table(struct nouveau_bios *bios) +{ + if (bmp_version(bios) >= 0x0300) + return nv_ro16(bios, bios->bmp_offset + 28); + return 0x0000; +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h new file mode 100644 index 00000000000..c1270548fd0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h @@ -0,0 +1,27 @@ +#ifndef __NVBIOS_CONN_H__ +#define __NVBIOS_CONN_H__ + +enum dcb_connector_type { + DCB_CONNECTOR_VGA = 0x00, + DCB_CONNECTOR_TV_0 = 0x10, + DCB_CONNECTOR_TV_1 = 0x11, + DCB_CONNECTOR_TV_3 = 0x13, + DCB_CONNECTOR_DVI_I = 0x30, + DCB_CONNECTOR_DVI_D = 0x31, + DCB_CONNECTOR_DMS59_0 = 0x38, + DCB_CONNECTOR_DMS59_1 = 0x39, + DCB_CONNECTOR_LVDS = 0x40, + DCB_CONNECTOR_LVDS_SPWG = 0x41, + DCB_CONNECTOR_DP = 0x46, + DCB_CONNECTOR_eDP = 0x47, + DCB_CONNECTOR_HDMI_0 = 0x60, + DCB_CONNECTOR_HDMI_1 = 0x61, + DCB_CONNECTOR_DMS59_DP0 = 0x64, + DCB_CONNECTOR_DMS59_DP1 = 0x65, + DCB_CONNECTOR_NONE = 0xff +}; + +u16 dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h new file mode 100644 index 00000000000..d682fb62583 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h @@ -0,0 +1,90 @@ +#ifndef __NVBIOS_DCB_H__ +#define __NVBIOS_DCB_H__ + +struct nouveau_bios; + +enum dcb_output_type { + DCB_OUTPUT_ANALOG = 0x0, + DCB_OUTPUT_TV = 0x1, + DCB_OUTPUT_TMDS = 0x2, + DCB_OUTPUT_LVDS = 0x3, + DCB_OUTPUT_DP = 0x6, + DCB_OUTPUT_EOL = 0xe, + DCB_OUTPUT_UNUSED = 0xf, + DCB_OUTPUT_ANY = -1, +}; + +struct dcb_output { + int index; /* may not be raw dcb index if merging has happened */ + enum dcb_output_type type; + uint8_t i2c_index; + uint8_t heads; + uint8_t connector; + uint8_t bus; + uint8_t location; + uint8_t or; + bool duallink_possible; + union { + struct sor_conf { + int link; + } sorconf; + struct { + int maxfreq; + } crtconf; + struct { + struct sor_conf sor; + bool use_straps_for_mode; + bool use_acpi_for_edid; + bool use_power_scripts; + } lvdsconf; + struct { + bool has_component_output; + } tvconf; + struct { + struct sor_conf sor; + int link_nr; + int link_bw; + } dpconf; + struct { + struct sor_conf sor; + int slave_addr; + } tmdsconf; + }; + bool i2c_upper_default; +}; + +u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len); +u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); +int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec) + (struct nouveau_bios *, void *, int index, u16 entry)); + + +/* BIT 'U'/'d' table encoder subtables have hashes matching them to + * a particular set of encoders. + * + * This function returns true if a particular DCB entry matches. + */ +static inline bool +dcb_hash_match(struct dcb_output *dcb, u32 hash) +{ + if ((hash & 0x000000f0) != (dcb->location << 4)) + return false; + if ((hash & 0x0000000f) != dcb->type) + return false; + if (!(hash & (dcb->or << 16))) + return false; + + switch (dcb->type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_LVDS: + case DCB_OUTPUT_DP: + if (hash & 0x00c00000) { + if (!(hash & (dcb->sorconf.link << 22))) + return false; + } + default: + return true; + } +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h new file mode 100644 index 00000000000..73b5e5d3e75 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h @@ -0,0 +1,8 @@ +#ifndef __NVBIOS_DP_H__ +#define __NVBIOS_DP_H__ + +u16 dp_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 dp_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); +u16 dp_outp_match(struct nouveau_bios *, struct dcb_output *, u8 *ver, u8 *len); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h new file mode 100644 index 00000000000..949fee3af8f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h @@ -0,0 +1,30 @@ +#ifndef __NVBIOS_EXTDEV_H__ +#define __NVBIOS_EXTDEV_H__ + +struct nouveau_bios; + +enum nvbios_extdev_type { + NVBIOS_EXTDEV_LM89 = 0x02, + NVBIOS_EXTDEV_VT1103M = 0x40, + NVBIOS_EXTDEV_PX3540 = 0x41, + NVBIOS_EXTDEV_VT1105M = 0x42, /* or close enough... */ + NVBIOS_EXTDEV_ADT7473 = 0x70, /* can also be a LM64 */ + NVBIOS_EXTDEV_HDCP_EEPROM = 0x90, + NVBIOS_EXTDEV_NONE = 0xff, +}; + +struct nvbios_extdev_func { + u8 type; + u8 addr; + u8 bus; +}; + +int +nvbios_extdev_parse(struct nouveau_bios *, int, struct nvbios_extdev_func *); + +int +nvbios_extdev_find(struct nouveau_bios *, enum nvbios_extdev_type, + struct nvbios_extdev_func *); + + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h new file mode 100644 index 00000000000..2bf178082a3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h @@ -0,0 +1,33 @@ +#ifndef __NVBIOS_GPIO_H__ +#define __NVBIOS_GPIO_H__ + +struct nouveau_bios; + +enum dcb_gpio_func_name { + DCB_GPIO_PANEL_POWER = 0x01, + DCB_GPIO_TVDAC0 = 0x0c, + DCB_GPIO_TVDAC1 = 0x2d, + DCB_GPIO_PWM_FAN = 0x09, + DCB_GPIO_FAN_SENSE = 0x3d, + DCB_GPIO_UNUSED = 0xff +}; + +struct dcb_gpio_func { + u8 func; + u8 line; + u8 log[2]; + + /* so far, "param" seems to only have an influence on PWM-related + * GPIOs such as FAN_CONTROL and PANEL_BACKLIGHT_LEVEL. + * if param equals 1, hardware PWM is available + * if param equals 0, the host should toggle the GPIO itself + */ + u8 param; +}; + +u16 dcb_gpio_table(struct nouveau_bios *); +u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver); +int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line, + struct dcb_gpio_func *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h new file mode 100644 index 00000000000..5079bedfd98 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h @@ -0,0 +1,25 @@ +#ifndef __NVBIOS_I2C_H__ +#define __NVBIOS_I2C_H__ + +struct nouveau_bios; + +enum dcb_i2c_type { + DCB_I2C_NV04_BIT = 0, + DCB_I2C_NV4E_BIT = 4, + DCB_I2C_NVIO_BIT = 5, + DCB_I2C_NVIO_AUX = 6, + DCB_I2C_UNUSED = 0xff +}; + +struct dcb_i2c_entry { + enum dcb_i2c_type type; + u8 drive; + u8 sense; + u32 data; +}; + +u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 dcb_i2c_entry(struct nouveau_bios *, u8 index, u8 *ver, u8 *len); +int dcb_i2c_parse(struct nouveau_bios *, u8 index, struct dcb_i2c_entry *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h new file mode 100644 index 00000000000..e69a8bdc6e9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h @@ -0,0 +1,21 @@ +#ifndef __NVBIOS_INIT_H__ +#define __NVBIOS_INIT_H__ + +struct nvbios_init { + struct nouveau_subdev *subdev; + struct nouveau_bios *bios; + u16 offset; + struct dcb_output *outp; + int crtc; + + /* internal state used during parsing */ + u8 execute; + u32 nested; + u16 repeat; + u16 repend; +}; + +int nvbios_exec(struct nvbios_init *); +int nvbios_init(struct nouveau_subdev *, bool execute); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h new file mode 100644 index 00000000000..5572e60414e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h @@ -0,0 +1,9 @@ +#ifndef __NVBIOS_MXM_H__ +#define __NVBIOS_MXM_H__ + +u16 mxm_table(struct nouveau_bios *, u8 *ver, u8 *hdr); + +u8 mxm_sor_map(struct nouveau_bios *, u8 conn); +u8 mxm_ddc_map(struct nouveau_bios *, u8 port); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h new file mode 100644 index 00000000000..0b285e99be5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h @@ -0,0 +1,14 @@ +#ifndef __NVBIOS_PERF_H__ +#define __NVBIOS_PERF_H__ + +struct nouveau_bios; + +struct nvbios_perf_fan { + u32 pwm_divisor; +}; + +int +nvbios_perf_fan_parse(struct nouveau_bios *, struct nvbios_perf_fan *); + + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h new file mode 100644 index 00000000000..c345097592f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h @@ -0,0 +1,77 @@ +#ifndef __NVBIOS_PLL_H__ +#define __NVBIOS_PLL_H__ + +/*XXX: kill me */ +struct nouveau_pll_vals { + union { + struct { +#ifdef __BIG_ENDIAN + uint8_t N1, M1, N2, M2; +#else + uint8_t M1, N1, M2, N2; +#endif + }; + struct { + uint16_t NM1, NM2; + } __attribute__((packed)); + }; + int log2P; + + int refclk; +}; + +struct nouveau_bios; + +/* these match types in pll limits table version 0x40, + * nouveau uses them on all chipsets internally where a + * specific pll needs to be referenced, but the exact + * register isn't known. + */ +enum nvbios_pll_type { + PLL_CORE = 0x01, + PLL_SHADER = 0x02, + PLL_UNK03 = 0x03, + PLL_MEMORY = 0x04, + PLL_VDEC = 0x05, + PLL_UNK40 = 0x40, + PLL_UNK41 = 0x41, + PLL_UNK42 = 0x42, + PLL_VPLL0 = 0x80, + PLL_VPLL1 = 0x81, + PLL_MAX = 0xff +}; + +struct nvbios_pll { + enum nvbios_pll_type type; + u32 reg; + u32 refclk; + + u8 min_p; + u8 max_p; + u8 bias_p; + + /* + * for most pre nv50 cards setting a log2P of 7 (the common max_log2p + * value) is no different to 6 (at least for vplls) so allowing the MNP + * calc to use 7 causes the generated clock to be out by a factor of 2. + * however, max_log2p cannot be fixed-up during parsing as the + * unmodified max_log2p value is still needed for setting mplls, hence + * an additional max_usable_log2p member + */ + u8 max_p_usable; + + struct { + u32 min_freq; + u32 max_freq; + u32 min_inputfreq; + u32 max_inputfreq; + u8 min_m; + u8 max_m; + u8 min_n; + u8 max_n; + } vco1, vco2; +}; + +int nvbios_pll_parse(struct nouveau_bios *, u32 type, struct nvbios_pll *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h new file mode 100644 index 00000000000..a2c4296fc5f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h @@ -0,0 +1,46 @@ +#ifndef __NVBIOS_THERM_H__ +#define __NVBIOS_THERM_H__ + +struct nouveau_bios; + +struct nvbios_therm_threshold { + u8 temp; + u8 hysteresis; +}; + +struct nvbios_therm_sensor { + /* diode */ + s16 slope_mult; + s16 slope_div; + s16 offset_num; + s16 offset_den; + s8 offset_constant; + + /* thresholds */ + struct nvbios_therm_threshold thrs_fan_boost; + struct nvbios_therm_threshold thrs_down_clock; + struct nvbios_therm_threshold thrs_critical; + struct nvbios_therm_threshold thrs_shutdown; +}; + +struct nvbios_therm_fan { + u16 pwm_freq; + + u8 min_duty; + u8 max_duty; +}; + +enum nvbios_therm_domain { + NVBIOS_THERM_DOMAIN_CORE, + NVBIOS_THERM_DOMAIN_AMBIENT, +}; + +int +nvbios_therm_sensor_parse(struct nouveau_bios *, enum nvbios_therm_domain, + struct nvbios_therm_sensor *); + +int +nvbios_therm_fan_parse(struct nouveau_bios *, struct nvbios_therm_fan *); + + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h new file mode 100644 index 00000000000..39e73b91d36 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -0,0 +1,59 @@ +#ifndef __NOUVEAU_CLOCK_H__ +#define __NOUVEAU_CLOCK_H__ + +#include <core/device.h> +#include <core/subdev.h> + +struct nouveau_pll_vals; +struct nvbios_pll; + +struct nouveau_clock { + struct nouveau_subdev base; + + int (*pll_set)(struct nouveau_clock *, u32 type, u32 freq); + + /*XXX: die, these are here *only* to support the completely + * bat-shit insane what-was-nouveau_hw.c code + */ + int (*pll_calc)(struct nouveau_clock *, struct nvbios_pll *, + int clk, struct nouveau_pll_vals *pv); + int (*pll_prog)(struct nouveau_clock *, u32 reg1, + struct nouveau_pll_vals *pv); +}; + +static inline struct nouveau_clock * +nouveau_clock(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_CLOCK]; +} + +#define nouveau_clock_create(p,e,o,d) \ + nouveau_subdev_create((p), (e), (o), 0, "CLOCK", "clock", d) +#define nouveau_clock_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_clock_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_clock_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +int nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, int, void **); + +#define _nouveau_clock_dtor _nouveau_subdev_dtor +#define _nouveau_clock_init _nouveau_subdev_init +#define _nouveau_clock_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv04_clock_oclass; +extern struct nouveau_oclass nv40_clock_oclass; +extern struct nouveau_oclass nv50_clock_oclass; +extern struct nouveau_oclass nva3_clock_oclass; +extern struct nouveau_oclass nvc0_clock_oclass; + +int nv04_clock_pll_set(struct nouveau_clock *, u32 type, u32 freq); +int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, + int clk, struct nouveau_pll_vals *); +int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1, + struct nouveau_pll_vals *); + + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/device.h b/drivers/gpu/drm/nouveau/core/include/subdev/device.h new file mode 100644 index 00000000000..c9e4c4afa50 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/device.h @@ -0,0 +1,24 @@ +#ifndef __NOUVEAU_SUBDEV_DEVICE_H__ +#define __NOUVEAU_SUBDEV_DEVICE_H__ + +#include <core/device.h> + +#define nouveau_device_create(p,n,s,c,d,u) \ + nouveau_device_create_((p), (n), (s), (c), (d), sizeof(**u), (void **)u) + +int nouveau_device_create_(struct pci_dev *, u64 name, const char *sname, + const char *cfg, const char *dbg, int, void **); + +int nv04_identify(struct nouveau_device *); +int nv10_identify(struct nouveau_device *); +int nv20_identify(struct nouveau_device *); +int nv30_identify(struct nouveau_device *); +int nv40_identify(struct nouveau_device *); +int nv50_identify(struct nouveau_device *); +int nvc0_identify(struct nouveau_device *); +int nve0_identify(struct nouveau_device *); + +extern struct nouveau_oclass nouveau_device_sclass[]; +struct nouveau_device *nouveau_device_find(u64 name); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h new file mode 100644 index 00000000000..29e4cc1f6cc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h @@ -0,0 +1,40 @@ +#ifndef __NOUVEAU_DEVINIT_H__ +#define __NOUVEAU_DEVINIT_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_devinit { + struct nouveau_subdev base; + bool post; + void (*meminit)(struct nouveau_devinit *); +}; + +static inline struct nouveau_devinit * +nouveau_devinit(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_DEVINIT]; +} + +#define nouveau_devinit_create(p,e,o,d) \ + nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_devinit_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) + +int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int nouveau_devinit_init(struct nouveau_devinit *); +int nouveau_devinit_fini(struct nouveau_devinit *, bool suspend); + +extern struct nouveau_oclass nv04_devinit_oclass; +extern struct nouveau_oclass nv05_devinit_oclass; +extern struct nouveau_oclass nv10_devinit_oclass; +extern struct nouveau_oclass nv1a_devinit_oclass; +extern struct nouveau_oclass nv20_devinit_oclass; +extern struct nouveau_oclass nv50_devinit_oclass; + +void nv04_devinit_dtor(struct nouveau_object *); +int nv04_devinit_init(struct nouveau_object *); +int nv04_devinit_fini(struct nouveau_object *, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h new file mode 100644 index 00000000000..5c1b5e1904f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h @@ -0,0 +1,134 @@ +#ifndef __NOUVEAU_FB_H__ +#define __NOUVEAU_FB_H__ + +#include <core/subdev.h> +#include <core/device.h> +#include <core/mm.h> + +#include <subdev/vm.h> + +/* memory type/access flags, do not match hardware values */ +#define NV_MEM_ACCESS_RO 1 +#define NV_MEM_ACCESS_WO 2 +#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO) +#define NV_MEM_ACCESS_SYS 4 +#define NV_MEM_ACCESS_VM 8 +#define NV_MEM_ACCESS_NOSNOOP 16 + +#define NV_MEM_TARGET_VRAM 0 +#define NV_MEM_TARGET_PCI 1 +#define NV_MEM_TARGET_PCI_NOSNOOP 2 +#define NV_MEM_TARGET_VM 3 +#define NV_MEM_TARGET_GART 4 + +#define NV_MEM_TYPE_VM 0x7f +#define NV_MEM_COMP_VM 0x03 + +struct nouveau_mem { + struct drm_device *dev; + + struct nouveau_vma bar_vma; + struct nouveau_vma vma[2]; + u8 page_shift; + + struct nouveau_mm_node *tag; + struct list_head regions; + dma_addr_t *pages; + u32 memtype; + u64 offset; + u64 size; + struct sg_table *sg; +}; + +struct nouveau_fb_tile { + struct nouveau_mm_node *tag; + u32 addr; + u32 limit; + u32 pitch; + u32 zcomp; +}; + +struct nouveau_fb { + struct nouveau_subdev base; + + bool (*memtype_valid)(struct nouveau_fb *, u32 memtype); + + struct { + enum { + NV_MEM_TYPE_UNKNOWN = 0, + NV_MEM_TYPE_STOLEN, + NV_MEM_TYPE_SGRAM, + NV_MEM_TYPE_SDRAM, + NV_MEM_TYPE_DDR1, + NV_MEM_TYPE_DDR2, + NV_MEM_TYPE_DDR3, + NV_MEM_TYPE_GDDR2, + NV_MEM_TYPE_GDDR3, + NV_MEM_TYPE_GDDR4, + NV_MEM_TYPE_GDDR5 + } type; + u64 stolen; + u64 size; + int ranks; + + int (*get)(struct nouveau_fb *, u64 size, u32 align, + u32 size_nc, u32 type, struct nouveau_mem **); + void (*put)(struct nouveau_fb *, struct nouveau_mem **); + } ram; + + struct nouveau_mm vram; + struct nouveau_mm tags; + + struct { + struct nouveau_fb_tile region[16]; + int regions; + void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); + void (*fini)(struct nouveau_fb *, int i, + struct nouveau_fb_tile *); + void (*prog)(struct nouveau_fb *, int i, + struct nouveau_fb_tile *); + } tile; +}; + +static inline struct nouveau_fb * +nouveau_fb(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB]; +} + +#define nouveau_fb_create(p,e,c,d) \ + nouveau_subdev_create((p), (e), (c), 0, "PFB", "fb", (d)) +int nouveau_fb_created(struct nouveau_fb *); +void nouveau_fb_destroy(struct nouveau_fb *); +int nouveau_fb_init(struct nouveau_fb *); +#define nouveau_fb_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +void _nouveau_fb_dtor(struct nouveau_object *); +int _nouveau_fb_init(struct nouveau_object *); +#define _nouveau_fb_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv04_fb_oclass; +extern struct nouveau_oclass nv10_fb_oclass; +extern struct nouveau_oclass nv20_fb_oclass; +extern struct nouveau_oclass nv30_fb_oclass; +extern struct nouveau_oclass nv40_fb_oclass; +extern struct nouveau_oclass nv50_fb_oclass; +extern struct nouveau_oclass nvc0_fb_oclass; + +struct nouveau_bios; +int nouveau_fb_bios_memtype(struct nouveau_bios *); + +bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype); + +void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); +void nv30_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *); + +void nv50_fb_vram_del(struct nouveau_fb *, struct nouveau_mem **); +void nv50_fb_trap(struct nouveau_fb *, int display); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h new file mode 100644 index 00000000000..9ea2b12cc15 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h @@ -0,0 +1,64 @@ +#ifndef __NOUVEAU_GPIO_H__ +#define __NOUVEAU_GPIO_H__ + +#include <core/subdev.h> +#include <core/device.h> + +#include <subdev/bios.h> +#include <subdev/bios/gpio.h> + +struct nouveau_gpio { + struct nouveau_subdev base; + + /* hardware interfaces */ + void (*reset)(struct nouveau_gpio *); + int (*drive)(struct nouveau_gpio *, int line, int dir, int out); + int (*sense)(struct nouveau_gpio *, int line); + void (*irq_enable)(struct nouveau_gpio *, int line, bool); + + /* software interfaces */ + int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, + struct dcb_gpio_func *); + int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); + int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line); + int (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on); + + /* interrupt handling */ + struct list_head isr; + spinlock_t lock; + + void (*isr_run)(struct nouveau_gpio *, int idx, u32 mask); + int (*isr_add)(struct nouveau_gpio *, int idx, u8 tag, u8 line, + void (*)(void *, int state), void *data); + void (*isr_del)(struct nouveau_gpio *, int idx, u8 tag, u8 line, + void (*)(void *, int state), void *data); +}; + +static inline struct nouveau_gpio * +nouveau_gpio(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO]; +} + +#define nouveau_gpio_create(p,e,o,d) \ + nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_gpio_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_gpio_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int nouveau_gpio_init(struct nouveau_gpio *); + +extern struct nouveau_oclass nv10_gpio_oclass; +extern struct nouveau_oclass nv50_gpio_oclass; +extern struct nouveau_oclass nvd0_gpio_oclass; + +void nv50_gpio_dtor(struct nouveau_object *); +int nv50_gpio_init(struct nouveau_object *); +int nv50_gpio_fini(struct nouveau_object *, bool); +void nv50_gpio_intr(struct nouveau_subdev *); +void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h new file mode 100644 index 00000000000..b93ab01e378 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h @@ -0,0 +1,60 @@ +#ifndef __NOUVEAU_I2C_H__ +#define __NOUVEAU_I2C_H__ + +#include <core/subdev.h> +#include <core/device.h> + +#include <subdev/bios.h> +#include <subdev/bios/i2c.h> + +#define NV_I2C_PORT(n) (0x00 + (n)) +#define NV_I2C_DEFAULT(n) (0x80 + (n)) + +struct nouveau_i2c_port { + struct i2c_adapter adapter; + struct nouveau_i2c *i2c; + struct i2c_algo_bit_data bit; + struct list_head head; + u8 index; + u8 type; + u32 dcb; + u32 drive; + u32 sense; + u32 state; +}; + +struct nouveau_i2c { + struct nouveau_subdev base; + + struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); + int (*identify)(struct nouveau_i2c *, int index, + const char *what, struct i2c_board_info *, + bool (*match)(struct nouveau_i2c_port *, + struct i2c_board_info *)); + struct list_head ports; +}; + +static inline struct nouveau_i2c * +nouveau_i2c(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C]; +} + +extern struct nouveau_oclass nouveau_i2c_oclass; + +void nouveau_i2c_drive_scl(void *, int); +void nouveau_i2c_drive_sda(void *, int); +int nouveau_i2c_sense_scl(void *); +int nouveau_i2c_sense_sda(void *); + +int nv_rdi2cr(struct nouveau_i2c_port *, u8 addr, u8 reg); +int nv_wri2cr(struct nouveau_i2c_port *, u8 addr, u8 reg, u8 val); +bool nv_probe_i2c(struct nouveau_i2c_port *, u8 addr); + +int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); +int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); + +extern const struct i2c_algorithm nouveau_i2c_bit_algo; +extern const struct i2c_algorithm nouveau_i2c_aux_algo; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h b/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h new file mode 100644 index 00000000000..88814f159d8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h @@ -0,0 +1,34 @@ +#ifndef __NOUVEAU_IBUS_H__ +#define __NOUVEAU_IBUS_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_ibus { + struct nouveau_subdev base; +}; + +static inline struct nouveau_ibus * +nouveau_ibus(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_IBUS]; +} + +#define nouveau_ibus_create(p,e,o,d) \ + nouveau_subdev_create_((p), (e), (o), 0, "PIBUS", "ibus", \ + sizeof(**d), (void **)d) +#define nouveau_ibus_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_ibus_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_ibus_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +#define _nouveau_ibus_dtor _nouveau_subdev_dtor +#define _nouveau_ibus_init _nouveau_subdev_init +#define _nouveau_ibus_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nvc0_ibus_oclass; +extern struct nouveau_oclass nve0_ibus_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h new file mode 100644 index 00000000000..ec7a54e91a0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h @@ -0,0 +1,73 @@ +#ifndef __NOUVEAU_INSTMEM_H__ +#define __NOUVEAU_INSTMEM_H__ + +#include <core/subdev.h> +#include <core/device.h> +#include <core/mm.h> + +struct nouveau_instobj { + struct nouveau_object base; + struct list_head head; + u32 *suspend; + u64 addr; + u32 size; +}; + +static inline struct nouveau_instobj * +nv_memobj(void *obj) +{ +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + if (unlikely(!nv_iclass(obj, NV_MEMOBJ_CLASS))) + nv_assert("BAD CAST -> NvMemObj, %08x", nv_hclass(obj)); +#endif + return obj; +} + +#define nouveau_instobj_create(p,e,o,d) \ + nouveau_instobj_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_instobj_init(p) \ + nouveau_object_init(&(p)->base) +#define nouveau_instobj_fini(p,s) \ + nouveau_object_fini(&(p)->base, (s)) + +int nouveau_instobj_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void nouveau_instobj_destroy(struct nouveau_instobj *); + +void _nouveau_instobj_dtor(struct nouveau_object *); +#define _nouveau_instobj_init nouveau_object_init +#define _nouveau_instobj_fini nouveau_object_fini + +struct nouveau_instmem { + struct nouveau_subdev base; + struct list_head list; + + u32 reserved; + int (*alloc)(struct nouveau_instmem *, struct nouveau_object *, + u32 size, u32 align, struct nouveau_object **); +}; + +static inline struct nouveau_instmem * +nouveau_instmem(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_INSTMEM]; +} + +#define nouveau_instmem_create(p,e,o,d) \ + nouveau_instmem_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_instmem_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +int nouveau_instmem_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int nouveau_instmem_init(struct nouveau_instmem *); +int nouveau_instmem_fini(struct nouveau_instmem *, bool); + +#define _nouveau_instmem_dtor _nouveau_subdev_dtor +int _nouveau_instmem_init(struct nouveau_object *); +int _nouveau_instmem_fini(struct nouveau_object *, bool); + +extern struct nouveau_oclass nv04_instmem_oclass; +extern struct nouveau_oclass nv40_instmem_oclass; +extern struct nouveau_oclass nv50_instmem_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h new file mode 100644 index 00000000000..f351f63bc65 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h @@ -0,0 +1,33 @@ +#ifndef __NOUVEAU_LTCG_H__ +#define __NOUVEAU_LTCG_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_ltcg { + struct nouveau_subdev base; +}; + +static inline struct nouveau_ltcg * +nouveau_ltcg(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_LTCG]; +} + +#define nouveau_ltcg_create(p,e,o,d) \ + nouveau_subdev_create_((p), (e), (o), 0, "PLTCG", "level2", \ + sizeof(**d), (void **)d) +#define nouveau_ltcg_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_ltcg_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_ltcg_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +#define _nouveau_ltcg_dtor _nouveau_subdev_dtor +#define _nouveau_ltcg_init _nouveau_subdev_init +#define _nouveau_ltcg_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nvc0_ltcg_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h new file mode 100644 index 00000000000..fded97cea50 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h @@ -0,0 +1,49 @@ +#ifndef __NOUVEAU_MC_H__ +#define __NOUVEAU_MC_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_mc_intr { + u32 stat; + u32 unit; +}; + +struct nouveau_mc { + struct nouveau_subdev base; + const struct nouveau_mc_intr *intr_map; +}; + +static inline struct nouveau_mc * +nouveau_mc(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC]; +} + +#define nouveau_mc_create(p,e,o,d) \ + nouveau_subdev_create_((p), (e), (o), 0, "PMC", "master", \ + sizeof(**d), (void **)d) +#define nouveau_mc_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_mc_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_mc_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +#define _nouveau_mc_dtor _nouveau_subdev_dtor +#define _nouveau_mc_init _nouveau_subdev_init +#define _nouveau_mc_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv04_mc_oclass; +extern struct nouveau_oclass nv44_mc_oclass; +extern struct nouveau_oclass nv50_mc_oclass; +extern struct nouveau_oclass nv98_mc_oclass; +extern struct nouveau_oclass nvc0_mc_oclass; + +void nouveau_mc_intr(struct nouveau_subdev *); + +extern const struct nouveau_mc_intr nv04_mc_intr[]; +int nv04_mc_init(struct nouveau_object *); +int nv50_mc_init(struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h b/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h new file mode 100644 index 00000000000..b93b152cb56 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h @@ -0,0 +1,37 @@ +#ifndef __NOUVEAU_MXM_H__ +#define __NOUVEAU_MXM_H__ + +#include <core/subdev.h> +#include <core/device.h> + +#define MXM_SANITISE_DCB 0x00000001 + +struct nouveau_mxm { + struct nouveau_subdev base; + u32 action; + u8 *mxms; +}; + +static inline struct nouveau_mxm * +nouveau_mxm(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MXM]; +} + +#define nouveau_mxm_create(p,e,o,d) \ + nouveau_mxm_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_mxm_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_mxm_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) +int nouveau_mxm_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void nouveau_mxm_destroy(struct nouveau_mxm *); + +#define _nouveau_mxm_dtor _nouveau_subdev_dtor +#define _nouveau_mxm_init _nouveau_subdev_init +#define _nouveau_mxm_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv50_mxm_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h new file mode 100644 index 00000000000..faee569fd45 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h @@ -0,0 +1,58 @@ +#ifndef __NOUVEAU_THERM_H__ +#define __NOUVEAU_THERM_H__ + +#include <core/device.h> +#include <core/subdev.h> + +enum nouveau_therm_fan_mode { + FAN_CONTROL_NONE = 0, + FAN_CONTROL_MANUAL = 1, + FAN_CONTROL_NR, +}; + +enum nouveau_therm_attr_type { + NOUVEAU_THERM_ATTR_FAN_MIN_DUTY = 0, + NOUVEAU_THERM_ATTR_FAN_MAX_DUTY = 1, + NOUVEAU_THERM_ATTR_FAN_MODE = 2, + + NOUVEAU_THERM_ATTR_THRS_FAN_BOOST = 10, + NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST = 11, + NOUVEAU_THERM_ATTR_THRS_DOWN_CLK = 12, + NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST = 13, + NOUVEAU_THERM_ATTR_THRS_CRITICAL = 14, + NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST = 15, + NOUVEAU_THERM_ATTR_THRS_SHUTDOWN = 16, + NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST = 17, +}; + +struct nouveau_therm { + struct nouveau_subdev base; + + int (*fan_get)(struct nouveau_therm *); + int (*fan_set)(struct nouveau_therm *, int); + int (*fan_sense)(struct nouveau_therm *); + + int (*temp_get)(struct nouveau_therm *); + + int (*attr_get)(struct nouveau_therm *, enum nouveau_therm_attr_type); + int (*attr_set)(struct nouveau_therm *, + enum nouveau_therm_attr_type, int); +}; + +static inline struct nouveau_therm * +nouveau_therm(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_THERM]; +} + +#define nouveau_therm_create(p,e,o,d) \ + nouveau_subdev_create((p), (e), (o), 0, "THERM", "therm", d) +#define nouveau_therm_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) + +#define _nouveau_therm_dtor _nouveau_subdev_dtor + +extern struct nouveau_oclass nv40_therm_oclass; +extern struct nouveau_oclass nv50_therm_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h new file mode 100644 index 00000000000..49bff901544 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h @@ -0,0 +1,53 @@ +#ifndef __NOUVEAU_TIMER_H__ +#define __NOUVEAU_TIMER_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_alarm { + struct list_head head; + u64 timestamp; + void (*func)(struct nouveau_alarm *); +}; + +bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data); +bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data); +bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data); +void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *); + +#define NV_WAIT_DEFAULT 2000000000ULL +#define nv_wait(o,a,m,v) \ + nouveau_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v)) +#define nv_wait_ne(o,a,m,v) \ + nouveau_timer_wait_ne((o), NV_WAIT_DEFAULT, (a), (m), (v)) +#define nv_wait_cb(o,c,d) \ + nouveau_timer_wait_cb((o), NV_WAIT_DEFAULT, (c), (d)) + +struct nouveau_timer { + struct nouveau_subdev base; + u64 (*read)(struct nouveau_timer *); + void (*alarm)(struct nouveau_timer *, u32 time, struct nouveau_alarm *); +}; + +static inline struct nouveau_timer * +nouveau_timer(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_TIMER]; +} + +#define nouveau_timer_create(p,e,o,d) \ + nouveau_subdev_create_((p), (e), (o), 0, "PTIMER", "timer", \ + sizeof(**d), (void **)d) +#define nouveau_timer_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_timer_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_timer_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +int nouveau_timer_create_(struct nouveau_object *, struct nouveau_engine *, + struct nouveau_oclass *, int size, void **); + +extern struct nouveau_oclass nv04_timer_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vga.h b/drivers/gpu/drm/nouveau/core/include/subdev/vga.h new file mode 100644 index 00000000000..fee09ad818e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/vga.h @@ -0,0 +1,30 @@ +#ifndef __NOUVEAU_VGA_H__ +#define __NOUVEAU_VGA_H__ + +#include <core/os.h> + +/* access to various legacy io ports */ +u8 nv_rdport(void *obj, int head, u16 port); +void nv_wrport(void *obj, int head, u16 port, u8 value); + +/* VGA Sequencer */ +u8 nv_rdvgas(void *obj, int head, u8 index); +void nv_wrvgas(void *obj, int head, u8 index, u8 value); + +/* VGA Graphics */ +u8 nv_rdvgag(void *obj, int head, u8 index); +void nv_wrvgag(void *obj, int head, u8 index, u8 value); + +/* VGA CRTC */ +u8 nv_rdvgac(void *obj, int head, u8 index); +void nv_wrvgac(void *obj, int head, u8 index, u8 value); + +/* VGA indexed port access dispatcher */ +u8 nv_rdvgai(void *obj, int head, u16 port, u8 index); +void nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value); + +bool nv_lockvgac(void *obj, bool lock); +u8 nv_rdvgaowner(void *obj); +void nv_wrvgaowner(void *obj, u8); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h new file mode 100644 index 00000000000..9d595efe667 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h @@ -0,0 +1,142 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#ifndef __NOUVEAU_VM_H__ +#define __NOUVEAU_VM_H__ + +#include <core/object.h> +#include <core/subdev.h> +#include <core/device.h> +#include <core/mm.h> + +struct nouveau_vm_pgt { + struct nouveau_gpuobj *obj[2]; + u32 refcount[2]; +}; + +struct nouveau_vm_pgd { + struct list_head head; + struct nouveau_gpuobj *obj; +}; + +struct nouveau_gpuobj; +struct nouveau_mem; + +struct nouveau_vma { + struct list_head head; + int refcount; + struct nouveau_vm *vm; + struct nouveau_mm_node *node; + u64 offset; + u32 access; +}; + +struct nouveau_vm { + struct nouveau_vmmgr *vmm; + struct nouveau_mm mm; + int refcount; + + struct list_head pgd_list; + atomic_t engref[64]; //NVDEV_SUBDEV_NR]; + + struct nouveau_vm_pgt *pgt; + u32 fpde; + u32 lpde; +}; + +struct nouveau_vmmgr { + struct nouveau_subdev base; + + u64 limit; + u8 dma_bits; + u32 pgt_bits; + u8 spg_shift; + u8 lpg_shift; + + int (*create)(struct nouveau_vmmgr *, u64 offset, u64 length, + u64 mm_offset, struct nouveau_vm **); + + void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]); + void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *, + struct nouveau_mem *, u32 pte, u32 cnt, + u64 phys, u64 delta); + void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *, + struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *); + void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt); + void (*flush)(struct nouveau_vm *); +}; + +static inline struct nouveau_vmmgr * +nouveau_vmmgr(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VM]; +} + +#define nouveau_vmmgr_create(p,e,o,i,f,d) \ + nouveau_subdev_create((p), (e), (o), 0, (i), (f), (d)) +#define nouveau_vmmgr_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_vmmgr_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_vmmgr_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +#define _nouveau_vmmgr_dtor _nouveau_subdev_dtor +#define _nouveau_vmmgr_init _nouveau_subdev_init +#define _nouveau_vmmgr_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv04_vmmgr_oclass; +extern struct nouveau_oclass nv41_vmmgr_oclass; +extern struct nouveau_oclass nv44_vmmgr_oclass; +extern struct nouveau_oclass nv50_vmmgr_oclass; +extern struct nouveau_oclass nvc0_vmmgr_oclass; + +int nv04_vm_create(struct nouveau_vmmgr *, u64, u64, u64, + struct nouveau_vm **); +void nv04_vmmgr_dtor(struct nouveau_object *); + +void nv50_vm_flush_engine(struct nouveau_subdev *, int engine); +void nvc0_vm_flush_engine(struct nouveau_subdev *, u64 addr, int type); + +/* nouveau_vm.c */ +int nouveau_vm_create(struct nouveau_vmmgr *, u64 offset, u64 length, + u64 mm_offset, u32 block, struct nouveau_vm **); +int nouveau_vm_new(struct nouveau_device *, u64 offset, u64 length, + u64 mm_offset, struct nouveau_vm **); +int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **, + struct nouveau_gpuobj *pgd); +int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift, + u32 access, struct nouveau_vma *); +void nouveau_vm_put(struct nouveau_vma *); +void nouveau_vm_map(struct nouveau_vma *, struct nouveau_mem *); +void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_mem *); +void nouveau_vm_unmap(struct nouveau_vma *); +void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length); +void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length, + struct nouveau_mem *); +void nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length, + struct nouveau_mem *mem); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h new file mode 100644 index 00000000000..cfe3b9cad15 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/os.h @@ -0,0 +1,47 @@ +#ifndef __NOUVEAU_OS_H__ +#define __NOUVEAU_OS_H__ + +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/pci.h> +#include <linux/printk.h> +#include <linux/bitops.h> +#include <linux/firmware.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/delay.h> +#include <linux/io-mapping.h> +#include <linux/vmalloc.h> +#include <linux/acpi.h> +#include <linux/dmi.h> + +#include <asm/unaligned.h> + +static inline int +ffsll(u64 mask) +{ + int i; + for (i = 0; i < 64; i++) { + if (mask & (1ULL << i)) + return i + 1; + } + return 0; +} + +#ifndef ioread32_native +#ifdef __BIG_ENDIAN +#define ioread16_native ioread16be +#define iowrite16_native iowrite16be +#define ioread32_native ioread32be +#define iowrite32_native iowrite32be +#else /* def __BIG_ENDIAN */ +#define ioread16_native ioread16 +#define iowrite16_native iowrite16 +#define ioread32_native ioread32 +#define iowrite32_native iowrite32 +#endif /* def __BIG_ENDIAN else */ +#endif /* !ioread32_native */ + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c new file mode 100644 index 00000000000..cd01c533007 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c @@ -0,0 +1,135 @@ +/* + * 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 <subdev/bar.h> + +struct nouveau_barobj { + struct nouveau_object base; + struct nouveau_vma vma; + void __iomem *iomem; +}; + +static int +nouveau_barobj_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *mem, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_bar *bar = (void *)engine; + struct nouveau_barobj *barobj; + int ret; + + ret = nouveau_object_create(parent, engine, oclass, 0, &barobj); + *pobject = nv_object(barobj); + if (ret) + return ret; + + ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma); + if (ret) + return ret; + + barobj->iomem = bar->iomem + (u32)barobj->vma.offset; + return 0; +} + +static void +nouveau_barobj_dtor(struct nouveau_object *object) +{ + struct nouveau_bar *bar = (void *)object->engine; + struct nouveau_barobj *barobj = (void *)object; + if (barobj->vma.node) + bar->unmap(bar, &barobj->vma); + nouveau_object_destroy(&barobj->base); +} + +static u32 +nouveau_barobj_rd32(struct nouveau_object *object, u32 addr) +{ + struct nouveau_barobj *barobj = (void *)object; + return ioread32_native(barobj->iomem + addr); +} + +static void +nouveau_barobj_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + struct nouveau_barobj *barobj = (void *)object; + iowrite32_native(data, barobj->iomem + addr); +} + +static struct nouveau_oclass +nouveau_barobj_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nouveau_barobj_ctor, + .dtor = nouveau_barobj_dtor, + .init = nouveau_object_init, + .fini = nouveau_object_fini, + .rd32 = nouveau_barobj_rd32, + .wr32 = nouveau_barobj_wr32, + }, +}; + +int +nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent, + struct nouveau_mem *mem, struct nouveau_object **pobject) +{ + struct nouveau_object *engine = nv_object(bar); + return nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass, + mem, 0, pobject); +} + +int +nouveau_bar_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_bar *bar; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "BARCTL", + "bar", length, pobject); + bar = *pobject; + if (ret) + return ret; + + bar->iomem = ioremap(pci_resource_start(device->pdev, 3), + pci_resource_len(device->pdev, 3)); + return 0; +} + +void +nouveau_bar_destroy(struct nouveau_bar *bar) +{ + if (bar->iomem) + iounmap(bar->iomem); + nouveau_subdev_destroy(&bar->base); +} + +void +_nouveau_bar_dtor(struct nouveau_object *object) +{ + struct nouveau_bar *bar = (void *)object; + nouveau_bar_destroy(bar); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c new file mode 100644 index 00000000000..c3acf5b70d9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c @@ -0,0 +1,263 @@ +/* + * 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/timer.h> +#include <subdev/bar.h> +#include <subdev/fb.h> +#include <subdev/vm.h> + +struct nv50_bar_priv { + struct nouveau_bar base; + spinlock_t lock; + struct nouveau_gpuobj *mem; + struct nouveau_gpuobj *pad; + struct nouveau_gpuobj *pgd; + struct nouveau_vm *bar1_vm; + struct nouveau_gpuobj *bar1; + struct nouveau_vm *bar3_vm; + struct nouveau_gpuobj *bar3; +}; + +static int +nv50_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem, + u32 flags, struct nouveau_vma *vma) +{ + struct nv50_bar_priv *priv = (void *)bar; + int ret; + + ret = nouveau_vm_get(priv->bar3_vm, mem->size << 12, 12, flags, vma); + if (ret) + return ret; + + nouveau_vm_map(vma, mem); + nv50_vm_flush_engine(nv_subdev(bar), 6); + return 0; +} + +static int +nv50_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem, + u32 flags, struct nouveau_vma *vma) +{ + struct nv50_bar_priv *priv = (void *)bar; + int ret; + + ret = nouveau_vm_get(priv->bar1_vm, mem->size << 12, 12, flags, vma); + if (ret) + return ret; + + nouveau_vm_map(vma, mem); + nv50_vm_flush_engine(nv_subdev(bar), 6); + return 0; +} + +static void +nv50_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma) +{ + nouveau_vm_unmap(vma); + nv50_vm_flush_engine(nv_subdev(bar), 6); + nouveau_vm_put(vma); +} + +static void +nv50_bar_flush(struct nouveau_bar *bar) +{ + struct nv50_bar_priv *priv = (void *)bar; + unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); + nv_wr32(priv, 0x00330c, 0x00000001); + if (!nv_wait(priv, 0x00330c, 0x00000002, 0x00000000)) + nv_warn(priv, "flush timeout\n"); + spin_unlock_irqrestore(&priv->lock, flags); +} + +void +nv84_bar_flush(struct nouveau_bar *bar) +{ + struct nv50_bar_priv *priv = (void *)bar; + unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); + nv_wr32(bar, 0x070000, 0x00000001); + if (!nv_wait(priv, 0x070000, 0x00000002, 0x00000000)) + nv_warn(priv, "flush timeout\n"); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int +nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_object *heap; + struct nouveau_vm *vm; + struct nv50_bar_priv *priv; + u64 start, limit; + int ret; + + ret = nouveau_bar_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x20000, 0, NVOBJ_FLAG_HEAP, + &priv->mem); + heap = nv_object(priv->mem); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, heap, (device->chipset == 0x50) ? + 0x1400 : 0x0200, 0, 0, &priv->pad); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, heap, 0x4000, 0, 0, &priv->pgd); + if (ret) + return ret; + + /* BAR3 */ + start = 0x0100000000ULL; + limit = start + pci_resource_len(device->pdev, 3); + + ret = nouveau_vm_new(device, start, limit, start, &vm); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, heap, ((limit-- - start) >> 12) * 8, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, + &vm->pgt[0].obj[0]); + vm->pgt[0].refcount[0] = 1; + if (ret) + return ret; + + ret = nouveau_vm_ref(vm, &priv->bar3_vm, priv->pgd); + nouveau_vm_ref(NULL, &vm, NULL); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, heap, 24, 16, 0, &priv->bar3); + if (ret) + return ret; + + nv_wo32(priv->bar3, 0x00, 0x7fc00000); + nv_wo32(priv->bar3, 0x04, lower_32_bits(limit)); + nv_wo32(priv->bar3, 0x08, lower_32_bits(start)); + nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nv_wo32(priv->bar3, 0x10, 0x00000000); + nv_wo32(priv->bar3, 0x14, 0x00000000); + + /* BAR1 */ + start = 0x0000000000ULL; + limit = start + pci_resource_len(device->pdev, 1); + + ret = nouveau_vm_new(device, start, limit--, start, &vm); + if (ret) + return ret; + + ret = nouveau_vm_ref(vm, &priv->bar1_vm, priv->pgd); + nouveau_vm_ref(NULL, &vm, NULL); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, heap, 24, 16, 0, &priv->bar1); + if (ret) + return ret; + + nv_wo32(priv->bar1, 0x00, 0x7fc00000); + nv_wo32(priv->bar1, 0x04, lower_32_bits(limit)); + nv_wo32(priv->bar1, 0x08, lower_32_bits(start)); + nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nv_wo32(priv->bar1, 0x10, 0x00000000); + nv_wo32(priv->bar1, 0x14, 0x00000000); + + priv->base.alloc = nouveau_bar_alloc; + priv->base.kmap = nv50_bar_kmap; + priv->base.umap = nv50_bar_umap; + priv->base.unmap = nv50_bar_unmap; + if (device->chipset == 0x50) + priv->base.flush = nv50_bar_flush; + else + priv->base.flush = nv84_bar_flush; + spin_lock_init(&priv->lock); + return 0; +} + +static void +nv50_bar_dtor(struct nouveau_object *object) +{ + struct nv50_bar_priv *priv = (void *)object; + nouveau_gpuobj_ref(NULL, &priv->bar1); + nouveau_vm_ref(NULL, &priv->bar1_vm, priv->pgd); + nouveau_gpuobj_ref(NULL, &priv->bar3); + if (priv->bar3_vm) { + nouveau_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]); + nouveau_vm_ref(NULL, &priv->bar3_vm, priv->pgd); + } + nouveau_gpuobj_ref(NULL, &priv->pgd); + nouveau_gpuobj_ref(NULL, &priv->pad); + nouveau_gpuobj_ref(NULL, &priv->mem); + nouveau_bar_destroy(&priv->base); +} + +static int +nv50_bar_init(struct nouveau_object *object) +{ + struct nv50_bar_priv *priv = (void *)object; + int ret; + + ret = nouveau_bar_init(&priv->base); + if (ret) + return ret; + + nv_mask(priv, 0x000200, 0x00000100, 0x00000000); + nv_mask(priv, 0x000200, 0x00000100, 0x00000100); + nv50_vm_flush_engine(nv_subdev(priv), 6); + + nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12); + nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12); + nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4); + nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4); + return 0; +} + +static int +nv50_bar_fini(struct nouveau_object *object, bool suspend) +{ + struct nv50_bar_priv *priv = (void *)object; + return nouveau_bar_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv50_bar_oclass = { + .handle = NV_SUBDEV(BAR, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_bar_ctor, + .dtor = nv50_bar_dtor, + .init = nv50_bar_init, + .fini = nv50_bar_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c new file mode 100644 index 00000000000..77a6fb725d3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c @@ -0,0 +1,215 @@ +/* + * 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/timer.h> +#include <subdev/bar.h> +#include <subdev/fb.h> +#include <subdev/vm.h> + +struct nvc0_bar_priv { + struct nouveau_bar base; + spinlock_t lock; + struct { + struct nouveau_gpuobj *mem; + struct nouveau_gpuobj *pgd; + struct nouveau_vm *vm; + } bar[2]; +}; + +static int +nvc0_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem, + u32 flags, struct nouveau_vma *vma) +{ + struct nvc0_bar_priv *priv = (void *)bar; + int ret; + + ret = nouveau_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma); + if (ret) + return ret; + + nouveau_vm_map(vma, mem); + nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[0].pgd->addr, 5); + return 0; +} + +static int +nvc0_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem, + u32 flags, struct nouveau_vma *vma) +{ + struct nvc0_bar_priv *priv = (void *)bar; + int ret; + + ret = nouveau_vm_get(priv->bar[1].vm, mem->size << 12, + mem->page_shift, flags, vma); + if (ret) + return ret; + + nouveau_vm_map(vma, mem); + nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[1].pgd->addr, 5); + return 0; +} + +static void +nvc0_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma) +{ + struct nvc0_bar_priv *priv = (void *)bar; + int i = !(vma->vm == priv->bar[0].vm); + + nouveau_vm_unmap(vma); + nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[i].pgd->addr, 5); + nouveau_vm_put(vma); +} + +static int +nvc0_bar_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 pci_dev *pdev = device->pdev; + struct nvc0_bar_priv *priv; + struct nouveau_gpuobj *mem; + struct nouveau_vm *vm; + int ret; + + ret = nouveau_bar_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + /* BAR3 */ + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0, 0, &priv->bar[0].mem); + mem = priv->bar[0].mem; + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x8000, 0, 0, &priv->bar[0].pgd); + if (ret) + return ret; + + ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 3), 0, &vm); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, + (pci_resource_len(pdev, 3) >> 12) * 8, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, + &vm->pgt[0].obj[0]); + vm->pgt[0].refcount[0] = 1; + if (ret) + return ret; + + ret = nouveau_vm_ref(vm, &priv->bar[0].vm, priv->bar[0].pgd); + nouveau_vm_ref(NULL, &vm, NULL); + if (ret) + return ret; + + nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[0].pgd->addr)); + nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[0].pgd->addr)); + nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 3) - 1)); + nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 3) - 1)); + + /* BAR1 */ + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0, 0, &priv->bar[1].mem); + mem = priv->bar[1].mem; + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x8000, 0, 0, &priv->bar[1].pgd); + if (ret) + return ret; + + ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 1), 0, &vm); + if (ret) + return ret; + + ret = nouveau_vm_ref(vm, &priv->bar[1].vm, priv->bar[1].pgd); + nouveau_vm_ref(NULL, &vm, NULL); + if (ret) + return ret; + + nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[1].pgd->addr)); + nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[1].pgd->addr)); + nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 1) - 1)); + nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 1) - 1)); + + priv->base.alloc = nouveau_bar_alloc; + priv->base.kmap = nvc0_bar_kmap; + priv->base.umap = nvc0_bar_umap; + priv->base.unmap = nvc0_bar_unmap; + priv->base.flush = nv84_bar_flush; + spin_lock_init(&priv->lock); + return 0; +} + +static void +nvc0_bar_dtor(struct nouveau_object *object) +{ + struct nvc0_bar_priv *priv = (void *)object; + + nouveau_vm_ref(NULL, &priv->bar[1].vm, priv->bar[1].pgd); + nouveau_gpuobj_ref(NULL, &priv->bar[1].pgd); + nouveau_gpuobj_ref(NULL, &priv->bar[1].mem); + + if (priv->bar[0].vm) { + nouveau_gpuobj_ref(NULL, &priv->bar[0].vm->pgt[0].obj[0]); + nouveau_vm_ref(NULL, &priv->bar[0].vm, priv->bar[0].pgd); + } + nouveau_gpuobj_ref(NULL, &priv->bar[0].pgd); + nouveau_gpuobj_ref(NULL, &priv->bar[0].mem); + + nouveau_bar_destroy(&priv->base); +} + +static int +nvc0_bar_init(struct nouveau_object *object) +{ + struct nvc0_bar_priv *priv = (void *)object; + int ret; + + ret = nouveau_bar_init(&priv->base); + if (ret) + return ret; + + nv_mask(priv, 0x000200, 0x00000100, 0x00000000); + nv_mask(priv, 0x000200, 0x00000100, 0x00000100); + nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); + + nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12); + nv_wr32(priv, 0x001714, 0xc0000000 | priv->bar[0].mem->addr >> 12); + return 0; +} + +struct nouveau_oclass +nvc0_bar_oclass = { + .handle = NV_SUBDEV(BAR, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_bar_ctor, + .dtor = nvc0_bar_dtor, + .init = nvc0_bar_init, + .fini = _nouveau_bar_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c new file mode 100644 index 00000000000..2fbb6df697c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -0,0 +1,479 @@ +/* + * 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/device.h> +#include <core/subdev.h> +#include <core/option.h> + +#include <subdev/bios.h> +#include <subdev/bios/bmp.h> +#include <subdev/bios/bit.h> + +u8 +nvbios_checksum(const u8 *data, int size) +{ + u8 sum = 0; + while (size--) + sum += *data++; + return sum; +} + +u16 +nvbios_findstr(const u8 *data, int size, const char *str, int len) +{ + int i, j; + + for (i = 0; i <= (size - len); i++) { + for (j = 0; j < len; j++) + if ((char)data[i + j] != str[j]) + break; + if (j == len) + return i; + } + + return 0; +} + +#if defined(__powerpc__) +static void +nouveau_bios_shadow_of(struct nouveau_bios *bios) +{ + struct pci_dev *pdev = nv_device(bios)->pdev; + struct device_node *dn; + const u32 *data; + int size, i; + + dn = pci_device_to_OF_node(pdev); + if (!dn) { + nv_info(bios, "Unable to get the OF node\n"); + return; + } + + data = of_get_property(dn, "NVDA,BMP", &size); + if (data) { + bios->size = size; + bios->data = kmalloc(bios->size, GFP_KERNEL); + if (bios->data) + memcpy(bios->data, data, size); + } +} +#endif + +static void +nouveau_bios_shadow_pramin(struct nouveau_bios *bios) +{ + struct nouveau_device *device = nv_device(bios); + u32 bar0 = 0; + int i; + + if (device->card_type >= NV_50) { + u64 addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8; + if (!addr) { + addr = (u64)nv_rd32(bios, 0x001700) << 16; + addr += 0xf0000; + } + + bar0 = nv_mask(bios, 0x001700, 0xffffffff, addr >> 16); + } + + /* bail if no rom signature */ + if (nv_rd08(bios, 0x700000) != 0x55 || + nv_rd08(bios, 0x700001) != 0xaa) + goto out; + + bios->size = nv_rd08(bios, 0x700002) * 512; + bios->data = kmalloc(bios->size, GFP_KERNEL); + if (bios->data) { + for (i = 0; i < bios->size; i++) + nv_wo08(bios, i, nv_rd08(bios, 0x700000 + i)); + } + +out: + if (device->card_type >= NV_50) + nv_wr32(bios, 0x001700, bar0); +} + +static void +nouveau_bios_shadow_prom(struct nouveau_bios *bios) +{ + struct nouveau_device *device = nv_device(bios); + u32 pcireg, access; + u16 pcir; + int i; + + /* enable access to rom */ + if (device->card_type >= NV_50) + pcireg = 0x088050; + else + pcireg = 0x001850; + access = nv_mask(bios, pcireg, 0x00000001, 0x00000000); + + /* bail if no rom signature, with a workaround for a PROM reading + * issue on some chipsets. the first read after a period of + * inactivity returns the wrong result, so retry the first header + * byte a few times before giving up as a workaround + */ + i = 16; + do { + if (nv_rd08(bios, 0x300000) == 0x55) + break; + } while (i--); + + if (!i || nv_rd08(bios, 0x300001) != 0xaa) + goto out; + + /* additional check (see note below) - read PCI record header */ + pcir = nv_rd08(bios, 0x300018) | + nv_rd08(bios, 0x300019) << 8; + if (nv_rd08(bios, 0x300000 + pcir) != 'P' || + nv_rd08(bios, 0x300001 + pcir) != 'C' || + nv_rd08(bios, 0x300002 + pcir) != 'I' || + nv_rd08(bios, 0x300003 + pcir) != 'R') + goto out; + + /* read entire bios image to system memory */ + bios->size = nv_rd08(bios, 0x300002) * 512; + bios->data = kmalloc(bios->size, GFP_KERNEL); + if (bios->data) { + for (i = 0; i < bios->size; i++) + nv_wo08(bios, i, nv_rd08(bios, 0x300000 + i)); + } + +out: + /* disable access to rom */ + nv_wr32(bios, pcireg, access); +} + +#if defined(CONFIG_ACPI) +int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); +bool nouveau_acpi_rom_supported(struct pci_dev *pdev); +#else +static inline bool +nouveau_acpi_rom_supported(struct pci_dev *pdev) { + return false; +} + +static inline int +nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { + return -EINVAL; +} +#endif + +static void +nouveau_bios_shadow_acpi(struct nouveau_bios *bios) +{ + struct pci_dev *pdev = nv_device(bios)->pdev; + int cnt = 65536 / 4096; + int ret; + + if (!nouveau_acpi_rom_supported(pdev)) + return; + + bios->data = kmalloc(65536, GFP_KERNEL); + bios->size = 0; + if (!bios->data) + return; + + while (cnt--) { + ret = nouveau_acpi_get_bios_chunk(bios->data, bios->size, 4096); + if (ret != 4096) + return; + + bios->size += 4096; + } +} + +static void +nouveau_bios_shadow_pci(struct nouveau_bios *bios) +{ + struct pci_dev *pdev = nv_device(bios)->pdev; + size_t size; + + if (!pci_enable_rom(pdev)) { + void __iomem *rom = pci_map_rom(pdev, &size); + if (rom && size) { + bios->data = kmalloc(size, GFP_KERNEL); + if (bios->data) { + memcpy_fromio(bios->data, rom, size); + bios->size = size; + } + } + if (rom) + pci_unmap_rom(pdev, rom); + + pci_disable_rom(pdev); + } +} + +static int +nouveau_bios_score(struct nouveau_bios *bios, const bool writeable) +{ + if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) { + nv_info(bios, "... signature not found\n"); + return 0; + } + + if (nvbios_checksum(bios->data, bios->data[2] * 512)) { + nv_info(bios, "... checksum invalid\n"); + /* if a ro image is somewhat bad, it's probably all rubbish */ + return writeable ? 2 : 1; + } + + nv_info(bios, "... appears to be valid\n"); + return 3; +} + +struct methods { + const char desc[16]; + void (*shadow)(struct nouveau_bios *); + const bool rw; + int score; + u32 size; + u8 *data; +}; + +static int +nouveau_bios_shadow(struct nouveau_bios *bios) +{ + struct methods shadow_methods[] = { +#if defined(__powerpc__) + { "OpenFirmware", nouveau_bios_shadow_of, true, 0, 0, NULL }, +#endif + { "PRAMIN", nouveau_bios_shadow_pramin, true, 0, 0, NULL }, + { "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL }, + { "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL }, + { "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL }, + {} + }; + struct methods *mthd, *best; + const struct firmware *fw; + const char *optarg; + int optlen, ret; + char *source; + + optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen); + source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL; + if (source) { + /* try to match one of the built-in methods */ + mthd = shadow_methods; + do { + if (strcasecmp(source, mthd->desc)) + continue; + nv_info(bios, "source: %s\n", mthd->desc); + + mthd->shadow(bios); + mthd->score = nouveau_bios_score(bios, mthd->rw); + if (mthd->score) { + kfree(source); + return 0; + } + } while ((++mthd)->shadow); + + /* attempt to load firmware image */ + ret = request_firmware(&fw, source, &nv_device(bios)->pdev->dev); + if (ret == 0) { + bios->size = fw->size; + bios->data = kmemdup(fw->data, fw->size, GFP_KERNEL); + release_firmware(fw); + + nv_info(bios, "image: %s\n", source); + if (nouveau_bios_score(bios, 1)) { + kfree(source); + return 0; + } + + kfree(bios->data); + bios->data = NULL; + } + + nv_error(bios, "source \'%s\' invalid\n", source); + kfree(source); + } + + mthd = shadow_methods; + do { + nv_info(bios, "checking %s for image...\n", mthd->desc); + mthd->shadow(bios); + mthd->score = nouveau_bios_score(bios, mthd->rw); + mthd->size = bios->size; + mthd->data = bios->data; + bios->data = NULL; + } while (mthd->score != 3 && (++mthd)->shadow); + + mthd = shadow_methods; + best = mthd; + do { + if (mthd->score > best->score) { + kfree(best->data); + best = mthd; + } + } while ((++mthd)->shadow); + + if (best->score) { + nv_info(bios, "using image from %s\n", best->desc); + bios->size = best->size; + bios->data = best->data; + return 0; + } + + nv_error(bios, "unable to locate usable image\n"); + return -EINVAL; +} + +static u8 +nouveau_bios_rd08(struct nouveau_object *object, u32 addr) +{ + struct nouveau_bios *bios = (void *)object; + return bios->data[addr]; +} + +static u16 +nouveau_bios_rd16(struct nouveau_object *object, u32 addr) +{ + struct nouveau_bios *bios = (void *)object; + return get_unaligned_le16(&bios->data[addr]); +} + +static u32 +nouveau_bios_rd32(struct nouveau_object *object, u32 addr) +{ + struct nouveau_bios *bios = (void *)object; + return get_unaligned_le32(&bios->data[addr]); +} + +static void +nouveau_bios_wr08(struct nouveau_object *object, u32 addr, u8 data) +{ + struct nouveau_bios *bios = (void *)object; + bios->data[addr] = data; +} + +static void +nouveau_bios_wr16(struct nouveau_object *object, u32 addr, u16 data) +{ + struct nouveau_bios *bios = (void *)object; + put_unaligned_le16(data, &bios->data[addr]); +} + +static void +nouveau_bios_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + struct nouveau_bios *bios = (void *)object; + put_unaligned_le32(data, &bios->data[addr]); +} + +static int +nouveau_bios_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_bios *bios; + struct bit_entry bit_i; + int ret; + + ret = nouveau_subdev_create(parent, engine, oclass, 0, + "VBIOS", "bios", &bios); + *pobject = nv_object(bios); + if (ret) + return ret; + + ret = nouveau_bios_shadow(bios); + if (ret) + return ret; + + /* detect type of vbios we're dealing with */ + bios->bmp_offset = nvbios_findstr(bios->data, bios->size, + "\xff\x7f""NV\0", 5); + if (bios->bmp_offset) { + nv_info(bios, "BMP version %x.%x\n", + bmp_version(bios) >> 8, + bmp_version(bios) & 0xff); + } + + bios->bit_offset = nvbios_findstr(bios->data, bios->size, + "\xff\xb8""BIT", 5); + if (bios->bit_offset) + nv_info(bios, "BIT signature found\n"); + + /* determine the vbios version number */ + if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) { + bios->version.major = nv_ro08(bios, bit_i.offset + 3); + bios->version.chip = nv_ro08(bios, bit_i.offset + 2); + bios->version.minor = nv_ro08(bios, bit_i.offset + 1); + bios->version.micro = nv_ro08(bios, bit_i.offset + 0); + } else + if (bmp_version(bios)) { + bios->version.major = nv_ro08(bios, bios->bmp_offset + 13); + bios->version.chip = nv_ro08(bios, bios->bmp_offset + 12); + bios->version.minor = nv_ro08(bios, bios->bmp_offset + 11); + bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10); + } + + nv_info(bios, "version %02x.%02x.%02x.%02x\n", + bios->version.major, bios->version.chip, + bios->version.minor, bios->version.micro); + + return 0; +} + +static void +nouveau_bios_dtor(struct nouveau_object *object) +{ + struct nouveau_bios *bios = (void *)object; + kfree(bios->data); + nouveau_subdev_destroy(&bios->base); +} + +static int +nouveau_bios_init(struct nouveau_object *object) +{ + struct nouveau_bios *bios = (void *)object; + return nouveau_subdev_init(&bios->base); +} + +static int +nouveau_bios_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_bios *bios = (void *)object; + return nouveau_subdev_fini(&bios->base, suspend); +} + +struct nouveau_oclass +nouveau_bios_oclass = { + .handle = NV_SUBDEV(VBIOS, 0x00), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nouveau_bios_ctor, + .dtor = nouveau_bios_dtor, + .init = nouveau_bios_init, + .fini = nouveau_bios_fini, + .rd08 = nouveau_bios_rd08, + .rd16 = nouveau_bios_rd16, + .rd32 = nouveau_bios_rd32, + .wr08 = nouveau_bios_wr08, + .wr16 = nouveau_bios_wr16, + .wr32 = nouveau_bios_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c b/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c new file mode 100644 index 00000000000..1d03a3f2b2d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c @@ -0,0 +1,52 @@ +/* + * 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 "subdev/bios.h" +#include "subdev/bios/bit.h" + +int +bit_entry(struct nouveau_bios *bios, u8 id, struct bit_entry *bit) +{ + if (likely(bios->bit_offset)) { + u8 entries = nv_ro08(bios, bios->bit_offset + 10); + u32 entry = bios->bit_offset + 12; + while (entries--) { + if (nv_ro08(bios, entry + 0) == id) { + bit->id = nv_ro08(bios, entry + 0); + bit->version = nv_ro08(bios, entry + 1); + bit->length = nv_ro16(bios, entry + 2); + bit->offset = nv_ro16(bios, entry + 4); + return 0; + } + + entry += nv_ro08(bios, bios->bit_offset + 9); + } + + return -ENOENT; + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c new file mode 100644 index 00000000000..5ac010efd95 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c @@ -0,0 +1,56 @@ +/* + * 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/device.h> + +#include <subdev/bios.h> +#include <subdev/bios/dcb.h> +#include <subdev/bios/conn.h> + +u16 +dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u16 dcb = dcb_table(bios, ver, hdr, cnt, len); + if (dcb && *ver >= 0x30 && *hdr >= 0x16) { + u16 data = nv_ro16(bios, dcb + 0x14); + if (data) { + *ver = nv_ro08(bios, data + 0); + *hdr = nv_ro08(bios, data + 1); + *cnt = nv_ro08(bios, data + 2); + *len = nv_ro08(bios, data + 3); + return data; + } + } + return 0x0000; +} + +u16 +dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 data = dcb_conntab(bios, ver, &hdr, &cnt, len); + if (data && idx < cnt) + return data + hdr + (idx * *len); + return 0x0000; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c new file mode 100644 index 00000000000..9ed6e728a94 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -0,0 +1,135 @@ +/* + * 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/device.h" + +#include "subdev/bios.h" +#include "subdev/bios/dcb.h" + +u16 +dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + struct nouveau_device *device = nv_device(bios); + u16 dcb = 0x0000; + + if (device->card_type > NV_04) + dcb = nv_ro16(bios, 0x36); + if (!dcb) { + nv_warn(bios, "DCB table not found\n"); + return dcb; + } + + *ver = nv_ro08(bios, dcb); + + if (*ver >= 0x41) { + nv_warn(bios, "DCB *ver 0x%02x unknown\n", *ver); + return 0x0000; + } else + if (*ver >= 0x30) { + if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) { + *hdr = nv_ro08(bios, dcb + 1); + *cnt = nv_ro08(bios, dcb + 2); + *len = nv_ro08(bios, dcb + 3); + return dcb; + } + } else + if (*ver >= 0x20) { + if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) { + u16 i2c = nv_ro16(bios, dcb + 2); + *hdr = 8; + *cnt = (i2c - dcb) / 8; + *len = 8; + return dcb; + } + } else + if (*ver >= 0x15) { + if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) { + u16 i2c = nv_ro16(bios, dcb + 2); + *hdr = 4; + *cnt = (i2c - dcb) / 10; + *len = 10; + return dcb; + } + } else { + /* + * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but + * always has the same single (crt) entry, even when tv-out + * present, so the conclusion is this version cannot really + * be used. + * + * v1.2 tables (some NV6/10, and NV15+) normally have the + * same 5 entries, which are not specific to the card and so + * no use. + * + * v1.2 does have an I2C table that read_dcb_i2c_table can + * handle, but cards exist (nv11 in #14821) with a bad i2c + * table pointer, so use the indices parsed in + * parse_bmp_structure. + * + * v1.1 (NV5+, maybe some NV4) is entirely unhelpful + */ + nv_warn(bios, "DCB contains no useful data\n"); + return 0x0000; + } + + nv_warn(bios, "DCB header validation failed\n"); + return 0x0000; +} + +u16 +dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len); + if (dcb && idx < cnt) + return dcb + hdr + (idx * *len); + return 0x0000; +} + +int +dcb_outp_foreach(struct nouveau_bios *bios, void *data, + int (*exec)(struct nouveau_bios *, void *, int, u16)) +{ + int ret, idx = -1; + u8 ver, len; + u16 outp; + + while ((outp = dcb_outp(bios, ++idx, &ver, &len))) { + if (nv_ro32(bios, outp) == 0x00000000) + break; /* seen on an NV11 with DCB v1.5 */ + if (nv_ro32(bios, outp) == 0xffffffff) + break; /* seen on an NV17 with DCB v2.0 */ + + if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED) + continue; + if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL) + break; + + ret = exec(bios, data, idx, outp); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c new file mode 100644 index 00000000000..3cbc0f3e8d5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c @@ -0,0 +1,76 @@ +/* + * 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/bios.h" +#include "subdev/bios/bit.h" +#include "subdev/bios/dcb.h" +#include "subdev/bios/dp.h" + +u16 +dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + struct bit_entry bit_d; + + if (!bit_entry(bios, 'd', &bit_d)) { + if (bit_d.version == 1) { + u16 data = nv_ro16(bios, bit_d.offset); + if (data) { + *ver = nv_ro08(bios, data + 0); + *hdr = nv_ro08(bios, data + 1); + *len = nv_ro08(bios, data + 2); + *cnt = nv_ro08(bios, data + 3); + return data; + } + } + } + + return 0x0000; +} + +u16 +dp_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 table = dp_table(bios, ver, &hdr, &cnt, len); + if (table && idx < cnt) + return nv_ro16(bios, table + hdr + (idx * *len)); + return 0xffff; +} + +u16 +dp_outp_match(struct nouveau_bios *bios, struct dcb_output *outp, + u8 *ver, u8 *len) +{ + u8 idx = 0; + u16 data; + while ((data = dp_outp(bios, idx++, ver, len)) != 0xffff) { + if (data) { + u32 hash = nv_ro32(bios, data); + if (dcb_hash_match(outp, hash)) + return data; + } + } + return 0x0000; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c new file mode 100644 index 00000000000..5afb568b2d6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c @@ -0,0 +1,100 @@ +/* + * Copyright 2012 Nouveau Community + * + * 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: Martin Peres + */ + +#include <subdev/bios.h> +#include <subdev/bios/dcb.h> +#include <subdev/bios/extdev.h> + +static u16 +extdev_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) +{ + u8 dcb_ver, dcb_hdr, dcb_cnt, dcb_len; + u16 dcb, extdev = 0; + + dcb = dcb_table(bios, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len); + if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40)) + return 0x0000; + + extdev = nv_ro16(bios, dcb + 18); + if (!extdev) + return 0x0000; + + *ver = nv_ro08(bios, extdev + 0); + *hdr = nv_ro08(bios, extdev + 1); + *cnt = nv_ro08(bios, extdev + 2); + *len = nv_ro08(bios, extdev + 3); + + return extdev + *hdr; +} + +u16 +nvbios_extdev_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 extdev = extdev_table(bios, ver, &hdr, len, &cnt); + if (extdev && idx < cnt) + return extdev + idx * *len; + return 0x0000; +} + +static void +extdev_parse_entry(struct nouveau_bios *bios, u16 offset, + struct nvbios_extdev_func *entry) +{ + entry->type = nv_ro08(bios, offset + 0); + entry->addr = nv_ro08(bios, offset + 1); + entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1; +} + +int +nvbios_extdev_parse(struct nouveau_bios *bios, int idx, + struct nvbios_extdev_func *func) +{ + u8 ver, len; + u16 entry; + + if (!(entry = nvbios_extdev_entry(bios, idx, &ver, &len))) + return -EINVAL; + + extdev_parse_entry(bios, entry, func); + + return 0; +} + +int +nvbios_extdev_find(struct nouveau_bios *bios, enum nvbios_extdev_type type, + struct nvbios_extdev_func *func) +{ + u8 ver, len, i; + u16 entry; + + i = 0; + while (!(entry = nvbios_extdev_entry(bios, i++, &ver, &len))) { + extdev_parse_entry(bios, entry, func); + if (func->type == type) + return 0; + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c new file mode 100644 index 00000000000..4c9f1e50816 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c @@ -0,0 +1,121 @@ +/* + * 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/bios.h> +#include <subdev/bios/dcb.h> +#include <subdev/bios/gpio.h> + +u16 +dcb_gpio_table(struct nouveau_bios *bios) +{ + u8 ver, hdr, cnt, len; + u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); + if (dcb) { + if (ver >= 0x30 && hdr >= 0x0c) + return nv_ro16(bios, dcb + 0x0a); + if (ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) + return nv_ro16(bios, dcb - 0x0f); + } + return 0x0000; +} + +u16 +dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver) +{ + u16 gpio = dcb_gpio_table(bios); + if (gpio) { + *ver = nv_ro08(bios, gpio); + if (*ver < 0x30 && ent < nv_ro08(bios, gpio + 2)) + return gpio + 3 + (ent * nv_ro08(bios, gpio + 1)); + else if (ent < nv_ro08(bios, gpio + 2)) + return gpio + nv_ro08(bios, gpio + 1) + + (ent * nv_ro08(bios, gpio + 3)); + } + return 0x0000; +} + +int +dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, + struct dcb_gpio_func *gpio) +{ + u8 ver, hdr, cnt, len; + u16 entry; + int i = -1; + + while ((entry = dcb_gpio_entry(bios, idx, ++i, &ver))) { + if (ver < 0x40) { + u16 data = nv_ro16(bios, entry); + *gpio = (struct dcb_gpio_func) { + .line = (data & 0x001f) >> 0, + .func = (data & 0x07e0) >> 5, + .log[0] = (data & 0x1800) >> 11, + .log[1] = (data & 0x6000) >> 13, + .param = !!(data & 0x8000), + }; + } else + if (ver < 0x41) { + u32 data = nv_ro32(bios, entry); + *gpio = (struct dcb_gpio_func) { + .line = (data & 0x0000001f) >> 0, + .func = (data & 0x0000ff00) >> 8, + .log[0] = (data & 0x18000000) >> 27, + .log[1] = (data & 0x60000000) >> 29, + .param = !!(data & 0x80000000), + }; + } else { + u32 data = nv_ro32(bios, entry + 0); + u8 data1 = nv_ro32(bios, entry + 4); + *gpio = (struct dcb_gpio_func) { + .line = (data & 0x0000003f) >> 0, + .func = (data & 0x0000ff00) >> 8, + .log[0] = (data1 & 0x30) >> 4, + .log[1] = (data1 & 0xc0) >> 6, + .param = !!(data & 0x80000000), + }; + } + + if ((line == 0xff || line == gpio->line) && + (func == 0xff || func == gpio->func)) + return 0; + } + + /* DCB 2.2, fixed TVDAC GPIO data */ + if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len)) && ver >= 0x22) { + if (func == DCB_GPIO_TVDAC0) { + u8 conf = nv_ro08(bios, entry - 5); + u8 addr = nv_ro08(bios, entry - 4); + if (conf & 0x01) { + *gpio = (struct dcb_gpio_func) { + .func = DCB_GPIO_TVDAC0, + .line = addr >> 4, + .log[0] = !!(conf & 0x02), + .log[1] = !(conf & 0x02), + }; + return 0; + } + } + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c new file mode 100644 index 00000000000..ad577db8376 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c @@ -0,0 +1,129 @@ +/* + * 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/bios.h" +#include "subdev/bios/dcb.h" +#include "subdev/bios/i2c.h" + +u16 +dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u16 i2c = 0x0000; + u16 dcb = dcb_table(bios, ver, hdr, cnt, len); + if (dcb) { + if (*ver >= 0x15) + i2c = nv_ro16(bios, dcb + 2); + if (*ver >= 0x30) + i2c = nv_ro16(bios, dcb + 4); + } + + if (i2c && *ver >= 0x30) { + *ver = nv_ro08(bios, i2c + 0); + *hdr = nv_ro08(bios, i2c + 1); + *cnt = nv_ro08(bios, i2c + 2); + *len = nv_ro08(bios, i2c + 3); + } else { + *ver = *ver; /* use DCB version */ + *hdr = 0; + *cnt = 16; + *len = 4; + } + + return i2c; +} + +u16 +dcb_i2c_entry(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 i2c = dcb_i2c_table(bios, ver, &hdr, &cnt, len); + if (i2c && idx < cnt) + return i2c + hdr + (idx * *len); + return 0x0000; +} + +int +dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info) +{ + u8 ver, len; + u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); + if (ent) { + info->data = nv_ro32(bios, ent + 0); + info->type = nv_ro08(bios, ent + 3); + if (ver < 0x30) { + info->type &= 0x07; + if (info->type == 0x07) + info->type = 0xff; + } + + switch (info->type) { + case DCB_I2C_NV04_BIT: + info->drive = nv_ro08(bios, ent + 0); + info->sense = nv_ro08(bios, ent + 1); + return 0; + case DCB_I2C_NV4E_BIT: + info->drive = nv_ro08(bios, ent + 1); + return 0; + case DCB_I2C_NVIO_BIT: + case DCB_I2C_NVIO_AUX: + info->drive = nv_ro08(bios, ent + 0); + return 0; + case DCB_I2C_UNUSED: + return 0; + default: + nv_warn(bios, "unknown i2c type %d\n", info->type); + info->type = DCB_I2C_UNUSED; + return 0; + } + } + + if (bios->bmp_offset && idx < 2) { + /* BMP (from v4.0 has i2c info in the structure, it's in a + * fixed location on earlier VBIOS + */ + if (nv_ro08(bios, bios->bmp_offset + 5) < 4) + ent = 0x0048; + else + ent = 0x0036 + bios->bmp_offset; + + if (idx == 0) { + info->drive = nv_ro08(bios, ent + 4); + if (!info->drive) info->drive = 0x3f; + info->sense = nv_ro08(bios, ent + 5); + if (!info->sense) info->sense = 0x3e; + } else + if (idx == 1) { + info->drive = nv_ro08(bios, ent + 6); + if (!info->drive) info->drive = 0x37; + info->sense = nv_ro08(bios, ent + 7); + if (!info->sense) info->sense = 0x36; + } + + info->type = DCB_I2C_NV04_BIT; + return 0; + } + + return -ENOENT; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c new file mode 100644 index 00000000000..6be8c32f6e4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -0,0 +1,2120 @@ +#include <core/engine.h> +#include <core/device.h> + +#include <subdev/bios.h> +#include <subdev/bios/conn.h> +#include <subdev/bios/bmp.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/dcb.h> +#include <subdev/bios/dp.h> +#include <subdev/bios/init.h> +#include <subdev/devinit.h> +#include <subdev/clock.h> +#include <subdev/i2c.h> +#include <subdev/vga.h> +#include <subdev/gpio.h> + +#define bioslog(lvl, fmt, args...) do { \ + nv_printk(init->bios, lvl, "0x%04x[%c]: "fmt, init->offset, \ + init_exec(init) ? '0' + (init->nested - 1) : ' ', ##args); \ +} while(0) +#define cont(fmt, args...) do { \ + if (nv_subdev(init->bios)->debug >= NV_DBG_TRACE) \ + printk(fmt, ##args); \ +} while(0) +#define trace(fmt, args...) bioslog(TRACE, fmt, ##args) +#define warn(fmt, args...) bioslog(WARN, fmt, ##args) +#define error(fmt, args...) bioslog(ERROR, fmt, ##args) + +/****************************************************************************** + * init parser control flow helpers + *****************************************************************************/ + +static inline bool +init_exec(struct nvbios_init *init) +{ + return (init->execute == 1) || ((init->execute & 5) == 5); +} + +static inline void +init_exec_set(struct nvbios_init *init, bool exec) +{ + if (exec) init->execute &= 0xfd; + else init->execute |= 0x02; +} + +static inline void +init_exec_inv(struct nvbios_init *init) +{ + init->execute ^= 0x02; +} + +static inline void +init_exec_force(struct nvbios_init *init, bool exec) +{ + if (exec) init->execute |= 0x04; + else init->execute &= 0xfb; +} + +/****************************************************************************** + * init parser wrappers for normal register/i2c/whatever accessors + *****************************************************************************/ + +static inline int +init_or(struct nvbios_init *init) +{ + if (init->outp) + return ffs(init->outp->or) - 1; + error("script needs OR!!\n"); + return 0; +} + +static inline int +init_link(struct nvbios_init *init) +{ + if (init->outp) + return !(init->outp->sorconf.link & 1); + error("script needs OR link\n"); + return 0; +} + +static inline int +init_crtc(struct nvbios_init *init) +{ + if (init->crtc >= 0) + return init->crtc; + error("script needs crtc\n"); + return 0; +} + +static u8 +init_conn(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + + if (init->outp) { + u8 ver, len; + u16 conn = dcb_conn(bios, init->outp->connector, &ver, &len); + if (conn) + return nv_ro08(bios, conn); + } + + error("script needs connector type\n"); + return 0x00; +} + +static inline u32 +init_nvreg(struct nvbios_init *init, u32 reg) +{ + /* C51 (at least) sometimes has the lower bits set which the VBIOS + * interprets to mean that access needs to go through certain IO + * ports instead. The NVIDIA binary driver has been seen to access + * these through the NV register address, so lets assume we can + * do the same + */ + reg &= ~0x00000003; + + /* GF8+ display scripts need register addresses mangled a bit to + * select a specific CRTC/OR + */ + if (nv_device(init->bios)->card_type >= NV_50) { + if (reg & 0x80000000) { + reg += init_crtc(init) * 0x800; + reg &= ~0x80000000; + } + + if (reg & 0x40000000) { + reg += init_or(init) * 0x800; + reg &= ~0x40000000; + if (reg & 0x20000000) { + reg += init_link(init) * 0x80; + reg &= ~0x20000000; + } + } + } + + if (reg & ~0x00fffffc) + warn("unknown bits in register 0x%08x\n", reg); + return reg; +} + +static u32 +init_rd32(struct nvbios_init *init, u32 reg) +{ + reg = init_nvreg(init, reg); + if (init_exec(init)) + return nv_rd32(init->subdev, reg); + return 0x00000000; +} + +static void +init_wr32(struct nvbios_init *init, u32 reg, u32 val) +{ + reg = init_nvreg(init, reg); + if (init_exec(init)) + nv_wr32(init->subdev, reg, val); +} + +static u32 +init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val) +{ + reg = init_nvreg(init, reg); + if (init_exec(init)) { + u32 tmp = nv_rd32(init->subdev, reg); + nv_wr32(init->subdev, reg, (tmp & ~mask) | val); + return tmp; + } + return 0x00000000; +} + +static u8 +init_rdport(struct nvbios_init *init, u16 port) +{ + if (init_exec(init)) + return nv_rdport(init->subdev, init->crtc, port); + return 0x00; +} + +static void +init_wrport(struct nvbios_init *init, u16 port, u8 value) +{ + if (init_exec(init)) + nv_wrport(init->subdev, init->crtc, port, value); +} + +static u8 +init_rdvgai(struct nvbios_init *init, u16 port, u8 index) +{ + struct nouveau_subdev *subdev = init->subdev; + if (init_exec(init)) { + int head = init->crtc < 0 ? 0 : init->crtc; + return nv_rdvgai(subdev, head, port, index); + } + return 0x00; +} + +static void +init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value) +{ + /* force head 0 for updates to cr44, it only exists on first head */ + if (nv_device(init->subdev)->card_type < NV_50) { + if (port == 0x03d4 && index == 0x44) + init->crtc = 0; + } + + if (init_exec(init)) { + int head = init->crtc < 0 ? 0 : init->crtc; + nv_wrvgai(init->subdev, head, port, index, value); + } + + /* select head 1 if cr44 write selected it */ + if (nv_device(init->subdev)->card_type < NV_50) { + if (port == 0x03d4 && index == 0x44 && value == 3) + init->crtc = 1; + } +} + +static struct nouveau_i2c_port * +init_i2c(struct nvbios_init *init, int index) +{ + struct nouveau_i2c *i2c = nouveau_i2c(init->bios); + + if (index == 0xff) { + index = NV_I2C_DEFAULT(0); + if (init->outp && init->outp->i2c_upper_default) + index = NV_I2C_DEFAULT(1); + } else + if (index < 0) { + if (!init->outp) { + error("script needs output for i2c\n"); + return NULL; + } + + index = init->outp->i2c_index; + } + + return i2c->find(i2c, index); +} + +static int +init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg) +{ + struct nouveau_i2c_port *port = init_i2c(init, index); + if (port && init_exec(init)) + return nv_rdi2cr(port, addr, reg); + return -ENODEV; +} + +static int +init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val) +{ + struct nouveau_i2c_port *port = init_i2c(init, index); + if (port && init_exec(init)) + return nv_wri2cr(port, addr, reg, val); + return -ENODEV; +} + +static int +init_rdauxr(struct nvbios_init *init, u32 addr) +{ + struct nouveau_i2c_port *port = init_i2c(init, -1); + u8 data; + + if (port && init_exec(init)) { + int ret = nv_rdaux(port, addr, &data, 1); + if (ret) + return ret; + return data; + } + + return -ENODEV; +} + +static int +init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) +{ + struct nouveau_i2c_port *port = init_i2c(init, -1); + if (port && init_exec(init)) + return nv_wraux(port, addr, &data, 1); + return -ENODEV; +} + +static void +init_prog_pll(struct nvbios_init *init, u32 id, u32 freq) +{ + struct nouveau_clock *clk = nouveau_clock(init->bios); + if (clk && clk->pll_set && init_exec(init)) { + int ret = clk->pll_set(clk, id, freq); + if (ret) + warn("failed to prog pll 0x%08x to %dkHz\n", id, freq); + } +} + +/****************************************************************************** + * parsing of bios structures that are required to execute init tables + *****************************************************************************/ + +static u16 +init_table(struct nouveau_bios *bios, u16 *len) +{ + struct bit_entry bit_I; + + if (!bit_entry(bios, 'I', &bit_I)) { + *len = bit_I.length; + return bit_I.offset; + } + + if (bmp_version(bios) >= 0x0510) { + *len = 14; + return bios->bmp_offset + 75; + } + + return 0x0000; +} + +static u16 +init_table_(struct nvbios_init *init, u16 offset, const char *name) +{ + struct nouveau_bios *bios = init->bios; + u16 len, data = init_table(bios, &len); + if (data) { + if (len >= offset + 2) { + data = nv_ro16(bios, data + offset); + if (data) + return data; + + warn("%s pointer invalid\n", name); + return 0x0000; + } + + warn("init data too short for %s pointer", name); + return 0x0000; + } + + warn("init data not found\n"); + return 0x0000; +} + +#define init_script_table(b) init_table_((b), 0x00, "script table") +#define init_macro_index_table(b) init_table_((b), 0x02, "macro index table") +#define init_macro_table(b) init_table_((b), 0x04, "macro table") +#define init_condition_table(b) init_table_((b), 0x06, "condition table") +#define init_io_condition_table(b) init_table_((b), 0x08, "io condition table") +#define init_io_flag_condition_table(b) init_table_((b), 0x0a, "io flag conditon table") +#define init_function_table(b) init_table_((b), 0x0c, "function table") +#define init_xlat_table(b) init_table_((b), 0x10, "xlat table"); + +static u16 +init_script(struct nouveau_bios *bios, int index) +{ + struct nvbios_init init = { .bios = bios }; + u16 data; + + if (bmp_version(bios) && bmp_version(bios) < 0x0510) { + if (index > 1) + return 0x0000; + + data = bios->bmp_offset + (bios->version.major < 2 ? 14 : 18); + return nv_ro16(bios, data + (index * 2)); + } + + data = init_script_table(&init); + if (data) + return nv_ro16(bios, data + (index * 2)); + + return 0x0000; +} + +static u16 +init_unknown_script(struct nouveau_bios *bios) +{ + u16 len, data = init_table(bios, &len); + if (data && len >= 16) + return nv_ro16(bios, data + 14); + return 0x0000; +} + +static u16 +init_ram_restrict_table(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + struct bit_entry bit_M; + u16 data = 0x0000; + + if (!bit_entry(bios, 'M', &bit_M)) { + if (bit_M.version == 1 && bit_M.length >= 5) + data = nv_ro16(bios, bit_M.offset + 3); + if (bit_M.version == 2 && bit_M.length >= 3) + data = nv_ro16(bios, bit_M.offset + 1); + } + + if (data == 0x0000) + warn("ram restrict table not found\n"); + return data; +} + +static u8 +init_ram_restrict_group_count(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + struct bit_entry bit_M; + + if (!bit_entry(bios, 'M', &bit_M)) { + if (bit_M.version == 1 && bit_M.length >= 5) + return nv_ro08(bios, bit_M.offset + 2); + if (bit_M.version == 2 && bit_M.length >= 3) + return nv_ro08(bios, bit_M.offset + 0); + } + + return 0x00; +} + +static u8 +init_ram_restrict(struct nvbios_init *init) +{ + u32 strap = (init_rd32(init, 0x101000) & 0x0000003c) >> 2; + u16 table = init_ram_restrict_table(init); + if (table) + return nv_ro08(init->bios, table + strap); + return 0x00; +} + +static u8 +init_xlat_(struct nvbios_init *init, u8 index, u8 offset) +{ + struct nouveau_bios *bios = init->bios; + u16 table = init_xlat_table(init); + if (table) { + u16 data = nv_ro16(bios, table + (index * 2)); + if (data) + return nv_ro08(bios, data + offset); + warn("xlat table pointer %d invalid\n", index); + } + return 0x00; +} + +/****************************************************************************** + * utility functions used by various init opcode handlers + *****************************************************************************/ + +static bool +init_condition_met(struct nvbios_init *init, u8 cond) +{ + struct nouveau_bios *bios = init->bios; + u16 table = init_condition_table(init); + if (table) { + u32 reg = nv_ro32(bios, table + (cond * 12) + 0); + u32 msk = nv_ro32(bios, table + (cond * 12) + 4); + u32 val = nv_ro32(bios, table + (cond * 12) + 8); + trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n", + cond, reg, msk, val); + return (init_rd32(init, reg) & msk) == val; + } + return false; +} + +static bool +init_io_condition_met(struct nvbios_init *init, u8 cond) +{ + struct nouveau_bios *bios = init->bios; + u16 table = init_io_condition_table(init); + if (table) { + u16 port = nv_ro16(bios, table + (cond * 5) + 0); + u8 index = nv_ro08(bios, table + (cond * 5) + 2); + u8 mask = nv_ro08(bios, table + (cond * 5) + 3); + u8 value = nv_ro08(bios, table + (cond * 5) + 4); + trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n", + cond, port, index, mask, value); + return (init_rdvgai(init, port, index) & mask) == value; + } + return false; +} + +static bool +init_io_flag_condition_met(struct nvbios_init *init, u8 cond) +{ + struct nouveau_bios *bios = init->bios; + u16 table = init_io_flag_condition_table(init); + if (table) { + u16 port = nv_ro16(bios, table + (cond * 9) + 0); + u8 index = nv_ro08(bios, table + (cond * 9) + 2); + u8 mask = nv_ro08(bios, table + (cond * 9) + 3); + u8 shift = nv_ro08(bios, table + (cond * 9) + 4); + u16 data = nv_ro16(bios, table + (cond * 9) + 5); + u8 dmask = nv_ro08(bios, table + (cond * 9) + 7); + u8 value = nv_ro08(bios, table + (cond * 9) + 8); + u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift; + return (nv_ro08(bios, data + ioval) & dmask) == value; + } + return false; +} + +static inline u32 +init_shift(u32 data, u8 shift) +{ + if (shift < 0x80) + return data >> shift; + return data << (0x100 - shift); +} + +static u32 +init_tmds_reg(struct nvbios_init *init, u8 tmds) +{ + /* For mlv < 0x80, it is an index into a table of TMDS base addresses. + * For mlv == 0x80 use the "or" value of the dcb_entry indexed by + * CR58 for CR57 = 0 to index a table of offsets to the basic + * 0x6808b0 address. + * For mlv == 0x81 use the "or" value of the dcb_entry indexed by + * CR58 for CR57 = 0 to index a table of offsets to the basic + * 0x6808b0 address, and then flip the offset by 8. + */ + + const int pramdac_offset[13] = { + 0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 }; + const u32 pramdac_table[4] = { + 0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 }; + + if (tmds >= 0x80) { + if (init->outp) { + u32 dacoffset = pramdac_offset[init->outp->or]; + if (tmds == 0x81) + dacoffset ^= 8; + return 0x6808b0 + dacoffset; + } + + error("tmds opcodes need dcb\n"); + } else { + if (tmds < ARRAY_SIZE(pramdac_table)) + return pramdac_table[tmds]; + + error("tmds selector 0x%02x unknown\n", tmds); + } + + return 0; +} + +/****************************************************************************** + * init opcode handlers + *****************************************************************************/ + +/** + * init_reserved - stub for various unknown/unused single-byte opcodes + * + */ +static void +init_reserved(struct nvbios_init *init) +{ + u8 opcode = nv_ro08(init->bios, init->offset); + trace("RESERVED\t0x%02x\n", opcode); + init->offset += 1; +} + +/** + * INIT_DONE - opcode 0x71 + * + */ +static void +init_done(struct nvbios_init *init) +{ + trace("DONE\n"); + init->offset = 0x0000; +} + +/** + * INIT_IO_RESTRICT_PROG - opcode 0x32 + * + */ +static void +init_io_restrict_prog(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 port = nv_ro16(bios, init->offset + 1); + u8 index = nv_ro08(bios, init->offset + 3); + u8 mask = nv_ro08(bios, init->offset + 4); + u8 shift = nv_ro08(bios, init->offset + 5); + u8 count = nv_ro08(bios, init->offset + 6); + u32 reg = nv_ro32(bios, init->offset + 7); + u8 conf, i; + + trace("IO_RESTRICT_PROG\tR[0x%06x] = " + "((0x%04x[0x%02x] & 0x%02x) >> %d) [{\n", + reg, port, index, mask, shift); + init->offset += 11; + + conf = (init_rdvgai(init, port, index) & mask) >> shift; + for (i = 0; i < count; i++) { + u32 data = nv_ro32(bios, init->offset); + + if (i == conf) { + trace("\t0x%08x *\n", data); + init_wr32(init, reg, data); + } else { + trace("\t0x%08x\n", data); + } + + init->offset += 4; + } + trace("}]\n"); +} + +/** + * INIT_REPEAT - opcode 0x33 + * + */ +static void +init_repeat(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 count = nv_ro08(bios, init->offset + 1); + u16 repeat = init->repeat; + + trace("REPEAT\t0x%02x\n", count); + init->offset += 2; + + init->repeat = init->offset; + init->repend = init->offset; + while (count--) { + init->offset = init->repeat; + nvbios_exec(init); + if (count) + trace("REPEAT\t0x%02x\n", count); + } + init->offset = init->repend; + init->repeat = repeat; +} + +/** + * INIT_IO_RESTRICT_PLL - opcode 0x34 + * + */ +static void +init_io_restrict_pll(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 port = nv_ro16(bios, init->offset + 1); + u8 index = nv_ro08(bios, init->offset + 3); + u8 mask = nv_ro08(bios, init->offset + 4); + u8 shift = nv_ro08(bios, init->offset + 5); + s8 iofc = nv_ro08(bios, init->offset + 6); + u8 count = nv_ro08(bios, init->offset + 7); + u32 reg = nv_ro32(bios, init->offset + 8); + u8 conf, i; + + trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= " + "((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) IOFCOND 0x%02x [{\n", + reg, port, index, mask, shift, iofc); + init->offset += 12; + + conf = (init_rdvgai(init, port, index) & mask) >> shift; + for (i = 0; i < count; i++) { + u32 freq = nv_ro16(bios, init->offset) * 10; + + if (i == conf) { + trace("\t%dkHz *\n", freq); + if (iofc > 0 && init_io_flag_condition_met(init, iofc)) + freq *= 2; + init_prog_pll(init, reg, freq); + } else { + trace("\t%dkHz\n", freq); + } + + init->offset += 2; + } + trace("}]\n"); +} + +/** + * INIT_END_REPEAT - opcode 0x36 + * + */ +static void +init_end_repeat(struct nvbios_init *init) +{ + trace("END_REPEAT\n"); + init->offset += 1; + + if (init->repeat) { + init->repend = init->offset; + init->offset = 0; + } +} + +/** + * INIT_COPY - opcode 0x37 + * + */ +static void +init_copy(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 reg = nv_ro32(bios, init->offset + 1); + u8 shift = nv_ro08(bios, init->offset + 5); + u8 smask = nv_ro08(bios, init->offset + 6); + u16 port = nv_ro16(bios, init->offset + 7); + u8 index = nv_ro08(bios, init->offset + 9); + u8 mask = nv_ro08(bios, init->offset + 10); + u8 data; + + trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= " + "((R[0x%06x] %s 0x%02x) & 0x%02x)\n", + port, index, mask, reg, (shift & 0x80) ? "<<" : ">>", + (shift & 0x80) ? (0x100 - shift) : shift, smask); + init->offset += 11; + + data = init_rdvgai(init, port, index) & mask; + data |= init_shift(init_rd32(init, reg), shift) & smask; + init_wrvgai(init, port, index, data); +} + +/** + * INIT_NOT - opcode 0x38 + * + */ +static void +init_not(struct nvbios_init *init) +{ + trace("NOT\n"); + init->offset += 1; + init_exec_inv(init); +} + +/** + * INIT_IO_FLAG_CONDITION - opcode 0x39 + * + */ +static void +init_io_flag_condition(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 cond = nv_ro08(bios, init->offset + 1); + + trace("IO_FLAG_CONDITION\t0x%02x\n", cond); + init->offset += 2; + + if (!init_io_flag_condition_met(init, cond)) + init_exec_set(init, false); +} + +/** + * INIT_DP_CONDITION - opcode 0x3a + * + */ +static void +init_dp_condition(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 cond = nv_ro08(bios, init->offset + 1); + u8 unkn = nv_ro08(bios, init->offset + 2); + u8 ver, len; + u16 data; + + trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn); + init->offset += 3; + + switch (cond) { + case 0: + if (init_conn(init) != DCB_CONNECTOR_eDP) + init_exec_set(init, false); + break; + case 1: + case 2: + if ( init->outp && + (data = dp_outp_match(bios, init->outp, &ver, &len))) { + if (ver <= 0x40 && !(nv_ro08(bios, data + 5) & cond)) + init_exec_set(init, false); + if (ver == 0x40 && !(nv_ro08(bios, data + 4) & cond)) + init_exec_set(init, false); + break; + } + + warn("script needs dp output table data\n"); + break; + case 5: + if (!(init_rdauxr(init, 0x0d) & 1)) + init_exec_set(init, false); + break; + default: + warn("unknown dp condition 0x%02x\n", cond); + break; + } +} + +/** + * INIT_IO_MASK_OR - opcode 0x3b + * + */ +static void +init_io_mask_or(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u8 or = init_or(init); + u8 data; + + trace("IO_MASK_OR\t0x03d4[0x%02x] &= ~(1 << 0x%02x)", index, or); + init->offset += 2; + + data = init_rdvgai(init, 0x03d4, index); + init_wrvgai(init, 0x03d4, index, data &= ~(1 << or)); +} + +/** + * INIT_IO_OR - opcode 0x3c + * + */ +static void +init_io_or(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u8 or = init_or(init); + u8 data; + + trace("IO_OR\t0x03d4[0x%02x] |= (1 << 0x%02x)", index, or); + init->offset += 2; + + data = init_rdvgai(init, 0x03d4, index); + init_wrvgai(init, 0x03d4, index, data | (1 << or)); +} + +/** + * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49 + * + */ +static void +init_idx_addr_latched(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 creg = nv_ro32(bios, init->offset + 1); + u32 dreg = nv_ro32(bios, init->offset + 5); + u32 mask = nv_ro32(bios, init->offset + 9); + u32 data = nv_ro32(bios, init->offset + 13); + u8 count = nv_ro08(bios, init->offset + 17); + + trace("INDEX_ADDRESS_LATCHED\t" + "R[0x%06x] : R[0x%06x]\n\tCTRL &= 0x%08x |= 0x%08x\n", + creg, dreg, mask, data); + init->offset += 18; + + while (count--) { + u8 iaddr = nv_ro08(bios, init->offset + 0); + u8 idata = nv_ro08(bios, init->offset + 1); + + trace("\t[0x%02x] = 0x%02x\n", iaddr, idata); + init->offset += 2; + + init_wr32(init, dreg, idata); + init_mask(init, creg, ~mask, data | idata); + } +} + +/** + * INIT_IO_RESTRICT_PLL2 - opcode 0x4a + * + */ +static void +init_io_restrict_pll2(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 port = nv_ro16(bios, init->offset + 1); + u8 index = nv_ro08(bios, init->offset + 3); + u8 mask = nv_ro08(bios, init->offset + 4); + u8 shift = nv_ro08(bios, init->offset + 5); + u8 count = nv_ro08(bios, init->offset + 6); + u32 reg = nv_ro32(bios, init->offset + 7); + u8 conf, i; + + trace("IO_RESTRICT_PLL2\t" + "R[0x%06x] =PLL= ((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) [{\n", + reg, port, index, mask, shift); + init->offset += 11; + + conf = (init_rdvgai(init, port, index) & mask) >> shift; + for (i = 0; i < count; i++) { + u32 freq = nv_ro32(bios, init->offset); + if (i == conf) { + trace("\t%dkHz *\n", freq); + init_prog_pll(init, reg, freq); + } else { + trace("\t%dkHz\n", freq); + } + init->offset += 4; + } + trace("}]\n"); +} + +/** + * INIT_PLL2 - opcode 0x4b + * + */ +static void +init_pll2(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 reg = nv_ro32(bios, init->offset + 1); + u32 freq = nv_ro32(bios, init->offset + 5); + + trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq); + init->offset += 9; + + init_prog_pll(init, reg, freq); +} + +/** + * INIT_I2C_BYTE - opcode 0x4c + * + */ +static void +init_i2c_byte(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u8 addr = nv_ro08(bios, init->offset + 2) >> 1; + u8 count = nv_ro08(bios, init->offset + 3); + + trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr); + init->offset += 4; + + while (count--) { + u8 reg = nv_ro08(bios, init->offset + 0); + u8 mask = nv_ro08(bios, init->offset + 1); + u8 data = nv_ro08(bios, init->offset + 2); + int val; + + trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data); + init->offset += 3; + + val = init_rdi2cr(init, index, addr, reg); + if (val < 0) + continue; + init_wri2cr(init, index, addr, reg, (val & mask) | data); + } +} + +/** + * INIT_ZM_I2C_BYTE - opcode 0x4d + * + */ +static void +init_zm_i2c_byte(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u8 addr = nv_ro08(bios, init->offset + 2) >> 1; + u8 count = nv_ro08(bios, init->offset + 3); + + trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr); + init->offset += 4; + + while (count--) { + u8 reg = nv_ro08(bios, init->offset + 0); + u8 data = nv_ro08(bios, init->offset + 1); + + trace("\t[0x%02x] = 0x%02x\n", reg, data); + init->offset += 2; + + init_wri2cr(init, index, addr, reg, data); + } + +} + +/** + * INIT_ZM_I2C - opcode 0x4e + * + */ +static void +init_zm_i2c(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u8 addr = nv_ro08(bios, init->offset + 2) >> 1; + u8 count = nv_ro08(bios, init->offset + 3); + u8 data[256], i; + + trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr); + init->offset += 4; + + for (i = 0; i < count; i++) { + data[i] = nv_ro08(bios, init->offset); + trace("\t0x%02x\n", data[i]); + init->offset++; + } + + if (init_exec(init)) { + struct nouveau_i2c_port *port = init_i2c(init, index); + struct i2c_msg msg = { + .addr = addr, .flags = 0, .len = count, .buf = data, + }; + int ret; + + if (port && (ret = i2c_transfer(&port->adapter, &msg, 1)) != 1) + warn("i2c wr failed, %d\n", ret); + } +} + +/** + * INIT_TMDS - opcode 0x4f + * + */ +static void +init_tmds(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 tmds = nv_ro08(bios, init->offset + 1); + u8 addr = nv_ro08(bios, init->offset + 2); + u8 mask = nv_ro08(bios, init->offset + 3); + u8 data = nv_ro08(bios, init->offset + 4); + u32 reg = init_tmds_reg(init, tmds); + + trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n", + tmds, addr, mask, data); + init->offset += 5; + + if (reg == 0) + return; + + init_wr32(init, reg + 0, addr | 0x00010000); + init_wr32(init, reg + 4, data | (init_rd32(init, reg + 4) & mask)); + init_wr32(init, reg + 0, addr); +} + +/** + * INIT_ZM_TMDS_GROUP - opcode 0x50 + * + */ +static void +init_zm_tmds_group(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 tmds = nv_ro08(bios, init->offset + 1); + u8 count = nv_ro08(bios, init->offset + 2); + u32 reg = init_tmds_reg(init, tmds); + + trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds); + init->offset += 3; + + while (count--) { + u8 addr = nv_ro08(bios, init->offset + 0); + u8 data = nv_ro08(bios, init->offset + 1); + + trace("\t[0x%02x] = 0x%02x\n", addr, data); + init->offset += 2; + + init_wr32(init, reg + 4, data); + init_wr32(init, reg + 0, addr); + } +} + +/** + * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51 + * + */ +static void +init_cr_idx_adr_latch(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 addr0 = nv_ro08(bios, init->offset + 1); + u8 addr1 = nv_ro08(bios, init->offset + 2); + u8 base = nv_ro08(bios, init->offset + 3); + u8 count = nv_ro08(bios, init->offset + 4); + u8 save0; + + trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1); + init->offset += 5; + + save0 = init_rdvgai(init, 0x03d4, addr0); + while (count--) { + u8 data = nv_ro08(bios, init->offset); + + trace("\t\t[0x%02x] = 0x%02x\n", base, data); + init->offset += 1; + + init_wrvgai(init, 0x03d4, addr0, base++); + init_wrvgai(init, 0x03d4, addr1, data); + } + init_wrvgai(init, 0x03d4, addr0, save0); +} + +/** + * INIT_CR - opcode 0x52 + * + */ +static void +init_cr(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 addr = nv_ro08(bios, init->offset + 1); + u8 mask = nv_ro08(bios, init->offset + 2); + u8 data = nv_ro08(bios, init->offset + 3); + u8 val; + + trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data); + init->offset += 4; + + val = init_rdvgai(init, 0x03d4, addr) & mask; + init_wrvgai(init, 0x03d4, addr, val | data); +} + +/** + * INIT_ZM_CR - opcode 0x53 + * + */ +static void +init_zm_cr(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 addr = nv_ro08(bios, init->offset + 1); + u8 data = nv_ro08(bios, init->offset + 2); + + trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr, data); + init->offset += 3; + + init_wrvgai(init, 0x03d4, addr, data); +} + +/** + * INIT_ZM_CR_GROUP - opcode 0x54 + * + */ +static void +init_zm_cr_group(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 count = nv_ro08(bios, init->offset + 1); + + trace("ZM_CR_GROUP\n"); + init->offset += 2; + + while (count--) { + u8 addr = nv_ro08(bios, init->offset + 0); + u8 data = nv_ro08(bios, init->offset + 1); + + trace("\t\tC[0x%02x] = 0x%02x\n", addr, data); + init->offset += 2; + + init_wrvgai(init, 0x03d4, addr, data); + } +} + +/** + * INIT_CONDITION_TIME - opcode 0x56 + * + */ +static void +init_condition_time(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 cond = nv_ro08(bios, init->offset + 1); + u8 retry = nv_ro08(bios, init->offset + 2); + u8 wait = min((u16)retry * 50, 100); + + trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry); + init->offset += 3; + + if (!init_exec(init)) + return; + + while (wait--) { + if (init_condition_met(init, cond)) + return; + mdelay(20); + } + + init_exec_set(init, false); +} + +/** + * INIT_LTIME - opcode 0x57 + * + */ +static void +init_ltime(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 msec = nv_ro16(bios, init->offset + 1); + + trace("LTIME\t0x%04x\n", msec); + init->offset += 3; + + if (init_exec(init)) + mdelay(msec); +} + +/** + * INIT_ZM_REG_SEQUENCE - opcode 0x58 + * + */ +static void +init_zm_reg_sequence(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 base = nv_ro32(bios, init->offset + 1); + u8 count = nv_ro08(bios, init->offset + 5); + + trace("ZM_REG_SEQUENCE\t0x%02x\n", count); + init->offset += 6; + + while (count--) { + u32 data = nv_ro32(bios, init->offset); + + trace("\t\tR[0x%06x] = 0x%08x\n", base, data); + init->offset += 4; + + init_wr32(init, base, data); + base += 4; + } +} + +/** + * INIT_SUB_DIRECT - opcode 0x5b + * + */ +static void +init_sub_direct(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 addr = nv_ro16(bios, init->offset + 1); + u16 save; + + trace("SUB_DIRECT\t0x%04x\n", addr); + + if (init_exec(init)) { + save = init->offset; + init->offset = addr; + if (nvbios_exec(init)) { + error("error parsing sub-table\n"); + return; + } + init->offset = save; + } + + init->offset += 3; +} + +/** + * INIT_JUMP - opcode 0x5c + * + */ +static void +init_jump(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 offset = nv_ro16(bios, init->offset + 1); + + trace("JUMP\t0x%04x\n", offset); + init->offset = offset; +} + +/** + * INIT_I2C_IF - opcode 0x5e + * + */ +static void +init_i2c_if(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u8 addr = nv_ro08(bios, init->offset + 2); + u8 reg = nv_ro08(bios, init->offset + 3); + u8 mask = nv_ro08(bios, init->offset + 4); + u8 data = nv_ro08(bios, init->offset + 5); + u8 value; + + trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n", + index, addr, reg, mask, data); + init->offset += 6; + init_exec_force(init, true); + + value = init_rdi2cr(init, index, addr, reg); + if ((value & mask) != data) + init_exec_set(init, false); + + init_exec_force(init, false); +} + +/** + * INIT_COPY_NV_REG - opcode 0x5f + * + */ +static void +init_copy_nv_reg(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 sreg = nv_ro32(bios, init->offset + 1); + u8 shift = nv_ro08(bios, init->offset + 5); + u32 smask = nv_ro32(bios, init->offset + 6); + u32 sxor = nv_ro32(bios, init->offset + 10); + u32 dreg = nv_ro32(bios, init->offset + 14); + u32 dmask = nv_ro32(bios, init->offset + 18); + u32 data; + + trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= " + "((R[0x%06x] %s 0x%02x) & 0x%08x ^ 0x%08x)\n", + dreg, dmask, sreg, (shift & 0x80) ? "<<" : ">>", + (shift & 0x80) ? (0x100 - shift) : shift, smask, sxor); + init->offset += 22; + + data = init_shift(init_rd32(init, sreg), shift); + init_mask(init, dreg, ~dmask, (data & smask) ^ sxor); +} + +/** + * INIT_ZM_INDEX_IO - opcode 0x62 + * + */ +static void +init_zm_index_io(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 port = nv_ro16(bios, init->offset + 1); + u8 index = nv_ro08(bios, init->offset + 3); + u8 data = nv_ro08(bios, init->offset + 4); + + trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data); + init->offset += 5; + + init_wrvgai(init, port, index, data); +} + +/** + * INIT_COMPUTE_MEM - opcode 0x63 + * + */ +static void +init_compute_mem(struct nvbios_init *init) +{ + struct nouveau_devinit *devinit = nouveau_devinit(init->bios); + + trace("COMPUTE_MEM\n"); + init->offset += 1; + + init_exec_force(init, true); + if (init_exec(init) && devinit->meminit) + devinit->meminit(devinit); + init_exec_force(init, false); +} + +/** + * INIT_RESET - opcode 0x65 + * + */ +static void +init_reset(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 reg = nv_ro32(bios, init->offset + 1); + u32 data1 = nv_ro32(bios, init->offset + 5); + u32 data2 = nv_ro32(bios, init->offset + 9); + u32 savepci19; + + trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2); + init->offset += 13; + init_exec_force(init, true); + + savepci19 = init_mask(init, 0x00184c, 0x00000f00, 0x00000000); + init_wr32(init, reg, data1); + udelay(10); + init_wr32(init, reg, data2); + init_wr32(init, 0x00184c, savepci19); + init_mask(init, 0x001850, 0x00000001, 0x00000000); + + init_exec_force(init, false); +} + +/** + * INIT_CONFIGURE_MEM - opcode 0x66 + * + */ +static u16 +init_configure_mem_clk(struct nvbios_init *init) +{ + u16 mdata = bmp_mem_init_table(init->bios); + if (mdata) + mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66; + return mdata; +} + +static void +init_configure_mem(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 mdata, sdata; + u32 addr, data; + + trace("CONFIGURE_MEM\n"); + init->offset += 1; + + if (bios->version.major > 2) { + init_done(init); + return; + } + init_exec_force(init, true); + + mdata = init_configure_mem_clk(init); + sdata = bmp_sdr_seq_table(bios); + if (nv_ro08(bios, mdata) & 0x01) + sdata = bmp_ddr_seq_table(bios); + mdata += 6; /* skip to data */ + + data = init_rdvgai(init, 0x03c4, 0x01); + init_wrvgai(init, 0x03c4, 0x01, data | 0x20); + + while ((addr = nv_ro32(bios, sdata)) != 0xffffffff) { + switch (addr) { + case 0x10021c: /* CKE_NORMAL */ + case 0x1002d0: /* CMD_REFRESH */ + case 0x1002d4: /* CMD_PRECHARGE */ + data = 0x00000001; + break; + default: + data = nv_ro32(bios, mdata); + mdata += 4; + if (data == 0xffffffff) + continue; + break; + } + + init_wr32(init, addr, data); + } + + init_exec_force(init, false); +} + +/** + * INIT_CONFIGURE_CLK - opcode 0x67 + * + */ +static void +init_configure_clk(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 mdata, clock; + + trace("CONFIGURE_CLK\n"); + init->offset += 1; + + if (bios->version.major > 2) { + init_done(init); + return; + } + init_exec_force(init, true); + + mdata = init_configure_mem_clk(init); + + /* NVPLL */ + clock = nv_ro16(bios, mdata + 4) * 10; + init_prog_pll(init, 0x680500, clock); + + /* MPLL */ + clock = nv_ro16(bios, mdata + 2) * 10; + if (nv_ro08(bios, mdata) & 0x01) + clock *= 2; + init_prog_pll(init, 0x680504, clock); + + init_exec_force(init, false); +} + +/** + * INIT_CONFIGURE_PREINIT - opcode 0x68 + * + */ +static void +init_configure_preinit(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 strap; + + trace("CONFIGURE_PREINIT\n"); + init->offset += 1; + + if (bios->version.major > 2) { + init_done(init); + return; + } + init_exec_force(init, true); + + strap = init_rd32(init, 0x101000); + strap = ((strap << 2) & 0xf0) | ((strap & 0x40) >> 6); + init_wrvgai(init, 0x03d4, 0x3c, strap); + + init_exec_force(init, false); +} + +/** + * INIT_IO - opcode 0x69 + * + */ +static void +init_io(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 port = nv_ro16(bios, init->offset + 1); + u8 mask = nv_ro16(bios, init->offset + 3); + u8 data = nv_ro16(bios, init->offset + 4); + u8 value; + + trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data); + init->offset += 5; + + /* ummm.. yes.. should really figure out wtf this is and why it's + * needed some day.. it's almost certainly wrong, but, it also + * somehow makes things work... + */ + if (nv_device(init->bios)->card_type >= NV_50 && + port == 0x03c3 && data == 0x01) { + init_mask(init, 0x614100, 0xf0800000, 0x00800000); + init_mask(init, 0x00e18c, 0x00020000, 0x00020000); + init_mask(init, 0x614900, 0xf0800000, 0x00800000); + init_mask(init, 0x000200, 0x40000000, 0x00000000); + mdelay(10); + init_mask(init, 0x00e18c, 0x00020000, 0x00000000); + init_mask(init, 0x000200, 0x40000000, 0x40000000); + init_wr32(init, 0x614100, 0x00800018); + init_wr32(init, 0x614900, 0x00800018); + mdelay(10); + init_wr32(init, 0x614100, 0x10000018); + init_wr32(init, 0x614900, 0x10000018); + return; + } + + value = init_rdport(init, port) & mask; + init_wrport(init, port, data | value); +} + +/** + * INIT_SUB - opcode 0x6b + * + */ +static void +init_sub(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u16 addr, save; + + trace("SUB\t0x%02x\n", index); + + addr = init_script(bios, index); + if (addr && init_exec(init)) { + save = init->offset; + init->offset = addr; + if (nvbios_exec(init)) { + error("error parsing sub-table\n"); + return; + } + init->offset = save; + } + + init->offset += 2; +} + +/** + * INIT_RAM_CONDITION - opcode 0x6d + * + */ +static void +init_ram_condition(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 mask = nv_ro08(bios, init->offset + 1); + u8 value = nv_ro08(bios, init->offset + 2); + + trace("RAM_CONDITION\t" + "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value); + init->offset += 3; + + if ((init_rd32(init, 0x100000) & mask) != value) + init_exec_set(init, false); +} + +/** + * INIT_NV_REG - opcode 0x6e + * + */ +static void +init_nv_reg(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 reg = nv_ro32(bios, init->offset + 1); + u32 mask = nv_ro32(bios, init->offset + 5); + u32 data = nv_ro32(bios, init->offset + 9); + + trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data); + init->offset += 13; + + init_mask(init, reg, ~mask, data); +} + +/** + * INIT_MACRO - opcode 0x6f + * + */ +static void +init_macro(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 macro = nv_ro08(bios, init->offset + 1); + u16 table; + + trace("MACRO\t0x%02x\n", macro); + + table = init_macro_table(init); + if (table) { + u32 addr = nv_ro32(bios, table + (macro * 8) + 0); + u32 data = nv_ro32(bios, table + (macro * 8) + 4); + trace("\t\tR[0x%06x] = 0x%08x\n", addr, data); + init_wr32(init, addr, data); + } + + init->offset += 2; +} + +/** + * INIT_RESUME - opcode 0x72 + * + */ +static void +init_resume(struct nvbios_init *init) +{ + trace("RESUME\n"); + init->offset += 1; + init_exec_set(init, true); +} + +/** + * INIT_TIME - opcode 0x74 + * + */ +static void +init_time(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 usec = nv_ro16(bios, init->offset + 1); + + trace("TIME\t0x%04x\n", usec); + init->offset += 3; + + if (init_exec(init)) { + if (usec < 1000) + udelay(usec); + else + mdelay((usec + 900) / 1000); + } +} + +/** + * INIT_CONDITION - opcode 0x75 + * + */ +static void +init_condition(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 cond = nv_ro08(bios, init->offset + 1); + + trace("CONDITION\t0x%02x\n", cond); + init->offset += 2; + + if (!init_condition_met(init, cond)) + init_exec_set(init, false); +} + +/** + * INIT_IO_CONDITION - opcode 0x76 + * + */ +static void +init_io_condition(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 cond = nv_ro08(bios, init->offset + 1); + + trace("IO_CONDITION\t0x%02x\n", cond); + init->offset += 2; + + if (!init_io_condition_met(init, cond)) + init_exec_set(init, false); +} + +/** + * INIT_INDEX_IO - opcode 0x78 + * + */ +static void +init_index_io(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u16 port = nv_ro16(bios, init->offset + 1); + u8 index = nv_ro16(bios, init->offset + 3); + u8 mask = nv_ro08(bios, init->offset + 4); + u8 data = nv_ro08(bios, init->offset + 5); + u8 value; + + trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n", + port, index, mask, data); + init->offset += 6; + + value = init_rdvgai(init, port, index) & mask; + init_wrvgai(init, port, index, data | value); +} + +/** + * INIT_PLL - opcode 0x79 + * + */ +static void +init_pll(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 reg = nv_ro32(bios, init->offset + 1); + u32 freq = nv_ro16(bios, init->offset + 5) * 10; + + trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq); + init->offset += 7; + + init_prog_pll(init, reg, freq); +} + +/** + * INIT_ZM_REG - opcode 0x7a + * + */ +static void +init_zm_reg(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 addr = nv_ro32(bios, init->offset + 1); + u32 data = nv_ro32(bios, init->offset + 5); + + trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data); + init->offset += 9; + + if (addr == 0x000200) + data |= 0x00000001; + + init_wr32(init, addr, data); +} + +/** + * INIT_RAM_RESTRICT_PLL - opcde 0x87 + * + */ +static void +init_ram_restrict_pll(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 type = nv_ro08(bios, init->offset + 1); + u8 count = init_ram_restrict_group_count(init); + u8 strap = init_ram_restrict(init); + u8 cconf; + + trace("RAM_RESTRICT_PLL\t0x%02x\n", type); + init->offset += 2; + + for (cconf = 0; cconf < count; cconf++) { + u32 freq = nv_ro32(bios, init->offset); + + if (cconf == strap) { + trace("%dkHz *\n", freq); + init_prog_pll(init, type, freq); + } else { + trace("%dkHz\n", freq); + } + + init->offset += 4; + } +} + +/** + * INIT_GPIO - opcode 0x8e + * + */ +static void +init_gpio(struct nvbios_init *init) +{ + struct nouveau_gpio *gpio = nouveau_gpio(init->bios); + + trace("GPIO\n"); + init->offset += 1; + + if (init_exec(init) && gpio && gpio->reset) + gpio->reset(gpio); +} + +/** + * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f + * + */ +static void +init_ram_restrict_zm_reg_group(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 addr = nv_ro32(bios, init->offset + 1); + u8 incr = nv_ro08(bios, init->offset + 5); + u8 num = nv_ro08(bios, init->offset + 6); + u8 count = init_ram_restrict_group_count(init); + u8 index = init_ram_restrict(init); + u8 i, j; + + trace("RAM_RESTRICT_ZM_REG_GROUP\t" + "R[%08x] 0x%02x 0x%02x\n", addr, incr, num); + init->offset += 7; + + for (i = 0; i < num; i++) { + trace("\tR[0x%06x] = {\n", addr); + for (j = 0; j < count; j++) { + u32 data = nv_ro32(bios, init->offset); + + if (j == index) { + trace("\t\t0x%08x *\n", data); + init_wr32(init, addr, data); + } else { + trace("\t\t0x%08x\n", data); + } + + init->offset += 4; + } + trace("\t}\n"); + addr += incr; + } +} + +/** + * INIT_COPY_ZM_REG - opcode 0x90 + * + */ +static void +init_copy_zm_reg(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 sreg = nv_ro32(bios, init->offset + 1); + u32 dreg = nv_ro32(bios, init->offset + 5); + + trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", sreg, dreg); + init->offset += 9; + + init_wr32(init, dreg, init_rd32(init, sreg)); +} + +/** + * INIT_ZM_REG_GROUP - opcode 0x91 + * + */ +static void +init_zm_reg_group(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 addr = nv_ro32(bios, init->offset + 1); + u8 count = nv_ro08(bios, init->offset + 5); + + trace("ZM_REG_GROUP\tR[0x%06x] =\n"); + init->offset += 6; + + while (count--) { + u32 data = nv_ro32(bios, init->offset); + trace("\t0x%08x\n", data); + init_wr32(init, addr, data); + init->offset += 4; + } +} + +/** + * INIT_XLAT - opcode 0x96 + * + */ +static void +init_xlat(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 saddr = nv_ro32(bios, init->offset + 1); + u8 sshift = nv_ro08(bios, init->offset + 5); + u8 smask = nv_ro08(bios, init->offset + 6); + u8 index = nv_ro08(bios, init->offset + 7); + u32 daddr = nv_ro32(bios, init->offset + 8); + u32 dmask = nv_ro32(bios, init->offset + 12); + u8 shift = nv_ro08(bios, init->offset + 16); + u32 data; + + trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= " + "(X%02x((R[0x%06x] %s 0x%02x) & 0x%02x) << 0x%02x)\n", + daddr, dmask, index, saddr, (sshift & 0x80) ? "<<" : ">>", + (sshift & 0x80) ? (0x100 - sshift) : sshift, smask, shift); + init->offset += 17; + + data = init_shift(init_rd32(init, saddr), sshift) & smask; + data = init_xlat_(init, index, data) << shift; + init_mask(init, daddr, ~dmask, data); +} + +/** + * INIT_ZM_MASK_ADD - opcode 0x97 + * + */ +static void +init_zm_mask_add(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 addr = nv_ro32(bios, init->offset + 1); + u32 mask = nv_ro32(bios, init->offset + 5); + u32 add = nv_ro32(bios, init->offset + 9); + u32 data; + + trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add); + init->offset += 13; + + data = init_rd32(init, addr) & mask; + data |= ((data + add) & ~mask); + init_wr32(init, addr, data); +} + +/** + * INIT_AUXCH - opcode 0x98 + * + */ +static void +init_auxch(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 addr = nv_ro32(bios, init->offset + 1); + u8 count = nv_ro08(bios, init->offset + 5); + + trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count); + init->offset += 6; + + while (count--) { + u8 mask = nv_ro08(bios, init->offset + 0); + u8 data = nv_ro08(bios, init->offset + 1); + trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data); + mask = init_rdauxr(init, addr) & mask; + init_wrauxr(init, addr, mask | data); + init->offset += 2; + } +} + +/** + * INIT_AUXCH - opcode 0x99 + * + */ +static void +init_zm_auxch(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u32 addr = nv_ro32(bios, init->offset + 1); + u8 count = nv_ro08(bios, init->offset + 5); + + trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count); + init->offset += 6; + + while (count--) { + u8 data = nv_ro08(bios, init->offset + 0); + trace("\tAUX[0x%08x] = 0x%02x\n", addr, data); + init_wrauxr(init, addr, data); + init->offset += 1; + } +} + +/** + * INIT_I2C_LONG_IF - opcode 0x9a + * + */ +static void +init_i2c_long_if(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + u8 index = nv_ro08(bios, init->offset + 1); + u8 addr = nv_ro08(bios, init->offset + 2) >> 1; + u8 reglo = nv_ro08(bios, init->offset + 3); + u8 reghi = nv_ro08(bios, init->offset + 4); + u8 mask = nv_ro08(bios, init->offset + 5); + u8 data = nv_ro08(bios, init->offset + 6); + struct nouveau_i2c_port *port; + + trace("I2C_LONG_IF\t" + "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n", + index, addr, reglo, reghi, mask, data); + init->offset += 7; + + port = init_i2c(init, index); + if (port) { + u8 i[2] = { reghi, reglo }; + u8 o[1] = {}; + struct i2c_msg msg[] = { + { .addr = addr, .flags = 0, .len = 2, .buf = i }, + { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = o } + }; + int ret; + + ret = i2c_transfer(&port->adapter, msg, 2); + if (ret == 2 && ((o[0] & mask) == data)) + return; + } + + init_exec_set(init, false); +} + +static struct nvbios_init_opcode { + void (*exec)(struct nvbios_init *); +} init_opcode[] = { + [0x32] = { init_io_restrict_prog }, + [0x33] = { init_repeat }, + [0x34] = { init_io_restrict_pll }, + [0x36] = { init_end_repeat }, + [0x37] = { init_copy }, + [0x38] = { init_not }, + [0x39] = { init_io_flag_condition }, + [0x3a] = { init_dp_condition }, + [0x3b] = { init_io_mask_or }, + [0x3c] = { init_io_or }, + [0x49] = { init_idx_addr_latched }, + [0x4a] = { init_io_restrict_pll2 }, + [0x4b] = { init_pll2 }, + [0x4c] = { init_i2c_byte }, + [0x4d] = { init_zm_i2c_byte }, + [0x4e] = { init_zm_i2c }, + [0x4f] = { init_tmds }, + [0x50] = { init_zm_tmds_group }, + [0x51] = { init_cr_idx_adr_latch }, + [0x52] = { init_cr }, + [0x53] = { init_zm_cr }, + [0x54] = { init_zm_cr_group }, + [0x56] = { init_condition_time }, + [0x57] = { init_ltime }, + [0x58] = { init_zm_reg_sequence }, + [0x5b] = { init_sub_direct }, + [0x5c] = { init_jump }, + [0x5e] = { init_i2c_if }, + [0x5f] = { init_copy_nv_reg }, + [0x62] = { init_zm_index_io }, + [0x63] = { init_compute_mem }, + [0x65] = { init_reset }, + [0x66] = { init_configure_mem }, + [0x67] = { init_configure_clk }, + [0x68] = { init_configure_preinit }, + [0x69] = { init_io }, + [0x6b] = { init_sub }, + [0x6d] = { init_ram_condition }, + [0x6e] = { init_nv_reg }, + [0x6f] = { init_macro }, + [0x71] = { init_done }, + [0x72] = { init_resume }, + [0x74] = { init_time }, + [0x75] = { init_condition }, + [0x76] = { init_io_condition }, + [0x78] = { init_index_io }, + [0x79] = { init_pll }, + [0x7a] = { init_zm_reg }, + [0x87] = { init_ram_restrict_pll }, + [0x8c] = { init_reserved }, + [0x8d] = { init_reserved }, + [0x8e] = { init_gpio }, + [0x8f] = { init_ram_restrict_zm_reg_group }, + [0x90] = { init_copy_zm_reg }, + [0x91] = { init_zm_reg_group }, + [0x92] = { init_reserved }, + [0x96] = { init_xlat }, + [0x97] = { init_zm_mask_add }, + [0x98] = { init_auxch }, + [0x99] = { init_zm_auxch }, + [0x9a] = { init_i2c_long_if }, +}; + +#define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0])) + +int +nvbios_exec(struct nvbios_init *init) +{ + init->nested++; + while (init->offset) { + u8 opcode = nv_ro08(init->bios, init->offset); + if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) { + error("unknown opcode 0x%02x\n", opcode); + return -EINVAL; + } + + init_opcode[opcode].exec(init); + } + init->nested--; + return 0; +} + +int +nvbios_init(struct nouveau_subdev *subdev, bool execute) +{ + struct nouveau_bios *bios = nouveau_bios(subdev); + int ret = 0; + int i = -1; + u16 data; + + if (execute) + nv_info(bios, "running init tables\n"); + while (!ret && (data = (init_script(bios, ++i)))) { + struct nvbios_init init = { + .subdev = subdev, + .bios = bios, + .offset = data, + .outp = NULL, + .crtc = -1, + .execute = execute ? 1 : 0, + }; + + ret = nvbios_exec(&init); + } + + /* the vbios parser will run this right after the normal init + * tables, whereas the binary driver appears to run it later. + */ + if (!ret && (data = init_unknown_script(bios))) { + struct nvbios_init init = { + .subdev = subdev, + .bios = bios, + .offset = data, + .outp = NULL, + .crtc = -1, + .execute = execute ? 1 : 0, + }; + + ret = nvbios_exec(&init); + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c new file mode 100644 index 00000000000..2610b11a99b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c @@ -0,0 +1,135 @@ +/* + * 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/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/mxm.h> + +u16 +mxm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr) +{ + struct bit_entry x; + + if (bit_entry(bios, 'x', &x)) { + nv_debug(bios, "BIT 'x' table not present\n"); + return 0x0000; + } + + *ver = x.version; + *hdr = x.length; + if (*ver != 1 || *hdr < 3) { + nv_warn(bios, "BIT 'x' table %d/%d unknown\n", *ver, *hdr); + return 0x0000; + } + + return x.offset; +} + +/* These map MXM v2.x digital connection values to the appropriate SOR/link, + * hopefully they're correct for all boards within the same chipset... + * + * MXM v3.x VBIOS are nicer and provide pointers to these tables. + */ +static u8 nv84_sor_map[16] = { + 0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static u8 nv92_sor_map[16] = { + 0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31, + 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static u8 nv94_sor_map[16] = { + 0x00, 0x14, 0x24, 0x11, 0x34, 0x31, 0x11, 0x31, + 0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static u8 nv98_sor_map[16] = { + 0x00, 0x14, 0x12, 0x11, 0x00, 0x31, 0x11, 0x31, + 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +u8 +mxm_sor_map(struct nouveau_bios *bios, u8 conn) +{ + u8 ver, hdr; + u16 mxm = mxm_table(bios, &ver, &hdr); + if (mxm && hdr >= 6) { + u16 map = nv_ro16(bios, mxm + 4); + if (map) { + ver = nv_ro08(bios, map); + if (ver == 0x10) { + if (conn < nv_ro08(bios, map + 3)) { + map += nv_ro08(bios, map + 1); + map += conn; + return nv_ro08(bios, map); + } + + return 0x00; + } + + nv_warn(bios, "unknown sor map v%02x\n", ver); + } + } + + if (bios->version.chip == 0x84 || bios->version.chip == 0x86) + return nv84_sor_map[conn]; + if (bios->version.chip == 0x92) + return nv92_sor_map[conn]; + if (bios->version.chip == 0x94 || bios->version.chip == 0x96) + return nv94_sor_map[conn]; + if (bios->version.chip == 0x98) + return nv98_sor_map[conn]; + + nv_warn(bios, "missing sor map\n"); + return 0x00; +} + +u8 +mxm_ddc_map(struct nouveau_bios *bios, u8 port) +{ + u8 ver, hdr; + u16 mxm = mxm_table(bios, &ver, &hdr); + if (mxm && hdr >= 8) { + u16 map = nv_ro16(bios, mxm + 6); + if (map) { + ver = nv_ro08(bios, map); + if (ver == 0x10) { + if (port < nv_ro08(bios, map + 3)) { + map += nv_ro08(bios, map + 1); + map += port; + return nv_ro08(bios, map); + } + + return 0x00; + } + + nv_warn(bios, "unknown ddc map v%02x\n", ver); + } + } + + /* v2.x: directly write port as dcb i2cidx */ + return (port << 4) | port; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c new file mode 100644 index 00000000000..bcbb056c288 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c @@ -0,0 +1,75 @@ +/* + * Copyright 2012 Nouveau Community + * + * 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: Martin Peres + */ + +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/perf.h> + +static u16 +perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + struct bit_entry bit_P; + u16 perf = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version <= 2) { + perf = nv_ro16(bios, bit_P.offset + 0); + if (perf) { + *ver = nv_ro08(bios, perf + 0); + *hdr = nv_ro08(bios, perf + 1); + } + } else + nv_error(bios, "unknown offset for perf in BIT P %d\n", + bit_P.version); + } + + if (bios->bmp_offset) { + if (nv_ro08(bios, bios->bmp_offset + 6) >= 0x25) { + perf = nv_ro16(bios, bios->bmp_offset + 0x94); + if (perf) { + *hdr = nv_ro08(bios, perf + 0); + *ver = nv_ro08(bios, perf + 1); + } + } + } + + return perf; +} + +int +nvbios_perf_fan_parse(struct nouveau_bios *bios, + struct nvbios_perf_fan *fan) +{ + u8 ver = 0, hdr = 0, cnt = 0, len = 0; + u16 perf = perf_table(bios, &ver, &hdr, &cnt, &len); + if (!perf) + return -ENODEV; + + if (ver >= 0x20 && ver < 0x40 && hdr > 6) + fan->pwm_divisor = nv_ro16(bios, perf + 6); + else + fan->pwm_divisor = 0; + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c new file mode 100644 index 00000000000..5e5f4cddae3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c @@ -0,0 +1,417 @@ +/* + * Copyright 2005-2006 Erik Waling + * Copyright 2006 Stephane Marchesin + * Copyright 2007-2009 Stuart Bennett + * + * 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 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <subdev/vga.h> +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/bmp.h> +#include <subdev/bios/pll.h> + +struct pll_mapping { + u8 type; + u32 reg; +}; + +static struct pll_mapping +nv04_pll_mapping[] = { + { PLL_CORE , 0x680500 }, + { PLL_MEMORY, 0x680504 }, + { PLL_VPLL0 , 0x680508 }, + { PLL_VPLL1 , 0x680520 }, + {} +}; + +static struct pll_mapping +nv40_pll_mapping[] = { + { PLL_CORE , 0x004000 }, + { PLL_MEMORY, 0x004020 }, + { PLL_VPLL0 , 0x680508 }, + { PLL_VPLL1 , 0x680520 }, + {} +}; + +static struct pll_mapping +nv50_pll_mapping[] = { + { PLL_CORE , 0x004028 }, + { PLL_SHADER, 0x004020 }, + { PLL_UNK03 , 0x004000 }, + { PLL_MEMORY, 0x004008 }, + { PLL_UNK40 , 0x00e810 }, + { PLL_UNK41 , 0x00e818 }, + { PLL_UNK42 , 0x00e824 }, + { PLL_VPLL0 , 0x614100 }, + { PLL_VPLL1 , 0x614900 }, + {} +}; + +static struct pll_mapping +nv84_pll_mapping[] = { + { PLL_CORE , 0x004028 }, + { PLL_SHADER, 0x004020 }, + { PLL_MEMORY, 0x004008 }, + { PLL_VDEC , 0x004030 }, + { PLL_UNK41 , 0x00e818 }, + { PLL_VPLL0 , 0x614100 }, + { PLL_VPLL1 , 0x614900 }, + {} +}; + +static u16 +pll_limits_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + struct bit_entry bit_C; + + if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) { + u16 data = nv_ro16(bios, bit_C.offset + 8); + if (data) { + *ver = nv_ro08(bios, data + 0); + *hdr = nv_ro08(bios, data + 1); + *len = nv_ro08(bios, data + 2); + *cnt = nv_ro08(bios, data + 3); + return data; + } + } + + if (bmp_version(bios) >= 0x0524) { + u16 data = nv_ro16(bios, bios->bmp_offset + 142); + if (data) { + *ver = nv_ro08(bios, data + 0); + *hdr = 1; + *cnt = 1; + *len = 0x18; + return data; + } + } + + *ver = 0x00; + return 0x0000; +} + +static struct pll_mapping * +pll_map(struct nouveau_bios *bios) +{ + switch (nv_device(bios)->card_type) { + case NV_04: + case NV_10: + case NV_20: + case NV_30: + return nv04_pll_mapping; + break; + case NV_40: + return nv40_pll_mapping; + case NV_50: + if (nv_device(bios)->chipset == 0x50) + return nv50_pll_mapping; + else + if (nv_device(bios)->chipset < 0xa3 || + nv_device(bios)->chipset == 0xaa || + nv_device(bios)->chipset == 0xac) + return nv84_pll_mapping; + default: + return NULL; + } +} + +static u16 +pll_map_reg(struct nouveau_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) +{ + struct pll_mapping *map; + u8 hdr, cnt; + u16 data; + + data = pll_limits_table(bios, ver, &hdr, &cnt, len); + if (data && *ver >= 0x30) { + data += hdr; + while (cnt--) { + if (nv_ro32(bios, data + 3) == reg) { + *type = nv_ro08(bios, data + 0); + return data; + } + data += *len; + } + return 0x0000; + } + + map = pll_map(bios); + while (map->reg) { + if (map->reg == reg && *ver >= 0x20) { + u16 addr = (data += hdr); + while (cnt--) { + if (nv_ro32(bios, data) == map->reg) { + *type = map->type; + return data; + } + data += *len; + } + return addr; + } else + if (map->reg == reg) { + *type = map->type; + return data + 1; + } + map++; + } + + return 0x0000; +} + +static u16 +pll_map_type(struct nouveau_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) +{ + struct pll_mapping *map; + u8 hdr, cnt; + u16 data; + + data = pll_limits_table(bios, ver, &hdr, &cnt, len); + if (data && *ver >= 0x30) { + data += hdr; + while (cnt--) { + if (nv_ro08(bios, data + 0) == type) { + *reg = nv_ro32(bios, data + 3); + return data; + } + data += *len; + } + return 0x0000; + } + + map = pll_map(bios); + while (map->reg) { + if (map->type == type && *ver >= 0x20) { + u16 addr = (data += hdr); + while (cnt--) { + if (nv_ro32(bios, data) == map->reg) { + *reg = map->reg; + return data; + } + data += *len; + } + return addr; + } else + if (map->type == type) { + *reg = map->reg; + return data + 1; + } + map++; + } + + return 0x0000; +} + +int +nvbios_pll_parse(struct nouveau_bios *bios, u32 type, struct nvbios_pll *info) +{ + u8 ver, len; + u32 reg = type; + u16 data; + + if (type > PLL_MAX) { + reg = type; + data = pll_map_reg(bios, reg, &type, &ver, &len); + } else { + data = pll_map_type(bios, type, ®, &ver, &len); + } + + if (ver && !data) + return -ENOENT; + + memset(info, 0, sizeof(*info)); + info->type = type; + info->reg = reg; + + switch (ver) { + case 0x00: + break; + case 0x10: + case 0x11: + info->vco1.min_freq = nv_ro32(bios, data + 0); + info->vco1.max_freq = nv_ro32(bios, data + 4); + info->vco2.min_freq = nv_ro32(bios, data + 8); + info->vco2.max_freq = nv_ro32(bios, data + 12); + info->vco1.min_inputfreq = nv_ro32(bios, data + 16); + info->vco2.min_inputfreq = nv_ro32(bios, data + 20); + info->vco1.max_inputfreq = INT_MAX; + info->vco2.max_inputfreq = INT_MAX; + + info->max_p = 0x7; + info->max_p_usable = 0x6; + + /* these values taken from nv30/31/36 */ + switch (bios->version.chip) { + case 0x36: + info->vco1.min_n = 0x5; + break; + default: + info->vco1.min_n = 0x1; + break; + } + info->vco1.max_n = 0xff; + info->vco1.min_m = 0x1; + info->vco1.max_m = 0xd; + + /* + * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this + * table version (apart from nv35)), N2 is compared to + * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and + * save a comparison + */ + info->vco2.min_n = 0x4; + switch (bios->version.chip) { + case 0x30: + case 0x35: + info->vco2.max_n = 0x1f; + break; + default: + info->vco2.max_n = 0x28; + break; + } + info->vco2.min_m = 0x1; + info->vco2.max_m = 0x4; + break; + case 0x20: + case 0x21: + info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000; + info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000; + info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000; + info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000; + info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000; + info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000; + info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000; + info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000; + info->vco1.min_n = nv_ro08(bios, data + 20); + info->vco1.max_n = nv_ro08(bios, data + 21); + info->vco1.min_m = nv_ro08(bios, data + 22); + info->vco1.max_m = nv_ro08(bios, data + 23); + info->vco2.min_n = nv_ro08(bios, data + 24); + info->vco2.max_n = nv_ro08(bios, data + 25); + info->vco2.min_m = nv_ro08(bios, data + 26); + info->vco2.max_m = nv_ro08(bios, data + 27); + + info->max_p = nv_ro08(bios, data + 29); + info->max_p_usable = info->max_p; + if (bios->version.chip < 0x60) + info->max_p_usable = 0x6; + info->bias_p = nv_ro08(bios, data + 30); + + if (len > 0x22) + info->refclk = nv_ro32(bios, data + 31); + break; + case 0x30: + data = nv_ro16(bios, data + 1); + + info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; + info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; + info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000; + info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000; + info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000; + info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000; + info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000; + info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000; + info->vco1.min_n = nv_ro08(bios, data + 16); + info->vco1.max_n = nv_ro08(bios, data + 17); + info->vco1.min_m = nv_ro08(bios, data + 18); + info->vco1.max_m = nv_ro08(bios, data + 19); + info->vco2.min_n = nv_ro08(bios, data + 20); + info->vco2.max_n = nv_ro08(bios, data + 21); + info->vco2.min_m = nv_ro08(bios, data + 22); + info->vco2.max_m = nv_ro08(bios, data + 23); + info->max_p_usable = info->max_p = nv_ro08(bios, data + 25); + info->bias_p = nv_ro08(bios, data + 27); + info->refclk = nv_ro32(bios, data + 28); + break; + case 0x40: + info->refclk = nv_ro16(bios, data + 9) * 1000; + data = nv_ro16(bios, data + 1); + + info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; + info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; + info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000; + info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000; + info->vco1.min_m = nv_ro08(bios, data + 8); + info->vco1.max_m = nv_ro08(bios, data + 9); + info->vco1.min_n = nv_ro08(bios, data + 10); + info->vco1.max_n = nv_ro08(bios, data + 11); + info->min_p = nv_ro08(bios, data + 12); + info->max_p = nv_ro08(bios, data + 13); + break; + default: + nv_error(bios, "unknown pll limits version 0x%02x\n", ver); + return -EINVAL; + } + + if (!info->refclk) { + info->refclk = nv_device(bios)->crystal; + if (bios->version.chip == 0x51) { + u32 sel_clk = nv_rd32(bios, 0x680524); + if ((info->reg == 0x680508 && sel_clk & 0x20) || + (info->reg == 0x680520 && sel_clk & 0x80)) { + if (nv_rdvgac(bios, 0, 0x27) < 0xa3) + info->refclk = 200000; + else + info->refclk = 25000; + } + } + } + + /* + * By now any valid limit table ought to have set a max frequency for + * vco1, so if it's zero it's either a pre limit table bios, or one + * with an empty limit table (seen on nv18) + */ + if (!info->vco1.max_freq) { + info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67); + info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71); + if (bmp_version(bios) < 0x0506) { + info->vco1.max_freq = 256000; + info->vco1.min_freq = 128000; + } + + info->vco1.min_inputfreq = 0; + info->vco1.max_inputfreq = INT_MAX; + info->vco1.min_n = 0x1; + info->vco1.max_n = 0xff; + info->vco1.min_m = 0x1; + + if (nv_device(bios)->crystal == 13500) { + /* nv05 does this, nv11 doesn't, nv10 unknown */ + if (bios->version.chip < 0x11) + info->vco1.min_m = 0x7; + info->vco1.max_m = 0xd; + } else { + if (bios->version.chip < 0x11) + info->vco1.min_m = 0x8; + info->vco1.max_m = 0xe; + } + + if (bios->version.chip < 0x17 || + bios->version.chip == 0x1a || + bios->version.chip == 0x20) + info->max_p = 4; + else + info->max_p = 5; + info->max_p_usable = info->max_p; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c new file mode 100644 index 00000000000..862a08a2ae2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c @@ -0,0 +1,177 @@ +/* + * Copyright 2012 Nouveau Community + * + * 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: Martin Peres + */ + +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/therm.h> + +static u16 +therm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) +{ + struct bit_entry bit_P; + u16 therm = 0; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 1) + therm = nv_ro16(bios, bit_P.offset + 12); + else if (bit_P.version == 2) + therm = nv_ro16(bios, bit_P.offset + 16); + else + nv_error(bios, + "unknown offset for thermal in BIT P %d\n", + bit_P.version); + } + + /* exit now if we haven't found the thermal table */ + if (!therm) + return 0x0000; + + *ver = nv_ro08(bios, therm + 0); + *hdr = nv_ro08(bios, therm + 1); + *len = nv_ro08(bios, therm + 2); + *cnt = nv_ro08(bios, therm + 3); + + return therm + nv_ro08(bios, therm + 1); +} + +u16 +nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 therm = therm_table(bios, ver, &hdr, len, &cnt); + if (therm && idx < cnt) + return therm + idx * *len; + return 0x0000; +} + +int +nvbios_therm_sensor_parse(struct nouveau_bios *bios, + enum nvbios_therm_domain domain, + struct nvbios_therm_sensor *sensor) +{ + s8 thrs_section, sensor_section, offset; + u8 ver, len, i; + u16 entry; + + /* we only support the core domain for now */ + if (domain != NVBIOS_THERM_DOMAIN_CORE) + return -EINVAL; + + /* Read the entries from the table */ + thrs_section = 0; + sensor_section = -1; + i = 0; + while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { + s16 value = nv_ro16(bios, entry + 1); + + switch (nv_ro08(bios, entry + 0)) { + case 0x0: + thrs_section = value; + if (value > 0) + return 0; /* we do not try to support ambient */ + break; + case 0x01: + sensor_section++; + if (sensor_section == 0) { + offset = ((s8) nv_ro08(bios, entry + 2)) / 2; + sensor->offset_constant = offset; + } + break; + + case 0x04: + if (thrs_section == 0) { + sensor->thrs_critical.temp = (value & 0xff0) >> 4; + sensor->thrs_critical.hysteresis = value & 0xf; + } + break; + + case 0x07: + if (thrs_section == 0) { + sensor->thrs_down_clock.temp = (value & 0xff0) >> 4; + sensor->thrs_down_clock.hysteresis = value & 0xf; + } + break; + + case 0x08: + if (thrs_section == 0) { + sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4; + sensor->thrs_fan_boost.hysteresis = value & 0xf; + } + break; + + case 0x10: + if (sensor_section == 0) + sensor->offset_num = value; + break; + + case 0x11: + if (sensor_section == 0) + sensor->offset_den = value; + break; + + case 0x12: + if (sensor_section == 0) + sensor->slope_mult = value; + break; + + case 0x13: + if (sensor_section == 0) + sensor->slope_div = value; + break; + case 0x32: + if (thrs_section == 0) { + sensor->thrs_shutdown.temp = (value & 0xff0) >> 4; + sensor->thrs_shutdown.hysteresis = value & 0xf; + } + break; + } + } + + return 0; +} + +int +nvbios_therm_fan_parse(struct nouveau_bios *bios, + struct nvbios_therm_fan *fan) +{ + u8 ver, len, i; + u16 entry; + + i = 0; + while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { + s16 value = nv_ro16(bios, entry + 1); + + switch (nv_ro08(bios, entry + 0)) { + case 0x22: + fan->min_duty = value & 0xff; + fan->max_duty = (value & 0xff00) >> 8; + break; + case 0x26: + fan->pwm_freq = value; + break; + } + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c new file mode 100644 index 00000000000..b7fd1151166 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c @@ -0,0 +1,359 @@ +/* + * 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/clock.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" + +struct nv04_clock_priv { + struct nouveau_clock base; +}; + +static int +powerctrl_1_shift(int chip_version, int reg) +{ + int shift = -4; + + if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20) + return shift; + + switch (reg) { + case 0x680520: + shift += 4; + case 0x680508: + shift += 4; + case 0x680504: + shift += 4; + case 0x680500: + shift += 4; + } + + /* + * the shift for vpll regs is only used for nv3x chips with a single + * stage pll + */ + if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 || + chip_version == 0x36 || chip_version >= 0x40)) + shift = -4; + + return shift; +} + +static void +setPLL_single(struct nv04_clock_priv *priv, u32 reg, + struct nouveau_pll_vals *pv) +{ + int chip_version = nouveau_bios(priv)->version.chip; + uint32_t oldpll = nv_rd32(priv, reg); + int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff; + uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1; + uint32_t saved_powerctrl_1 = 0; + int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg); + + if (oldpll == pll) + return; /* already set */ + + if (shift_powerctrl_1 >= 0) { + saved_powerctrl_1 = nv_rd32(priv, 0x001584); + nv_wr32(priv, 0x001584, + (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | + 1 << shift_powerctrl_1); + } + + if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1)) + /* upclock -- write new post divider first */ + nv_wr32(priv, reg, pv->log2P << 16 | (oldpll & 0xffff)); + else + /* downclock -- write new NM first */ + nv_wr32(priv, reg, (oldpll & 0xffff0000) | pv->NM1); + + if (chip_version < 0x17 && chip_version != 0x11) + /* wait a bit on older chips */ + msleep(64); + nv_rd32(priv, reg); + + /* then write the other half as well */ + nv_wr32(priv, reg, pll); + + if (shift_powerctrl_1 >= 0) + nv_wr32(priv, 0x001584, saved_powerctrl_1); +} + +static uint32_t +new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580) +{ + bool head_a = (reg1 == 0x680508); + + if (ss) /* single stage pll mode */ + ramdac580 |= head_a ? 0x00000100 : 0x10000000; + else + ramdac580 &= head_a ? 0xfffffeff : 0xefffffff; + + return ramdac580; +} + +static void +setPLL_double_highregs(struct nv04_clock_priv *priv, u32 reg1, + struct nouveau_pll_vals *pv) +{ + int chip_version = nouveau_bios(priv)->version.chip; + bool nv3035 = chip_version == 0x30 || chip_version == 0x35; + uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70); + uint32_t oldpll1 = nv_rd32(priv, reg1); + uint32_t oldpll2 = !nv3035 ? nv_rd32(priv, reg2) : 0; + uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1; + uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2; + uint32_t oldramdac580 = 0, ramdac580 = 0; + bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */ + uint32_t saved_powerctrl_1 = 0, savedc040 = 0; + int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1); + + /* model specific additions to generic pll1 and pll2 set up above */ + if (nv3035) { + pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 | + (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4; + pll2 = 0; + } + if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */ + oldramdac580 = nv_rd32(priv, 0x680580); + ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580); + if (oldramdac580 != ramdac580) + oldpll1 = ~0; /* force mismatch */ + if (single_stage) + /* magic value used by nvidia in single stage mode */ + pll2 |= 0x011f; + } + if (chip_version > 0x70) + /* magic bits set by the blob (but not the bios) on g71-73 */ + pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28; + + if (oldpll1 == pll1 && oldpll2 == pll2) + return; /* already set */ + + if (shift_powerctrl_1 >= 0) { + saved_powerctrl_1 = nv_rd32(priv, 0x001584); + nv_wr32(priv, 0x001584, + (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | + 1 << shift_powerctrl_1); + } + + if (chip_version >= 0x40) { + int shift_c040 = 14; + + switch (reg1) { + case 0x680504: + shift_c040 += 2; + case 0x680500: + shift_c040 += 2; + case 0x680520: + shift_c040 += 2; + case 0x680508: + shift_c040 += 2; + } + + savedc040 = nv_rd32(priv, 0xc040); + if (shift_c040 != 14) + nv_wr32(priv, 0xc040, savedc040 & ~(3 << shift_c040)); + } + + if (oldramdac580 != ramdac580) + nv_wr32(priv, 0x680580, ramdac580); + + if (!nv3035) + nv_wr32(priv, reg2, pll2); + nv_wr32(priv, reg1, pll1); + + if (shift_powerctrl_1 >= 0) + nv_wr32(priv, 0x001584, saved_powerctrl_1); + if (chip_version >= 0x40) + nv_wr32(priv, 0xc040, savedc040); +} + +static void +setPLL_double_lowregs(struct nv04_clock_priv *priv, u32 NMNMreg, + struct nouveau_pll_vals *pv) +{ + /* When setting PLLs, there is a merry game of disabling and enabling + * various bits of hardware during the process. This function is a + * synthesis of six nv4x traces, nearly each card doing a subtly + * different thing. With luck all the necessary bits for each card are + * combined herein. Without luck it deviates from each card's formula + * so as to not work on any :) + */ + + uint32_t Preg = NMNMreg - 4; + bool mpll = Preg == 0x4020; + uint32_t oldPval = nv_rd32(priv, Preg); + uint32_t NMNM = pv->NM2 << 16 | pv->NM1; + uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) | + 0xc << 28 | pv->log2P << 16; + uint32_t saved4600 = 0; + /* some cards have different maskc040s */ + uint32_t maskc040 = ~(3 << 14), savedc040; + bool single_stage = !pv->NM2 || pv->N2 == pv->M2; + + if (nv_rd32(priv, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) + return; + + if (Preg == 0x4000) + maskc040 = ~0x333; + if (Preg == 0x4058) + maskc040 = ~(0xc << 24); + + if (mpll) { + struct nvbios_pll info; + uint8_t Pval2; + + if (nvbios_pll_parse(nouveau_bios(priv), Preg, &info)) + return; + + Pval2 = pv->log2P + info.bias_p; + if (Pval2 > info.max_p) + Pval2 = info.max_p; + Pval |= 1 << 28 | Pval2 << 20; + + saved4600 = nv_rd32(priv, 0x4600); + nv_wr32(priv, 0x4600, saved4600 | 8 << 28); + } + if (single_stage) + Pval |= mpll ? 1 << 12 : 1 << 8; + + nv_wr32(priv, Preg, oldPval | 1 << 28); + nv_wr32(priv, Preg, Pval & ~(4 << 28)); + if (mpll) { + Pval |= 8 << 20; + nv_wr32(priv, 0x4020, Pval & ~(0xc << 28)); + nv_wr32(priv, 0x4038, Pval & ~(0xc << 28)); + } + + savedc040 = nv_rd32(priv, 0xc040); + nv_wr32(priv, 0xc040, savedc040 & maskc040); + + nv_wr32(priv, NMNMreg, NMNM); + if (NMNMreg == 0x4024) + nv_wr32(priv, 0x403c, NMNM); + + nv_wr32(priv, Preg, Pval); + if (mpll) { + Pval &= ~(8 << 20); + nv_wr32(priv, 0x4020, Pval); + nv_wr32(priv, 0x4038, Pval); + nv_wr32(priv, 0x4600, saved4600); + } + + nv_wr32(priv, 0xc040, savedc040); + + if (mpll) { + nv_wr32(priv, 0x4020, Pval & ~(1 << 28)); + nv_wr32(priv, 0x4038, Pval & ~(1 << 28)); + } +} + +int +nv04_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) +{ + struct nv04_clock_priv *priv = (void *)clk; + struct nouveau_pll_vals pv; + struct nvbios_pll info; + int ret; + + ret = nvbios_pll_parse(nouveau_bios(priv), type > 0x405c ? + type : type - 4, &info); + if (ret) + return ret; + + ret = clk->pll_calc(clk, &info, freq, &pv); + if (!ret) + return ret; + + return clk->pll_prog(clk, type, &pv); +} + +int +nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, + int clk, struct nouveau_pll_vals *pv) +{ + int N1, M1, N2, M2, P; + int ret = nv04_pll_calc(clock, info, clk, &N1, &M1, &N2, &M2, &P); + if (ret) { + pv->refclk = info->refclk; + pv->N1 = N1; + pv->M1 = M1; + pv->N2 = N2; + pv->M2 = M2; + pv->log2P = P; + } + return ret; +} + +int +nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1, + struct nouveau_pll_vals *pv) +{ + struct nv04_clock_priv *priv = (void *)clk; + int cv = nouveau_bios(clk)->version.chip; + + if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || + cv >= 0x40) { + if (reg1 > 0x405c) + setPLL_double_highregs(priv, reg1, pv); + else + setPLL_double_lowregs(priv, reg1, pv); + } else + setPLL_single(priv, reg1, pv); + + return 0; +} + +static int +nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_clock_priv *priv; + int ret; + + ret = nouveau_clock_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.pll_set = nv04_clock_pll_set; + priv->base.pll_calc = nv04_clock_pll_calc; + priv->base.pll_prog = nv04_clock_pll_prog; + return 0; +} + +struct nouveau_oclass +nv04_clock_oclass = { + .handle = NV_SUBDEV(CLOCK, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c new file mode 100644 index 00000000000..a4b2b7ebf9a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c @@ -0,0 +1,59 @@ +/* + * 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/clock.h> + +struct nv40_clock_priv { + struct nouveau_clock base; +}; + +static int +nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv40_clock_priv *priv; + int ret; + + ret = nouveau_clock_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.pll_set = nv04_clock_pll_set; + priv->base.pll_calc = nv04_clock_pll_calc; + priv->base.pll_prog = nv04_clock_pll_prog; + return 0; +} + +struct nouveau_oclass +nv40_clock_oclass = { + .handle = NV_SUBDEV(CLOCK, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c new file mode 100644 index 00000000000..fd181fbcedd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c @@ -0,0 +1,105 @@ +/* + * 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/clock.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" + +struct nv50_clock_priv { + struct nouveau_clock base; +}; + +static int +nv50_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) +{ + struct nv50_clock_priv *priv = (void *)clk; + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll info; + int N1, M1, N2, M2, P; + int ret; + + ret = nvbios_pll_parse(bios, type, &info); + if (ret) { + nv_error(clk, "failed to retrieve pll data, %d\n", ret); + return ret; + } + + ret = nv04_pll_calc(clk, &info, freq, &N1, &M1, &N2, &M2, &P); + if (!ret) { + nv_error(clk, "failed pll calculation\n"); + return ret; + } + + switch (info.type) { + case PLL_VPLL0: + case PLL_VPLL1: + nv_wr32(priv, info.reg + 0, 0x10000611); + nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); + nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) | + (M2 << 16) | N2); + break; + case PLL_MEMORY: + nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) | + (info.bias_p << 19) | + (P << 16)); + nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); + break; + default: + nv_mask(priv, info.reg + 0, 0x00070000, (P << 16)); + nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); + break; + } + + return 0; +} + +static int +nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_clock_priv *priv; + int ret; + + ret = nouveau_clock_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.pll_set = nv50_clock_pll_set; + return 0; +} + +struct nouveau_oclass +nv50_clock_oclass = { + .handle = NV_SUBDEV(CLOCK, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c new file mode 100644 index 00000000000..cc8d7d162d7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -0,0 +1,95 @@ +/* + * 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/clock.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" + +struct nva3_clock_priv { + struct nouveau_clock base; +}; + +static int +nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) +{ + struct nva3_clock_priv *priv = (void *)clk; + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll info; + int N, fN, M, P; + int ret; + + ret = nvbios_pll_parse(bios, type, &info); + if (ret) + return ret; + + ret = nva3_pll_calc(clk, &info, freq, &N, &fN, &M, &P); + if (ret < 0) + return ret; + + switch (info.type) { + case PLL_VPLL0: + case PLL_VPLL1: + nv_wr32(priv, info.reg + 0, 0x50000610); + nv_mask(priv, info.reg + 4, 0x003fffff, + (P << 16) | (M << 8) | N); + nv_wr32(priv, info.reg + 8, fN); + break; + default: + nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); + ret = -EINVAL; + break; + } + + return ret; +} + +static int +nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nva3_clock_priv *priv; + int ret; + + ret = nouveau_clock_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.pll_set = nva3_clock_pll_set; + return 0; +} + +struct nouveau_oclass +nva3_clock_oclass = { + .handle = NV_SUBDEV(CLOCK, 0xa3), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nva3_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c new file mode 100644 index 00000000000..5ccce0b17bf --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -0,0 +1,94 @@ +/* + * 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/clock.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" + +struct nvc0_clock_priv { + struct nouveau_clock base; +}; + +static int +nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) +{ + struct nvc0_clock_priv *priv = (void *)clk; + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll info; + int N, fN, M, P; + int ret; + + ret = nvbios_pll_parse(bios, type, &info); + if (ret) + return ret; + + ret = nva3_pll_calc(clk, &info, freq, &N, &fN, &M, &P); + if (ret < 0) + return ret; + + switch (info.type) { + case PLL_VPLL0: + case PLL_VPLL1: + nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); + nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); + nv_wr32(priv, info.reg + 0x10, fN << 16); + break; + default: + nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); + ret = -EINVAL; + break; + } + + return ret; +} + +static int +nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_clock_priv *priv; + int ret; + + ret = nouveau_clock_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.pll_set = nvc0_clock_pll_set; + return 0; +} + +struct nouveau_oclass +nvc0_clock_oclass = { + .handle = NV_SUBDEV(CLOCK, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h new file mode 100644 index 00000000000..ef2c0078f33 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h @@ -0,0 +1,9 @@ +#ifndef __NOUVEAU_PLL_H__ +#define __NOUVEAU_PLL_H__ + +int nv04_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq, + int *N1, int *M1, int *N2, int *M2, int *P); +int nva3_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq, + int *N, int *fN, int *M, int *P); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c new file mode 100644 index 00000000000..a2ab6d051ba --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c @@ -0,0 +1,242 @@ +/* + * Copyright 1993-2003 NVIDIA, Corporation + * Copyright 2007-2009 Stuart Bennett + * + * 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 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <subdev/clock.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" + +static int +getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, + int *pN, int *pM, int *pP) +{ + /* Find M, N and P for a single stage PLL + * + * Note that some bioses (NV3x) have lookup tables of precomputed MNP + * values, but we're too lazy to use those atm + * + * "clk" parameter in kHz + * returns calculated clock + */ + int cv = nouveau_bios(clock)->version.chip; + int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq; + int minM = info->vco1.min_m, maxM = info->vco1.max_m; + int minN = info->vco1.min_n, maxN = info->vco1.max_n; + int minU = info->vco1.min_inputfreq; + int maxU = info->vco1.max_inputfreq; + int minP = info->min_p; + int maxP = info->max_p_usable; + int crystal = info->refclk; + int M, N, thisP, P; + int clkP, calcclk; + int delta, bestdelta = INT_MAX; + int bestclk = 0; + + /* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */ + /* possibly correlated with introduction of 27MHz crystal */ + if (cv < 0x17 || cv == 0x1a || cv == 0x20) { + if (clk > 250000) + maxM = 6; + if (clk > 340000) + maxM = 2; + } else if (cv < 0x40) { + if (clk > 150000) + maxM = 6; + if (clk > 200000) + maxM = 4; + if (clk > 340000) + maxM = 2; + } + + P = 1 << maxP; + if ((clk * P) < minvco) { + minvco = clk * maxP; + maxvco = minvco * 2; + } + + if (clk + clk/200 > maxvco) /* +0.5% */ + maxvco = clk + clk/200; + + /* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */ + for (thisP = minP; thisP <= maxP; thisP++) { + P = 1 << thisP; + clkP = clk * P; + + if (clkP < minvco) + continue; + if (clkP > maxvco) + return bestclk; + + for (M = minM; M <= maxM; M++) { + if (crystal/M < minU) + return bestclk; + if (crystal/M > maxU) + continue; + + /* add crystal/2 to round better */ + N = (clkP * M + crystal/2) / crystal; + + if (N < minN) + continue; + if (N > maxN) + break; + + /* more rounding additions */ + calcclk = ((N * crystal + P/2) / P + M/2) / M; + delta = abs(calcclk - clk); + /* we do an exhaustive search rather than terminating + * on an optimality condition... + */ + if (delta < bestdelta) { + bestdelta = delta; + bestclk = calcclk; + *pN = N; + *pM = M; + *pP = thisP; + if (delta == 0) /* except this one */ + return bestclk; + } + } + } + + return bestclk; +} + +static int +getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, + int *pN1, int *pM1, int *pN2, int *pM2, int *pP) +{ + /* Find M, N and P for a two stage PLL + * + * Note that some bioses (NV30+) have lookup tables of precomputed MNP + * values, but we're too lazy to use those atm + * + * "clk" parameter in kHz + * returns calculated clock + */ + int chip_version = nouveau_bios(clock)->version.chip; + int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq; + int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq; + int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq; + int maxU1 = info->vco1.max_inputfreq, maxU2 = info->vco2.max_inputfreq; + int minM1 = info->vco1.min_m, maxM1 = info->vco1.max_m; + int minN1 = info->vco1.min_n, maxN1 = info->vco1.max_n; + int minM2 = info->vco2.min_m, maxM2 = info->vco2.max_m; + int minN2 = info->vco2.min_n, maxN2 = info->vco2.max_n; + int maxlog2P = info->max_p_usable; + int crystal = info->refclk; + bool fixedgain2 = (minM2 == maxM2 && minN2 == maxN2); + int M1, N1, M2, N2, log2P; + int clkP, calcclk1, calcclk2, calcclkout; + int delta, bestdelta = INT_MAX; + int bestclk = 0; + + int vco2 = (maxvco2 - maxvco2/200) / 2; + for (log2P = 0; clk && log2P < maxlog2P && clk <= (vco2 >> log2P); log2P++) + ; + clkP = clk << log2P; + + if (maxvco2 < clk + clk/200) /* +0.5% */ + maxvco2 = clk + clk/200; + + for (M1 = minM1; M1 <= maxM1; M1++) { + if (crystal/M1 < minU1) + return bestclk; + if (crystal/M1 > maxU1) + continue; + + for (N1 = minN1; N1 <= maxN1; N1++) { + calcclk1 = crystal * N1 / M1; + if (calcclk1 < minvco1) + continue; + if (calcclk1 > maxvco1) + break; + + for (M2 = minM2; M2 <= maxM2; M2++) { + if (calcclk1/M2 < minU2) + break; + if (calcclk1/M2 > maxU2) + continue; + + /* add calcclk1/2 to round better */ + N2 = (clkP * M2 + calcclk1/2) / calcclk1; + if (N2 < minN2) + continue; + if (N2 > maxN2) + break; + + if (!fixedgain2) { + if (chip_version < 0x60) + if (N2/M2 < 4 || N2/M2 > 10) + continue; + + calcclk2 = calcclk1 * N2 / M2; + if (calcclk2 < minvco2) + break; + if (calcclk2 > maxvco2) + continue; + } else + calcclk2 = calcclk1; + + calcclkout = calcclk2 >> log2P; + delta = abs(calcclkout - clk); + /* we do an exhaustive search rather than terminating + * on an optimality condition... + */ + if (delta < bestdelta) { + bestdelta = delta; + bestclk = calcclkout; + *pN1 = N1; + *pM1 = M1; + *pN2 = N2; + *pM2 = M2; + *pP = log2P; + if (delta == 0) /* except this one */ + return bestclk; + } + } + } + } + + return bestclk; +} + +int +nv04_pll_calc(struct nouveau_clock *clk, struct nvbios_pll *info, u32 freq, + int *N1, int *M1, int *N2, int *M2, int *P) +{ + int ret; + + if (!info->vco2.max_freq) { + ret = getMNP_single(clk, info, freq, N1, M1, P); + *N2 = 1; + *M2 = 1; + } else { + ret = getMNP_double(clk, info, freq, N1, M1, N2, M2, P); + } + + if (!ret) + nv_error(clk, "unable to compute acceptable pll values\n"); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c new file mode 100644 index 00000000000..eed5c16cf61 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c @@ -0,0 +1,80 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/clock.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" + +int +nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, + u32 freq, int *pN, int *pfN, int *pM, int *P) +{ + u32 best_err = ~0, err; + int M, lM, hM, N, fN; + + *P = info->vco1.max_freq / freq; + if (*P > info->max_p) + *P = info->max_p; + if (*P < info->min_p) + *P = info->min_p; + + lM = (info->refclk + info->vco1.max_inputfreq) / info->vco1.max_inputfreq; + lM = max(lM, (int)info->vco1.min_m); + hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq; + hM = min(hM, (int)info->vco1.max_m); + + for (M = lM; M <= hM; M++) { + u32 tmp = freq * *P * M; + N = tmp / info->refclk; + fN = tmp % info->refclk; + if (!pfN && fN >= info->refclk / 2) + N++; + + if (N < info->vco1.min_n) + continue; + if (N > info->vco1.max_n) + break; + + err = abs(freq - (info->refclk * N / M / *P)); + if (err < best_err) { + best_err = err; + *pN = N; + *pM = M; + } + + if (pfN) { + *pfN = (((fN << 13) / info->refclk) - 4096) & 0xffff; + return freq; + } + } + + if (unlikely(best_err == ~0)) { + nv_error(clock, "unable to find matching pll values\n"); + return -EINVAL; + } + + return info->refclk * *pN / *pM / *P; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/base.c b/drivers/gpu/drm/nouveau/core/subdev/device/base.c new file mode 100644 index 00000000000..ca9a4648bd8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/base.c @@ -0,0 +1,472 @@ +/* + * 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/device.h> +#include <core/client.h> +#include <core/device.h> +#include <core/option.h> + +#include <core/class.h> + +#include <subdev/device.h> + +static DEFINE_MUTEX(nv_devices_mutex); +static LIST_HEAD(nv_devices); + +struct nouveau_device * +nouveau_device_find(u64 name) +{ + struct nouveau_device *device, *match = NULL; + mutex_lock(&nv_devices_mutex); + list_for_each_entry(device, &nv_devices, head) { + if (device->handle == name) { + match = device; + break; + } + } + mutex_unlock(&nv_devices_mutex); + return match; +} + +/****************************************************************************** + * nouveau_devobj (0x0080): class implementation + *****************************************************************************/ +struct nouveau_devobj { + struct nouveau_parent base; + struct nouveau_object *subdev[NVDEV_SUBDEV_NR]; + bool created; +}; + +static const u64 disable_map[] = { + [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_DISABLE_VBIOS, + [NVDEV_SUBDEV_GPIO] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_I2C] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_VM] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE, + [NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE, + [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE, + [NVDEV_ENGINE_GR] = NV_DEVICE_DISABLE_GRAPH, + [NVDEV_ENGINE_MPEG] = NV_DEVICE_DISABLE_MPEG, + [NVDEV_ENGINE_ME] = NV_DEVICE_DISABLE_ME, + [NVDEV_ENGINE_VP] = NV_DEVICE_DISABLE_VP, + [NVDEV_ENGINE_CRYPT] = NV_DEVICE_DISABLE_CRYPT, + [NVDEV_ENGINE_BSP] = NV_DEVICE_DISABLE_BSP, + [NVDEV_ENGINE_PPP] = NV_DEVICE_DISABLE_PPP, + [NVDEV_ENGINE_COPY0] = NV_DEVICE_DISABLE_COPY0, + [NVDEV_ENGINE_COPY1] = NV_DEVICE_DISABLE_COPY1, + [NVDEV_ENGINE_UNK1C1] = NV_DEVICE_DISABLE_UNK1C1, + [NVDEV_ENGINE_FIFO] = NV_DEVICE_DISABLE_FIFO, + [NVDEV_ENGINE_DISP] = NV_DEVICE_DISABLE_DISP, + [NVDEV_SUBDEV_NR] = 0, +}; + +static int +nouveau_devobj_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_client *client = nv_client(parent); + struct nouveau_device *device; + struct nouveau_devobj *devobj; + struct nv_device_class *args = data; + u64 disable, boot0, strap; + u64 mmio_base, mmio_size; + void __iomem *map; + int ret, i, c; + + if (size < sizeof(struct nv_device_class)) + return -EINVAL; + + /* find the device subdev that matches what the client requested */ + device = nv_device(client->device); + if (args->device != ~0) { + device = nouveau_device_find(args->device); + if (!device) + return -ENODEV; + } + + ret = nouveau_parent_create(parent, nv_object(device), oclass, 0, NULL, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_FIFO) | + (1ULL << NVDEV_ENGINE_DISP), &devobj); + *pobject = nv_object(devobj); + if (ret) + return ret; + + mmio_base = pci_resource_start(device->pdev, 0); + mmio_size = pci_resource_len(device->pdev, 0); + + /* translate api disable mask into internal mapping */ + disable = args->debug0; + for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + if (args->disable & disable_map[i]) + disable |= (1ULL << i); + } + + /* identify the chipset, and determine classes of subdev/engines */ + if (!(args->disable & NV_DEVICE_DISABLE_IDENTIFY) && + !device->card_type) { + map = ioremap(mmio_base, 0x102000); + if (map == NULL) + return -ENOMEM; + + /* switch mmio to cpu's native endianness */ +#ifndef __BIG_ENDIAN + if (ioread32_native(map + 0x000004) != 0x00000000) +#else + if (ioread32_native(map + 0x000004) == 0x00000000) +#endif + iowrite32_native(0x01000001, map + 0x000004); + + /* read boot0 and strapping information */ + boot0 = ioread32_native(map + 0x000000); + strap = ioread32_native(map + 0x101000); + iounmap(map); + + /* determine chipset and derive architecture from it */ + if ((boot0 & 0x0f000000) > 0) { + device->chipset = (boot0 & 0xff00000) >> 20; + switch (device->chipset & 0xf0) { + case 0x10: device->card_type = NV_10; break; + case 0x20: device->card_type = NV_20; break; + case 0x30: device->card_type = NV_30; break; + case 0x40: + case 0x60: device->card_type = NV_40; break; + case 0x50: + case 0x80: + case 0x90: + case 0xa0: device->card_type = NV_50; break; + case 0xc0: device->card_type = NV_C0; break; + case 0xd0: device->card_type = NV_D0; break; + case 0xe0: device->card_type = NV_E0; break; + default: + break; + } + } else + if ((boot0 & 0xff00fff0) == 0x20004000) { + if (boot0 & 0x00f00000) + device->chipset = 0x05; + else + device->chipset = 0x04; + device->card_type = NV_04; + } + + switch (device->card_type) { + case NV_04: ret = nv04_identify(device); break; + case NV_10: ret = nv10_identify(device); break; + case NV_20: ret = nv20_identify(device); break; + case NV_30: ret = nv30_identify(device); break; + case NV_40: ret = nv40_identify(device); break; + case NV_50: ret = nv50_identify(device); break; + case NV_C0: + case NV_D0: ret = nvc0_identify(device); break; + case NV_E0: ret = nve0_identify(device); break; + default: + ret = -EINVAL; + break; + } + + if (ret) { + nv_error(device, "unknown chipset, 0x%08x\n", boot0); + return ret; + } + + nv_info(device, "BOOT0 : 0x%08x\n", boot0); + nv_info(device, "Chipset: %s (NV%02X)\n", + device->cname, device->chipset); + nv_info(device, "Family : NV%02X\n", device->card_type); + + /* determine frequency of timing crystal */ + if ( device->chipset < 0x17 || + (device->chipset >= 0x20 && device->chipset <= 0x25)) + strap &= 0x00000040; + else + strap &= 0x00400040; + + switch (strap) { + case 0x00000000: device->crystal = 13500; break; + case 0x00000040: device->crystal = 14318; break; + case 0x00400000: device->crystal = 27000; break; + case 0x00400040: device->crystal = 25000; break; + } + + nv_debug(device, "crystal freq: %dKHz\n", device->crystal); + } + + if (!(args->disable & NV_DEVICE_DISABLE_MMIO) && + !nv_subdev(device)->mmio) { + nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size); + if (!nv_subdev(device)->mmio) { + nv_error(device, "unable to map device registers\n"); + return -ENOMEM; + } + } + + /* ensure requested subsystems are available for use */ + for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) { + if (!(oclass = device->oclass[i]) || (disable & (1ULL << i))) + continue; + + if (!device->subdev[i]) { + ret = nouveau_object_ctor(nv_object(device), NULL, + oclass, NULL, i, + &devobj->subdev[i]); + if (ret == -ENODEV) + continue; + if (ret) + return ret; + + if (nv_iclass(devobj->subdev[i], NV_ENGINE_CLASS)) + nouveau_subdev_reset(devobj->subdev[i]); + } else { + nouveau_object_ref(device->subdev[i], + &devobj->subdev[i]); + } + + /* note: can't init *any* subdevs until devinit has been run + * due to not knowing exactly what the vbios init tables will + * mess with. devinit also can't be run until all of its + * dependencies have been created. + * + * this code delays init of any subdev until all of devinit's + * dependencies have been created, and then initialises each + * subdev in turn as they're created. + */ + while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) { + struct nouveau_object *subdev = devobj->subdev[c++]; + if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) { + ret = nouveau_object_inc(subdev); + if (ret) + return ret; + } + } + } + + return 0; +} + +static void +nouveau_devobj_dtor(struct nouveau_object *object) +{ + struct nouveau_devobj *devobj = (void *)object; + int i; + + for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) + nouveau_object_ref(NULL, &devobj->subdev[i]); + + nouveau_parent_destroy(&devobj->base); +} + +static int +nouveau_devobj_init(struct nouveau_object *object) +{ + struct nouveau_devobj *devobj = (void *)object; + struct nouveau_object *subdev; + int ret, i; + + ret = nouveau_parent_init(&devobj->base); + if (ret) + return ret; + + for (i = 0; devobj->created && i < NVDEV_SUBDEV_NR; i++) { + if ((subdev = devobj->subdev[i])) { + if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { + ret = nouveau_object_inc(subdev); + if (ret) + goto fail; + } + } + } + + devobj->created = true; + return 0; + +fail: + for (--i; i >= 0; i--) { + if ((subdev = devobj->subdev[i])) { + if (!nv_iclass(subdev, NV_ENGINE_CLASS)) + nouveau_object_dec(subdev, false); + } + } + + return ret; +} + +static int +nouveau_devobj_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_devobj *devobj = (void *)object; + struct nouveau_object *subdev; + int ret, i; + + for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { + if ((subdev = devobj->subdev[i])) { + if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { + ret = nouveau_object_dec(subdev, suspend); + if (ret && suspend) + goto fail; + } + } + } + + ret = nouveau_parent_fini(&devobj->base, suspend); +fail: + for (; ret && suspend && i < NVDEV_SUBDEV_NR; i++) { + if ((subdev = devobj->subdev[i])) { + if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { + ret = nouveau_object_inc(subdev); + if (ret) { + /* XXX */ + } + } + } + } + + return ret; +} + +static u8 +nouveau_devobj_rd08(struct nouveau_object *object, u32 addr) +{ + return nv_rd08(object->engine, addr); +} + +static u16 +nouveau_devobj_rd16(struct nouveau_object *object, u32 addr) +{ + return nv_rd16(object->engine, addr); +} + +static u32 +nouveau_devobj_rd32(struct nouveau_object *object, u32 addr) +{ + return nv_rd32(object->engine, addr); +} + +static void +nouveau_devobj_wr08(struct nouveau_object *object, u32 addr, u8 data) +{ + nv_wr08(object->engine, addr, data); +} + +static void +nouveau_devobj_wr16(struct nouveau_object *object, u32 addr, u16 data) +{ + nv_wr16(object->engine, addr, data); +} + +static void +nouveau_devobj_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + nv_wr32(object->engine, addr, data); +} + +static struct nouveau_ofuncs +nouveau_devobj_ofuncs = { + .ctor = nouveau_devobj_ctor, + .dtor = nouveau_devobj_dtor, + .init = nouveau_devobj_init, + .fini = nouveau_devobj_fini, + .rd08 = nouveau_devobj_rd08, + .rd16 = nouveau_devobj_rd16, + .rd32 = nouveau_devobj_rd32, + .wr08 = nouveau_devobj_wr08, + .wr16 = nouveau_devobj_wr16, + .wr32 = nouveau_devobj_wr32, +}; + +/****************************************************************************** + * nouveau_device: engine functions + *****************************************************************************/ +struct nouveau_oclass +nouveau_device_sclass[] = { + { 0x0080, &nouveau_devobj_ofuncs }, + {} +}; + +static void +nouveau_device_dtor(struct nouveau_object *object) +{ + struct nouveau_device *device = (void *)object; + + mutex_lock(&nv_devices_mutex); + list_del(&device->head); + mutex_unlock(&nv_devices_mutex); + + if (device->base.mmio) + iounmap(device->base.mmio); + + nouveau_subdev_destroy(&device->base); +} + +static struct nouveau_oclass +nouveau_device_oclass = { + .handle = NV_SUBDEV(DEVICE, 0x00), + .ofuncs = &(struct nouveau_ofuncs) { + .dtor = nouveau_device_dtor, + }, +}; + +int +nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname, + const char *cfg, const char *dbg, + int length, void **pobject) +{ + struct nouveau_device *device; + int ret = -EEXIST; + + mutex_lock(&nv_devices_mutex); + list_for_each_entry(device, &nv_devices, head) { + if (device->handle == name) + goto done; + } + + ret = nouveau_subdev_create_(NULL, NULL, &nouveau_device_oclass, 0, + "DEVICE", "device", length, pobject); + device = *pobject; + if (ret) + goto done; + + atomic_set(&nv_object(device)->usecount, 2); + device->pdev = pdev; + device->handle = name; + device->cfgopt = cfg; + device->dbgopt = dbg; + device->name = sname; + + nv_subdev(device)->debug = nouveau_dbgopt(device->dbgopt, "DEVICE"); + list_add(&device->head, &nv_devices); +done: + mutex_unlock(&nv_devices_mutex); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c new file mode 100644 index 00000000000..8626d0d6cbb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c @@ -0,0 +1,86 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/disp.h> + +int +nv04_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x04: + device->cname = "NV04"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv04_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv04_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x05: + device->cname = "NV05"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv04_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv04_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + default: + nv_fatal(device, "unknown RIVA chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c new file mode 100644 index 00000000000..f09accfd0e3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c @@ -0,0 +1,195 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/disp.h> + +int +nv10_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x10: + device->cname = "NV10"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x15: + device->cname = "NV15"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x16: + device->cname = "NV16"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x1a: + device->cname = "nForce"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x11: + device->cname = "NV11"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x17: + device->cname = "NV17"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x1f: + device->cname = "nForce2"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x18: + device->cname = "NV18"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + default: + nv_fatal(device, "unknown Celsius chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c new file mode 100644 index 00000000000..5fa58b7369b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c @@ -0,0 +1,126 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/disp.h> + +int +nv20_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x20: + device->cname = "NV20"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv20_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x25: + device->cname = "NV25"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x28: + device->cname = "NV28"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x2a: + device->cname = "NV2A"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv2a_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + default: + nv_fatal(device, "unknown Kelvin chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c new file mode 100644 index 00000000000..7f4b8fe6ccc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c @@ -0,0 +1,147 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/mpeg.h> +#include <engine/disp.h> + +int +nv30_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x30: + device->cname = "NV30"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x35: + device->cname = "NV35"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x31: + device->cname = "NV31"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x36: + device->cname = "NV36"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x34: + device->cname = "NV34"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv34_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + default: + nv_fatal(device, "unknown Rankine chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c new file mode 100644 index 00000000000..42deadca0f0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c @@ -0,0 +1,375 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/mpeg.h> +#include <engine/disp.h> + +int +nv40_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x40: + device->cname = "NV40"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x41: + device->cname = "NV41"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x42: + device->cname = "NV42"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x43: + device->cname = "NV43"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x45: + device->cname = "NV45"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x47: + device->cname = "G70"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x49: + device->cname = "G71"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x4b: + device->cname = "G73"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x44: + device->cname = "NV44"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x46: + device->cname = "G72"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x4a: + device->cname = "NV44A"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x4c: + device->cname = "C61"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x4e: + device->cname = "C51"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x63: + device->cname = "C73"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x67: + device->cname = "C67"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + case 0x68: + device->cname = "C68"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + break; + default: + nv_fatal(device, "unknown Curie chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c new file mode 100644 index 00000000000..fec3bcc9a6f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c @@ -0,0 +1,410 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/mxm.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> +#include <subdev/bar.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/mpeg.h> +#include <engine/vp.h> +#include <engine/crypt.h> +#include <engine/bsp.h> +#include <engine/ppp.h> +#include <engine/copy.h> +#include <engine/disp.h> + +int +nv50_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x50: + device->cname = "G80"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv50_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0x84: + device->cname = "G84"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0x86: + device->cname = "G86"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0x92: + device->cname = "G92"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0x94: + device->cname = "G94"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0x96: + device->cname = "G96"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0x98: + device->cname = "G98"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xa0: + device->cname = "G200"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xaa: + device->cname = "MCP77/MCP78"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xac: + device->cname = "MCP79/MCP7A"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xa3: + device->cname = "GT215"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xa5: + device->cname = "GT216"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xa8: + device->cname = "GT218"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xaf: + device->cname = "MCP89"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + default: + nv_fatal(device, "unknown Tesla chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c new file mode 100644 index 00000000000..6697f0f9c29 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c @@ -0,0 +1,285 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/mxm.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/ltcg.h> +#include <subdev/ibus.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> +#include <subdev/bar.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/vp.h> +#include <engine/bsp.h> +#include <engine/ppp.h> +#include <engine/copy.h> +#include <engine/disp.h> + +int +nvc0_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0xc0: + device->cname = "GF100"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xc4: + device->cname = "GF104"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xc3: + device->cname = "GF106"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xce: + device->cname = "GF114"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xcf: + device->cname = "GF116"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xc1: + device->cname = "GF108"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xc8: + device->cname = "GF110"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + break; + case 0xd9: + device->cname = "GF119"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass; + break; + default: + nv_fatal(device, "unknown Fermi chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c new file mode 100644 index 00000000000..4a280b7ab85 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c @@ -0,0 +1,109 @@ +/* + * 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/device.h> +#include <subdev/bios.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/mxm.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/ltcg.h> +#include <subdev/ibus.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> +#include <subdev/bar.h> + +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/disp.h> +#include <engine/copy.h> + +int +nve0_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0xe4: + device->cname = "GK104"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; + break; + case 0xe7: + device->cname = "GK107"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; + break; + default: + nv_fatal(device, "unknown Kepler chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c new file mode 100644 index 00000000000..5a07a39c173 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c @@ -0,0 +1,69 @@ +/* + * 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/option.h> + +#include <subdev/devinit.h> +#include <subdev/bios.h> +#include <subdev/bios/init.h> + +int +nouveau_devinit_init(struct nouveau_devinit *devinit) +{ + int ret = nouveau_subdev_init(&devinit->base); + if (ret) + return ret; + + return nvbios_init(&devinit->base, devinit->post); +} + +int +nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend) +{ + /* force full reinit on resume */ + if (suspend) + devinit->post = true; + + return nouveau_subdev_fini(&devinit->base, suspend); +} + +int +nouveau_devinit_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + int size, void **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_devinit *devinit; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "DEVINIT", + "init", size, pobject); + devinit = *pobject; + if (ret) + return ret; + + devinit->post = nouveau_boolopt(device->cfgopt, "NvForcePost", false); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h new file mode 100644 index 00000000000..6b56a0f4cb4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define NV04_PFB_BOOT_0 0x00100000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 +# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 +# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 +# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 +# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 +#define NV04_PFB_DEBUG_0 0x00100080 +# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001 +# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010 +# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00 +# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000 +# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000 +# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000 +# define NV04_PFB_DEBUG_0_CASOE 0x00100000 +# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000 +# define NV04_PFB_DEBUG_0_REFINC 0x20000000 +# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000 +#define NV04_PFB_CFG0 0x00100200 +# define NV04_PFB_CFG0_SCRAMBLE 0x20000000 +#define NV04_PFB_CFG1 0x00100204 +#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i)) + +#define NV10_PFB_REFCTRL 0x00100210 +# define NV10_PFB_REFCTRL_VALID_1 (1 << 31) + +static inline struct io_mapping * +fbmem_init(struct pci_dev *pdev) +{ + return io_mapping_create_wc(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); +} + +static inline void +fbmem_fini(struct io_mapping *fb) +{ + io_mapping_free(fb); +} + +static inline u32 +fbmem_peek(struct io_mapping *fb, u32 off) +{ + u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK); + u32 val = ioread32(p + (off & ~PAGE_MASK)); + io_mapping_unmap_atomic(p); + return val; +} + +static inline void +fbmem_poke(struct io_mapping *fb, u32 off, u32 val) +{ + u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK); + iowrite32(val, p + (off & ~PAGE_MASK)); + wmb(); + io_mapping_unmap_atomic(p); +} + +static inline bool +fbmem_readback(struct io_mapping *fb, u32 off, u32 val) +{ + fbmem_poke(fb, off, val); + return val == fbmem_peek(fb, off); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c new file mode 100644 index 00000000000..7a72d939434 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/devinit.h> +#include <subdev/vga.h> + +#include "fbmem.h" + +struct nv04_devinit_priv { + struct nouveau_devinit base; + int owner; +}; + +static void +nv04_devinit_meminit(struct nouveau_devinit *devinit) +{ + struct nv04_devinit_priv *priv = (void *)devinit; + u32 patt = 0xdeadbeef; + struct io_mapping *fb; + int i; + + /* Map the framebuffer aperture */ + fb = fbmem_init(nv_device(priv)->pdev); + if (!fb) { + nv_error(priv, "failed to map fb\n"); + return; + } + + /* Sequencer and refresh off */ + nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20); + nv_mask(priv, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); + + nv_mask(priv, NV04_PFB_BOOT_0, ~0, + NV04_PFB_BOOT_0_RAM_AMOUNT_16MB | + NV04_PFB_BOOT_0_RAM_WIDTH_128 | + NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT); + + for (i = 0; i < 4; i++) + fbmem_poke(fb, 4 * i, patt); + + fbmem_poke(fb, 0x400000, patt + 1); + + if (fbmem_peek(fb, 0) == patt + 1) { + nv_mask(priv, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_TYPE, + NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT); + nv_mask(priv, NV04_PFB_DEBUG_0, + NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + + for (i = 0; i < 4; i++) + fbmem_poke(fb, 4 * i, patt); + + if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff)) + nv_mask(priv, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_WIDTH_128 | + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + } else + if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) { + nv_mask(priv, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_WIDTH_128 | + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); + } else + if (fbmem_peek(fb, 0) != patt) { + if (fbmem_readback(fb, 0x800000, patt)) + nv_mask(priv, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + else + nv_mask(priv, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); + + nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, + NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT); + } else + if (!fbmem_readback(fb, 0x800000, patt)) { + nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + + } + + /* Refresh on, sequencer on */ + nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20); + fbmem_fini(fb); +} + +static int +nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_devinit_priv *priv; + int ret; + + ret = nouveau_devinit_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.meminit = nv04_devinit_meminit; + priv->owner = -1; + return 0; +} + +void +nv04_devinit_dtor(struct nouveau_object *object) +{ + struct nv04_devinit_priv *priv = (void *)object; + + /* restore vga owner saved at first init, and lock crtc regs */ + nv_wrvgaowner(priv, priv->owner); + nv_lockvgac(priv, true); + + nouveau_devinit_destroy(&priv->base); +} + +int +nv04_devinit_init(struct nouveau_object *object) +{ + struct nv04_devinit_priv *priv = (void *)object; + + if (!priv->base.post) { + u32 htotal = nv_rdvgac(priv, 0, 0x06); + htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8; + htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4; + htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10; + htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11; + if (!htotal) { + nv_info(priv, "adaptor not initialised\n"); + priv->base.post = true; + } + } + + return nouveau_devinit_init(&priv->base); +} + +int +nv04_devinit_fini(struct nouveau_object *object, bool suspend) +{ + struct nv04_devinit_priv *priv = (void *)object; + + /* make i2c busses accessible */ + nv_mask(priv, 0x000200, 0x00000001, 0x00000001); + + /* unlock extended vga crtc regs, and unslave crtcs */ + nv_lockvgac(priv, false); + if (priv->owner < 0) + priv->owner = nv_rdvgaowner(priv); + nv_wrvgaowner(priv, 0); + + return nouveau_devinit_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv04_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_devinit_ctor, + .dtor = nv04_devinit_dtor, + .init = nv04_devinit_init, + .fini = nv04_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c new file mode 100644 index 00000000000..191447d0d25 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/devinit.h> +#include <subdev/bios.h> +#include <subdev/bios/bmp.h> +#include <subdev/vga.h> + +#include "fbmem.h" + +struct nv05_devinit_priv { + struct nouveau_devinit base; + u8 owner; +}; + +static void +nv05_devinit_meminit(struct nouveau_devinit *devinit) +{ + static const u8 default_config_tab[][2] = { + { 0x24, 0x00 }, + { 0x28, 0x00 }, + { 0x24, 0x01 }, + { 0x1f, 0x00 }, + { 0x0f, 0x00 }, + { 0x17, 0x00 }, + { 0x06, 0x00 }, + { 0x00, 0x00 } + }; + struct nv05_devinit_priv *priv = (void *)devinit; + struct nouveau_bios *bios = nouveau_bios(priv); + struct io_mapping *fb; + u32 patt = 0xdeadbeef; + u16 data; + u8 strap, ramcfg[2]; + int i, v; + + /* Map the framebuffer aperture */ + fb = fbmem_init(nv_device(priv)->pdev); + if (!fb) { + nv_error(priv, "failed to map fb\n"); + return; + } + + strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2; + if ((data = bmp_mem_init_table(bios))) { + ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0); + ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1); + } else { + ramcfg[0] = default_config_tab[strap][0]; + ramcfg[1] = default_config_tab[strap][1]; + } + + /* Sequencer off */ + nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20); + + if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) + goto out; + + nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + + /* If present load the hardcoded scrambling table */ + if (data) { + for (i = 0, data += 0x10; i < 8; i++, data += 4) { + u32 scramble = nv_ro32(bios, data); + nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble); + } + } + + /* Set memory type/width/length defaults depending on the straps */ + nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); + + if (ramcfg[1] & 0x80) + nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); + + nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); + nv_mask(priv, NV04_PFB_CFG1, 0, 1); + + /* Probe memory bus width */ + for (i = 0; i < 4; i++) + fbmem_poke(fb, 4 * i, patt); + + if (fbmem_peek(fb, 0xc) != patt) + nv_mask(priv, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_WIDTH_128, 0); + + /* Probe memory length */ + v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; + + if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB && + (!fbmem_readback(fb, 0x1000000, ++patt) || + !fbmem_readback(fb, 0, ++patt))) + nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_16MB); + + if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB && + !fbmem_readback(fb, 0x800000, ++patt)) + nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + + if (!fbmem_readback(fb, 0x400000, ++patt)) + nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); + +out: + /* Sequencer on */ + nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20); + fbmem_fini(fb); +} + +static int +nv05_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv05_devinit_priv *priv; + int ret; + + ret = nouveau_devinit_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.meminit = nv05_devinit_meminit; + return 0; +} + +struct nouveau_oclass +nv05_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0x05), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv05_devinit_ctor, + .dtor = nv04_devinit_dtor, + .init = nv04_devinit_init, + .fini = nv04_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c new file mode 100644 index 00000000000..eb76ffab6b0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/devinit.h> +#include <subdev/vga.h> + +#include "fbmem.h" + +struct nv10_devinit_priv { + struct nouveau_devinit base; + u8 owner; +}; + +static void +nv10_devinit_meminit(struct nouveau_devinit *devinit) +{ + struct nv10_devinit_priv *priv = (void *)devinit; + const int mem_width[] = { 0x10, 0x00, 0x20 }; + const int mem_width_count = nv_device(priv)->chipset >= 0x17 ? 3 : 2; + uint32_t patt = 0xdeadbeef; + struct io_mapping *fb; + int i, j, k; + + /* Map the framebuffer aperture */ + fb = fbmem_init(nv_device(priv)->pdev); + if (!fb) { + nv_error(priv, "failed to map fb\n"); + return; + } + + nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + + /* Probe memory bus width */ + for (i = 0; i < mem_width_count; i++) { + nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]); + + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) + fbmem_poke(fb, 0x1c, 0); + + fbmem_poke(fb, 0x1c, patt); + fbmem_poke(fb, 0x3c, 0); + + if (fbmem_peek(fb, 0x1c) == patt) + goto mem_width_found; + } + } + +mem_width_found: + patt <<= 1; + + /* Probe amount of installed memory */ + for (i = 0; i < 4; i++) { + int off = nv_rd32(priv, 0x10020c) - 0x100000; + + fbmem_poke(fb, off, patt); + fbmem_poke(fb, 0, 0); + + fbmem_peek(fb, 0); + fbmem_peek(fb, 0); + fbmem_peek(fb, 0); + fbmem_peek(fb, 0); + + if (fbmem_peek(fb, off) == patt) + goto amount_found; + } + + /* IC missing - disable the upper half memory space. */ + nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0); + +amount_found: + fbmem_fini(fb); +} + +static int +nv10_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv10_devinit_priv *priv; + int ret; + + ret = nouveau_devinit_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.meminit = nv10_devinit_meminit; + return 0; +} + +struct nouveau_oclass +nv10_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_devinit_ctor, + .dtor = nv04_devinit_dtor, + .init = nv04_devinit_init, + .fini = nv04_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c new file mode 100644 index 00000000000..5b2ba630d91 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c @@ -0,0 +1,58 @@ +/* + * 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/devinit.h> +#include <subdev/vga.h> + +struct nv1a_devinit_priv { + struct nouveau_devinit base; + u8 owner; +}; + +static int +nv1a_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv1a_devinit_priv *priv; + int ret; + + ret = nouveau_devinit_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass +nv1a_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0x1a), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv1a_devinit_ctor, + .dtor = nv04_devinit_dtor, + .init = nv04_devinit_init, + .fini = nv04_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c new file mode 100644 index 00000000000..eb32e99005e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/devinit.h> +#include <subdev/vga.h> + +#include "fbmem.h" + +struct nv20_devinit_priv { + struct nouveau_devinit base; + u8 owner; +}; + +static void +nv20_devinit_meminit(struct nouveau_devinit *devinit) +{ + struct nv20_devinit_priv *priv = (void *)devinit; + struct nouveau_device *device = nv_device(priv); + uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900); + uint32_t amount, off; + struct io_mapping *fb; + + /* Map the framebuffer aperture */ + fb = fbmem_init(nv_device(priv)->pdev); + if (!fb) { + nv_error(priv, "failed to map fb\n"); + return; + } + + nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + + /* Allow full addressing */ + nv_mask(priv, NV04_PFB_CFG0, 0, mask); + + amount = nv_rd32(priv, 0x10020c); + for (off = amount; off > 0x2000000; off -= 0x2000000) + fbmem_poke(fb, off - 4, off); + + amount = nv_rd32(priv, 0x10020c); + if (amount != fbmem_peek(fb, amount - 4)) + /* IC missing - disable the upper half memory space. */ + nv_mask(priv, NV04_PFB_CFG0, mask, 0); + + fbmem_fini(fb); +} + +static int +nv20_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv20_devinit_priv *priv; + int ret; + + ret = nouveau_devinit_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.meminit = nv20_devinit_meminit; + return 0; +} + +struct nouveau_oclass +nv20_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0x20), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv20_devinit_ctor, + .dtor = nv04_devinit_dtor, + .init = nv04_devinit_init, + .fini = nv04_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c new file mode 100644 index 00000000000..61becfa732e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.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 <subdev/devinit.h> +#include <subdev/vga.h> + +struct nv50_devinit_priv { + struct nouveau_devinit base; +}; + +static int +nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_devinit_priv *priv; + int ret; + + ret = nouveau_devinit_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +static void +nv50_devinit_dtor(struct nouveau_object *object) +{ + struct nv50_devinit_priv *priv = (void *)object; + nouveau_devinit_destroy(&priv->base); +} + +static int +nv50_devinit_init(struct nouveau_object *object) +{ + struct nv50_devinit_priv *priv = (void *)object; + + if (!priv->base.post) { + if (!nv_rdvgac(priv, 0, 0x00) && + !nv_rdvgac(priv, 0, 0x1a)) { + nv_info(priv, "adaptor not initialised\n"); + priv->base.post = true; + } + } + + return nouveau_devinit_init(&priv->base); +} + +static int +nv50_devinit_fini(struct nouveau_object *object, bool suspend) +{ + struct nv50_devinit_priv *priv = (void *)object; + return nouveau_devinit_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv50_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_devinit_ctor, + .dtor = nv50_devinit_dtor, + .init = nv50_devinit_init, + .fini = nv50_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c new file mode 100644 index 00000000000..f0086de8af3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c @@ -0,0 +1,130 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "subdev/fb.h" +#include "subdev/bios.h" +#include "subdev/bios/bit.h" + +int +nouveau_fb_bios_memtype(struct nouveau_bios *bios) +{ + struct bit_entry M; + u8 ramcfg; + + ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2; + if (!bit_entry(bios, 'M', &M) && M.version == 2 && M.length >= 5) { + u16 table = nv_ro16(bios, M.offset + 3); + u8 version = nv_ro08(bios, table + 0); + u8 header = nv_ro08(bios, table + 1); + u8 record = nv_ro08(bios, table + 2); + u8 entries = nv_ro08(bios, table + 3); + if (table && version == 0x10 && ramcfg < entries) { + u16 entry = table + header + (ramcfg * record); + switch (nv_ro08(bios, entry) & 0x0f) { + case 0: return NV_MEM_TYPE_DDR2; + case 1: return NV_MEM_TYPE_DDR3; + case 2: return NV_MEM_TYPE_GDDR3; + case 3: return NV_MEM_TYPE_GDDR5; + default: + break; + } + + } + } + + return NV_MEM_TYPE_UNKNOWN; +} + +int +nouveau_fb_init(struct nouveau_fb *pfb) +{ + int ret, i; + + ret = nouveau_subdev_init(&pfb->base); + if (ret) + return ret; + + for (i = 0; i < pfb->tile.regions; i++) + pfb->tile.prog(pfb, i, &pfb->tile.region[i]); + + return 0; +} + +int +_nouveau_fb_init(struct nouveau_object *object) +{ + struct nouveau_fb *pfb = (void *)object; + return nouveau_fb_init(pfb); +} + +void +nouveau_fb_destroy(struct nouveau_fb *pfb) +{ + int i; + + for (i = 0; i < pfb->tile.regions; i++) + pfb->tile.fini(pfb, i, &pfb->tile.region[i]); + + if (pfb->tags.block_size) + nouveau_mm_fini(&pfb->tags); + + if (pfb->vram.block_size) + nouveau_mm_fini(&pfb->vram); + + nouveau_subdev_destroy(&pfb->base); +} + +void +_nouveau_fb_dtor(struct nouveau_object *object) +{ + struct nouveau_fb *pfb = (void *)object; + nouveau_fb_destroy(pfb); +} + +int +nouveau_fb_created(struct nouveau_fb *pfb) +{ + static const char *name[] = { + [NV_MEM_TYPE_UNKNOWN] = "unknown", + [NV_MEM_TYPE_STOLEN ] = "stolen system memory", + [NV_MEM_TYPE_SGRAM ] = "SGRAM", + [NV_MEM_TYPE_SDRAM ] = "SDRAM", + [NV_MEM_TYPE_DDR1 ] = "DDR1", + [NV_MEM_TYPE_DDR2 ] = "DDR2", + [NV_MEM_TYPE_DDR3 ] = "DDR3", + [NV_MEM_TYPE_GDDR2 ] = "GDDR2", + [NV_MEM_TYPE_GDDR3 ] = "GDDR3", + [NV_MEM_TYPE_GDDR4 ] = "GDDR4", + [NV_MEM_TYPE_GDDR5 ] = "GDDR5", + }; + + if (pfb->ram.size == 0) { + nv_fatal(pfb, "no vram detected!!\n"); + return -ERANGE; + } + + nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]); + nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20)); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c new file mode 100644 index 00000000000..eb06836b69f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c @@ -0,0 +1,130 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/fb.h> + +#define NV04_PFB_BOOT_0 0x00100000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 +# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 +# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 +# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 +# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 +#define NV04_PFB_CFG0 0x00100200 + +struct nv04_fb_priv { + struct nouveau_fb base; +}; + +bool +nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) +{ + if (!(tile_flags & 0xff00)) + return true; + + return false; +} + +static int +nv04_fb_init(struct nouveau_object *object) +{ + struct nv04_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + /* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows + * nvidia reading PFB_CFG_0, then writing back its original value. + * (which was 0x701114 in this case) + */ + nv_wr32(priv, NV04_PFB_CFG0, 0x1114); + return 0; +} + +static int +nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_fb_priv *priv; + u32 boot0; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + boot0 = nv_rd32(priv, NV04_PFB_BOOT_0); + if (boot0 & 0x00000100) { + priv->base.ram.size = ((boot0 >> 12) & 0xf) * 2 + 2; + priv->base.ram.size *= 1024 * 1024; + } else { + switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { + case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: + priv->base.ram.size = 32 * 1024 * 1024; + break; + case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: + priv->base.ram.size = 16 * 1024 * 1024; + break; + case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: + priv->base.ram.size = 8 * 1024 * 1024; + break; + case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: + priv->base.ram.size = 4 * 1024 * 1024; + break; + } + } + + if ((boot0 & 0x00000038) <= 0x10) + priv->base.ram.type = NV_MEM_TYPE_SGRAM; + else + priv->base.ram.type = NV_MEM_TYPE_SDRAM; + + + priv->base.memtype_valid = nv04_fb_memtype_valid; + return nouveau_fb_created(&priv->base); +} + +struct nouveau_oclass +nv04_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = nv04_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c new file mode 100644 index 00000000000..f037a422d2f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/fb.h> + +struct nv10_fb_priv { + struct nouveau_fb base; +}; + +static void +nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, + u32 flags, struct nouveau_fb_tile *tile) +{ + tile->addr = 0x80000000 | addr; + tile->limit = max(1u, addr + size) - 1; + tile->pitch = pitch; +} + +static void +nv10_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) +{ + tile->addr = 0; + tile->limit = 0; + tile->pitch = 0; + tile->zcomp = 0; +} + +void +nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) +{ + nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); + nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); + nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); +} + +static int +nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nv10_fb_priv *priv; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + if (device->chipset == 0x1a || device->chipset == 0x1f) { + struct pci_dev *bridge; + u32 mem, mib; + + bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); + if (!bridge) { + nv_fatal(device, "no bridge device\n"); + return 0; + } + + if (device->chipset == 0x1a) { + pci_read_config_dword(bridge, 0x7c, &mem); + mib = ((mem >> 6) & 31) + 1; + } else { + pci_read_config_dword(bridge, 0x84, &mem); + mib = ((mem >> 4) & 127) + 1; + } + + priv->base.ram.type = NV_MEM_TYPE_STOLEN; + priv->base.ram.size = mib * 1024 * 1024; + } else { + u32 cfg0 = nv_rd32(priv, 0x100200); + if (cfg0 & 0x00000001) + priv->base.ram.type = NV_MEM_TYPE_DDR1; + else + priv->base.ram.type = NV_MEM_TYPE_SDRAM; + + priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000; + } + + priv->base.memtype_valid = nv04_fb_memtype_valid; + priv->base.tile.regions = 8; + priv->base.tile.init = nv10_fb_tile_init; + priv->base.tile.fini = nv10_fb_tile_fini; + priv->base.tile.prog = nv10_fb_tile_prog; + return nouveau_fb_created(&priv->base); +} + +struct nouveau_oclass +nv10_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = _nouveau_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c new file mode 100644 index 00000000000..4b3578fcb7f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/fb.h> + +struct nv20_fb_priv { + struct nouveau_fb base; +}; + +static void +nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, + u32 flags, struct nouveau_fb_tile *tile) +{ + struct nouveau_device *device = nv_device(pfb); + int bpp = (flags & 2) ? 32 : 16; + + tile->addr = 0x00000001 | addr; + tile->limit = max(1u, addr + size) - 1; + tile->pitch = pitch; + + /* Allocate some of the on-die tag memory, used to store Z + * compression meta-data (most likely just a bitmap determining + * if a given tile is compressed or not). + */ + size /= 256; + if (flags & 4) { + if (!nouveau_mm_head(&pfb->tags, 1, size, size, 1, &tile->tag)) { + /* Enable Z compression */ + tile->zcomp = tile->tag->offset; + if (device->chipset >= 0x25) { + if (bpp == 16) + tile->zcomp |= 0x00100000; + else + tile->zcomp |= 0x00200000; + } else { + tile->zcomp |= 0x80000000; + if (bpp != 16) + tile->zcomp |= 0x04000000; + } + } + + tile->addr |= 2; + } +} + +static void +nv20_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) +{ + tile->addr = 0; + tile->limit = 0; + tile->pitch = 0; + tile->zcomp = 0; + nouveau_mm_free(&pfb->tags, &tile->tag); +} + +static void +nv20_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) +{ + nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); + nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); + nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); + nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp); +} + +static int +nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nv20_fb_priv *priv; + u32 pbus1218; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + pbus1218 = nv_rd32(priv, 0x001218); + switch (pbus1218 & 0x00000300) { + case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break; + case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break; + case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break; + case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break; + } + priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000; + + if (device->chipset >= 0x25) + ret = nouveau_mm_init(&priv->base.tags, 0, 64 * 1024, 1); + else + ret = nouveau_mm_init(&priv->base.tags, 0, 32 * 1024, 1); + if (ret) + return ret; + + priv->base.memtype_valid = nv04_fb_memtype_valid; + priv->base.tile.regions = 8; + priv->base.tile.init = nv20_fb_tile_init; + priv->base.tile.fini = nv20_fb_tile_fini; + priv->base.tile.prog = nv20_fb_tile_prog; + return nouveau_fb_created(&priv->base); +} + +struct nouveau_oclass +nv20_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x20), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv20_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = _nouveau_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c new file mode 100644 index 00000000000..cba67bc9139 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/fb.h> + +struct nv30_fb_priv { + struct nouveau_fb base; +}; + +void +nv30_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, + u32 flags, struct nouveau_fb_tile *tile) +{ + tile->addr = addr | 1; + tile->limit = max(1u, addr + size) - 1; + tile->pitch = pitch; +} + +void +nv30_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) +{ + tile->addr = 0; + tile->limit = 0; + tile->pitch = 0; +} + +static int +calc_bias(struct nv30_fb_priv *priv, int k, int i, int j) +{ + struct nouveau_device *device = nv_device(priv); + int b = (device->chipset > 0x30 ? + nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : + 0) & 0xf; + + return 2 * (b & 0x8 ? b - 0x10 : b); +} + +static int +calc_ref(struct nv30_fb_priv *priv, int l, int k, int i) +{ + int j, x = 0; + + for (j = 0; j < 4; j++) { + int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j); + + x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j); + } + + return x; +} + +static int +nv30_fb_init(struct nouveau_object *object) +{ + struct nouveau_device *device = nv_device(object); + struct nv30_fb_priv *priv = (void *)object; + int ret, i, j; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + /* Init the memory timing regs at 0x10037c/0x1003ac */ + if (device->chipset == 0x30 || + device->chipset == 0x31 || + device->chipset == 0x35) { + /* Related to ROP count */ + int n = (device->chipset == 0x31 ? 2 : 4); + int l = nv_rd32(priv, 0x1003d0); + + for (i = 0; i < n; i++) { + for (j = 0; j < 3; j++) + nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j, + calc_ref(priv, l, 0, j)); + + for (j = 0; j < 2; j++) + nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j, + calc_ref(priv, l, 1, j)); + } + } + + return 0; +} + +static int +nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv30_fb_priv *priv; + u32 pbus1218; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + pbus1218 = nv_rd32(priv, 0x001218); + switch (pbus1218 & 0x00000300) { + case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break; + case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break; + case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break; + case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break; + } + priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000; + + priv->base.memtype_valid = nv04_fb_memtype_valid; + priv->base.tile.regions = 8; + priv->base.tile.init = nv30_fb_tile_init; + priv->base.tile.fini = nv30_fb_tile_fini; + priv->base.tile.prog = nv10_fb_tile_prog; + return nouveau_fb_created(&priv->base); +} + +struct nouveau_oclass +nv30_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x30), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv30_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = nv30_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c new file mode 100644 index 00000000000..347a496fcad --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/fb.h> + +struct nv40_fb_priv { + struct nouveau_fb base; +}; + +static inline int +nv44_graph_class(struct nouveau_device *device) +{ + if ((device->chipset & 0xf0) == 0x60) + return 1; + + return !(0x0baf & (1 << (device->chipset & 0x0f))); +} + +static void +nv40_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) +{ + nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit); + nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch); + nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr); +} + +static void +nv40_fb_init_gart(struct nv40_fb_priv *priv) +{ + nv_wr32(priv, 0x100800, 0x00000001); +} + +static void +nv44_fb_init_gart(struct nv40_fb_priv *priv) +{ + nv_wr32(priv, 0x100850, 0x80000000); + nv_wr32(priv, 0x100800, 0x00000001); +} + +static int +nv40_fb_init(struct nouveau_object *object) +{ + struct nv40_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + switch (nv_device(priv)->chipset) { + case 0x40: + case 0x45: + nv_mask(priv, 0x10033c, 0x00008000, 0x00000000); + break; + default: + if (nv44_graph_class(nv_device(priv))) + nv44_fb_init_gart(priv); + else + nv40_fb_init_gart(priv); + break; + } + + return 0; +} + +static int +nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nv40_fb_priv *priv; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + /* 0x001218 is actually present on a few other NV4X I looked at, + * and even contains sane values matching 0x100474. From looking + * at various vbios images however, this isn't the case everywhere. + * So, I chose to use the same regs I've seen NVIDIA reading around + * the memory detection, hopefully that'll get us the right numbers + */ + if (device->chipset == 0x40) { + u32 pbus1218 = nv_rd32(priv, 0x001218); + switch (pbus1218 & 0x00000300) { + case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break; + case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break; + case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break; + case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_DDR2; break; + } + } else + if (device->chipset == 0x49 || device->chipset == 0x4b) { + u32 pfb914 = nv_rd32(priv, 0x100914); + switch (pfb914 & 0x00000003) { + case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_DDR1; break; + case 0x00000001: priv->base.ram.type = NV_MEM_TYPE_DDR2; break; + case 0x00000002: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break; + case 0x00000003: break; + } + } else + if (device->chipset != 0x4e) { + u32 pfb474 = nv_rd32(priv, 0x100474); + if (pfb474 & 0x00000004) + priv->base.ram.type = NV_MEM_TYPE_GDDR3; + if (pfb474 & 0x00000002) + priv->base.ram.type = NV_MEM_TYPE_DDR2; + if (pfb474 & 0x00000001) + priv->base.ram.type = NV_MEM_TYPE_DDR1; + } else { + priv->base.ram.type = NV_MEM_TYPE_STOLEN; + } + + priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000; + + priv->base.memtype_valid = nv04_fb_memtype_valid; + switch (device->chipset) { + case 0x40: + case 0x45: + priv->base.tile.regions = 8; + break; + case 0x46: + case 0x47: + case 0x49: + case 0x4b: + case 0x4c: + priv->base.tile.regions = 15; + break; + default: + priv->base.tile.regions = 12; + break; + } + priv->base.tile.init = nv30_fb_tile_init; + priv->base.tile.fini = nv30_fb_tile_fini; + if (device->chipset == 0x40) + priv->base.tile.prog = nv10_fb_tile_prog; + else + priv->base.tile.prog = nv40_fb_tile_prog; + + return nouveau_fb_created(&priv->base); +} + + +struct nouveau_oclass +nv40_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = nv40_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c new file mode 100644 index 00000000000..436e9efe7ef --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -0,0 +1,498 @@ +/* + * 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/enum.h> + +#include <subdev/fb.h> +#include <subdev/bios.h> + +struct nv50_fb_priv { + struct nouveau_fb base; + struct page *r100c08_page; + dma_addr_t r100c08; +}; + +static int types[0x80] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 +}; + +static bool +nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype) +{ + return types[(memtype & 0xff00) >> 8] != 0; +} + +static int +nv50_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, + u32 memtype, struct nouveau_mem **pmem) +{ + struct nv50_fb_priv *priv = (void *)pfb; + struct nouveau_mm *heap = &priv->base.vram; + struct nouveau_mm *tags = &priv->base.tags; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int comp = (memtype & 0x300) >> 8; + int type = (memtype & 0x07f); + int back = (memtype & 0x800); + int min, max, ret; + + max = (size >> 12); + min = ncmin ? (ncmin >> 12) : max; + align >>= 12; + + mem = kzalloc(sizeof(*mem), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + mutex_lock(&pfb->base.mutex); + if (comp) { + if (align == 16) { + int n = (max >> 4) * comp; + + ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag); + if (ret) + mem->tag = NULL; + } + + if (unlikely(!mem->tag)) + comp = 0; + } + + INIT_LIST_HEAD(&mem->regions); + mem->memtype = (comp << 7) | type; + mem->size = max; + + type = types[type]; + do { + if (back) + ret = nouveau_mm_tail(heap, type, max, min, align, &r); + else + ret = nouveau_mm_head(heap, type, max, min, align, &r); + if (ret) { + mutex_unlock(&pfb->base.mutex); + pfb->ram.put(pfb, &mem); + return ret; + } + + list_add_tail(&r->rl_entry, &mem->regions); + max -= r->length; + } while (max); + mutex_unlock(&pfb->base.mutex); + + r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); + mem->offset = (u64)r->offset << 12; + *pmem = mem; + return 0; +} + +void +nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem) +{ + struct nv50_fb_priv *priv = (void *)pfb; + struct nouveau_mm_node *this; + struct nouveau_mem *mem; + + mem = *pmem; + *pmem = NULL; + if (unlikely(mem == NULL)) + return; + + mutex_lock(&pfb->base.mutex); + while (!list_empty(&mem->regions)) { + this = list_first_entry(&mem->regions, typeof(*this), rl_entry); + + list_del(&this->rl_entry); + nouveau_mm_free(&priv->base.vram, &this); + } + + nouveau_mm_free(&priv->base.tags, &mem->tag); + mutex_unlock(&pfb->base.mutex); + + kfree(mem); +} + +static u32 +nv50_vram_rblock(struct nv50_fb_priv *priv) +{ + int i, parts, colbits, rowbitsa, rowbitsb, banks; + u64 rowsize, predicted; + u32 r0, r4, rt, ru, rblock_size; + + r0 = nv_rd32(priv, 0x100200); + r4 = nv_rd32(priv, 0x100204); + rt = nv_rd32(priv, 0x100250); + ru = nv_rd32(priv, 0x001540); + nv_debug(priv, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); + + for (i = 0, parts = 0; i < 8; i++) { + if (ru & (0x00010000 << i)) + parts++; + } + + colbits = (r4 & 0x0000f000) >> 12; + rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; + rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; + banks = 1 << (((r4 & 0x03000000) >> 24) + 2); + + rowsize = parts * banks * (1 << colbits) * 8; + predicted = rowsize << rowbitsa; + if (r0 & 0x00000004) + predicted += rowsize << rowbitsb; + + if (predicted != priv->base.ram.size) { + nv_warn(priv, "memory controller reports %d MiB VRAM\n", + (u32)(priv->base.ram.size >> 20)); + } + + rblock_size = rowsize; + if (rt & 1) + rblock_size *= 3; + + nv_debug(priv, "rblock %d bytes\n", rblock_size); + return rblock_size; +} + +static int +nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_bios *bios = nouveau_bios(device); + const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ + const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ + struct nv50_fb_priv *priv; + u32 tags; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + switch (nv_rd32(priv, 0x100714) & 0x00000007) { + case 0: priv->base.ram.type = NV_MEM_TYPE_DDR1; break; + case 1: + if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) + priv->base.ram.type = NV_MEM_TYPE_DDR3; + else + priv->base.ram.type = NV_MEM_TYPE_DDR2; + break; + case 2: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break; + case 3: priv->base.ram.type = NV_MEM_TYPE_GDDR4; break; + case 4: priv->base.ram.type = NV_MEM_TYPE_GDDR5; break; + default: + break; + } + + priv->base.ram.size = nv_rd32(priv, 0x10020c); + priv->base.ram.size = (priv->base.ram.size & 0xffffff00) | + ((priv->base.ram.size & 0x000000ff) << 32); + + tags = nv_rd32(priv, 0x100320); + if (tags) { + ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1); + if (ret) + return ret; + + nv_debug(priv, "%d compression tags\n", tags); + } + + size = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail; + switch (device->chipset) { + case 0xaa: + case 0xac: + case 0xaf: /* IGPs, no reordering, no real VRAM */ + ret = nouveau_mm_init(&priv->base.vram, rsvd_head, size, 1); + if (ret) + return ret; + + priv->base.ram.stolen = (u64)nv_rd32(priv, 0x100e10) << 12; + break; + default: + ret = nouveau_mm_init(&priv->base.vram, rsvd_head, size, + nv50_vram_rblock(priv) >> 12); + if (ret) + return ret; + + priv->base.ram.ranks = (nv_rd32(priv, 0x100200) & 0x4) ? 2 : 1; + break; + } + + priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (priv->r100c08_page) { + priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page, + 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(device->pdev, priv->r100c08)) + nv_warn(priv, "failed 0x100c08 page map\n"); + } else { + nv_warn(priv, "failed 0x100c08 page alloc\n"); + } + + priv->base.memtype_valid = nv50_fb_memtype_valid; + priv->base.ram.get = nv50_fb_vram_new; + priv->base.ram.put = nv50_fb_vram_del; + return nouveau_fb_created(&priv->base); +} + +static void +nv50_fb_dtor(struct nouveau_object *object) +{ + struct nouveau_device *device = nv_device(object); + struct nv50_fb_priv *priv = (void *)object; + + if (priv->r100c08_page) { + pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + __free_page(priv->r100c08_page); + } + + nouveau_mm_fini(&priv->base.vram); + nouveau_fb_destroy(&priv->base); +} + +static int +nv50_fb_init(struct nouveau_object *object) +{ + struct nouveau_device *device = nv_device(object); + struct nv50_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + /* Not a clue what this is exactly. Without pointing it at a + * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) + * cause IOMMU "read from address 0" errors (rh#561267) + */ + nv_wr32(priv, 0x100c08, priv->r100c08 >> 8); + + /* This is needed to get meaningful information from 100c90 + * on traps. No idea what these values mean exactly. */ + switch (device->chipset) { + case 0x50: + nv_wr32(priv, 0x100c90, 0x000707ff); + break; + case 0xa3: + case 0xa5: + case 0xa8: + nv_wr32(priv, 0x100c90, 0x000d0fff); + break; + case 0xaf: + nv_wr32(priv, 0x100c90, 0x089d1fff); + break; + default: + nv_wr32(priv, 0x100c90, 0x001d07ff); + break; + } + + return 0; +} + +struct nouveau_oclass +nv50_fb_oclass = { + .handle = NV_SUBDEV(FB, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fb_ctor, + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .fini = _nouveau_fb_fini, + }, +}; + +static const struct nouveau_enum vm_dispatch_subclients[] = { + { 0x00000000, "GRCTX", NULL }, + { 0x00000001, "NOTIFY", NULL }, + { 0x00000002, "QUERY", NULL }, + { 0x00000003, "COND", NULL }, + { 0x00000004, "M2M_IN", NULL }, + { 0x00000005, "M2M_OUT", NULL }, + { 0x00000006, "M2M_NOTIFY", NULL }, + {} +}; + +static const struct nouveau_enum vm_ccache_subclients[] = { + { 0x00000000, "CB", NULL }, + { 0x00000001, "TIC", NULL }, + { 0x00000002, "TSC", NULL }, + {} +}; + +static const struct nouveau_enum vm_prop_subclients[] = { + { 0x00000000, "RT0", NULL }, + { 0x00000001, "RT1", NULL }, + { 0x00000002, "RT2", NULL }, + { 0x00000003, "RT3", NULL }, + { 0x00000004, "RT4", NULL }, + { 0x00000005, "RT5", NULL }, + { 0x00000006, "RT6", NULL }, + { 0x00000007, "RT7", NULL }, + { 0x00000008, "ZETA", NULL }, + { 0x00000009, "LOCAL", NULL }, + { 0x0000000a, "GLOBAL", NULL }, + { 0x0000000b, "STACK", NULL }, + { 0x0000000c, "DST2D", NULL }, + {} +}; + +static const struct nouveau_enum vm_pfifo_subclients[] = { + { 0x00000000, "PUSHBUF", NULL }, + { 0x00000001, "SEMAPHORE", NULL }, + {} +}; + +static const struct nouveau_enum vm_bar_subclients[] = { + { 0x00000000, "FB", NULL }, + { 0x00000001, "IN", NULL }, + {} +}; + +static const struct nouveau_enum vm_client[] = { + { 0x00000000, "STRMOUT", NULL }, + { 0x00000003, "DISPATCH", vm_dispatch_subclients }, + { 0x00000004, "PFIFO_WRITE", NULL }, + { 0x00000005, "CCACHE", vm_ccache_subclients }, + { 0x00000006, "PPPP", NULL }, + { 0x00000007, "CLIPID", NULL }, + { 0x00000008, "PFIFO_READ", NULL }, + { 0x00000009, "VFETCH", NULL }, + { 0x0000000a, "TEXTURE", NULL }, + { 0x0000000b, "PROP", vm_prop_subclients }, + { 0x0000000c, "PVP", NULL }, + { 0x0000000d, "PBSP", NULL }, + { 0x0000000e, "PCRYPT", NULL }, + { 0x0000000f, "PCOUNTER", NULL }, + { 0x00000011, "PDAEMON", NULL }, + {} +}; + +static const struct nouveau_enum vm_engine[] = { + { 0x00000000, "PGRAPH", NULL }, + { 0x00000001, "PVP", NULL }, + { 0x00000004, "PEEPHOLE", NULL }, + { 0x00000005, "PFIFO", vm_pfifo_subclients }, + { 0x00000006, "BAR", vm_bar_subclients }, + { 0x00000008, "PPPP", NULL }, + { 0x00000009, "PBSP", NULL }, + { 0x0000000a, "PCRYPT", NULL }, + { 0x0000000b, "PCOUNTER", NULL }, + { 0x0000000c, "SEMAPHORE_BG", NULL }, + { 0x0000000d, "PCOPY", NULL }, + { 0x0000000e, "PDAEMON", NULL }, + {} +}; + +static const struct nouveau_enum vm_fault[] = { + { 0x00000000, "PT_NOT_PRESENT", NULL }, + { 0x00000001, "PT_TOO_SHORT", NULL }, + { 0x00000002, "PAGE_NOT_PRESENT", NULL }, + { 0x00000003, "PAGE_SYSTEM_ONLY", NULL }, + { 0x00000004, "PAGE_READ_ONLY", NULL }, + { 0x00000006, "NULL_DMAOBJ", NULL }, + { 0x00000007, "WRONG_MEMTYPE", NULL }, + { 0x0000000b, "VRAM_LIMIT", NULL }, + { 0x0000000f, "DMAOBJ_LIMIT", NULL }, + {} +}; + +void +nv50_fb_trap(struct nouveau_fb *pfb, int display) +{ + struct nouveau_device *device = nv_device(pfb); + struct nv50_fb_priv *priv = (void *)pfb; + const struct nouveau_enum *en, *cl; + u32 trap[6], idx, chan; + u8 st0, st1, st2, st3; + int i; + + idx = nv_rd32(priv, 0x100c90); + if (!(idx & 0x80000000)) + return; + idx &= 0x00ffffff; + + for (i = 0; i < 6; i++) { + nv_wr32(priv, 0x100c90, idx | i << 24); + trap[i] = nv_rd32(priv, 0x100c94); + } + nv_wr32(priv, 0x100c90, idx | 0x80000000); + + if (!display) + return; + + /* decode status bits into something more useful */ + if (device->chipset < 0xa3 || + device->chipset == 0xaa || device->chipset == 0xac) { + st0 = (trap[0] & 0x0000000f) >> 0; + st1 = (trap[0] & 0x000000f0) >> 4; + st2 = (trap[0] & 0x00000f00) >> 8; + st3 = (trap[0] & 0x0000f000) >> 12; + } else { + st0 = (trap[0] & 0x000000ff) >> 0; + st1 = (trap[0] & 0x0000ff00) >> 8; + st2 = (trap[0] & 0x00ff0000) >> 16; + st3 = (trap[0] & 0xff000000) >> 24; + } + chan = (trap[2] << 16) | trap[1]; + + nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x ", + (trap[5] & 0x00000100) ? "read" : "write", + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan); + + en = nouveau_enum_find(vm_engine, st0); + if (en) + printk("%s/", en->name); + else + printk("%02x/", st0); + + cl = nouveau_enum_find(vm_client, st2); + if (cl) + printk("%s/", cl->name); + else + printk("%02x/", st2); + + if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3); + else if (en && en->data) cl = nouveau_enum_find(en->data, st3); + else cl = NULL; + if (cl) + printk("%s", cl->name); + else + printk("%02x", st3); + + printk(" reason: "); + en = nouveau_enum_find(vm_fault, st1); + if (en) + printk("%s\n", en->name); + else + printk("0x%08x\n", st1); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c new file mode 100644 index 00000000000..9f59f2bf007 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c @@ -0,0 +1,245 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/fb.h> +#include <subdev/bios.h> + +struct nvc0_fb_priv { + struct nouveau_fb base; + struct page *r100c10_page; + dma_addr_t r100c10; +}; + +/* 0 = unsupported + * 1 = non-compressed + * 3 = compressed + */ +static const u8 types[256] = { + 1, 1, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, + 3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, + 3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3, + 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0 +}; + +static bool +nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) +{ + u8 memtype = (tile_flags & 0x0000ff00) >> 8; + return likely((types[memtype] == 1)); +} + +static int +nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, + u32 memtype, struct nouveau_mem **pmem) +{ + struct nouveau_mm *mm = &pfb->vram; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int type = (memtype & 0x0ff); + int back = (memtype & 0x800); + int ret; + + size >>= 12; + align >>= 12; + ncmin >>= 12; + if (!ncmin) + ncmin = size; + + mem = kzalloc(sizeof(*mem), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + INIT_LIST_HEAD(&mem->regions); + mem->memtype = type; + mem->size = size; + + mutex_lock(&mm->mutex); + do { + if (back) + ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); + else + ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); + if (ret) { + mutex_unlock(&mm->mutex); + pfb->ram.put(pfb, &mem); + return ret; + } + + list_add_tail(&r->rl_entry, &mem->regions); + size -= r->length; + } while (size); + mutex_unlock(&mm->mutex); + + r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); + mem->offset = (u64)r->offset << 12; + *pmem = mem; + return 0; +} + +static int +nvc0_fb_init(struct nouveau_object *object) +{ + struct nvc0_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, 0x100c10, priv->r100c10 >> 8); + return 0; +} + +static void +nvc0_fb_dtor(struct nouveau_object *object) +{ + struct nouveau_device *device = nv_device(object); + struct nvc0_fb_priv *priv = (void *)object; + + if (priv->r100c10_page) { + pci_unmap_page(device->pdev, priv->r100c10, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + __free_page(priv->r100c10_page); + } + + nouveau_fb_destroy(&priv->base); +} + +static int +nvc0_vram_detect(struct nvc0_fb_priv *priv) +{ + struct nouveau_bios *bios = nouveau_bios(priv); + struct nouveau_fb *pfb = &priv->base; + const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ + const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ + u32 parts = nv_rd32(priv, 0x022438); + u32 pmask = nv_rd32(priv, 0x022554); + u32 bsize = nv_rd32(priv, 0x10f20c); + u32 offset, length; + bool uniform = true; + int ret, part; + + nv_debug(priv, "0x100800: 0x%08x\n", nv_rd32(priv, 0x100800)); + nv_debug(priv, "parts 0x%08x mask 0x%08x\n", parts, pmask); + + priv->base.ram.type = nouveau_fb_bios_memtype(bios); + priv->base.ram.ranks = (nv_rd32(priv, 0x10f200) & 0x00000004) ? 2 : 1; + + /* read amount of vram attached to each memory controller */ + for (part = 0; part < parts; part++) { + if (!(pmask & (1 << part))) { + u32 psize = nv_rd32(priv, 0x11020c + (part * 0x1000)); + if (psize != bsize) { + if (psize < bsize) + bsize = psize; + uniform = false; + } + + nv_debug(priv, "%d: mem_amount 0x%08x\n", part, psize); + priv->base.ram.size += (u64)psize << 20; + } + } + + /* if all controllers have the same amount attached, there's no holes */ + if (uniform) { + offset = rsvd_head; + length = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail; + return nouveau_mm_init(&pfb->vram, offset, length, 1); + } + + /* otherwise, address lowest common amount from 0GiB */ + ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1); + if (ret) + return ret; + + /* and the rest starting from (8GiB + common_size) */ + offset = (0x0200000000ULL >> 12) + (bsize << 8); + length = (priv->base.ram.size >> 12) - (bsize << 8) - rsvd_tail; + + ret = nouveau_mm_init(&pfb->vram, offset, length, 0); + if (ret) { + nouveau_mm_fini(&pfb->vram); + return ret; + } + + return 0; +} + +static int +nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nvc0_fb_priv *priv; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.memtype_valid = nvc0_fb_memtype_valid; + priv->base.ram.get = nvc0_fb_vram_new; + priv->base.ram.put = nv50_fb_vram_del; + + ret = nvc0_vram_detect(priv); + if (ret) + return ret; + + priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!priv->r100c10_page) + return -ENOMEM; + + priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(device->pdev, priv->r100c10)) + return -EFAULT; + + return nouveau_fb_created(&priv->base); +} + + +struct nouveau_oclass +nvc0_fb_oclass = { + .handle = NV_SUBDEV(FB, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_fb_ctor, + .dtor = nvc0_fb_dtor, + .init = nvc0_fb_init, + .fini = _nouveau_fb_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c new file mode 100644 index 00000000000..abb135f7495 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -0,0 +1,271 @@ +/* + * Copyright 2011 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/gpio.h> +#include <subdev/bios.h> +#include <subdev/bios/gpio.h> + +static int +nouveau_gpio_drive(struct nouveau_gpio *gpio, + int idx, int line, int dir, int out) +{ + return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV; +} + +static int +nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line) +{ + return gpio->sense ? gpio->sense(gpio, line) : -ENODEV; +} + +static int +nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, + struct dcb_gpio_func *func) +{ + if (line == 0xff && tag == 0xff) + return -EINVAL; + + if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func)) + return 0; + + /* Apple iMac G4 NV18 */ + if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) { + if (tag == DCB_GPIO_TVDAC0) { + *func = (struct dcb_gpio_func) { + .func = DCB_GPIO_TVDAC0, + .line = 4, + .log[0] = 0, + .log[1] = 1, + }; + return 0; + } + } + + return -EINVAL; +} + +static int +nouveau_gpio_set(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, int state) +{ + struct dcb_gpio_func func; + int ret; + + ret = nouveau_gpio_find(gpio, idx, tag, line, &func); + if (ret == 0) { + int dir = !!(func.log[state] & 0x02); + int out = !!(func.log[state] & 0x01); + ret = nouveau_gpio_drive(gpio, idx, func.line, dir, out); + } + + return ret; +} + +static int +nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) +{ + struct dcb_gpio_func func; + int ret; + + ret = nouveau_gpio_find(gpio, idx, tag, line, &func); + if (ret == 0) { + ret = nouveau_gpio_sense(gpio, idx, func.line); + if (ret >= 0) + ret = (ret == (func.log[1] & 1)); + } + + return ret; +} + +static int +nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on) +{ + struct dcb_gpio_func func; + int ret; + + ret = nouveau_gpio_find(gpio, idx, tag, line, &func); + if (ret == 0) { + if (idx == 0 && gpio->irq_enable) + gpio->irq_enable(gpio, func.line, on); + else + ret = -ENODEV; + } + + return ret; +} + +struct gpio_isr { + struct nouveau_gpio *gpio; + struct list_head head; + struct work_struct work; + int idx; + struct dcb_gpio_func func; + void (*handler)(void *, int); + void *data; + bool inhibit; +}; + +static void +nouveau_gpio_isr_bh(struct work_struct *work) +{ + struct gpio_isr *isr = container_of(work, struct gpio_isr, work); + struct nouveau_gpio *gpio = isr->gpio; + unsigned long flags; + int state; + + state = nouveau_gpio_get(gpio, isr->idx, isr->func.func, + isr->func.line); + if (state >= 0) + isr->handler(isr->data, state); + + spin_lock_irqsave(&gpio->lock, flags); + isr->inhibit = false; + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void +nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask) +{ + struct gpio_isr *isr; + + if (idx != 0) + return; + + spin_lock(&gpio->lock); + list_for_each_entry(isr, &gpio->isr, head) { + if (line_mask & (1 << isr->func.line)) { + if (isr->inhibit) + continue; + isr->inhibit = true; + schedule_work(&isr->work); + } + } + spin_unlock(&gpio->lock); +} + +static int +nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, + void (*handler)(void *, int), void *data) +{ + struct gpio_isr *isr; + unsigned long flags; + int ret; + + isr = kzalloc(sizeof(*isr), GFP_KERNEL); + if (!isr) + return -ENOMEM; + + ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func); + if (ret) { + kfree(isr); + return ret; + } + + INIT_WORK(&isr->work, nouveau_gpio_isr_bh); + isr->gpio = gpio; + isr->handler = handler; + isr->data = data; + isr->idx = idx; + + spin_lock_irqsave(&gpio->lock, flags); + list_add(&isr->head, &gpio->isr); + spin_unlock_irqrestore(&gpio->lock, flags); + return 0; +} + +static void +nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, + void (*handler)(void *, int), void *data) +{ + struct gpio_isr *isr, *tmp; + struct dcb_gpio_func func; + unsigned long flags; + LIST_HEAD(tofree); + int ret; + + ret = nouveau_gpio_find(gpio, idx, tag, line, &func); + if (ret == 0) { + spin_lock_irqsave(&gpio->lock, flags); + list_for_each_entry_safe(isr, tmp, &gpio->isr, head) { + if (memcmp(&isr->func, &func, sizeof(func)) || + isr->idx != idx || + isr->handler != handler || isr->data != data) + continue; + list_move_tail(&isr->head, &tofree); + } + spin_unlock_irqrestore(&gpio->lock, flags); + + list_for_each_entry_safe(isr, tmp, &tofree, head) { + flush_work_sync(&isr->work); + kfree(isr); + } + } +} + +int +nouveau_gpio_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) +{ + struct nouveau_gpio *gpio; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "GPIO", "gpio", + length, pobject); + gpio = *pobject; + if (ret) + return ret; + + gpio->find = nouveau_gpio_find; + gpio->set = nouveau_gpio_set; + gpio->get = nouveau_gpio_get; + gpio->irq = nouveau_gpio_irq; + gpio->isr_run = nouveau_gpio_isr_run; + gpio->isr_add = nouveau_gpio_isr_add; + gpio->isr_del = nouveau_gpio_isr_del; + INIT_LIST_HEAD(&gpio->isr); + spin_lock_init(&gpio->lock); + return 0; +} + +static struct dmi_system_id gpio_reset_ids[] = { + { + .ident = "Apple Macbook 10,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), + } + }, + { } +}; + +int +nouveau_gpio_init(struct nouveau_gpio *gpio) +{ + int ret = nouveau_subdev_init(&gpio->base); + if (ret == 0 && gpio->reset) { + if (dmi_check_system(gpio_reset_ids)) + gpio->reset(gpio); + } + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c new file mode 100644 index 00000000000..168d16a9a8e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <subdev/gpio.h> + +struct nv10_gpio_priv { + struct nouveau_gpio base; +}; + +static int +nv10_gpio_sense(struct nouveau_gpio *gpio, int line) +{ + if (line < 2) { + line = line * 16; + line = nv_rd32(gpio, 0x600818) >> line; + return !!(line & 0x0100); + } else + if (line < 10) { + line = (line - 2) * 4; + line = nv_rd32(gpio, 0x60081c) >> line; + return !!(line & 0x04); + } else + if (line < 14) { + line = (line - 10) * 4; + line = nv_rd32(gpio, 0x600850) >> line; + return !!(line & 0x04); + } + + return -EINVAL; +} + +static int +nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) +{ + u32 reg, mask, data; + + if (line < 2) { + line = line * 16; + reg = 0x600818; + mask = 0x00000011; + data = (dir << 4) | out; + } else + if (line < 10) { + line = (line - 2) * 4; + reg = 0x60081c; + mask = 0x00000003; + data = (dir << 1) | out; + } else + if (line < 14) { + line = (line - 10) * 4; + reg = 0x600850; + mask = 0x00000003; + data = (dir << 1) | out; + } else { + return -EINVAL; + } + + nv_mask(gpio, reg, mask << line, data << line); + return 0; +} + +static void +nv10_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on) +{ + u32 mask = 0x00010001 << line; + + nv_wr32(gpio, 0x001104, mask); + nv_mask(gpio, 0x001144, mask, on ? mask : 0); +} + +static void +nv10_gpio_intr(struct nouveau_subdev *subdev) +{ + struct nv10_gpio_priv *priv = (void *)subdev; + u32 intr = nv_rd32(priv, 0x001104); + u32 hi = (intr & 0x0000ffff) >> 0; + u32 lo = (intr & 0xffff0000) >> 16; + + priv->base.isr_run(&priv->base, 0, hi | lo); + + nv_wr32(priv, 0x001104, intr); +} + +static int +nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv10_gpio_priv *priv; + int ret; + + ret = nouveau_gpio_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.drive = nv10_gpio_drive; + priv->base.sense = nv10_gpio_sense; + priv->base.irq_enable = nv10_gpio_irq_enable; + nv_subdev(priv)->intr = nv10_gpio_intr; + return 0; +} + +static void +nv10_gpio_dtor(struct nouveau_object *object) +{ + struct nv10_gpio_priv *priv = (void *)object; + nouveau_gpio_destroy(&priv->base); +} + +static int +nv10_gpio_init(struct nouveau_object *object) +{ + struct nv10_gpio_priv *priv = (void *)object; + int ret; + + ret = nouveau_gpio_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, 0x001140, 0x00000000); + nv_wr32(priv, 0x001100, 0xffffffff); + nv_wr32(priv, 0x001144, 0x00000000); + nv_wr32(priv, 0x001104, 0xffffffff); + return 0; +} + +static int +nv10_gpio_fini(struct nouveau_object *object, bool suspend) +{ + struct nv10_gpio_priv *priv = (void *)object; + nv_wr32(priv, 0x001140, 0x00000000); + nv_wr32(priv, 0x001144, 0x00000000); + return nouveau_gpio_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv10_gpio_oclass = { + .handle = NV_SUBDEV(GPIO, 0x10), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_gpio_ctor, + .dtor = nv10_gpio_dtor, + .init = nv10_gpio_init, + .fini = nv10_gpio_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c new file mode 100644 index 00000000000..f3502c961cd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -0,0 +1,194 @@ +/* + * 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/gpio.h> + +struct nv50_gpio_priv { + struct nouveau_gpio base; +}; + +static void +nv50_gpio_reset(struct nouveau_gpio *gpio) +{ + struct nouveau_bios *bios = nouveau_bios(gpio); + struct nv50_gpio_priv *priv = (void *)gpio; + u16 entry; + u8 ver; + int ent = -1; + + while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { + static const u32 regs[] = { 0xe100, 0xe28c }; + u32 data = nv_ro32(bios, entry); + u8 line = (data & 0x0000001f); + u8 func = (data & 0x0000ff00) >> 8; + u8 defs = !!(data & 0x01000000); + u8 unk0 = !!(data & 0x02000000); + u8 unk1 = !!(data & 0x04000000); + u32 val = (unk1 << 16) | unk0; + u32 reg = regs[line >> 4]; line &= 0x0f; + + if (func == 0xff) + continue; + + gpio->set(gpio, 0, func, line, defs); + + nv_mask(priv, reg, 0x00010001 << line, val << line); + } +} + +static int +nv50_gpio_location(int line, u32 *reg, u32 *shift) +{ + const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; + + if (line >= 32) + return -EINVAL; + + *reg = nv50_gpio_reg[line >> 3]; + *shift = (line & 7) << 2; + return 0; +} + +static int +nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) +{ + u32 reg, shift; + + if (nv50_gpio_location(line, ®, &shift)) + return -EINVAL; + + nv_mask(gpio, reg, 7 << shift, (((dir ^ 1) << 1) | out) << shift); + return 0; +} + +static int +nv50_gpio_sense(struct nouveau_gpio *gpio, int line) +{ + u32 reg, shift; + + if (nv50_gpio_location(line, ®, &shift)) + return -EINVAL; + + return !!(nv_rd32(gpio, reg) & (4 << shift)); +} + +void +nv50_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on) +{ + u32 reg = line < 16 ? 0xe050 : 0xe070; + u32 mask = 0x00010001 << (line & 0xf); + + nv_wr32(gpio, reg + 4, mask); + nv_mask(gpio, reg + 0, mask, on ? mask : 0); +} + +void +nv50_gpio_intr(struct nouveau_subdev *subdev) +{ + struct nv50_gpio_priv *priv = (void *)subdev; + u32 intr0, intr1 = 0; + u32 hi, lo; + + intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); + if (nv_device(priv)->chipset >= 0x90) + intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070); + + hi = (intr0 & 0x0000ffff) | (intr1 << 16); + lo = (intr0 >> 16) | (intr1 & 0xffff0000); + priv->base.isr_run(&priv->base, 0, hi | lo); + + nv_wr32(priv, 0xe054, intr0); + if (nv_device(priv)->chipset >= 0x90) + nv_wr32(priv, 0xe074, intr1); +} + +static int +nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_gpio_priv *priv; + int ret; + + ret = nouveau_gpio_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.reset = nv50_gpio_reset; + priv->base.drive = nv50_gpio_drive; + priv->base.sense = nv50_gpio_sense; + priv->base.irq_enable = nv50_gpio_irq_enable; + nv_subdev(priv)->intr = nv50_gpio_intr; + return 0; +} + +void +nv50_gpio_dtor(struct nouveau_object *object) +{ + struct nv50_gpio_priv *priv = (void *)object; + nouveau_gpio_destroy(&priv->base); +} + +int +nv50_gpio_init(struct nouveau_object *object) +{ + struct nv50_gpio_priv *priv = (void *)object; + int ret; + + ret = nouveau_gpio_init(&priv->base); + if (ret) + return ret; + + /* disable, and ack any pending gpio interrupts */ + nv_wr32(priv, 0xe050, 0x00000000); + nv_wr32(priv, 0xe054, 0xffffffff); + if (nv_device(priv)->chipset >= 0x90) { + nv_wr32(priv, 0xe070, 0x00000000); + nv_wr32(priv, 0xe074, 0xffffffff); + } + + return 0; +} + +int +nv50_gpio_fini(struct nouveau_object *object, bool suspend) +{ + struct nv50_gpio_priv *priv = (void *)object; + nv_wr32(priv, 0xe050, 0x00000000); + if (nv_device(priv)->chipset >= 0x90) + nv_wr32(priv, 0xe070, 0x00000000); + return nouveau_gpio_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv50_gpio_oclass = { + .handle = NV_SUBDEV(GPIO, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_gpio_ctor, + .dtor = nv50_gpio_dtor, + .init = nv50_gpio_init, + .fini = nv50_gpio_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c new file mode 100644 index 00000000000..8d18fcad26e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.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 <subdev/gpio.h> + +struct nvd0_gpio_priv { + struct nouveau_gpio base; +}; + +static void +nvd0_gpio_reset(struct nouveau_gpio *gpio) +{ + struct nouveau_bios *bios = nouveau_bios(gpio); + struct nvd0_gpio_priv *priv = (void *)gpio; + u16 entry; + u8 ver; + int ent = -1; + + while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { + u32 data = nv_ro32(bios, entry); + u8 line = (data & 0x0000003f); + u8 defs = !!(data & 0x00000080); + u8 func = (data & 0x0000ff00) >> 8; + u8 unk0 = (data & 0x00ff0000) >> 16; + u8 unk1 = (data & 0x1f000000) >> 24; + + if (func == 0xff) + continue; + + gpio->set(gpio, 0, func, line, defs); + + nv_mask(priv, 0x00d610 + (line * 4), 0xff, unk0); + if (unk1--) + nv_mask(priv, 0x00d740 + (unk1 * 4), 0xff, line); + } +} + +static int +nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) +{ + u32 data = ((dir ^ 1) << 13) | (out << 12); + nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data); + nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */ + return 0; +} + +static int +nvd0_gpio_sense(struct nouveau_gpio *gpio, int line) +{ + return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); +} + +static int +nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvd0_gpio_priv *priv; + int ret; + + ret = nouveau_gpio_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.reset = nvd0_gpio_reset; + priv->base.drive = nvd0_gpio_drive; + priv->base.sense = nvd0_gpio_sense; + priv->base.irq_enable = nv50_gpio_irq_enable; + nv_subdev(priv)->intr = nv50_gpio_intr; + return 0; +} + +struct nouveau_oclass +nvd0_gpio_oclass = { + .handle = NV_SUBDEV(GPIO, 0xd0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvd0_gpio_ctor, + .dtor = nv50_gpio_dtor, + .init = nv50_gpio_init, + .fini = nv50_gpio_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c new file mode 100644 index 00000000000..fe1ebf199ba --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c @@ -0,0 +1,212 @@ +/* + * Copyright 2009 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/i2c.h> + +/****************************************************************************** + * aux channel util functions + *****************************************************************************/ +#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) + +static void +auxch_fini(struct nouveau_i2c *aux, int ch) +{ + nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); +} + +static int +auxch_init(struct nouveau_i2c *aux, int ch) +{ + const u32 unksel = 1; /* nfi which to use, or if it matters.. */ + const u32 ureq = unksel ? 0x00100000 : 0x00200000; + const u32 urep = unksel ? 0x01000000 : 0x02000000; + u32 ctrl, timeout; + + /* wait up to 1ms for any previous transaction to be done... */ + timeout = 1000; + do { + ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR("begin idle timeout 0x%08x", ctrl); + return -EBUSY; + } + } while (ctrl & 0x03010000); + + /* set some magic, and wait up to 1ms for it to appear */ + nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); + timeout = 1000; + do { + ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR("magic wait 0x%08x\n", ctrl); + auxch_fini(aux, ch); + return -EBUSY; + } + } while ((ctrl & 0x03000000) != urep); + + return 0; +} + +static int +auxch_tx(struct nouveau_i2c *aux, int ch, u8 type, u32 addr, u8 *data, u8 size) +{ + u32 ctrl, stat, timeout, retries; + u32 xbuf[4] = {}; + int ret, i; + + AUX_DBG("%d: 0x%08x %d\n", type, addr, size); + + ret = auxch_init(aux, ch); + if (ret) + goto out; + + stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50)); + if (!(stat & 0x10000000)) { + AUX_DBG("sink not detected\n"); + ret = -ENXIO; + goto out; + } + + if (!(type & 1)) { + memcpy(xbuf, data, size); + for (i = 0; i < 16; i += 4) { + AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); + nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); + } + } + + ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + ctrl &= ~0x0001f0ff; + ctrl |= type << 12; + ctrl |= size - 1; + nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); + + /* retry transaction a number of times on failure... */ + ret = -EREMOTEIO; + for (retries = 0; retries < 32; retries++) { + /* reset, and delay a while if this is a retry */ + nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); + nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); + if (retries) + udelay(400); + + /* transaction request, wait up to 1ms for it to complete */ + nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); + + timeout = 1000; + do { + ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR("tx req timeout 0x%08x\n", ctrl); + goto out; + } + } while (ctrl & 0x00010000); + + /* read status, and check if transaction completed ok */ + stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); + if (!(stat & 0x000f0f00)) { + ret = 0; + break; + } + + AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); + } + + if (type & 1) { + for (i = 0; i < 16; i += 4) { + xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i); + AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); + } + memcpy(data, xbuf, size); + } + +out: + auxch_fini(aux, ch); + return ret; +} + +int +nv_rdaux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) +{ + return auxch_tx(auxch->i2c, auxch->drive, 9, addr, data, size); +} + +int +nv_wraux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) +{ + return auxch_tx(auxch->i2c, auxch->drive, 8, addr, data, size); +} + +static int +aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nouveau_i2c_port *auxch = (struct nouveau_i2c_port *)adap; + struct i2c_msg *msg = msgs; + int ret, mcnt = num; + + while (mcnt--) { + u8 remaining = msg->len; + u8 *ptr = msg->buf; + + while (remaining) { + u8 cnt = (remaining > 16) ? 16 : remaining; + u8 cmd; + + if (msg->flags & I2C_M_RD) + cmd = 1; + else + cmd = 0; + + if (mcnt || remaining > 16) + cmd |= 4; /* MOT */ + + ret = auxch_tx(auxch->i2c, auxch->drive, cmd, + msg->addr, ptr, cnt); + if (ret < 0) + return ret; + + ptr += cnt; + remaining -= cnt; + } + + msg++; + } + + return num; +} + +static u32 +aux_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +const struct i2c_algorithm nouveau_i2c_aux_algo = { + .master_xfer = aux_xfer, + .functionality = aux_func +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c new file mode 100644 index 00000000000..3d2c88310f9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c @@ -0,0 +1,407 @@ +/* + * 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/option.h" + +#include "subdev/i2c.h" +#include "subdev/vga.h" + +int +nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) +{ + u8 val; + struct i2c_msg msgs[] = { + { .addr = addr, .flags = 0, .len = 1, .buf = ® }, + { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val }, + }; + + int ret = i2c_transfer(&port->adapter, msgs, 2); + if (ret != 2) + return -EIO; + + return val; +} + +int +nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val) +{ + struct i2c_msg msgs[] = { + { .addr = addr, .flags = 0, .len = 1, .buf = ® }, + { .addr = addr, .flags = 0, .len = 1, .buf = &val }, + }; + + int ret = i2c_transfer(&port->adapter, msgs, 2); + if (ret != 2) + return -EIO; + + return 0; +} + +bool +nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr) +{ + u8 buf[] = { 0 }; + struct i2c_msg msgs[] = { + { + .addr = addr, + .flags = 0, + .len = 1, + .buf = buf, + }, + { + .addr = addr, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + return i2c_transfer(&port->adapter, msgs, 2) == 2; +} + +static struct nouveau_i2c_port * +nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index) +{ + struct nouveau_bios *bios = nouveau_bios(i2c); + struct nouveau_i2c_port *port; + + if (index == NV_I2C_DEFAULT(0) || + index == NV_I2C_DEFAULT(1)) { + u8 ver, hdr, cnt, len; + u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len); + if (i2c && ver >= 0x30) { + u8 auxidx = nv_ro08(bios, i2c + 4); + if (index == NV_I2C_DEFAULT(0)) + index = (auxidx & 0x0f) >> 0; + else + index = (auxidx & 0xf0) >> 4; + } else { + index = 2; + } + } + + list_for_each_entry(port, &i2c->ports, head) { + if (port->index == index) + break; + } + + if (&port->head == &i2c->ports) + return NULL; + + if (nv_device(i2c)->card_type >= NV_50 && (port->dcb & 0x00000100)) { + u32 reg = 0x00e500, val; + if (port->type == 6) { + reg += port->drive * 0x50; + val = 0x2002; + } else { + reg += ((port->dcb & 0x1e00) >> 9) * 0x50; + val = 0xe001; + } + + /* nfi, but neither auxch or i2c work if it's 1 */ + nv_mask(i2c, reg + 0x0c, 0x00000001, 0x00000000); + /* nfi, but switches auxch vs normal i2c */ + nv_mask(i2c, reg + 0x00, 0x0000f003, val); + } + + return port; +} + +static int +nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, + struct i2c_board_info *info, + bool (*match)(struct nouveau_i2c_port *, + struct i2c_board_info *)) +{ + struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index); + int i; + + if (!port) { + nv_debug(i2c, "no bus when probing %s on %d\n", what, index); + return -ENODEV; + } + + nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index); + for (i = 0; info[i].addr; i++) { + if (nv_probe_i2c(port, info[i].addr) && + (!match || match(port, &info[i]))) { + nv_info(i2c, "detected %s: %s\n", what, info[i].type); + return i; + } + } + + nv_debug(i2c, "no devices found.\n"); + return -ENODEV; +} + +void +nouveau_i2c_drive_scl(void *data, int state) +{ + struct nouveau_i2c_port *port = data; + + if (port->type == DCB_I2C_NV04_BIT) { + u8 val = nv_rdvgac(port->i2c, 0, port->drive); + if (state) val |= 0x20; + else val &= 0xdf; + nv_wrvgac(port->i2c, 0, port->drive, val | 0x01); + } else + if (port->type == DCB_I2C_NV4E_BIT) { + nv_mask(port->i2c, port->drive, 0x2f, state ? 0x21 : 0x01); + } else + if (port->type == DCB_I2C_NVIO_BIT) { + if (state) port->state |= 0x01; + else port->state &= 0xfe; + nv_wr32(port->i2c, port->drive, 4 | port->state); + } +} + +void +nouveau_i2c_drive_sda(void *data, int state) +{ + struct nouveau_i2c_port *port = data; + + if (port->type == DCB_I2C_NV04_BIT) { + u8 val = nv_rdvgac(port->i2c, 0, port->drive); + if (state) val |= 0x10; + else val &= 0xef; + nv_wrvgac(port->i2c, 0, port->drive, val | 0x01); + } else + if (port->type == DCB_I2C_NV4E_BIT) { + nv_mask(port->i2c, port->drive, 0x1f, state ? 0x11 : 0x01); + } else + if (port->type == DCB_I2C_NVIO_BIT) { + if (state) port->state |= 0x02; + else port->state &= 0xfd; + nv_wr32(port->i2c, port->drive, 4 | port->state); + } +} + +int +nouveau_i2c_sense_scl(void *data) +{ + struct nouveau_i2c_port *port = data; + struct nouveau_device *device = nv_device(port->i2c); + + if (port->type == DCB_I2C_NV04_BIT) { + return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x04); + } else + if (port->type == DCB_I2C_NV4E_BIT) { + return !!(nv_rd32(port->i2c, port->sense) & 0x00040000); + } else + if (port->type == DCB_I2C_NVIO_BIT) { + if (device->card_type < NV_D0) + return !!(nv_rd32(port->i2c, port->sense) & 0x01); + else + return !!(nv_rd32(port->i2c, port->sense) & 0x10); + } + + return 0; +} + +int +nouveau_i2c_sense_sda(void *data) +{ + struct nouveau_i2c_port *port = data; + struct nouveau_device *device = nv_device(port->i2c); + + if (port->type == DCB_I2C_NV04_BIT) { + return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x08); + } else + if (port->type == DCB_I2C_NV4E_BIT) { + return !!(nv_rd32(port->i2c, port->sense) & 0x00080000); + } else + if (port->type == DCB_I2C_NVIO_BIT) { + if (device->card_type < NV_D0) + return !!(nv_rd32(port->i2c, port->sense) & 0x02); + else + return !!(nv_rd32(port->i2c, port->sense) & 0x20); + } + + return 0; +} + +static const u32 nv50_i2c_port[] = { + 0x00e138, 0x00e150, 0x00e168, 0x00e180, + 0x00e254, 0x00e274, 0x00e764, 0x00e780, + 0x00e79c, 0x00e7b8 +}; + +static int +nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_bios *bios = nouveau_bios(parent); + struct nouveau_i2c_port *port; + struct nouveau_i2c *i2c; + struct dcb_i2c_entry info; + int ret, i = -1; + + ret = nouveau_subdev_create(parent, engine, oclass, 0, + "I2C", "i2c", &i2c); + *pobject = nv_object(i2c); + if (ret) + return ret; + + i2c->find = nouveau_i2c_find; + i2c->identify = nouveau_i2c_identify; + INIT_LIST_HEAD(&i2c->ports); + + while (!dcb_i2c_parse(bios, ++i, &info)) { + if (info.type == DCB_I2C_UNUSED) + continue; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) { + nv_error(i2c, "failed port memory alloc at %d\n", i); + break; + } + + port->type = info.type; + switch (port->type) { + case DCB_I2C_NV04_BIT: + port->drive = info.drive; + port->sense = info.sense; + break; + case DCB_I2C_NV4E_BIT: + port->drive = 0x600800 + info.drive; + port->sense = port->drive; + break; + case DCB_I2C_NVIO_BIT: + port->drive = info.drive & 0x0f; + if (device->card_type < NV_D0) { + if (info.drive >= ARRAY_SIZE(nv50_i2c_port)) + break; + port->drive = nv50_i2c_port[port->drive]; + port->sense = port->drive; + } else { + port->drive = 0x00d014 + (port->drive * 0x20); + port->sense = port->drive; + } + break; + case DCB_I2C_NVIO_AUX: + port->drive = info.drive & 0x0f; + port->sense = port->drive; + port->adapter.algo = &nouveau_i2c_aux_algo; + break; + default: + break; + } + + if (!port->adapter.algo && !port->drive) { + nv_error(i2c, "I2C%d: type %d index %x/%x unknown\n", + i, port->type, port->drive, port->sense); + kfree(port); + continue; + } + + snprintf(port->adapter.name, sizeof(port->adapter.name), + "nouveau-%s-%d", device->name, i); + port->adapter.owner = THIS_MODULE; + port->adapter.dev.parent = &device->pdev->dev; + port->i2c = i2c; + port->index = i; + port->dcb = info.data; + i2c_set_adapdata(&port->adapter, i2c); + + if (port->adapter.algo != &nouveau_i2c_aux_algo) { + nouveau_i2c_drive_scl(port, 0); + nouveau_i2c_drive_sda(port, 1); + nouveau_i2c_drive_scl(port, 1); + +#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT + if (nouveau_boolopt(device->cfgopt, "NvI2C", true)) { +#else + if (nouveau_boolopt(device->cfgopt, "NvI2C", false)) { +#endif + port->adapter.algo = &nouveau_i2c_bit_algo; + ret = i2c_add_adapter(&port->adapter); + } else { + port->adapter.algo_data = &port->bit; + port->bit.udelay = 10; + port->bit.timeout = usecs_to_jiffies(2200); + port->bit.data = port; + port->bit.setsda = nouveau_i2c_drive_sda; + port->bit.setscl = nouveau_i2c_drive_scl; + port->bit.getsda = nouveau_i2c_sense_sda; + port->bit.getscl = nouveau_i2c_sense_scl; + ret = i2c_bit_add_bus(&port->adapter); + } + } else { + port->adapter.algo = &nouveau_i2c_aux_algo; + ret = i2c_add_adapter(&port->adapter); + } + + if (ret) { + nv_error(i2c, "I2C%d: failed register: %d\n", i, ret); + kfree(port); + continue; + } + + list_add_tail(&port->head, &i2c->ports); + } + + return 0; +} + +static void +nouveau_i2c_dtor(struct nouveau_object *object) +{ + struct nouveau_i2c *i2c = (void *)object; + struct nouveau_i2c_port *port, *temp; + + list_for_each_entry_safe(port, temp, &i2c->ports, head) { + i2c_del_adapter(&port->adapter); + list_del(&port->head); + kfree(port); + } + + nouveau_subdev_destroy(&i2c->base); +} + +static int +nouveau_i2c_init(struct nouveau_object *object) +{ + struct nouveau_i2c *i2c = (void *)object; + return nouveau_subdev_init(&i2c->base); +} + +static int +nouveau_i2c_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_i2c *i2c = (void *)object; + return nouveau_subdev_fini(&i2c->base, suspend); +} + +struct nouveau_oclass +nouveau_i2c_oclass = { + .handle = NV_SUBDEV(I2C, 0x00), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nouveau_i2c_ctor, + .dtor = nouveau_i2c_dtor, + .init = nouveau_i2c_init, + .fini = nouveau_i2c_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c new file mode 100644 index 00000000000..1c4c9a5c8e2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c @@ -0,0 +1,230 @@ +/* + * 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/i2c.h" + +#ifdef CONFIG_NOUVEAU_I2C_INTERNAL +#define T_TIMEOUT 2200000 +#define T_RISEFALL 1000 +#define T_HOLD 5000 + +static inline void +i2c_drive_scl(struct nouveau_i2c_port *port, int state) +{ + nouveau_i2c_drive_scl(port, state); +} + +static inline void +i2c_drive_sda(struct nouveau_i2c_port *port, int state) +{ + nouveau_i2c_drive_sda(port, state); +} + +static inline int +i2c_sense_scl(struct nouveau_i2c_port *port) +{ + return nouveau_i2c_sense_scl(port); +} + +static inline int +i2c_sense_sda(struct nouveau_i2c_port *port) +{ + return nouveau_i2c_sense_sda(port); +} + +static void +i2c_delay(struct nouveau_i2c_port *port, u32 nsec) +{ + udelay((nsec + 500) / 1000); +} + +static bool +i2c_raise_scl(struct nouveau_i2c_port *port) +{ + u32 timeout = T_TIMEOUT / T_RISEFALL; + + i2c_drive_scl(port, 1); + do { + i2c_delay(port, T_RISEFALL); + } while (!i2c_sense_scl(port) && --timeout); + + return timeout != 0; +} + +static int +i2c_start(struct nouveau_i2c_port *port) +{ + int ret = 0; + + port->state = i2c_sense_scl(port); + port->state |= i2c_sense_sda(port) << 1; + if (port->state != 3) { + i2c_drive_scl(port, 0); + i2c_drive_sda(port, 1); + if (!i2c_raise_scl(port)) + ret = -EBUSY; + } + + i2c_drive_sda(port, 0); + i2c_delay(port, T_HOLD); + i2c_drive_scl(port, 0); + i2c_delay(port, T_HOLD); + return ret; +} + +static void +i2c_stop(struct nouveau_i2c_port *port) +{ + i2c_drive_scl(port, 0); + i2c_drive_sda(port, 0); + i2c_delay(port, T_RISEFALL); + + i2c_drive_scl(port, 1); + i2c_delay(port, T_HOLD); + i2c_drive_sda(port, 1); + i2c_delay(port, T_HOLD); +} + +static int +i2c_bitw(struct nouveau_i2c_port *port, int sda) +{ + i2c_drive_sda(port, sda); + i2c_delay(port, T_RISEFALL); + + if (!i2c_raise_scl(port)) + return -ETIMEDOUT; + i2c_delay(port, T_HOLD); + + i2c_drive_scl(port, 0); + i2c_delay(port, T_HOLD); + return 0; +} + +static int +i2c_bitr(struct nouveau_i2c_port *port) +{ + int sda; + + i2c_drive_sda(port, 1); + i2c_delay(port, T_RISEFALL); + + if (!i2c_raise_scl(port)) + return -ETIMEDOUT; + i2c_delay(port, T_HOLD); + + sda = i2c_sense_sda(port); + + i2c_drive_scl(port, 0); + i2c_delay(port, T_HOLD); + return sda; +} + +static int +i2c_get_byte(struct nouveau_i2c_port *port, u8 *byte, bool last) +{ + int i, bit; + + *byte = 0; + for (i = 7; i >= 0; i--) { + bit = i2c_bitr(port); + if (bit < 0) + return bit; + *byte |= bit << i; + } + + return i2c_bitw(port, last ? 1 : 0); +} + +static int +i2c_put_byte(struct nouveau_i2c_port *port, u8 byte) +{ + int i, ret; + for (i = 7; i >= 0; i--) { + ret = i2c_bitw(port, !!(byte & (1 << i))); + if (ret < 0) + return ret; + } + + ret = i2c_bitr(port); + if (ret == 1) /* nack */ + ret = -EIO; + return ret; +} + +static int +i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg) +{ + u32 addr = msg->addr << 1; + if (msg->flags & I2C_M_RD) + addr |= 1; + return i2c_put_byte(port, addr); +} + +static int +i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap; + struct i2c_msg *msg = msgs; + int ret = 0, mcnt = num; + + while (!ret && mcnt--) { + u8 remaining = msg->len; + u8 *ptr = msg->buf; + + ret = i2c_start(port); + if (ret == 0) + ret = i2c_addr(port, msg); + + if (msg->flags & I2C_M_RD) { + while (!ret && remaining--) + ret = i2c_get_byte(port, ptr++, !remaining); + } else { + while (!ret && remaining--) + ret = i2c_put_byte(port, *ptr++); + } + + msg++; + } + + i2c_stop(port); + return (ret < 0) ? ret : num; +} +#else +static int +i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + return -ENODEV; +} +#endif + +static u32 +i2c_bit_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +const struct i2c_algorithm nouveau_i2c_bit_algo = { + .master_xfer = i2c_bit_xfer, + .functionality = i2c_bit_func +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c new file mode 100644 index 00000000000..4e977ff27e4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c @@ -0,0 +1,123 @@ +/* + * 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/ibus.h> + +struct nvc0_ibus_priv { + struct nouveau_ibus base; +}; + +static void +nvc0_ibus_intr_hub(struct nvc0_ibus_priv *priv, int i) +{ + u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0400)); + u32 data = nv_rd32(priv, 0x122124 + (i * 0x0400)); + u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0400)); + nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(priv, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); +} + +static void +nvc0_ibus_intr_rop(struct nvc0_ibus_priv *priv, int i) +{ + u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0400)); + u32 data = nv_rd32(priv, 0x124124 + (i * 0x0400)); + u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0400)); + nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(priv, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); +} + +static void +nvc0_ibus_intr_gpc(struct nvc0_ibus_priv *priv, int i) +{ + u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0400)); + u32 data = nv_rd32(priv, 0x128124 + (i * 0x0400)); + u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0400)); + nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(priv, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); +} + +static void +nvc0_ibus_intr(struct nouveau_subdev *subdev) +{ + struct nvc0_ibus_priv *priv = (void *)subdev; + u32 intr0 = nv_rd32(priv, 0x121c58); + u32 intr1 = nv_rd32(priv, 0x121c5c); + u32 hubnr = nv_rd32(priv, 0x121c70); + u32 ropnr = nv_rd32(priv, 0x121c74); + u32 gpcnr = nv_rd32(priv, 0x121c78); + u32 i; + + for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { + u32 stat = 0x00000100 << i; + if (intr0 & stat) { + nvc0_ibus_intr_hub(priv, i); + intr0 &= ~stat; + } + } + + for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) { + u32 stat = 0x00010000 << i; + if (intr0 & stat) { + nvc0_ibus_intr_rop(priv, i); + intr0 &= ~stat; + } + } + + for (i = 0; intr1 && i < gpcnr; i++) { + u32 stat = 0x00000001 << i; + if (intr1 & stat) { + nvc0_ibus_intr_gpc(priv, i); + intr1 &= ~stat; + } + } +} + +static int +nvc0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_ibus_priv *priv; + int ret; + + ret = nouveau_ibus_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = nvc0_ibus_intr; + return 0; +} + +struct nouveau_oclass +nvc0_ibus_oclass = { + .handle = NV_SUBDEV(IBUS, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_ibus_ctor, + .dtor = _nouveau_ibus_dtor, + .init = _nouveau_ibus_init, + .fini = _nouveau_ibus_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c new file mode 100644 index 00000000000..7120124dcea --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c @@ -0,0 +1,123 @@ +/* + * 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/ibus.h> + +struct nve0_ibus_priv { + struct nouveau_ibus base; +}; + +static void +nve0_ibus_intr_hub(struct nve0_ibus_priv *priv, int i) +{ + u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0800)); + u32 data = nv_rd32(priv, 0x122124 + (i * 0x0800)); + u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0800)); + nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(priv, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); +} + +static void +nve0_ibus_intr_rop(struct nve0_ibus_priv *priv, int i) +{ + u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0800)); + u32 data = nv_rd32(priv, 0x124124 + (i * 0x0800)); + u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0800)); + nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(priv, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); +} + +static void +nve0_ibus_intr_gpc(struct nve0_ibus_priv *priv, int i) +{ + u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0800)); + u32 data = nv_rd32(priv, 0x128124 + (i * 0x0800)); + u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0800)); + nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(priv, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); +} + +static void +nve0_ibus_intr(struct nouveau_subdev *subdev) +{ + struct nve0_ibus_priv *priv = (void *)subdev; + u32 intr0 = nv_rd32(priv, 0x120058); + u32 intr1 = nv_rd32(priv, 0x12005c); + u32 hubnr = nv_rd32(priv, 0x120070); + u32 ropnr = nv_rd32(priv, 0x120074); + u32 gpcnr = nv_rd32(priv, 0x120078); + u32 i; + + for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { + u32 stat = 0x00000100 << i; + if (intr0 & stat) { + nve0_ibus_intr_hub(priv, i); + intr0 &= ~stat; + } + } + + for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) { + u32 stat = 0x00010000 << i; + if (intr0 & stat) { + nve0_ibus_intr_rop(priv, i); + intr0 &= ~stat; + } + } + + for (i = 0; intr1 && i < gpcnr; i++) { + u32 stat = 0x00000001 << i; + if (intr1 & stat) { + nve0_ibus_intr_gpc(priv, i); + intr1 &= ~stat; + } + } +} + +static int +nve0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nve0_ibus_priv *priv; + int ret; + + ret = nouveau_ibus_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = nve0_ibus_intr; + return 0; +} + +struct nouveau_oclass +nve0_ibus_oclass = { + .handle = NV_SUBDEV(IBUS, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_ibus_ctor, + .dtor = _nouveau_ibus_dtor, + .init = _nouveau_ibus_init, + .fini = _nouveau_ibus_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c new file mode 100644 index 00000000000..1188227ca6a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c @@ -0,0 +1,135 @@ +/* + * 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/instmem.h> + +int +nouveau_instobj_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + int length, void **pobject) +{ + struct nouveau_instmem *imem = (void *)engine; + struct nouveau_instobj *iobj; + int ret; + + ret = nouveau_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS, + length, pobject); + iobj = *pobject; + if (ret) + return ret; + + list_add(&iobj->head, &imem->list); + return 0; +} + +void +nouveau_instobj_destroy(struct nouveau_instobj *iobj) +{ + if (iobj->head.prev) + list_del(&iobj->head); + return nouveau_object_destroy(&iobj->base); +} + +void +_nouveau_instobj_dtor(struct nouveau_object *object) +{ + struct nouveau_instobj *iobj = (void *)object; + return nouveau_instobj_destroy(iobj); +} + +int +nouveau_instmem_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + int length, void **pobject) +{ + struct nouveau_instmem *imem; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, + "INSTMEM", "instmem", length, pobject); + imem = *pobject; + if (ret) + return ret; + + INIT_LIST_HEAD(&imem->list); + return 0; +} + +int +nouveau_instmem_init(struct nouveau_instmem *imem) +{ + struct nouveau_instobj *iobj; + int ret, i; + + ret = nouveau_subdev_init(&imem->base); + if (ret) + return ret; + + list_for_each_entry(iobj, &imem->list, head) { + if (iobj->suspend) { + for (i = 0; i < iobj->size; i += 4) + nv_wo32(iobj, i, iobj->suspend[i / 4]); + vfree(iobj->suspend); + iobj->suspend = NULL; + } + } + + return 0; +} + +int +nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) +{ + struct nouveau_instobj *iobj; + int i; + + if (suspend) { + list_for_each_entry(iobj, &imem->list, head) { + iobj->suspend = vmalloc(iobj->size); + if (iobj->suspend) { + for (i = 0; i < iobj->size; i += 4) + iobj->suspend[i / 4] = nv_ro32(iobj, i); + } else + return -ENOMEM; + } + } + + return nouveau_subdev_fini(&imem->base, suspend); +} + +int +_nouveau_instmem_init(struct nouveau_object *object) +{ + struct nouveau_instmem *imem = (void *)object; + return nouveau_instmem_init(imem); +} + +int +_nouveau_instmem_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_instmem *imem = (void *)object; + return nouveau_instmem_fini(imem, suspend); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c new file mode 100644 index 00000000000..ba4d28b5036 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.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 <subdev/fb.h> + +#include "nv04.h" + +static int +nv04_instobj_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 *priv = (void *)engine; + struct nv04_instobj_priv *node; + int ret, align; + + align = (unsigned long)data; + if (!align) + align = 1; + + ret = nouveau_instobj_create(parent, engine, oclass, &node); + *pobject = nv_object(node); + if (ret) + return ret; + + ret = nouveau_mm_head(&priv->heap, 1, size, size, align, &node->mem); + if (ret) + return ret; + + node->base.addr = node->mem->offset; + node->base.size = node->mem->length; + return 0; +} + +static void +nv04_instobj_dtor(struct nouveau_object *object) +{ + struct nv04_instmem_priv *priv = (void *)object->engine; + struct nv04_instobj_priv *node = (void *)object; + nouveau_mm_free(&priv->heap, &node->mem); + nouveau_instobj_destroy(&node->base); +} + +static u32 +nv04_instobj_rd32(struct nouveau_object *object, u32 addr) +{ + struct nv04_instobj_priv *node = (void *)object; + return nv_ro32(object->engine, node->mem->offset + addr); +} + +static void +nv04_instobj_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + struct nv04_instobj_priv *node = (void *)object; + nv_wo32(object->engine, node->mem->offset + addr, data); +} + +static struct nouveau_oclass +nv04_instobj_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_instobj_ctor, + .dtor = nv04_instobj_dtor, + .init = _nouveau_instobj_init, + .fini = _nouveau_instobj_fini, + .rd32 = nv04_instobj_rd32, + .wr32 = nv04_instobj_wr32, + }, +}; + +int +nv04_instmem_alloc(struct nouveau_instmem *imem, struct nouveau_object *parent, + u32 size, u32 align, struct nouveau_object **pobject) +{ + struct nouveau_object *engine = nv_object(imem); + struct nv04_instmem_priv *priv = (void *)(imem); + int ret; + + ret = nouveau_object_ctor(parent, engine, &nv04_instobj_oclass, + (void *)(unsigned long)align, size, pobject); + if (ret) + return ret; + + /* INSTMEM itself creates objects to reserve (and preserve across + * suspend/resume) various fixed data locations, each one of these + * takes a reference on INSTMEM itself, causing it to never be + * freed. We drop all the self-references here to avoid this. + */ + if (unlikely(!priv->created)) + atomic_dec(&engine->refcount); + + return 0; +} + +static int +nv04_instmem_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 *priv; + int ret; + + ret = nouveau_instmem_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + /* PRAMIN aperture maps over the end of VRAM, reserve it */ + priv->base.reserved = 512 * 1024; + priv->base.alloc = nv04_instmem_alloc; + + ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1); + if (ret) + return ret; + + /* 0x00000-0x10000: reserve for probable vbios image */ + ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0, 0, &priv->vbios); + if (ret) + return ret; + + /* 0x10000-0x18000: reserve for RAMHT */ + ret = nouveau_ramht_new(parent, NULL, 0x08000, 0, &priv->ramht); + if (ret) + return ret; + + /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */ + ret = nouveau_gpuobj_new(parent, NULL, 0x00800, 0, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc); + if (ret) + return ret; + + /* 0x18800-0x18a00: reserve for RAMRO */ + ret = nouveau_gpuobj_new(parent, NULL, 0x00200, 0, 0, &priv->ramro); + if (ret) + return ret; + + priv->created = true; + return 0; +} + +void +nv04_instmem_dtor(struct nouveau_object *object) +{ + struct nv04_instmem_priv *priv = (void *)object; + nouveau_gpuobj_ref(NULL, &priv->ramfc); + nouveau_gpuobj_ref(NULL, &priv->ramro); + nouveau_ramht_ref(NULL, &priv->ramht); + nouveau_gpuobj_ref(NULL, &priv->vbios); + nouveau_mm_fini(&priv->heap); + if (priv->iomem) + iounmap(priv->iomem); + nouveau_instmem_destroy(&priv->base); +} + +static u32 +nv04_instmem_rd32(struct nouveau_object *object, u32 addr) +{ + return nv_rd32(object, 0x700000 + addr); +} + +static void +nv04_instmem_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + return nv_wr32(object, 0x700000 + addr, data); +} + +struct nouveau_oclass +nv04_instmem_oclass = { + .handle = NV_SUBDEV(INSTMEM, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_instmem_ctor, + .dtor = nv04_instmem_dtor, + .init = _nouveau_instmem_init, + .fini = _nouveau_instmem_fini, + .rd32 = nv04_instmem_rd32, + .wr32 = nv04_instmem_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h new file mode 100644 index 00000000000..7983d8d9b35 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h @@ -0,0 +1,39 @@ +#ifndef __NV04_INSTMEM_H__ +#define __NV04_INSTMEM_H__ + +#include <core/gpuobj.h> +#include <core/ramht.h> +#include <core/mm.h> + +#include <subdev/instmem.h> + +struct nv04_instmem_priv { + struct nouveau_instmem base; + bool created; + + void __iomem *iomem; + struct nouveau_mm heap; + + struct nouveau_gpuobj *vbios; + struct nouveau_ramht *ramht; + struct nouveau_gpuobj *ramro; + struct nouveau_gpuobj *ramfc; +}; + +static inline struct nv04_instmem_priv * +nv04_instmem(void *obj) +{ + return (void *)nouveau_instmem(obj); +} + +struct nv04_instobj_priv { + struct nouveau_instobj base; + struct nouveau_mm_node *mem; +}; + +void nv04_instmem_dtor(struct nouveau_object *); + +int nv04_instmem_alloc(struct nouveau_instmem *, struct nouveau_object *, + u32 size, u32 align, struct nouveau_object **pobject); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c new file mode 100644 index 00000000000..73c52ebd593 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c @@ -0,0 +1,138 @@ +/* + * 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 "nv04.h" + +static inline int +nv44_graph_class(struct nv04_instmem_priv *priv) +{ + if ((nv_device(priv)->chipset & 0xf0) == 0x60) + return 1; + return !(0x0baf & (1 << (nv_device(priv)->chipset & 0x0f))); +} + +static int +nv40_instmem_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 pci_dev *pdev = device->pdev; + struct nv04_instmem_priv *priv; + int ret, bar, vs; + + ret = nouveau_instmem_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + /* map bar */ + if (pci_resource_len(pdev, 2)) + bar = 2; + else + bar = 3; + + priv->iomem = ioremap(pci_resource_start(pdev, bar), + pci_resource_len(pdev, bar)); + if (!priv->iomem) { + nv_error(priv, "unable to map PRAMIN BAR\n"); + return -EFAULT; + } + + /* PRAMIN aperture maps over the end of vram, reserve enough space + * to fit graphics contexts for every channel, the magics come + * from engine/graph/nv40.c + */ + vs = hweight8((nv_rd32(priv, 0x001540) & 0x0000ff00) >> 8); + if (device->chipset == 0x40) priv->base.reserved = 0x6aa0 * vs; + else if (device->chipset < 0x43) priv->base.reserved = 0x4f00 * vs; + else if (nv44_graph_class(priv)) priv->base.reserved = 0x4980 * vs; + else priv->base.reserved = 0x4a40 * vs; + priv->base.reserved += 16 * 1024; + priv->base.reserved *= 32; /* per-channel */ + priv->base.reserved += 512 * 1024; /* pci(e)gart table */ + priv->base.reserved += 512 * 1024; /* object storage */ + + priv->base.reserved = round_up(priv->base.reserved, 4096); + priv->base.alloc = nv04_instmem_alloc; + + ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1); + if (ret) + return ret; + + /* 0x00000-0x10000: reserve for probable vbios image */ + ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0, 0, &priv->vbios); + if (ret) + return ret; + + /* 0x10000-0x18000: reserve for RAMHT */ + ret = nouveau_ramht_new(parent, NULL, 0x08000, 0, &priv->ramht); + if (ret) + return ret; + + /* 0x18000-0x18200: reserve for RAMRO + * 0x18200-0x20000: padding + */ + ret = nouveau_gpuobj_new(parent, NULL, 0x08000, 0, 0, &priv->ramro); + if (ret) + return ret; + + /* 0x20000-0x21000: reserve for RAMFC + * 0x21000-0x40000: padding and some unknown crap + */ + ret = nouveau_gpuobj_new(parent, NULL, 0x20000, 0, + NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc); + if (ret) + return ret; + + priv->created = true; + return 0; +} + +static u32 +nv40_instmem_rd32(struct nouveau_object *object, u32 addr) +{ + struct nv04_instmem_priv *priv = (void *)object; + return ioread32_native(priv->iomem + addr); +} + +static void +nv40_instmem_wr32(struct nouveau_object *object, u32 addr, u32 data) +{ + struct nv04_instmem_priv *priv = (void *)object; + iowrite32_native(data, priv->iomem + addr); +} + +struct nouveau_oclass +nv40_instmem_oclass = { + .handle = NV_SUBDEV(INSTMEM, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_instmem_ctor, + .dtor = nv04_instmem_dtor, + .init = _nouveau_instmem_init, + .fini = _nouveau_instmem_fini, + .rd32 = nv40_instmem_rd32, + .wr32 = nv40_instmem_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c new file mode 100644 index 00000000000..27ef0891d10 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c @@ -0,0 +1,172 @@ +/* + * 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/instmem.h> +#include <subdev/fb.h> + +#include <core/mm.h> + +struct nv50_instmem_priv { + struct nouveau_instmem base; + spinlock_t lock; + u64 addr; +}; + +struct nv50_instobj_priv { + struct nouveau_instobj base; + struct nouveau_mem *mem; +}; + +static int +nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_fb *pfb = nouveau_fb(parent); + struct nv50_instobj_priv *node; + u32 align = (unsigned long)data; + int ret; + + size = max((size + 4095) & ~4095, (u32)4096); + align = max((align + 4095) & ~4095, (u32)4096); + + ret = nouveau_instobj_create(parent, engine, oclass, &node); + *pobject = nv_object(node); + if (ret) + return ret; + + ret = pfb->ram.get(pfb, size, align, 0, 0x800, &node->mem); + if (ret) + return ret; + + node->base.addr = node->mem->offset; + node->base.size = node->mem->size << 12; + node->mem->page_shift = 12; + return 0; +} + +static void +nv50_instobj_dtor(struct nouveau_object *object) +{ + struct nv50_instobj_priv *node = (void *)object; + struct nouveau_fb *pfb = nouveau_fb(object); + pfb->ram.put(pfb, &node->mem); + nouveau_instobj_destroy(&node->base); +} + +static u32 +nv50_instobj_rd32(struct nouveau_object *object, u32 offset) +{ + struct nv50_instmem_priv *priv = (void *)object->engine; + struct nv50_instobj_priv *node = (void *)object; + unsigned long flags; + u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; + u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; + u32 data; + + spin_lock_irqsave(&priv->lock, flags); + if (unlikely(priv->addr != base)) { + nv_wr32(priv, 0x001700, base >> 16); + priv->addr = base; + } + data = nv_rd32(priv, 0x700000 + addr); + spin_unlock_irqrestore(&priv->lock, flags); + return data; +} + +static void +nv50_instobj_wr32(struct nouveau_object *object, u32 offset, u32 data) +{ + struct nv50_instmem_priv *priv = (void *)object->engine; + struct nv50_instobj_priv *node = (void *)object; + unsigned long flags; + u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; + u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; + + spin_lock_irqsave(&priv->lock, flags); + if (unlikely(priv->addr != base)) { + nv_wr32(priv, 0x001700, base >> 16); + priv->addr = base; + } + nv_wr32(priv, 0x700000 + addr, data); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static struct nouveau_oclass +nv50_instobj_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_instobj_ctor, + .dtor = nv50_instobj_dtor, + .init = _nouveau_instobj_init, + .fini = _nouveau_instobj_fini, + .rd32 = nv50_instobj_rd32, + .wr32 = nv50_instobj_wr32, + }, +}; + +static int +nv50_instmem_alloc(struct nouveau_instmem *imem, struct nouveau_object *parent, + u32 size, u32 align, struct nouveau_object **pobject) +{ + struct nouveau_object *engine = nv_object(imem); + return nouveau_object_ctor(parent, engine, &nv50_instobj_oclass, + (void *)(unsigned long)align, size, pobject); +} + +static int +nv50_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_instmem_priv *priv; + int ret; + + ret = nouveau_instmem_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + spin_lock_init(&priv->lock); + priv->base.alloc = nv50_instmem_alloc; + return 0; +} + +static int +nv50_instmem_fini(struct nouveau_object *object, bool suspend) +{ + struct nv50_instmem_priv *priv = (void *)object; + priv->addr = ~0ULL; + return nouveau_instmem_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv50_instmem_oclass = { + .handle = NV_SUBDEV(INSTMEM, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_instmem_ctor, + .dtor = _nouveau_instmem_dtor, + .init = _nouveau_instmem_init, + .fini = nv50_instmem_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c new file mode 100644 index 00000000000..078a2b9d6bd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c @@ -0,0 +1,93 @@ +/* + * 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/ltcg.h> + +struct nvc0_ltcg_priv { + struct nouveau_ltcg base; + u32 subp_nr; +}; + +static void +nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp) +{ + u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); + u32 stat = nv_rd32(priv, subp_base + 0x020); + + if (stat) { + nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat); + nv_wr32(priv, subp_base + 0x020, stat); + } +} + +static void +nvc0_ltcg_intr(struct nouveau_subdev *subdev) +{ + struct nvc0_ltcg_priv *priv = (void *)subdev; + u32 units; + + units = nv_rd32(priv, 0x00017c); + while (units) { + u32 subp, unit = ffs(units) - 1; + for (subp = 0; subp < priv->subp_nr; subp++) + nvc0_ltcg_subp_isr(priv, unit, subp); + units &= ~(1 << unit); + } + + /* we do something horribly wrong and upset PMFB a lot, so mask off + * interrupts from it after the first one until it's fixed + */ + nv_mask(priv, 0x000640, 0x02000000, 0x00000000); +} + +static int +nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_ltcg_priv *priv; + int ret; + + ret = nouveau_ltcg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 24; + nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + + nv_subdev(priv)->intr = nvc0_ltcg_intr; + return 0; +} + +struct nouveau_oclass +nvc0_ltcg_oclass = { + .handle = NV_SUBDEV(LTCG, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_ltcg_ctor, + .dtor = _nouveau_ltcg_dtor, + .init = _nouveau_ltcg_init, + .fini = _nouveau_ltcg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c new file mode 100644 index 00000000000..de5721cfc4c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c @@ -0,0 +1,49 @@ +/* + * 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/mc.h> + +void +nouveau_mc_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_mc *pmc = nouveau_mc(subdev); + const struct nouveau_mc_intr *map = pmc->intr_map; + struct nouveau_subdev *unit; + u32 stat; + + stat = nv_rd32(pmc, 0x000100); + while (stat && map->stat) { + if (stat & map->stat) { + unit = nouveau_subdev(subdev, map->unit); + if (unit && unit->intr) + unit->intr(unit); + stat &= ~map->stat; + } + map++; + } + + if (stat) { + nv_error(pmc, "unknown intr 0x%08x\n", stat); + } +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c new file mode 100644 index 00000000000..23ebe477a6f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c @@ -0,0 +1,83 @@ +/* + * 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/mc.h> + +struct nv04_mc_priv { + struct nouveau_mc base; +}; + +const struct nouveau_mc_intr +nv04_mc_intr[] = { + { 0x00000001, NVDEV_ENGINE_MPEG }, /* NV17- MPEG/ME */ + { 0x00000100, NVDEV_ENGINE_FIFO }, + { 0x00001000, NVDEV_ENGINE_GR }, + { 0x00020000, NVDEV_ENGINE_VP }, /* NV40- */ + { 0x00100000, NVDEV_SUBDEV_TIMER }, + { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */ + { 0x02000000, NVDEV_ENGINE_DISP }, /* NV11- PCRTC1 */ + { 0x10000000, NVDEV_SUBDEV_GPIO }, /* PBUS */ + { 0x80000000, NVDEV_ENGINE_SW }, + {} +}; + +static int +nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_mc_priv *priv; + int ret; + + ret = nouveau_mc_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = nouveau_mc_intr; + priv->base.intr_map = nv04_mc_intr; + return 0; +} + +int +nv04_mc_init(struct nouveau_object *object) +{ + struct nv04_mc_priv *priv = (void *)object; + + nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ + nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */ + + return nouveau_mc_init(&priv->base); +} + +struct nouveau_oclass +nv04_mc_oclass = { + .handle = NV_SUBDEV(MC, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv04_mc_init, + .fini = _nouveau_mc_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c new file mode 100644 index 00000000000..397d868359a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c @@ -0,0 +1,74 @@ +/* + * 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/mc.h> + +struct nv44_mc_priv { + struct nouveau_mc base; +}; + +static int +nv44_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv44_mc_priv *priv; + int ret; + + ret = nouveau_mc_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = nouveau_mc_intr; + priv->base.intr_map = nv04_mc_intr; + return 0; +} + +static int +nv44_mc_init(struct nouveau_object *object) +{ + struct nv44_mc_priv *priv = (void *)object; + u32 tmp = nv_rd32(priv, 0x10020c); + + nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ + + nv_wr32(priv, 0x001700, tmp); + nv_wr32(priv, 0x001704, 0); + nv_wr32(priv, 0x001708, 0); + nv_wr32(priv, 0x00170c, tmp); + + return nouveau_mc_init(&priv->base); +} + +struct nouveau_oclass +nv44_mc_oclass = { + .handle = NV_SUBDEV(MC, 0x44), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv44_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv44_mc_init, + .fini = _nouveau_mc_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c new file mode 100644 index 00000000000..cedf33b0297 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c @@ -0,0 +1,80 @@ +/* + * 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/mc.h> + +struct nv50_mc_priv { + struct nouveau_mc base; +}; + +static const struct nouveau_mc_intr +nv50_mc_intr[] = { + { 0x00000001, NVDEV_ENGINE_MPEG }, + { 0x00000100, NVDEV_ENGINE_FIFO }, + { 0x00001000, NVDEV_ENGINE_GR }, + { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84- */ + { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ + { 0x00100000, NVDEV_SUBDEV_TIMER }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x04000000, NVDEV_ENGINE_DISP }, + { 0x80000000, NVDEV_ENGINE_SW }, + {}, +}; + +static int +nv50_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_mc_priv *priv; + int ret; + + ret = nouveau_mc_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = nouveau_mc_intr; + priv->base.intr_map = nv50_mc_intr; + return 0; +} + +int +nv50_mc_init(struct nouveau_object *object) +{ + struct nv50_mc_priv *priv = (void *)object; + nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */ + return nouveau_mc_init(&priv->base); +} + +struct nouveau_oclass +nv50_mc_oclass = { + .handle = NV_SUBDEV(MC, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv50_mc_init, + .fini = _nouveau_mc_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c new file mode 100644 index 00000000000..a001e4c4d38 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c @@ -0,0 +1,73 @@ +/* + * 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/mc.h> + +struct nv98_mc_priv { + struct nouveau_mc base; +}; + +static const struct nouveau_mc_intr +nv98_mc_intr[] = { + { 0x00000001, NVDEV_ENGINE_PPP }, + { 0x00000100, NVDEV_ENGINE_FIFO }, + { 0x00001000, NVDEV_ENGINE_GR }, + { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84:NVA3 */ + { 0x00008000, NVDEV_ENGINE_BSP }, + { 0x00100000, NVDEV_SUBDEV_TIMER }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */ + { 0x04000000, NVDEV_ENGINE_DISP }, + { 0x80000000, NVDEV_ENGINE_SW }, + {}, +}; + +static int +nv98_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv98_mc_priv *priv; + int ret; + + ret = nouveau_mc_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = nouveau_mc_intr; + priv->base.intr_map = nv98_mc_intr; + return 0; +} + +struct nouveau_oclass +nv98_mc_oclass = { + .handle = NV_SUBDEV(MC, 0x98), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv98_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv50_mc_init, + .fini = _nouveau_mc_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c new file mode 100644 index 00000000000..c2b81e30a17 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c @@ -0,0 +1,75 @@ +/* + * 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/mc.h> + +struct nvc0_mc_priv { + struct nouveau_mc base; +}; + +static const struct nouveau_mc_intr +nvc0_mc_intr[] = { + { 0x00000001, NVDEV_ENGINE_PPP }, + { 0x00000020, NVDEV_ENGINE_COPY0 }, + { 0x00000040, NVDEV_ENGINE_COPY1 }, + { 0x00000100, NVDEV_ENGINE_FIFO }, + { 0x00001000, NVDEV_ENGINE_GR }, + { 0x00008000, NVDEV_ENGINE_BSP }, + { 0x00100000, NVDEV_SUBDEV_TIMER }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x02000000, NVDEV_SUBDEV_LTCG }, + { 0x04000000, NVDEV_ENGINE_DISP }, + { 0x40000000, NVDEV_SUBDEV_IBUS }, + { 0x80000000, NVDEV_ENGINE_SW }, + {}, +}; + +static int +nvc0_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_mc_priv *priv; + int ret; + + ret = nouveau_mc_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = nouveau_mc_intr; + priv->base.intr_map = nvc0_mc_intr; + return 0; +} + +struct nouveau_oclass +nvc0_mc_oclass = { + .handle = NV_SUBDEV(MC, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv50_mc_init, + .fini = _nouveau_mc_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c new file mode 100644 index 00000000000..93e3ddf7303 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c @@ -0,0 +1,290 @@ +/* + * Copyright 2011 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/option.h> + +#include <subdev/i2c.h> +#include <subdev/mxm.h> +#include <subdev/bios.h> +#include <subdev/bios/mxm.h> + +#include "mxms.h" + +static bool +mxm_shadow_rom_fetch(struct nouveau_i2c_port *i2c, u8 addr, + u8 offset, u8 size, u8 *data) +{ + struct i2c_msg msgs[] = { + { .addr = addr, .flags = 0, .len = 1, .buf = &offset }, + { .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, }, + }; + + return i2c_transfer(&i2c->adapter, msgs, 2) == 2; +} + +static bool +mxm_shadow_rom(struct nouveau_mxm *mxm, u8 version) +{ + struct nouveau_bios *bios = nouveau_bios(mxm); + struct nouveau_i2c *i2c = nouveau_i2c(mxm); + struct nouveau_i2c_port *port = NULL; + u8 i2cidx, mxms[6], addr, size; + + i2cidx = mxm_ddc_map(bios, 1 /* LVDS_DDC */) & 0x0f; + if (i2cidx < 0x0f) + port = i2c->find(i2c, i2cidx); + if (!port) + return false; + + addr = 0x54; + if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) { + addr = 0x56; + if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) + return false; + } + + mxm->mxms = mxms; + size = mxms_headerlen(mxm) + mxms_structlen(mxm); + mxm->mxms = kmalloc(size, GFP_KERNEL); + + if (mxm->mxms && + mxm_shadow_rom_fetch(port, addr, 0, size, mxm->mxms)) + return true; + + kfree(mxm->mxms); + mxm->mxms = NULL; + return false; +} + +#if defined(CONFIG_ACPI) +static bool +mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version) +{ + struct nouveau_device *device = nv_device(mxm); + static char muid[] = { + 0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C, + 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 + }; + u32 mxms_args[] = { 0x00000000 }; + union acpi_object args[4] = { + /* _DSM MUID */ + { .buffer.type = 3, + .buffer.length = sizeof(muid), + .buffer.pointer = muid, + }, + /* spec says this can be zero to mean "highest revision", but + * of course there's at least one bios out there which fails + * unless you pass in exactly the version it supports.. + */ + { .integer.type = ACPI_TYPE_INTEGER, + .integer.value = (version & 0xf0) << 4 | (version & 0x0f), + }, + /* MXMS function */ + { .integer.type = ACPI_TYPE_INTEGER, + .integer.value = 0x00000010, + }, + /* Pointer to MXMS arguments */ + { .buffer.type = ACPI_TYPE_BUFFER, + .buffer.length = sizeof(mxms_args), + .buffer.pointer = (char *)mxms_args, + }, + }; + struct acpi_object_list list = { ARRAY_SIZE(args), args }; + struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_handle handle; + int ret; + + handle = DEVICE_ACPI_HANDLE(&device->pdev->dev); + if (!handle) + return false; + + ret = acpi_evaluate_object(handle, "_DSM", &list, &retn); + if (ret) { + nv_debug(mxm, "DSM MXMS failed: %d\n", ret); + return false; + } + + obj = retn.pointer; + if (obj->type == ACPI_TYPE_BUFFER) { + mxm->mxms = kmemdup(obj->buffer.pointer, + obj->buffer.length, GFP_KERNEL); + } else + if (obj->type == ACPI_TYPE_INTEGER) { + nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); + } + + kfree(obj); + return mxm->mxms != NULL; +} +#endif + +#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) + +#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0" + +static u8 +wmi_wmmx_mxmi(struct nouveau_mxm *mxm, u8 version) +{ + u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 }; + struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args }; + struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + + status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn); + if (ACPI_FAILURE(status)) { + nv_debug(mxm, "WMMX MXMI returned %d\n", status); + return 0x00; + } + + obj = retn.pointer; + if (obj->type == ACPI_TYPE_INTEGER) { + version = obj->integer.value; + nv_debug(mxm, "WMMX MXMI version %d.%d\n", + (version >> 4), version & 0x0f); + } else { + version = 0; + nv_debug(mxm, "WMMX MXMI returned non-integer\n"); + } + + kfree(obj); + return version; +} + +static bool +mxm_shadow_wmi(struct nouveau_mxm *mxm, u8 version) +{ + u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 }; + struct acpi_buffer args = { sizeof(mxms_args), mxms_args }; + struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + + if (!wmi_has_guid(WMI_WMMX_GUID)) { + nv_debug(mxm, "WMMX GUID not found\n"); + return false; + } + + mxms_args[1] = wmi_wmmx_mxmi(mxm, 0x00); + if (!mxms_args[1]) + mxms_args[1] = wmi_wmmx_mxmi(mxm, version); + if (!mxms_args[1]) + return false; + + status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn); + if (ACPI_FAILURE(status)) { + nv_debug(mxm, "WMMX MXMS returned %d\n", status); + return false; + } + + obj = retn.pointer; + if (obj->type == ACPI_TYPE_BUFFER) { + mxm->mxms = kmemdup(obj->buffer.pointer, + obj->buffer.length, GFP_KERNEL); + } + + kfree(obj); + return mxm->mxms != NULL; +} +#endif + +static struct mxm_shadow_h { + const char *name; + bool (*exec)(struct nouveau_mxm *, u8 version); +} _mxm_shadow[] = { + { "ROM", mxm_shadow_rom }, +#if defined(CONFIG_ACPI) + { "DSM", mxm_shadow_dsm }, +#endif +#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) + { "WMI", mxm_shadow_wmi }, +#endif + {} +}; + +static int +mxm_shadow(struct nouveau_mxm *mxm, u8 version) +{ + struct mxm_shadow_h *shadow = _mxm_shadow; + do { + nv_debug(mxm, "checking %s\n", shadow->name); + if (shadow->exec(mxm, version)) { + if (mxms_valid(mxm)) + return 0; + kfree(mxm->mxms); + mxm->mxms = NULL; + } + } while ((++shadow)->name); + return -ENOENT; +} + +int +nouveau_mxm_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_bios *bios = nouveau_bios(device); + struct nouveau_mxm *mxm; + u8 ver, len; + u16 data; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "MXM", "mxm", + length, pobject); + mxm = *pobject; + if (ret) + return ret; + + data = mxm_table(bios, &ver, &len); + if (!data || !(ver = nv_ro08(bios, data))) { + nv_info(mxm, "no VBIOS data, nothing to do\n"); + return 0; + } + + nv_info(mxm, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f); + + if (mxm_shadow(mxm, ver)) { + nv_info(mxm, "failed to locate valid SIS\n"); +#if 0 + /* we should, perhaps, fall back to some kind of limited + * mode here if the x86 vbios hasn't already done the + * work for us (so we prevent loading with completely + * whacked vbios tables). + */ + return -EINVAL; +#else + return 0; +#endif + } + + nv_info(mxm, "MXMS Version %d.%d\n", + mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff); + mxms_foreach(mxm, 0, NULL, NULL); + + if (nouveau_boolopt(device->cfgopt, "NvMXMDCB", true)) + mxm->action |= MXM_SANITISE_DCB; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c new file mode 100644 index 00000000000..839ca1edc13 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c @@ -0,0 +1,193 @@ +/* + * 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/mxm.h> +#include "mxms.h" + +#define ROM16(x) le16_to_cpu(*(u16 *)&(x)) +#define ROM32(x) le32_to_cpu(*(u32 *)&(x)) + +static u8 * +mxms_data(struct nouveau_mxm *mxm) +{ + return mxm->mxms; + +} + +u16 +mxms_version(struct nouveau_mxm *mxm) +{ + u8 *mxms = mxms_data(mxm); + u16 version = (mxms[4] << 8) | mxms[5]; + switch (version ) { + case 0x0200: + case 0x0201: + case 0x0300: + return version; + default: + break; + } + + nv_debug(mxm, "unknown version %d.%d\n", mxms[4], mxms[5]); + return 0x0000; +} + +u16 +mxms_headerlen(struct nouveau_mxm *mxm) +{ + return 8; +} + +u16 +mxms_structlen(struct nouveau_mxm *mxm) +{ + return *(u16 *)&mxms_data(mxm)[6]; +} + +bool +mxms_checksum(struct nouveau_mxm *mxm) +{ + u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm); + u8 *mxms = mxms_data(mxm), sum = 0; + while (size--) + sum += *mxms++; + if (sum) { + nv_debug(mxm, "checksum invalid\n"); + return false; + } + return true; +} + +bool +mxms_valid(struct nouveau_mxm *mxm) +{ + u8 *mxms = mxms_data(mxm); + if (*(u32 *)mxms != 0x5f4d584d) { + nv_debug(mxm, "signature invalid\n"); + return false; + } + + if (!mxms_version(mxm) || !mxms_checksum(mxm)) + return false; + + return true; +} + +bool +mxms_foreach(struct nouveau_mxm *mxm, u8 types, + bool (*exec)(struct nouveau_mxm *, u8 *, void *), void *info) +{ + u8 *mxms = mxms_data(mxm); + u8 *desc = mxms + mxms_headerlen(mxm); + u8 *fini = desc + mxms_structlen(mxm) - 1; + while (desc < fini) { + u8 type = desc[0] & 0x0f; + u8 headerlen = 0; + u8 recordlen = 0; + u8 entries = 0; + + switch (type) { + case 0: /* Output Device Structure */ + if (mxms_version(mxm) >= 0x0300) + headerlen = 8; + else + headerlen = 6; + break; + case 1: /* System Cooling Capability Structure */ + case 2: /* Thermal Structure */ + case 3: /* Input Power Structure */ + headerlen = 4; + break; + case 4: /* GPIO Device Structure */ + headerlen = 4; + recordlen = 2; + entries = (ROM32(desc[0]) & 0x01f00000) >> 20; + break; + case 5: /* Vendor Specific Structure */ + headerlen = 8; + break; + case 6: /* Backlight Control Structure */ + if (mxms_version(mxm) >= 0x0300) { + headerlen = 4; + recordlen = 8; + entries = (desc[1] & 0xf0) >> 4; + } else { + headerlen = 8; + } + break; + case 7: /* Fan Control Structure */ + headerlen = 8; + recordlen = 4; + entries = desc[1] & 0x07; + break; + default: + nv_debug(mxm, "unknown descriptor type %d\n", type); + return false; + } + + if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) { + static const char * mxms_desc_name[] = { + "ODS", "SCCS", "TS", "IPS", + "GSD", "VSS", "BCS", "FCS", + }; + u8 *dump = desc; + int i, j; + + nv_debug(mxm, "%4s: ", mxms_desc_name[type]); + for (j = headerlen - 1; j >= 0; j--) + printk("%02x", dump[j]); + printk("\n"); + dump += headerlen; + + for (i = 0; i < entries; i++, dump += recordlen) { + nv_debug(mxm, " "); + for (j = recordlen - 1; j >= 0; j--) + printk("%02x", dump[j]); + printk("\n"); + } + } + + if (types & (1 << type)) { + if (!exec(mxm, desc, info)) + return false; + } + + desc += headerlen + (entries * recordlen); + } + + return true; +} + +void +mxms_output_device(struct nouveau_mxm *mxm, u8 *pdata, struct mxms_odev *desc) +{ + u64 data = ROM32(pdata[0]); + if (mxms_version(mxm) >= 0x0300) + data |= (u64)ROM16(pdata[4]) << 32; + + desc->outp_type = (data & 0x00000000000000f0ULL) >> 4; + desc->ddc_port = (data & 0x0000000000000f00ULL) >> 8; + desc->conn_type = (data & 0x000000000001f000ULL) >> 12; + desc->dig_conn = (data & 0x0000000000780000ULL) >> 19; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h new file mode 100644 index 00000000000..5e0be0c591c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h @@ -0,0 +1,22 @@ +#ifndef __NVMXM_MXMS_H__ +#define __NVMXM_MXMS_H__ + +struct mxms_odev { + u8 outp_type; + u8 conn_type; + u8 ddc_port; + u8 dig_conn; +}; + +void mxms_output_device(struct nouveau_mxm *, u8 *, struct mxms_odev *); + +u16 mxms_version(struct nouveau_mxm *); +u16 mxms_headerlen(struct nouveau_mxm *); +u16 mxms_structlen(struct nouveau_mxm *); +bool mxms_checksum(struct nouveau_mxm *); +bool mxms_valid(struct nouveau_mxm *); + +bool mxms_foreach(struct nouveau_mxm *, u8, + bool (*)(struct nouveau_mxm *, u8 *, void *), void *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c new file mode 100644 index 00000000000..af129c2e811 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c @@ -0,0 +1,233 @@ +/* + * Copyright 2011 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/mxm.h> +#include <subdev/bios.h> +#include <subdev/bios/conn.h> +#include <subdev/bios/dcb.h> +#include <subdev/bios/mxm.h> + +#include "mxms.h" + +struct nv50_mxm_priv { + struct nouveau_mxm base; +}; + +struct context { + u32 *outp; + struct mxms_odev desc; +}; + +static bool +mxm_match_tmds_partner(struct nouveau_mxm *mxm, u8 *data, void *info) +{ + struct context *ctx = info; + struct mxms_odev desc; + + mxms_output_device(mxm, data, &desc); + if (desc.outp_type == 2 && + desc.dig_conn == ctx->desc.dig_conn) + return false; + return true; +} + +static bool +mxm_match_dcb(struct nouveau_mxm *mxm, u8 *data, void *info) +{ + struct nouveau_bios *bios = nouveau_bios(mxm); + struct context *ctx = info; + u64 desc = *(u64 *)data; + + mxms_output_device(mxm, data, &ctx->desc); + + /* match dcb encoder type to mxm-ods device type */ + if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type) + return true; + + /* digital output, have some extra stuff to match here, there's a + * table in the vbios that provides a mapping from the mxm digital + * connection enum values to SOR/link + */ + if ((desc & 0x00000000000000f0) >= 0x20) { + /* check against sor index */ + u8 link = mxm_sor_map(bios, ctx->desc.dig_conn); + if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24) + return true; + + /* check dcb entry has a compatible link field */ + link = (link & 0x30) >> 4; + if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link) + return true; + } + + /* mark this descriptor accounted for by setting invalid device type, + * except of course some manufactures don't follow specs properly and + * we need to avoid killing off the TMDS function on DP connectors + * if MXM-SIS is missing an entry for it. + */ + data[0] &= ~0xf0; + if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 && + mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) { + data[0] |= 0x20; /* modify descriptor to match TMDS now */ + } else { + data[0] |= 0xf0; + } + + return false; +} + +static int +mxm_dcb_sanitise_entry(struct nouveau_bios *bios, void *data, int idx, u16 pdcb) +{ + struct nouveau_mxm *mxm = nouveau_mxm(bios); + struct context ctx = { .outp = (u32 *)(bios->data + pdcb) }; + u8 type, i2cidx, link, ver, len; + u8 *conn; + + /* look for an output device structure that matches this dcb entry. + * if one isn't found, disable it. + */ + if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) { + nv_debug(mxm, "disable %d: 0x%08x 0x%08x\n", + idx, ctx.outp[0], ctx.outp[1]); + ctx.outp[0] |= 0x0000000f; + return 0; + } + + /* modify the output's ddc/aux port, there's a pointer to a table + * with the mapping from mxm ddc/aux port to dcb i2c_index in the + * vbios mxm table + */ + i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port); + if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP) + i2cidx = (i2cidx & 0x0f) << 4; + else + i2cidx = (i2cidx & 0xf0); + + if (i2cidx != 0xf0) { + ctx.outp[0] &= ~0x000000f0; + ctx.outp[0] |= i2cidx; + } + + /* override dcb sorconf.link, based on what mxm data says */ + switch (ctx.desc.outp_type) { + case 0x00: /* Analog CRT */ + case 0x01: /* Analog TV/HDTV */ + break; + default: + link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30; + ctx.outp[1] &= ~0x00000030; + ctx.outp[1] |= link; + break; + } + + /* we may need to fixup various other vbios tables based on what + * the descriptor says the connector type should be. + * + * in a lot of cases, the vbios tables will claim DVI-I is possible, + * and the mxm data says the connector is really HDMI. another + * common example is DP->eDP. + */ + conn = bios->data; + conn += dcb_conn(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len); + type = conn[0]; + switch (ctx.desc.conn_type) { + case 0x01: /* LVDS */ + ctx.outp[1] |= 0x00000004; /* use_power_scripts */ + /* XXX: modify default link width in LVDS table */ + break; + case 0x02: /* HDMI */ + type = DCB_CONNECTOR_HDMI_1; + break; + case 0x03: /* DVI-D */ + type = DCB_CONNECTOR_DVI_D; + break; + case 0x0e: /* eDP, falls through to DPint */ + ctx.outp[1] |= 0x00010000; + case 0x07: /* DP internal, wtf is this?? HP8670w */ + ctx.outp[1] |= 0x00000004; /* use_power_scripts? */ + type = DCB_CONNECTOR_eDP; + break; + default: + break; + } + + if (mxms_version(mxm) >= 0x0300) + conn[0] = type; + + return 0; +} + +static bool +mxm_show_unmatched(struct nouveau_mxm *mxm, u8 *data, void *info) +{ + u64 desc = *(u64 *)data; + if ((desc & 0xf0) != 0xf0) + nv_info(mxm, "unmatched output device 0x%016llx\n", desc); + return true; +} + +static void +mxm_dcb_sanitise(struct nouveau_mxm *mxm) +{ + struct nouveau_bios *bios = nouveau_bios(mxm); + u8 ver, hdr, cnt, len; + u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); + if (dcb == 0x0000 || ver != 0x40) { + nv_debug(mxm, "unsupported DCB version\n"); + return; + } + + dcb_outp_foreach(bios, NULL, mxm_dcb_sanitise_entry); + mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL); +} + +static int +nv50_mxm_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_mxm_priv *priv; + int ret; + + ret = nouveau_mxm_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + if (priv->base.action & MXM_SANITISE_DCB) + mxm_dcb_sanitise(&priv->base); + return 0; +} + +struct nouveau_oclass +nv50_mxm_oclass = { + .handle = NV_SUBDEV(MXM, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_mxm_ctor, + .dtor = _nouveau_mxm_dtor, + .init = _nouveau_mxm_init, + .fini = _nouveau_mxm_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c new file mode 100644 index 00000000000..1674c74a76c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c @@ -0,0 +1,144 @@ +/* + * Copyright 2012 The Nouveau community + * + * 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: Martin Peres + */ + +#include <core/object.h> +#include <core/device.h> + +#include <subdev/bios.h> + +#include "priv.h" + +int +nouveau_therm_attr_get(struct nouveau_therm *therm, + enum nouveau_therm_attr_type type) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + switch (type) { + case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY: + return priv->bios_fan.min_duty; + case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: + return priv->bios_fan.max_duty; + case NOUVEAU_THERM_ATTR_FAN_MODE: + return priv->fan.mode; + case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: + return priv->bios_sensor.thrs_fan_boost.temp; + case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: + return priv->bios_sensor.thrs_fan_boost.hysteresis; + case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK: + return priv->bios_sensor.thrs_down_clock.temp; + case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST: + return priv->bios_sensor.thrs_down_clock.hysteresis; + case NOUVEAU_THERM_ATTR_THRS_CRITICAL: + return priv->bios_sensor.thrs_critical.temp; + case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST: + return priv->bios_sensor.thrs_critical.hysteresis; + case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN: + return priv->bios_sensor.thrs_shutdown.temp; + case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST: + return priv->bios_sensor.thrs_shutdown.hysteresis; + } + + return -EINVAL; +} + +int +nouveau_therm_attr_set(struct nouveau_therm *therm, + enum nouveau_therm_attr_type type, int value) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + switch (type) { + case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY: + if (value < 0) + value = 0; + if (value > priv->bios_fan.max_duty) + value = priv->bios_fan.max_duty; + priv->bios_fan.min_duty = value; + return 0; + case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: + if (value < 0) + value = 0; + if (value < priv->bios_fan.min_duty) + value = priv->bios_fan.min_duty; + priv->bios_fan.max_duty = value; + return 0; + case NOUVEAU_THERM_ATTR_FAN_MODE: + return nouveau_therm_fan_set_mode(therm, value); + case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: + priv->bios_sensor.thrs_fan_boost.temp = value; + return 0; + case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: + priv->bios_sensor.thrs_fan_boost.hysteresis = value; + return 0; + case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK: + priv->bios_sensor.thrs_down_clock.temp = value; + return 0; + case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST: + priv->bios_sensor.thrs_down_clock.hysteresis = value; + return 0; + case NOUVEAU_THERM_ATTR_THRS_CRITICAL: + priv->bios_sensor.thrs_critical.temp = value; + return 0; + case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST: + priv->bios_sensor.thrs_critical.hysteresis = value; + return 0; + case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN: + priv->bios_sensor.thrs_shutdown.temp = value; + return 0; + case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST: + priv->bios_sensor.thrs_shutdown.hysteresis = value; + return 0; + } + + return -EINVAL; +} + +int +nouveau_therm_init(struct nouveau_object *object) +{ + struct nouveau_therm *therm = (void *)object; + struct nouveau_therm_priv *priv = (void *)therm; + int ret; + + ret = nouveau_subdev_init(&therm->base); + if (ret) + return ret; + + if (priv->fan.percent >= 0) + therm->fan_set(therm, priv->fan.percent); + + return 0; +} + +int +nouveau_therm_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_therm *therm = (void *)object; + struct nouveau_therm_priv *priv = (void *)therm; + + priv->fan.percent = therm->fan_get(therm); + + return nouveau_subdev_fini(&therm->base, suspend); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c new file mode 100644 index 00000000000..b29237970fa --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c @@ -0,0 +1,234 @@ +/* + * 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 + * Martin Peres + */ + +#include "priv.h" + +#include <core/object.h> +#include <core/device.h> +#include <subdev/gpio.h> +#include <subdev/timer.h> + +int +nouveau_therm_fan_get(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + struct nouveau_gpio *gpio = nouveau_gpio(therm); + struct dcb_gpio_func func; + int card_type = nv_device(therm)->card_type; + u32 divs, duty; + int ret; + + if (!priv->fan.pwm_get) + return -ENODEV; + + ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); + if (ret == 0) { + ret = priv->fan.pwm_get(therm, func.line, &divs, &duty); + if (ret == 0 && divs) { + divs = max(divs, duty); + if (card_type <= NV_40 || (func.log[0] & 1)) + duty = divs - duty; + return (duty * 100) / divs; + } + + return gpio->get(gpio, 0, func.func, func.line) * 100; + } + + return -ENODEV; +} + +int +nouveau_therm_fan_set(struct nouveau_therm *therm, int percent) +{ + struct nouveau_therm_priv *priv = (void *)therm; + struct nouveau_gpio *gpio = nouveau_gpio(therm); + struct dcb_gpio_func func; + int card_type = nv_device(therm)->card_type; + u32 divs, duty; + int ret; + + if (priv->fan.mode == FAN_CONTROL_NONE) + return -EINVAL; + + if (!priv->fan.pwm_set) + return -ENODEV; + + if (percent < priv->bios_fan.min_duty) + percent = priv->bios_fan.min_duty; + if (percent > priv->bios_fan.max_duty) + percent = priv->bios_fan.max_duty; + + ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); + if (ret == 0) { + divs = priv->bios_perf_fan.pwm_divisor; + if (priv->bios_fan.pwm_freq) { + divs = 1; + if (priv->fan.pwm_clock) + divs = priv->fan.pwm_clock(therm); + divs /= priv->bios_fan.pwm_freq; + } + + duty = ((divs * percent) + 99) / 100; + if (card_type <= NV_40 || (func.log[0] & 1)) + duty = divs - duty; + + ret = priv->fan.pwm_set(therm, func.line, divs, duty); + return ret; + } + + return -ENODEV; +} + +int +nouveau_therm_fan_sense(struct nouveau_therm *therm) +{ + struct nouveau_timer *ptimer = nouveau_timer(therm); + struct nouveau_gpio *gpio = nouveau_gpio(therm); + struct dcb_gpio_func func; + u32 cycles, cur, prev; + u64 start, end, tach; + + if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) + return -ENODEV; + + /* Time a complete rotation and extrapolate to RPM: + * When the fan spins, it changes the value of GPIO FAN_SENSE. + * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. + */ + start = ptimer->read(ptimer); + prev = gpio->get(gpio, 0, func.func, func.line); + cycles = 0; + do { + usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ + + cur = gpio->get(gpio, 0, func.func, func.line); + if (prev != cur) { + if (!start) + start = ptimer->read(ptimer); + cycles++; + prev = cur; + } + } while (cycles < 5 && ptimer->read(ptimer) - start < 250000000); + end = ptimer->read(ptimer); + + if (cycles == 5) { + tach = (u64)60000000000; + do_div(tach, (end - start)); + return tach; + } else + return 0; +} + +int +nouveau_therm_fan_set_mode(struct nouveau_therm *therm, + enum nouveau_therm_fan_mode mode) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + if (priv->fan.mode == mode) + return 0; + + if (mode < FAN_CONTROL_NONE || mode >= FAN_CONTROL_NR) + return -EINVAL; + + switch (mode) + { + case FAN_CONTROL_NONE: + nv_info(therm, "switch fan to no-control mode\n"); + break; + case FAN_CONTROL_MANUAL: + nv_info(therm, "switch fan to manual mode\n"); + break; + case FAN_CONTROL_NR: + break; + } + + priv->fan.mode = mode; + return 0; +} + +int +nouveau_therm_fan_user_get(struct nouveau_therm *therm) +{ + return nouveau_therm_fan_get(therm); +} + +int +nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + if (priv->fan.mode != FAN_CONTROL_MANUAL) + return -EINVAL; + + return nouveau_therm_fan_set(therm, percent); +} + +void +nouveau_therm_fan_set_defaults(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + priv->bios_fan.pwm_freq = 0; + priv->bios_fan.min_duty = 0; + priv->bios_fan.max_duty = 100; +} + + +static void +nouveau_therm_fan_safety_checks(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + if (priv->bios_fan.min_duty > 100) + priv->bios_fan.min_duty = 100; + if (priv->bios_fan.max_duty > 100) + priv->bios_fan.max_duty = 100; + + if (priv->bios_fan.min_duty > priv->bios_fan.max_duty) + priv->bios_fan.min_duty = priv->bios_fan.max_duty; +} + +int nouveau_fan_pwm_clock_dummy(struct nouveau_therm *therm) +{ + return 1; +} + +int +nouveau_therm_fan_ctor(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + struct nouveau_bios *bios = nouveau_bios(therm); + + nouveau_therm_fan_set_defaults(therm); + nvbios_perf_fan_parse(bios, &priv->bios_perf_fan); + if (nvbios_therm_fan_parse(bios, &priv->bios_fan)) + nv_error(therm, "parsing the thermal table failed\n"); + nouveau_therm_fan_safety_checks(therm); + + nouveau_therm_fan_set_mode(therm, FAN_CONTROL_NONE); + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c new file mode 100644 index 00000000000..e512ff0aae6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c @@ -0,0 +1,116 @@ +/* + * Copyright 2012 Nouveau community + * + * 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: Martin Peres + */ + +#include "priv.h" + +#include <subdev/i2c.h> +#include <subdev/bios/extdev.h> + +static bool +probe_monitoring_device(struct nouveau_i2c_port *i2c, + struct i2c_board_info *info) +{ + struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c->i2c); + struct i2c_client *client; + + request_module("%s%s", I2C_MODULE_PREFIX, info->type); + + client = i2c_new_device(&i2c->adapter, info); + if (!client) + return false; + + if (!client->driver || client->driver->detect(client, info)) { + i2c_unregister_device(client); + return false; + } + + nv_info(priv, + "Found an %s at address 0x%x (controlled by lm_sensors)\n", + info->type, info->addr); + priv->ic = client; + + return true; +} + +void +nouveau_therm_ic_ctor(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + struct nouveau_bios *bios = nouveau_bios(therm); + struct nouveau_i2c *i2c = nouveau_i2c(therm); + struct nvbios_extdev_func extdev_entry; + struct i2c_board_info info[] = { + { I2C_BOARD_INFO("w83l785ts", 0x2d) }, + { I2C_BOARD_INFO("w83781d", 0x2d) }, + { I2C_BOARD_INFO("adt7473", 0x2e) }, + { I2C_BOARD_INFO("adt7473", 0x2d) }, + { I2C_BOARD_INFO("adt7473", 0x2c) }, + { I2C_BOARD_INFO("f75375", 0x2e) }, + { I2C_BOARD_INFO("lm99", 0x4c) }, + { I2C_BOARD_INFO("lm90", 0x4c) }, + { I2C_BOARD_INFO("lm90", 0x4d) }, + { I2C_BOARD_INFO("adm1021", 0x18) }, + { I2C_BOARD_INFO("adm1021", 0x19) }, + { I2C_BOARD_INFO("adm1021", 0x1a) }, + { I2C_BOARD_INFO("adm1021", 0x29) }, + { I2C_BOARD_INFO("adm1021", 0x2a) }, + { I2C_BOARD_INFO("adm1021", 0x2b) }, + { I2C_BOARD_INFO("adm1021", 0x4c) }, + { I2C_BOARD_INFO("adm1021", 0x4d) }, + { I2C_BOARD_INFO("adm1021", 0x4e) }, + { I2C_BOARD_INFO("lm63", 0x18) }, + { I2C_BOARD_INFO("lm63", 0x4e) }, + { } + }; + + if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { + struct i2c_board_info board[] = { + { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, + { } + }; + + i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", + board, probe_monitoring_device); + if (priv->ic) + return; + } + + if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { + struct i2c_board_info board[] = { + { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, + { } + }; + + i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", + board, probe_monitoring_device); + if (priv->ic) + return; + } + + /* The vbios doesn't provide the address of an exisiting monitoring + device. Let's try our static list. + */ + i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info, + probe_monitoring_device); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c new file mode 100644 index 00000000000..fcf2cfe731d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c @@ -0,0 +1,163 @@ +/* + * 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 + * Martin Peres + */ + +#include "priv.h" + +static int +nv40_sensor_setup(struct nouveau_therm *therm) +{ + struct nouveau_device *device = nv_device(therm); + + /* enable ADC readout and disable the ALARM threshold */ + if (device->chipset >= 0x46) { + nv_mask(therm, 0x15b8, 0x80000000, 0); + nv_wr32(therm, 0x15b0, 0x80003fff); + return nv_rd32(therm, 0x15b4) & 0x3fff; + } else { + nv_wr32(therm, 0x15b0, 0xff); + return nv_rd32(therm, 0x15b4) & 0xff; + } +} + +static int +nv40_temp_get(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + struct nouveau_device *device = nv_device(therm); + struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + int core_temp; + + if (device->chipset >= 0x46) { + nv_wr32(therm, 0x15b0, 0x80003fff); + core_temp = nv_rd32(therm, 0x15b4) & 0x3fff; + } else { + nv_wr32(therm, 0x15b0, 0xff); + core_temp = nv_rd32(therm, 0x15b4) & 0xff; + } + + /* Setup the sensor if the temperature is 0 */ + if (core_temp == 0) + core_temp = nv40_sensor_setup(therm); + + if (sensor->slope_div == 0) + sensor->slope_div = 1; + if (sensor->offset_den == 0) + sensor->offset_den = 1; + if (sensor->slope_mult < 1) + sensor->slope_mult = 1; + + core_temp = core_temp * sensor->slope_mult / sensor->slope_div; + core_temp = core_temp + sensor->offset_num / sensor->offset_den; + core_temp = core_temp + sensor->offset_constant - 8; + + return core_temp; +} + +int +nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) +{ + if (line == 2) { + u32 reg = nv_rd32(therm, 0x0010f0); + if (reg & 0x80000000) { + *duty = (reg & 0x7fff0000) >> 16; + *divs = (reg & 0x00007fff); + return 0; + } + } else + if (line == 9) { + u32 reg = nv_rd32(therm, 0x0015f4); + if (reg & 0x80000000) { + *divs = nv_rd32(therm, 0x0015f8); + *duty = (reg & 0x7fffffff); + return 0; + } + } else { + nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + return -ENODEV; + } + + return -EINVAL; +} + +int +nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) +{ + if (line == 2) { + nv_wr32(therm, 0x0010f0, 0x80000000 | (duty << 16) | divs); + } else + if (line == 9) { + nv_wr32(therm, 0x0015f8, divs); + nv_wr32(therm, 0x0015f4, duty | 0x80000000); + } else { + nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + return -ENODEV; + } + + return 0; +} + +static int +nv40_therm_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_therm_priv *priv; + struct nouveau_therm *therm; + int ret; + + ret = nouveau_therm_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + therm = (void *) priv; + if (ret) + return ret; + + nouveau_therm_ic_ctor(therm); + nouveau_therm_sensor_ctor(therm); + nouveau_therm_fan_ctor(therm); + + priv->fan.pwm_get = nv40_fan_pwm_get; + priv->fan.pwm_set = nv40_fan_pwm_set; + + therm->temp_get = nv40_temp_get; + therm->fan_get = nouveau_therm_fan_user_get; + therm->fan_set = nouveau_therm_fan_user_set; + therm->fan_sense = nouveau_therm_fan_sense; + therm->attr_get = nouveau_therm_attr_get; + therm->attr_set = nouveau_therm_attr_set; + + return 0; +} + +struct nouveau_oclass +nv40_therm_oclass = { + .handle = NV_SUBDEV(THERM, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_therm_ctor, + .dtor = _nouveau_therm_dtor, + .init = nouveau_therm_init, + .fini = nouveau_therm_fini, + }, +};
\ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c new file mode 100644 index 00000000000..f87a7a3eb4e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c @@ -0,0 +1,157 @@ +/* + * 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 + * Martin Peres + */ + +#include "priv.h" + +static int +pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx) +{ + if (*line == 0x04) { + *ctrl = 0x00e100; + *line = 4; + *indx = 0; + } else + if (*line == 0x09) { + *ctrl = 0x00e100; + *line = 9; + *indx = 1; + } else + if (*line == 0x10) { + *ctrl = 0x00e28c; + *line = 0; + *indx = 0; + } else { + nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line); + return -ENODEV; + } + + return 0; +} + +int +nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) +{ + int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); + if (ret) + return ret; + + if (nv_rd32(therm, ctrl) & (1 << line)) { + *divs = nv_rd32(therm, 0x00e114 + (id * 8)); + *duty = nv_rd32(therm, 0x00e118 + (id * 8)); + return 0; + } + + return -EINVAL; +} + +int +nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) +{ + int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); + if (ret) + return ret; + + nv_mask(therm, ctrl, 0x00010001 << line, 0x00000001 << line); + nv_wr32(therm, 0x00e114 + (id * 8), divs); + nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000); + return 0; +} + +int +nv50_fan_pwm_clock(struct nouveau_therm *therm) +{ + int chipset = nv_device(therm)->chipset; + int crystal = nv_device(therm)->crystal; + int pwm_clock; + + /* determine the PWM source clock */ + if (chipset > 0x50 && chipset < 0x94) { + u8 pwm_div = nv_rd32(therm, 0x410c); + if (nv_rd32(therm, 0xc040) & 0x800000) { + /* Use the HOST clock (100 MHz) + * Where does this constant(2.4) comes from? */ + pwm_clock = (100000000 >> pwm_div) / 10 / 24; + } else { + /* Where does this constant(20) comes from? */ + pwm_clock = (crystal * 1000) >> pwm_div; + pwm_clock /= 20; + } + } else { + pwm_clock = (crystal * 1000) / 20; + } + + return pwm_clock; +} + +int +nv50_temp_get(struct nouveau_therm *therm) +{ + return nv_rd32(therm, 0x20400); +} + +static int +nv50_therm_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_therm_priv *priv; + struct nouveau_therm *therm; + int ret; + + ret = nouveau_therm_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + therm = (void *) priv; + if (ret) + return ret; + + nouveau_therm_ic_ctor(therm); + nouveau_therm_sensor_ctor(therm); + nouveau_therm_fan_ctor(therm); + + priv->fan.pwm_get = nv50_fan_pwm_get; + priv->fan.pwm_set = nv50_fan_pwm_set; + priv->fan.pwm_clock = nv50_fan_pwm_clock; + + therm->temp_get = nv50_temp_get; + therm->fan_get = nouveau_therm_fan_user_get; + therm->fan_set = nouveau_therm_fan_user_set; + therm->fan_sense = nouveau_therm_fan_sense; + therm->attr_get = nouveau_therm_attr_get; + therm->attr_set = nouveau_therm_attr_set; + + return 0; +} + +struct nouveau_oclass +nv50_therm_oclass = { + .handle = NV_SUBDEV(THERM, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_therm_ctor, + .dtor = _nouveau_therm_dtor, + .init = nouveau_therm_init, + .fini = nouveau_therm_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h new file mode 100644 index 00000000000..1c3cd6abc36 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h @@ -0,0 +1,73 @@ +/* + * Copyright 2012 The Nouveau community + * + * 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: Martin Peres + */ + +#include <subdev/therm.h> + +#include <subdev/bios/extdev.h> +#include <subdev/bios/perf.h> +#include <subdev/bios/therm.h> + +struct nouveau_therm_priv { + struct nouveau_therm base; + + /* bios */ + struct nvbios_therm_sensor bios_sensor; + struct nvbios_therm_fan bios_fan; + struct nvbios_perf_fan bios_perf_fan; + + /* fan priv */ + struct { + enum nouveau_therm_fan_mode mode; + int percent; + + int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*); + int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); + int (*pwm_clock)(struct nouveau_therm *); + } fan; + + /* ic */ + struct i2c_client *ic; +}; + +int nouveau_therm_init(struct nouveau_object *object); +int nouveau_therm_fini(struct nouveau_object *object, bool suspend); +int nouveau_therm_attr_get(struct nouveau_therm *therm, + enum nouveau_therm_attr_type type); +int nouveau_therm_attr_set(struct nouveau_therm *therm, + enum nouveau_therm_attr_type type, int value); + +void nouveau_therm_ic_ctor(struct nouveau_therm *therm); + +int nouveau_therm_sensor_ctor(struct nouveau_therm *therm); + +int nouveau_therm_fan_ctor(struct nouveau_therm *therm); +int nouveau_therm_fan_get(struct nouveau_therm *therm); +int nouveau_therm_fan_set(struct nouveau_therm *therm, int percent); +int nouveau_therm_fan_user_get(struct nouveau_therm *therm); +int nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent); +int nouveau_therm_fan_set_mode(struct nouveau_therm *therm, + enum nouveau_therm_fan_mode mode); + + +int nouveau_therm_fan_sense(struct nouveau_therm *therm); diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c new file mode 100644 index 00000000000..204282301fb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c @@ -0,0 +1,81 @@ +/* + * Copyright 2012 The Nouveau community + * + * 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: Martin Peres + */ + +#include "priv.h" + +#include <core/object.h> +#include <core/device.h> + +#include <subdev/bios.h> + +static void +nouveau_therm_temp_set_defaults(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + priv->bios_sensor.slope_mult = 1; + priv->bios_sensor.slope_div = 1; + priv->bios_sensor.offset_num = 0; + priv->bios_sensor.offset_den = 1; + priv->bios_sensor.offset_constant = 0; + + priv->bios_sensor.thrs_fan_boost.temp = 90; + priv->bios_sensor.thrs_fan_boost.hysteresis = 3; + + priv->bios_sensor.thrs_down_clock.temp = 95; + priv->bios_sensor.thrs_down_clock.hysteresis = 3; + + priv->bios_sensor.thrs_critical.temp = 105; + priv->bios_sensor.thrs_critical.hysteresis = 5; + + priv->bios_sensor.thrs_shutdown.temp = 135; + priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */ +} + + +static void +nouveau_therm_temp_safety_checks(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + if (!priv->bios_sensor.slope_div) + priv->bios_sensor.slope_div = 1; + if (!priv->bios_sensor.offset_den) + priv->bios_sensor.offset_den = 1; +} + +int +nouveau_therm_sensor_ctor(struct nouveau_therm *therm) +{ + struct nouveau_therm_priv *priv = (void *)therm; + struct nouveau_bios *bios = nouveau_bios(therm); + + nouveau_therm_temp_set_defaults(therm); + if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, + &priv->bios_sensor)) + nv_error(therm, "nvbios_therm_sensor_parse failed\n"); + nouveau_therm_temp_safety_checks(therm); + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/base.c b/drivers/gpu/drm/nouveau/core/subdev/timer/base.c new file mode 100644 index 00000000000..5d417cc9949 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/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 "subdev/timer.h" + +bool +nouveau_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) +{ + struct nouveau_timer *ptimer = nouveau_timer(obj); + u64 time0; + + time0 = ptimer->read(ptimer); + do { + if (nv_iclass(obj, NV_SUBDEV_CLASS)) { + if ((nv_rd32(obj, addr) & mask) == data) + return true; + } else { + if ((nv_ro32(obj, addr) & mask) == data) + return true; + } + } while (ptimer->read(ptimer) - time0 < nsec); + + return false; +} + +bool +nouveau_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) +{ + struct nouveau_timer *ptimer = nouveau_timer(obj); + u64 time0; + + time0 = ptimer->read(ptimer); + do { + if (nv_iclass(obj, NV_SUBDEV_CLASS)) { + if ((nv_rd32(obj, addr) & mask) != data) + return true; + } else { + if ((nv_ro32(obj, addr) & mask) != data) + return true; + } + } while (ptimer->read(ptimer) - time0 < nsec); + + return false; +} + +bool +nouveau_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data) +{ + struct nouveau_timer *ptimer = nouveau_timer(obj); + u64 time0; + + time0 = ptimer->read(ptimer); + do { + if (func(data) == true) + return true; + } while (ptimer->read(ptimer) - time0 < nsec); + + return false; +} + +void +nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm) +{ + struct nouveau_timer *ptimer = nouveau_timer(obj); + ptimer->alarm(ptimer, nsec, alarm); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c new file mode 100644 index 00000000000..49976be4d73 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c @@ -0,0 +1,249 @@ +/* + * 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/timer.h> + +#define NV04_PTIMER_INTR_0 0x009100 +#define NV04_PTIMER_INTR_EN_0 0x009140 +#define NV04_PTIMER_NUMERATOR 0x009200 +#define NV04_PTIMER_DENOMINATOR 0x009210 +#define NV04_PTIMER_TIME_0 0x009400 +#define NV04_PTIMER_TIME_1 0x009410 +#define NV04_PTIMER_ALARM_0 0x009420 + +struct nv04_timer_priv { + struct nouveau_timer base; + struct list_head alarms; + spinlock_t lock; +}; + +static u64 +nv04_timer_read(struct nouveau_timer *ptimer) +{ + struct nv04_timer_priv *priv = (void *)ptimer; + u32 hi, lo; + + do { + hi = nv_rd32(priv, NV04_PTIMER_TIME_1); + lo = nv_rd32(priv, NV04_PTIMER_TIME_0); + } while (hi != nv_rd32(priv, NV04_PTIMER_TIME_1)); + + return ((u64)hi << 32 | lo); +} + +static void +nv04_timer_alarm_trigger(struct nouveau_timer *ptimer) +{ + struct nv04_timer_priv *priv = (void *)ptimer; + struct nouveau_alarm *alarm, *atemp; + unsigned long flags; + LIST_HEAD(exec); + + /* move any due alarms off the pending list */ + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry_safe(alarm, atemp, &priv->alarms, head) { + if (alarm->timestamp <= ptimer->read(ptimer)) + list_move_tail(&alarm->head, &exec); + } + + /* reschedule interrupt for next alarm time */ + if (!list_empty(&priv->alarms)) { + alarm = list_first_entry(&priv->alarms, typeof(*alarm), head); + nv_wr32(priv, NV04_PTIMER_ALARM_0, alarm->timestamp); + nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000001); + } else { + nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); + } + spin_unlock_irqrestore(&priv->lock, flags); + + /* execute any pending alarm handlers */ + list_for_each_entry_safe(alarm, atemp, &exec, head) { + list_del(&alarm->head); + alarm->func(alarm); + } +} + +static void +nv04_timer_alarm(struct nouveau_timer *ptimer, u32 time, + struct nouveau_alarm *alarm) +{ + struct nv04_timer_priv *priv = (void *)ptimer; + struct nouveau_alarm *list; + unsigned long flags; + + alarm->timestamp = ptimer->read(ptimer) + time; + + /* append new alarm to list, in soonest-alarm-first order */ + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(list, &priv->alarms, head) { + if (list->timestamp > alarm->timestamp) + break; + } + list_add_tail(&alarm->head, &list->head); + spin_unlock_irqrestore(&priv->lock, flags); + + /* process pending alarms */ + nv04_timer_alarm_trigger(ptimer); +} + +static void +nv04_timer_intr(struct nouveau_subdev *subdev) +{ + struct nv04_timer_priv *priv = (void *)subdev; + u32 stat = nv_rd32(priv, NV04_PTIMER_INTR_0); + + if (stat & 0x00000001) { + nv04_timer_alarm_trigger(&priv->base); + nv_wr32(priv, NV04_PTIMER_INTR_0, 0x00000001); + stat &= ~0x00000001; + } + + if (stat) { + nv_error(priv, "unknown stat 0x%08x\n", stat); + nv_wr32(priv, NV04_PTIMER_INTR_0, stat); + } +} + +static int +nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_timer_priv *priv; + int ret; + + ret = nouveau_timer_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.base.intr = nv04_timer_intr; + priv->base.read = nv04_timer_read; + priv->base.alarm = nv04_timer_alarm; + + INIT_LIST_HEAD(&priv->alarms); + spin_lock_init(&priv->lock); + return 0; +} + +static void +nv04_timer_dtor(struct nouveau_object *object) +{ + struct nv04_timer_priv *priv = (void *)object; + return nouveau_timer_destroy(&priv->base); +} + +static int +nv04_timer_init(struct nouveau_object *object) +{ + struct nouveau_device *device = nv_device(object); + struct nv04_timer_priv *priv = (void *)object; + u32 m = 1, f, n, d; + int ret; + + ret = nouveau_timer_init(&priv->base); + if (ret) + return ret; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + + /* determine base clock for timer source */ +#if 0 /*XXX*/ + if (device->chipset < 0x40) { + n = nouveau_hw_get_clock(device, PLL_CORE); + } else +#endif + if (device->chipset <= 0x40) { + /*XXX: figure this out */ + f = -1; + n = 0; + } else { + f = device->crystal; + n = f; + while (n < (d * 2)) { + n += (n / m); + m++; + } + + nv_wr32(priv, 0x009220, m - 1); + } + + if (!n) { + nv_warn(priv, "unknown input clock freq\n"); + if (!nv_rd32(priv, NV04_PTIMER_NUMERATOR) || + !nv_rd32(priv, NV04_PTIMER_DENOMINATOR)) { + nv_wr32(priv, NV04_PTIMER_NUMERATOR, 1); + nv_wr32(priv, NV04_PTIMER_DENOMINATOR, 1); + } + return 0; + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; + } + + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + nv_debug(priv, "input frequency : %dHz\n", f); + nv_debug(priv, "input multiplier: %d\n", m); + nv_debug(priv, "numerator : 0x%08x\n", n); + nv_debug(priv, "denominator : 0x%08x\n", d); + nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n); + + nv_wr32(priv, NV04_PTIMER_NUMERATOR, n); + nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d); + nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff); + nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); + return 0; +} + +static int +nv04_timer_fini(struct nouveau_object *object, bool suspend) +{ + struct nv04_timer_priv *priv = (void *)object; + nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); + return nouveau_timer_fini(&priv->base, suspend); +} + +struct nouveau_oclass +nv04_timer_oclass = { + .handle = NV_SUBDEV(TIMER, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_timer_ctor, + .dtor = nv04_timer_dtor, + .init = nv04_timer_init, + .fini = nv04_timer_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c new file mode 100644 index 00000000000..082c11b75ac --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c @@ -0,0 +1,478 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <core/gpuobj.h> +#include <core/mm.h> + +#include <subdev/fb.h> +#include <subdev/vm.h> + +void +nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node) +{ + struct nouveau_vm *vm = vma->vm; + struct nouveau_vmmgr *vmm = vm->vmm; + struct nouveau_mm_node *r; + int big = vma->node->type != vmm->spg_shift; + u32 offset = vma->node->offset + (delta >> 12); + u32 bits = vma->node->type - 12; + u32 pde = (offset >> vmm->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits; + u32 max = 1 << (vmm->pgt_bits - bits); + u32 end, len; + + delta = 0; + list_for_each_entry(r, &node->regions, rl_entry) { + u64 phys = (u64)r->offset << 12; + u32 num = r->length >> bits; + + while (num) { + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; + + end = (pte + num); + if (unlikely(end >= max)) + end = max; + len = end - pte; + + vmm->map(vma, pgt, node, pte, len, phys, delta); + + num -= len; + pte += len; + if (unlikely(end >= max)) { + phys += len << (bits + 12); + pde++; + pte = 0; + } + + delta += (u64)len << vma->node->type; + } + } + + vmm->flush(vm); +} + +void +nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node) +{ + nouveau_vm_map_at(vma, 0, node); +} + +void +nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length, + struct nouveau_mem *mem) +{ + struct nouveau_vm *vm = vma->vm; + struct nouveau_vmmgr *vmm = vm->vmm; + int big = vma->node->type != vmm->spg_shift; + u32 offset = vma->node->offset + (delta >> 12); + u32 bits = vma->node->type - 12; + u32 num = length >> vma->node->type; + u32 pde = (offset >> vmm->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits; + u32 max = 1 << (vmm->pgt_bits - bits); + unsigned m, sglen; + u32 end, len; + int i; + struct scatterlist *sg; + + for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) { + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; + sglen = sg_dma_len(sg) >> PAGE_SHIFT; + + end = pte + sglen; + if (unlikely(end >= max)) + end = max; + len = end - pte; + + for (m = 0; m < len; m++) { + dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); + + vmm->map_sg(vma, pgt, mem, pte, 1, &addr); + num--; + pte++; + + if (num == 0) + goto finish; + } + if (unlikely(end >= max)) { + pde++; + pte = 0; + } + if (m < sglen) { + for (; m < sglen; m++) { + dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); + + vmm->map_sg(vma, pgt, mem, pte, 1, &addr); + num--; + pte++; + if (num == 0) + goto finish; + } + } + + } +finish: + vmm->flush(vm); +} + +void +nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, + struct nouveau_mem *mem) +{ + struct nouveau_vm *vm = vma->vm; + struct nouveau_vmmgr *vmm = vm->vmm; + dma_addr_t *list = mem->pages; + int big = vma->node->type != vmm->spg_shift; + u32 offset = vma->node->offset + (delta >> 12); + u32 bits = vma->node->type - 12; + u32 num = length >> vma->node->type; + u32 pde = (offset >> vmm->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits; + u32 max = 1 << (vmm->pgt_bits - bits); + u32 end, len; + + while (num) { + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; + + end = (pte + num); + if (unlikely(end >= max)) + end = max; + len = end - pte; + + vmm->map_sg(vma, pgt, mem, pte, len, list); + + num -= len; + pte += len; + list += len; + if (unlikely(end >= max)) { + pde++; + pte = 0; + } + } + + vmm->flush(vm); +} + +void +nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length) +{ + struct nouveau_vm *vm = vma->vm; + struct nouveau_vmmgr *vmm = vm->vmm; + int big = vma->node->type != vmm->spg_shift; + u32 offset = vma->node->offset + (delta >> 12); + u32 bits = vma->node->type - 12; + u32 num = length >> vma->node->type; + u32 pde = (offset >> vmm->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits; + u32 max = 1 << (vmm->pgt_bits - bits); + u32 end, len; + + while (num) { + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; + + end = (pte + num); + if (unlikely(end >= max)) + end = max; + len = end - pte; + + vmm->unmap(pgt, pte, len); + + num -= len; + pte += len; + if (unlikely(end >= max)) { + pde++; + pte = 0; + } + } + + vmm->flush(vm); +} + +void +nouveau_vm_unmap(struct nouveau_vma *vma) +{ + nouveau_vm_unmap_at(vma, 0, (u64)vma->node->length << 12); +} + +static void +nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde) +{ + struct nouveau_vmmgr *vmm = vm->vmm; + struct nouveau_vm_pgd *vpgd; + struct nouveau_vm_pgt *vpgt; + struct nouveau_gpuobj *pgt; + u32 pde; + + for (pde = fpde; pde <= lpde; pde++) { + vpgt = &vm->pgt[pde - vm->fpde]; + if (--vpgt->refcount[big]) + continue; + + pgt = vpgt->obj[big]; + vpgt->obj[big] = NULL; + + list_for_each_entry(vpgd, &vm->pgd_list, head) { + vmm->map_pgt(vpgd->obj, pde, vpgt->obj); + } + + mutex_unlock(&vm->mm.mutex); + nouveau_gpuobj_ref(NULL, &pgt); + mutex_lock(&vm->mm.mutex); + } +} + +static int +nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) +{ + struct nouveau_vmmgr *vmm = vm->vmm; + struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; + struct nouveau_vm_pgd *vpgd; + struct nouveau_gpuobj *pgt; + int big = (type != vmm->spg_shift); + u32 pgt_size; + int ret; + + pgt_size = (1 << (vmm->pgt_bits + 12)) >> type; + pgt_size *= 8; + + mutex_unlock(&vm->mm.mutex); + ret = nouveau_gpuobj_new(nv_object(vm->vmm), NULL, pgt_size, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &pgt); + mutex_lock(&vm->mm.mutex); + if (unlikely(ret)) + return ret; + + /* someone beat us to filling the PDE while we didn't have the lock */ + if (unlikely(vpgt->refcount[big]++)) { + mutex_unlock(&vm->mm.mutex); + nouveau_gpuobj_ref(NULL, &pgt); + mutex_lock(&vm->mm.mutex); + return 0; + } + + vpgt->obj[big] = pgt; + list_for_each_entry(vpgd, &vm->pgd_list, head) { + vmm->map_pgt(vpgd->obj, pde, vpgt->obj); + } + + return 0; +} + +int +nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, + u32 access, struct nouveau_vma *vma) +{ + struct nouveau_vmmgr *vmm = vm->vmm; + u32 align = (1 << page_shift) >> 12; + u32 msize = size >> 12; + u32 fpde, lpde, pde; + int ret; + + mutex_lock(&vm->mm.mutex); + ret = nouveau_mm_head(&vm->mm, page_shift, msize, msize, align, + &vma->node); + if (unlikely(ret != 0)) { + mutex_unlock(&vm->mm.mutex); + return ret; + } + + fpde = (vma->node->offset >> vmm->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits; + + for (pde = fpde; pde <= lpde; pde++) { + struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; + int big = (vma->node->type != vmm->spg_shift); + + if (likely(vpgt->refcount[big])) { + vpgt->refcount[big]++; + continue; + } + + ret = nouveau_vm_map_pgt(vm, pde, vma->node->type); + if (ret) { + if (pde != fpde) + nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1); + nouveau_mm_free(&vm->mm, &vma->node); + mutex_unlock(&vm->mm.mutex); + return ret; + } + } + mutex_unlock(&vm->mm.mutex); + + vma->vm = vm; + vma->offset = (u64)vma->node->offset << 12; + vma->access = access; + return 0; +} + +void +nouveau_vm_put(struct nouveau_vma *vma) +{ + struct nouveau_vm *vm = vma->vm; + struct nouveau_vmmgr *vmm = vm->vmm; + u32 fpde, lpde; + + if (unlikely(vma->node == NULL)) + return; + fpde = (vma->node->offset >> vmm->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits; + + mutex_lock(&vm->mm.mutex); + nouveau_vm_unmap_pgt(vm, vma->node->type != vmm->spg_shift, fpde, lpde); + nouveau_mm_free(&vm->mm, &vma->node); + mutex_unlock(&vm->mm.mutex); +} + +int +nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, + u64 mm_offset, u32 block, struct nouveau_vm **pvm) +{ + struct nouveau_vm *vm; + u64 mm_length = (offset + length) - mm_offset; + int ret; + + vm = *pvm = kzalloc(sizeof(*vm), GFP_KERNEL); + if (!vm) + return -ENOMEM; + + INIT_LIST_HEAD(&vm->pgd_list); + vm->vmm = vmm; + vm->refcount = 1; + vm->fpde = offset >> (vmm->pgt_bits + 12); + vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12); + + vm->pgt = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL); + if (!vm->pgt) { + kfree(vm); + return -ENOMEM; + } + + ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12, + block >> 12); + if (ret) { + kfree(vm->pgt); + kfree(vm); + return ret; + } + + return 0; +} + +int +nouveau_vm_new(struct nouveau_device *device, u64 offset, u64 length, + u64 mm_offset, struct nouveau_vm **pvm) +{ + struct nouveau_vmmgr *vmm = nouveau_vmmgr(device); + return vmm->create(vmm, offset, length, mm_offset, pvm); +} + +static int +nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) +{ + struct nouveau_vmmgr *vmm = vm->vmm; + struct nouveau_vm_pgd *vpgd; + int i; + + if (!pgd) + return 0; + + vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL); + if (!vpgd) + return -ENOMEM; + + nouveau_gpuobj_ref(pgd, &vpgd->obj); + + mutex_lock(&vm->mm.mutex); + for (i = vm->fpde; i <= vm->lpde; i++) + vmm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); + list_add(&vpgd->head, &vm->pgd_list); + mutex_unlock(&vm->mm.mutex); + return 0; +} + +static void +nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) +{ + struct nouveau_vm_pgd *vpgd, *tmp; + struct nouveau_gpuobj *pgd = NULL; + + if (!mpgd) + return; + + mutex_lock(&vm->mm.mutex); + list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { + if (vpgd->obj == mpgd) { + pgd = vpgd->obj; + list_del(&vpgd->head); + kfree(vpgd); + break; + } + } + mutex_unlock(&vm->mm.mutex); + + nouveau_gpuobj_ref(NULL, &pgd); +} + +static void +nouveau_vm_del(struct nouveau_vm *vm) +{ + struct nouveau_vm_pgd *vpgd, *tmp; + + list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { + nouveau_vm_unlink(vm, vpgd->obj); + } + + nouveau_mm_fini(&vm->mm); + kfree(vm->pgt); + kfree(vm); +} + +int +nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr, + struct nouveau_gpuobj *pgd) +{ + struct nouveau_vm *vm; + int ret; + + vm = ref; + if (vm) { + ret = nouveau_vm_link(vm, pgd); + if (ret) + return ret; + + vm->refcount++; + } + + vm = *ptr; + *ptr = ref; + + if (vm) { + nouveau_vm_unlink(vm, pgd); + + if (--vm->refcount == 0) + nouveau_vm_del(vm); + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c new file mode 100644 index 00000000000..6adbbc9cc36 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c @@ -0,0 +1,151 @@ +/* + * 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 "nv04.h" + +#define NV04_PDMA_SIZE (128 * 1024 * 1024) +#define NV04_PDMA_PAGE ( 4 * 1024) + +/******************************************************************************* + * VM map/unmap callbacks + ******************************************************************************/ + +static void +nv04_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) +{ + pte = 0x00008 + (pte * 4); + while (cnt) { + u32 page = PAGE_SIZE / NV04_PDMA_PAGE; + u32 phys = (u32)*list++; + while (cnt && page--) { + nv_wo32(pgt, pte, phys | 3); + phys += NV04_PDMA_PAGE; + pte += 4; + cnt -= 1; + } + } +} + +static void +nv04_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) +{ + pte = 0x00008 + (pte * 4); + while (cnt--) { + nv_wo32(pgt, pte, 0x00000000); + pte += 4; + } +} + +static void +nv04_vm_flush(struct nouveau_vm *vm) +{ +} + +/******************************************************************************* + * VM object + ******************************************************************************/ + +int +nv04_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, u64 mmstart, + struct nouveau_vm **pvm) +{ + return -EINVAL; +} + +/******************************************************************************* + * VMMGR subdev + ******************************************************************************/ + +static int +nv04_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_vmmgr_priv *priv; + struct nouveau_gpuobj *dma; + int ret; + + ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIGART", + "pcigart", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.create = nv04_vm_create; + priv->base.limit = NV04_PDMA_SIZE; + priv->base.dma_bits = 32; + priv->base.pgt_bits = 32 - 12; + priv->base.spg_shift = 12; + priv->base.lpg_shift = 12; + priv->base.map_sg = nv04_vm_map_sg; + priv->base.unmap = nv04_vm_unmap; + priv->base.flush = nv04_vm_flush; + + ret = nouveau_vm_create(&priv->base, 0, NV04_PDMA_SIZE, 0, 4096, + &priv->vm); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, + (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 + + 8, 16, NVOBJ_FLAG_ZERO_ALLOC, + &priv->vm->pgt[0].obj[0]); + dma = priv->vm->pgt[0].obj[0]; + priv->vm->pgt[0].refcount[0] = 1; + if (ret) + return ret; + + nv_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */ + nv_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1); + return 0; +} + +void +nv04_vmmgr_dtor(struct nouveau_object *object) +{ + struct nv04_vmmgr_priv *priv = (void *)object; + if (priv->vm) { + nouveau_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]); + nouveau_vm_ref(NULL, &priv->vm, NULL); + } + if (priv->nullp) { + pci_free_consistent(nv_device(priv)->pdev, 16 * 1024, + priv->nullp, priv->null); + } + nouveau_vmmgr_destroy(&priv->base); +} + +struct nouveau_oclass +nv04_vmmgr_oclass = { + .handle = NV_SUBDEV(VM, 0x04), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_vmmgr_ctor, + .dtor = nv04_vmmgr_dtor, + .init = _nouveau_vmmgr_init, + .fini = _nouveau_vmmgr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h new file mode 100644 index 00000000000..ec42d4bc86a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h @@ -0,0 +1,19 @@ +#ifndef __NV04_VMMGR_PRIV__ +#define __NV04_VMMGR_PRIV__ + +#include <subdev/vm.h> + +struct nv04_vmmgr_priv { + struct nouveau_vmmgr base; + struct nouveau_vm *vm; + dma_addr_t null; + void *nullp; +}; + +static inline struct nv04_vmmgr_priv * +nv04_vmmgr(void *obj) +{ + return (void *)nouveau_vmmgr(obj); +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c new file mode 100644 index 00000000000..0203e1e12ca --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c @@ -0,0 +1,158 @@ +/* + * 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 <core/option.h> + +#include <subdev/timer.h> +#include <subdev/vm.h> + +#include "nv04.h" + +#define NV41_GART_SIZE (512 * 1024 * 1024) +#define NV41_GART_PAGE ( 4 * 1024) + +/******************************************************************************* + * VM map/unmap callbacks + ******************************************************************************/ + +static void +nv41_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) +{ + pte = pte * 4; + while (cnt) { + u32 page = PAGE_SIZE / NV41_GART_PAGE; + u64 phys = (u64)*list++; + while (cnt && page--) { + nv_wo32(pgt, pte, (phys >> 7) | 1); + phys += NV41_GART_PAGE; + pte += 4; + cnt -= 1; + } + } +} + +static void +nv41_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) +{ + pte = pte * 4; + while (cnt--) { + nv_wo32(pgt, pte, 0x00000000); + pte += 4; + } +} + +static void +nv41_vm_flush(struct nouveau_vm *vm) +{ + struct nv04_vm_priv *priv = (void *)vm->vmm; + + mutex_lock(&nv_subdev(priv)->mutex); + nv_wr32(priv, 0x100810, 0x00000022); + if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) { + nv_warn(priv, "flush timeout, 0x%08x\n", + nv_rd32(priv, 0x100810)); + } + nv_wr32(priv, 0x100810, 0x00000000); + mutex_unlock(&nv_subdev(priv)->mutex); +} + +/******************************************************************************* + * VMMGR subdev + ******************************************************************************/ + +static int +nv41_vmmgr_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 nv04_vmmgr_priv *priv; + int ret; + + if (!nouveau_boolopt(device->cfgopt, "NvPCIE", true)) { + return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass, + data, size, pobject); + } + + ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART", + "pciegart", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.create = nv04_vm_create; + priv->base.limit = NV41_GART_SIZE; + priv->base.dma_bits = 39; + priv->base.pgt_bits = 32 - 12; + priv->base.spg_shift = 12; + priv->base.lpg_shift = 12; + priv->base.map_sg = nv41_vm_map_sg; + priv->base.unmap = nv41_vm_unmap; + priv->base.flush = nv41_vm_flush; + + ret = nouveau_vm_create(&priv->base, 0, NV41_GART_SIZE, 0, 4096, + &priv->vm); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, + (NV41_GART_SIZE / NV41_GART_PAGE) * 4, + 16, NVOBJ_FLAG_ZERO_ALLOC, + &priv->vm->pgt[0].obj[0]); + priv->vm->pgt[0].refcount[0] = 1; + if (ret) + return ret; + + return 0; +} + +static int +nv41_vmmgr_init(struct nouveau_object *object) +{ + struct nv04_vmmgr_priv *priv = (void *)object; + struct nouveau_gpuobj *dma = priv->vm->pgt[0].obj[0]; + int ret; + + ret = nouveau_vmmgr_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, 0x100800, dma->addr | 0x00000002); + nv_mask(priv, 0x10008c, 0x00000100, 0x00000100); + nv_wr32(priv, 0x100820, 0x00000000); + return 0; +} + +struct nouveau_oclass +nv41_vmmgr_oclass = { + .handle = NV_SUBDEV(VM, 0x41), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv41_vmmgr_ctor, + .dtor = nv04_vmmgr_dtor, + .init = nv41_vmmgr_init, + .fini = _nouveau_vmmgr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c new file mode 100644 index 00000000000..0ac18d05a14 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c @@ -0,0 +1,248 @@ +/* + * 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 <core/option.h> + +#include <subdev/timer.h> +#include <subdev/vm.h> + +#include "nv04.h" + +#define NV44_GART_SIZE (512 * 1024 * 1024) +#define NV44_GART_PAGE ( 4 * 1024) + +/******************************************************************************* + * VM map/unmap callbacks + ******************************************************************************/ + +static void +nv44_vm_fill(struct nouveau_gpuobj *pgt, dma_addr_t null, + dma_addr_t *list, u32 pte, u32 cnt) +{ + u32 base = (pte << 2) & ~0x0000000f; + u32 tmp[4]; + + tmp[0] = nv_ro32(pgt, base + 0x0); + tmp[1] = nv_ro32(pgt, base + 0x4); + tmp[2] = nv_ro32(pgt, base + 0x8); + tmp[3] = nv_ro32(pgt, base + 0xc); + + while (cnt--) { + u32 addr = list ? (*list++ >> 12) : (null >> 12); + switch (pte++ & 0x3) { + case 0: + tmp[0] &= ~0x07ffffff; + tmp[0] |= addr; + break; + case 1: + tmp[0] &= ~0xf8000000; + tmp[0] |= addr << 27; + tmp[1] &= ~0x003fffff; + tmp[1] |= addr >> 5; + break; + case 2: + tmp[1] &= ~0xffc00000; + tmp[1] |= addr << 22; + tmp[2] &= ~0x0001ffff; + tmp[2] |= addr >> 10; + break; + case 3: + tmp[2] &= ~0xfffe0000; + tmp[2] |= addr << 17; + tmp[3] &= ~0x00000fff; + tmp[3] |= addr >> 15; + break; + } + } + + nv_wo32(pgt, base + 0x0, tmp[0]); + nv_wo32(pgt, base + 0x4, tmp[1]); + nv_wo32(pgt, base + 0x8, tmp[2]); + nv_wo32(pgt, base + 0xc, tmp[3] | 0x40000000); +} + +static void +nv44_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) +{ + struct nv04_vmmgr_priv *priv = (void *)vma->vm->vmm; + u32 tmp[4]; + int i; + + if (pte & 3) { + u32 max = 4 - (pte & 3); + u32 part = (cnt > max) ? max : cnt; + nv44_vm_fill(pgt, priv->null, list, pte, part); + pte += part; + list += part; + cnt -= part; + } + + while (cnt >= 4) { + for (i = 0; i < 4; i++) + tmp[i] = *list++ >> 12; + nv_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27); + nv_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22); + nv_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17); + nv_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000); + cnt -= 4; + } + + if (cnt) + nv44_vm_fill(pgt, priv->null, list, pte, cnt); +} + +static void +nv44_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) +{ + struct nv04_vmmgr_priv *priv = (void *)nouveau_vmmgr(pgt); + + if (pte & 3) { + u32 max = 4 - (pte & 3); + u32 part = (cnt > max) ? max : cnt; + nv44_vm_fill(pgt, priv->null, NULL, pte, part); + pte += part; + cnt -= part; + } + + while (cnt >= 4) { + nv_wo32(pgt, pte++ * 4, 0x00000000); + nv_wo32(pgt, pte++ * 4, 0x00000000); + nv_wo32(pgt, pte++ * 4, 0x00000000); + nv_wo32(pgt, pte++ * 4, 0x00000000); + cnt -= 4; + } + + if (cnt) + nv44_vm_fill(pgt, priv->null, NULL, pte, cnt); +} + +static void +nv44_vm_flush(struct nouveau_vm *vm) +{ + struct nv04_vmmgr_priv *priv = (void *)vm->vmm; + nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE); + nv_wr32(priv, 0x100808, 0x00000020); + if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001)) + nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808)); + nv_wr32(priv, 0x100808, 0x00000000); +} + +/******************************************************************************* + * VMMGR subdev + ******************************************************************************/ + +static int +nv44_vmmgr_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 nv04_vmmgr_priv *priv; + int ret; + + if (!nouveau_boolopt(device->cfgopt, "NvPCIE", true)) { + return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass, + data, size, pobject); + } + + ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART", + "pciegart", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.create = nv04_vm_create; + priv->base.limit = NV44_GART_SIZE; + priv->base.dma_bits = 39; + priv->base.pgt_bits = 32 - 12; + priv->base.spg_shift = 12; + priv->base.lpg_shift = 12; + priv->base.map_sg = nv44_vm_map_sg; + priv->base.unmap = nv44_vm_unmap; + priv->base.flush = nv44_vm_flush; + + priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null); + if (!priv->nullp) { + nv_error(priv, "unable to allocate dummy pages\n"); + return -ENOMEM; + } + + ret = nouveau_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096, + &priv->vm); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, + (NV44_GART_SIZE / NV44_GART_PAGE) * 4, + 512 * 1024, NVOBJ_FLAG_ZERO_ALLOC, + &priv->vm->pgt[0].obj[0]); + priv->vm->pgt[0].refcount[0] = 1; + if (ret) + return ret; + + return 0; +} + +static int +nv44_vmmgr_init(struct nouveau_object *object) +{ + struct nv04_vmmgr_priv *priv = (void *)object; + struct nouveau_gpuobj *gart = priv->vm->pgt[0].obj[0]; + u32 addr; + int ret; + + ret = nouveau_vmmgr_init(&priv->base); + if (ret) + return ret; + + /* calculate vram address of this PRAMIN block, object must be + * allocated on 512KiB alignment, and not exceed a total size + * of 512KiB for this to work correctly + */ + addr = nv_rd32(priv, 0x10020c); + addr -= ((gart->addr >> 19) + 1) << 19; + + nv_wr32(priv, 0x100850, 0x80000000); + nv_wr32(priv, 0x100818, priv->null); + nv_wr32(priv, 0x100804, NV44_GART_SIZE); + nv_wr32(priv, 0x100850, 0x00008000); + nv_mask(priv, 0x10008c, 0x00000200, 0x00000200); + nv_wr32(priv, 0x100820, 0x00000000); + nv_wr32(priv, 0x10082c, 0x00000001); + nv_wr32(priv, 0x100800, addr | 0x00000010); + return 0; +} + +struct nouveau_oclass +nv44_vmmgr_oclass = { + .handle = NV_SUBDEV(VM, 0x44), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv44_vmmgr_ctor, + .dtor = nv04_vmmgr_dtor, + .init = nv44_vmmgr_init, + .fini = _nouveau_vmmgr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c new file mode 100644 index 00000000000..e067f81c97b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c @@ -0,0 +1,227 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <core/device.h> +#include <core/gpuobj.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/vm.h> + +struct nv50_vmmgr_priv { + struct nouveau_vmmgr base; + spinlock_t lock; +}; + +static void +nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]) +{ + u64 phys = 0xdeadcafe00000000ULL; + u32 coverage = 0; + + if (pgt[0]) { + phys = 0x00000003 | pgt[0]->addr; /* present, 4KiB pages */ + coverage = (pgt[0]->size >> 3) << 12; + } else + if (pgt[1]) { + phys = 0x00000001 | pgt[1]->addr; /* present */ + coverage = (pgt[1]->size >> 3) << 16; + } + + if (phys & 1) { + if (coverage <= 32 * 1024 * 1024) + phys |= 0x60; + else if (coverage <= 64 * 1024 * 1024) + phys |= 0x40; + else if (coverage <= 128 * 1024 * 1024) + phys |= 0x20; + } + + nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); + nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); +} + +static inline u64 +vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) +{ + phys |= 1; /* present */ + phys |= (u64)memtype << 40; + phys |= target << 4; + if (vma->access & NV_MEM_ACCESS_SYS) + phys |= (1 << 6); + if (!(vma->access & NV_MEM_ACCESS_WO)) + phys |= (1 << 3); + return phys; +} + +static void +nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) +{ + u32 comp = (mem->memtype & 0x180) >> 7; + u32 block, target; + int i; + + /* IGPs don't have real VRAM, re-target to stolen system memory */ + target = 0; + if (nouveau_fb(vma->vm->vmm)->ram.stolen) { + phys += nouveau_fb(vma->vm->vmm)->ram.stolen; + target = 3; + } + + phys = vm_addr(vma, phys, mem->memtype, target); + pte <<= 3; + cnt <<= 3; + + while (cnt) { + u32 offset_h = upper_32_bits(phys); + u32 offset_l = lower_32_bits(phys); + + for (i = 7; i >= 0; i--) { + block = 1 << (i + 3); + if (cnt >= block && !(pte & (block - 1))) + break; + } + offset_l |= (i << 7); + + phys += block << (vma->node->type - 3); + cnt -= block; + if (comp) { + u32 tag = mem->tag->offset + ((delta >> 16) * comp); + offset_h |= (tag << 17); + delta += block << (vma->node->type - 3); + } + + while (block) { + nv_wo32(pgt, pte + 0, offset_l); + nv_wo32(pgt, pte + 4, offset_h); + pte += 8; + block -= 8; + } + } +} + +static void +nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) +{ + u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2; + pte <<= 3; + while (cnt--) { + u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target); + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + pte += 8; + } +} + +static void +nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) +{ + pte <<= 3; + while (cnt--) { + nv_wo32(pgt, pte + 0, 0x00000000); + nv_wo32(pgt, pte + 4, 0x00000000); + pte += 8; + } +} + +static void +nv50_vm_flush(struct nouveau_vm *vm) +{ + struct nouveau_engine *engine; + int i; + + for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + if (atomic_read(&vm->engref[i])) { + engine = nouveau_engine(vm->vmm, i); + if (engine && engine->tlb_flush) + engine->tlb_flush(engine); + } + } +} + +void +nv50_vm_flush_engine(struct nouveau_subdev *subdev, int engine) +{ + struct nv50_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + nv_wr32(subdev, 0x100c80, (engine << 16) | 1); + if (!nv_wait(subdev, 0x100c80, 0x00000001, 0x00000000)) + nv_error(subdev, "vm flush timeout: engine %d\n", engine); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int +nv50_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, + u64 mm_offset, struct nouveau_vm **pvm) +{ + u32 block = (1 << (vmm->pgt_bits + 12)); + if (block > length) + block = length; + + return nouveau_vm_create(vmm, offset, length, mm_offset, block, pvm); +} + +static int +nv50_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_vmmgr_priv *priv; + int ret; + + ret = nouveau_vmmgr_create(parent, engine, oclass, "VM", "vm", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.limit = 1ULL << 40; + priv->base.dma_bits = 40; + priv->base.pgt_bits = 29 - 12; + priv->base.spg_shift = 12; + priv->base.lpg_shift = 16; + priv->base.create = nv50_vm_create; + priv->base.map_pgt = nv50_vm_map_pgt; + priv->base.map = nv50_vm_map; + priv->base.map_sg = nv50_vm_map_sg; + priv->base.unmap = nv50_vm_unmap; + priv->base.flush = nv50_vm_flush; + spin_lock_init(&priv->lock); + return 0; +} + +struct nouveau_oclass +nv50_vmmgr_oclass = { + .handle = NV_SUBDEV(VM, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_vmmgr_ctor, + .dtor = _nouveau_vmmgr_dtor, + .init = _nouveau_vmmgr_init, + .fini = _nouveau_vmmgr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c new file mode 100644 index 00000000000..30c61e6c201 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c @@ -0,0 +1,189 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <core/device.h> +#include <core/gpuobj.h> + +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/vm.h> + +struct nvc0_vmmgr_priv { + struct nouveau_vmmgr base; + spinlock_t lock; +}; + +static void +nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 index, + struct nouveau_gpuobj *pgt[2]) +{ + u32 pde[2] = { 0, 0 }; + + if (pgt[0]) + pde[1] = 0x00000001 | (pgt[0]->addr >> 8); + if (pgt[1]) + pde[0] = 0x00000001 | (pgt[1]->addr >> 8); + + nv_wo32(pgd, (index * 8) + 0, pde[0]); + nv_wo32(pgd, (index * 8) + 4, pde[1]); +} + +static inline u64 +nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) +{ + phys >>= 8; + + phys |= 0x00000001; /* present */ + if (vma->access & NV_MEM_ACCESS_SYS) + phys |= 0x00000002; + + phys |= ((u64)target << 32); + phys |= ((u64)memtype << 36); + + return phys; +} + +static void +nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) +{ + u32 next = 1 << (vma->node->type - 8); + + phys = nvc0_vm_addr(vma, phys, mem->memtype, 0); + pte <<= 3; + while (cnt--) { + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + phys += next; + pte += 8; + } +} + +static void +nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) +{ + u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5; + + pte <<= 3; + while (cnt--) { + u64 phys = nvc0_vm_addr(vma, *list++, mem->memtype, target); + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + pte += 8; + } +} + +static void +nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) +{ + pte <<= 3; + while (cnt--) { + nv_wo32(pgt, pte + 0, 0x00000000); + nv_wo32(pgt, pte + 4, 0x00000000); + pte += 8; + } +} + +void +nvc0_vm_flush_engine(struct nouveau_subdev *subdev, u64 addr, int type) +{ + struct nvc0_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev); + unsigned long flags; + + /* looks like maybe a "free flush slots" counter, the + * faster you write to 0x100cbc to more it decreases + */ + spin_lock_irqsave(&priv->lock, flags); + if (!nv_wait_ne(subdev, 0x100c80, 0x00ff0000, 0x00000000)) { + nv_error(subdev, "vm timeout 0: 0x%08x %d\n", + nv_rd32(subdev, 0x100c80), type); + } + + nv_wr32(subdev, 0x100cb8, addr >> 8); + nv_wr32(subdev, 0x100cbc, 0x80000000 | type); + + /* wait for flush to be queued? */ + if (!nv_wait(subdev, 0x100c80, 0x00008000, 0x00008000)) { + nv_error(subdev, "vm timeout 1: 0x%08x %d\n", + nv_rd32(subdev, 0x100c80), type); + } + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void +nvc0_vm_flush(struct nouveau_vm *vm) +{ + struct nouveau_vm_pgd *vpgd; + + list_for_each_entry(vpgd, &vm->pgd_list, head) { + nvc0_vm_flush_engine(nv_subdev(vm->vmm), vpgd->obj->addr, 1); + } +} + +static int +nvc0_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, + u64 mm_offset, struct nouveau_vm **pvm) +{ + return nouveau_vm_create(vmm, offset, length, mm_offset, 4096, pvm); +} + +static int +nvc0_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_vmmgr_priv *priv; + int ret; + + ret = nouveau_vmmgr_create(parent, engine, oclass, "VM", "vm", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.limit = 1ULL << 40; + priv->base.dma_bits = 40; + priv->base.pgt_bits = 27 - 12; + priv->base.spg_shift = 12; + priv->base.lpg_shift = 17; + priv->base.create = nvc0_vm_create; + priv->base.map_pgt = nvc0_vm_map_pgt; + priv->base.map = nvc0_vm_map; + priv->base.map_sg = nvc0_vm_map_sg; + priv->base.unmap = nvc0_vm_unmap; + priv->base.flush = nvc0_vm_flush; + spin_lock_init(&priv->lock); + return 0; +} + +struct nouveau_oclass +nvc0_vmmgr_oclass = { + .handle = NV_SUBDEV(VM, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_vmmgr_ctor, + .dtor = _nouveau_vmmgr_dtor, + .init = _nouveau_vmmgr_init, + .fini = _nouveau_vmmgr_fini, + }, +}; |