aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/core')
-rw-r--r--drivers/gpu/drm/nouveau/core/core/client.c103
-rw-r--r--drivers/gpu/drm/nouveau/core/core/engctx.c236
-rw-r--r--drivers/gpu/drm/nouveau/core/core/engine.c55
-rw-r--r--drivers/gpu/drm/nouveau/core/core/enum.c67
-rw-r--r--drivers/gpu/drm/nouveau/core/core/gpuobj.c318
-rw-r--r--drivers/gpu/drm/nouveau/core/core/handle.c223
-rw-r--r--drivers/gpu/drm/nouveau/core/core/mm.c245
-rw-r--r--drivers/gpu/drm/nouveau/core/core/namedb.c203
-rw-r--r--drivers/gpu/drm/nouveau/core/core/object.c468
-rw-r--r--drivers/gpu/drm/nouveau/core/core/option.c131
-rw-r--r--drivers/gpu/drm/nouveau/core/core/parent.c139
-rw-r--r--drivers/gpu/drm/nouveau/core/core/printk.c74
-rw-r--r--drivers/gpu/drm/nouveau/core/core/ramht.c109
-rw-r--r--drivers/gpu/drm/nouveau/core/core/subdev.c115
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c175
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc872
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h620
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h606
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nva3.c222
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c265
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nve0.c156
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc698
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h584
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c217
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c208
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv04.c90
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c125
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c118
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/vga.c215
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c87
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c185
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c173
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c99
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/base.c181
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c630
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h178
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c171
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c208
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c349
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c502
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h36
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c420
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c647
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c628
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctx.h129
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c689
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c3341
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c3039
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c2788
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc539
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h604
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc451
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h530
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc856
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h927
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc780
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h857
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc400
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc400
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv04.c1387
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv10.c1314
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv20.c381
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv20.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv25.c167
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c134
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv30.c238
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv34.c168
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv35.c166
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv40.c495
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv40.h21
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.c888
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c955
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h171
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nve0.c576
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/regs.h269
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c308
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c144
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c240
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c104
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c175
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv04.c147
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv10.c129
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv50.c199
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nvc0.c181
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nv84.c175
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/class.h118
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/client.h42
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/debug.h13
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/device.h136
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/engctx.h51
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/engine.h57
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/enum.h23
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/gpuobj.h71
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/handle.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/math.h16
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/mm.h33
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/namedb.h56
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/object.h188
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/option.h11
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/parent.h64
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/printk.h39
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/ramht.h23
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/subdev.h118
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/bsp.h45
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/copy.h49
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/crypt.h46
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/disp.h44
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h57
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/fifo.h111
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/graph.h72
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/mpeg.h61
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/ppp.h45
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/software.h60
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/vp.h45
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bar.h55
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios.h34
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h13
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h39
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h27
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h90
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h8
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h33
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h25
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h21
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h14
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h77
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h46
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/clock.h59
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/device.h24
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/devinit.h40
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/fb.h134
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/gpio.h64
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/i2c.h60
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/ibus.h34
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/instmem.h73
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h33
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mc.h49
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mxm.h37
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/therm.h58
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/timer.h53
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/vga.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/vm.h142
-rw-r--r--drivers/gpu/drm/nouveau/core/os.h47
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/base.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c263
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c215
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c479
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/bit.c52
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/conn.c56
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dp.c76
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c100
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c121
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c129
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/init.c2120
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/perf.c75
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/pll.c417
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/therm.c177
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c359
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c59
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c105
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c95
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c94
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pll.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c242
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c80
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/base.c472
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv04.c86
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv10.c195
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv20.c126
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv30.c147
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv40.c375
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nv50.c410
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c285
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/nve0.c109
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/base.c69
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h98
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c189
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c159
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c124
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c58
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c96
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c87
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/base.c130
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c130
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c120
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c136
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c148
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c178
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c498
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c245
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/base.c271
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c169
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c194
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c104
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c212
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c407
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c230
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c123
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c123
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/base.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c198
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c138
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c172
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c93
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/base.c49
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c83
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c74
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c80
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c73
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c75
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/base.c290
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c193
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c233
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/base.c144
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/fan.c234
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/ic.c116
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c163
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c157
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/priv.h73
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/temp.c81
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/base.c87
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c249
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/base.c478
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c151
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h19
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c158
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c248
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c227
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c189
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 000000000000..c617f0480071
--- /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 000000000000..e41b10d5eb59
--- /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 000000000000..09b3bd502fd0
--- /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 000000000000..7cc7133d82de
--- /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 000000000000..1f34549aff18
--- /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 000000000000..b8d2cbf8a7a7
--- /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 000000000000..bfddf87926dd
--- /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 000000000000..1ce95a8709df
--- /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 000000000000..0daab62ea14c
--- /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 000000000000..62a432ea39e5
--- /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 000000000000..a1ea034611d5
--- /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 000000000000..6161eaf5447c
--- /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 000000000000..86a64045dd60
--- /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 000000000000..f74c30aa33a0
--- /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 000000000000..66f7dfd907ee
--- /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 000000000000..219850d53286
--- /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 000000000000..c92520f3ed46
--- /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 000000000000..0d98c6c0958d
--- /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 000000000000..4df6da0af740
--- /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 000000000000..06d4a8791055
--- /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 000000000000..2017c1579ac5
--- /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 000000000000..629da02dc352
--- /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 000000000000..09962e4210e9
--- /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 000000000000..1d85e5b66ca0
--- /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 000000000000..9e3876c89b96
--- /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 000000000000..1c919f2af89f
--- /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 000000000000..16a9afb1060b
--- /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 000000000000..d93efbcf75b8
--- /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 000000000000..5a1c68474597
--- /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 000000000000..e1f013d39768
--- /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 000000000000..9f4cc2f31994
--- /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 000000000000..045d2565e289
--- /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 000000000000..5baa08695535
--- /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 000000000000..bbb43c67c2ae
--- /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 000000000000..ea76e3e8c9c2
--- /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 000000000000..496a4b4fdfaf
--- /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 000000000000..4ba75422b89d
--- /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 000000000000..b96e6b0ae2b1
--- /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 000000000000..559c3b4e1b86
--- /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 000000000000..536e7634a00d
--- /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 000000000000..3a9ceb315c20
--- /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 000000000000..b4fd26d8f166
--- /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 000000000000..6f21be600557
--- /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 000000000000..36e81b6fafbc
--- /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 000000000000..e1947013d3bc
--- /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 000000000000..e45035efb8ca
--- /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 000000000000..552fdbd45ebe
--- /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 000000000000..0b7951a85943
--- /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 000000000000..6d8c63931ee6
--- /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 000000000000..b86cc60dcd56
--- /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 000000000000..96050ddb22ca
--- /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 000000000000..7b715fda2763
--- /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 000000000000..26c2165bad0f
--- /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 000000000000..acfc457654bd
--- /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 000000000000..85a8d556f484
--- /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 000000000000..138eeaa28665
--- /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 000000000000..decf0c60ca3b
--- /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 000000000000..e6b228844a32
--- /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 000000000000..f16a5d53319d
--- /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 000000000000..618528248457
--- /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 000000000000..92521c89e77f
--- /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 000000000000..8f3f619c4a78
--- /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 000000000000..2bea7313e03f
--- /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 000000000000..b2b650dd8b28
--- /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 000000000000..700462fa0ae0
--- /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 000000000000..cedadaa92d3f
--- /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 000000000000..273f6320027b
--- /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 000000000000..f40ee2116ee1
--- /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 000000000000..8d0021049ec0
--- /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 000000000000..d2ac975afc2e
--- /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 000000000000..ab3b9dcaf478
--- /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 000000000000..0505fb419bde
--- /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 000000000000..c62f2d0f5f0a
--- /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 000000000000..18d2210e12eb
--- /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 000000000000..539d4c72f192
--- /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 000000000000..9c715a25cecb
--- /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 000000000000..1f394a2629e7
--- /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 000000000000..12418574efea
--- /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 000000000000..8678a9996d57
--- /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 000000000000..8f805b44d59e
--- /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 000000000000..50e7e0da1981
--- /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 000000000000..3ca4c3aa90b7
--- /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 000000000000..6e699afbfdb7
--- /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 000000000000..a2edcd38544a
--- /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 000000000000..b7b0d7e330d6
--- /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 000000000000..dd23c80e5405
--- /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 000000000000..6180ae9800fc
--- /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 000000000000..0193532ceac9
--- /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 000000000000..9ea18dfcb4d0
--- /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 000000000000..e58b6f0984c1
--- /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 000000000000..8a947b6872eb
--- /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 000000000000..666d06de77ec
--- /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 000000000000..e7b1e181943b
--- /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 000000000000..6eaff79377ae
--- /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 000000000000..363674cdf8ab
--- /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 000000000000..f808131c5cd8
--- /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 000000000000..9ee9bf4028ca
--- /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 000000000000..8897e0886085
--- /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 000000000000..818feabbf4a0
--- /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 000000000000..27074957fd21
--- /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 000000000000..d3aa251a5eb6
--- /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 000000000000..1d629664f32d
--- /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 000000000000..47e4cacbca37
--- /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 000000000000..e9632e931616
--- /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 000000000000..75d1ed5f85fd
--- /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 000000000000..70b9d8c5fcf5
--- /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 000000000000..e3674743baaa
--- /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 000000000000..38ec1252cbaa
--- /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 000000000000..700ccbb1941f
--- /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 000000000000..d67fed1e3970
--- /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 000000000000..6943b40d0817
--- /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 000000000000..bbf0d4a5bbd7
--- /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 000000000000..74d554fb3281
--- /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 000000000000..c945691c8564
--- /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 000000000000..05cd08fba377
--- /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 000000000000..4f4ff4502c3d
--- /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 000000000000..d145b25e6be4
--- /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 000000000000..73f060b07981
--- /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 000000000000..10e4dbca649a
--- /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 000000000000..c1270548fd0d
--- /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 000000000000..d682fb625833
--- /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 000000000000..73b5e5d3e75a
--- /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 000000000000..949fee3af8fb
--- /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 000000000000..2bf178082a36
--- /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 000000000000..5079bedfd985
--- /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 000000000000..e69a8bdc6e97
--- /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 000000000000..5572e60414e8
--- /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 000000000000..0b285e99be5a
--- /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 000000000000..c345097592f2
--- /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 000000000000..a2c4296fc5f6
--- /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 000000000000..39e73b91d360
--- /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 000000000000..c9e4c4afa50e
--- /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 000000000000..29e4cc1f6cc0
--- /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 000000000000..5c1b5e1904f9
--- /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 000000000000..9ea2b12cc15d
--- /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 000000000000..b93ab01e3785
--- /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 000000000000..88814f159d89
--- /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 000000000000..ec7a54e91a08
--- /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 000000000000..f351f63bc654
--- /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 000000000000..fded97cea500
--- /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 000000000000..b93b152cb566
--- /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 000000000000..faee569fd458
--- /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 000000000000..49bff901544c
--- /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 000000000000..fee09ad818e4
--- /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 000000000000..9d595efe667a
--- /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 000000000000..cfe3b9cad156
--- /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 000000000000..cd01c533007a
--- /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 000000000000..c3acf5b70d9e
--- /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 000000000000..77a6fb725d3f
--- /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 000000000000..2fbb6df697cd
--- /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 000000000000..1d03a3f2b2d2
--- /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 000000000000..5ac010efd959
--- /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 000000000000..9ed6e728a94c
--- /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 000000000000..3cbc0f3e8d5e
--- /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 000000000000..5afb568b2d69
--- /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 000000000000..4c9f1e508165
--- /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 000000000000..ad577db83766
--- /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 000000000000..6be8c32f6e4c
--- /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 000000000000..2610b11a99b3
--- /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 000000000000..bcbb056c2887
--- /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 000000000000..5e5f4cddae3c
--- /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, &reg, &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 000000000000..862a08a2ae27
--- /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 000000000000..b7fd1151166e
--- /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 000000000000..a4b2b7ebf9af
--- /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 000000000000..fd181fbceddb
--- /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 000000000000..cc8d7d162d7c
--- /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 000000000000..5ccce0b17bf3
--- /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 000000000000..ef2c0078f337
--- /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 000000000000..a2ab6d051ba8
--- /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 000000000000..eed5c16cf610
--- /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 000000000000..ca9a4648bd8a
--- /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 000000000000..8626d0d6cbbc
--- /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 000000000000..f09accfd0e31
--- /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 000000000000..5fa58b7369b5
--- /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 000000000000..7f4b8fe6cccc
--- /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 000000000000..42deadca0f0a
--- /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 000000000000..fec3bcc9a6fc
--- /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 000000000000..6697f0f9c293
--- /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 000000000000..4a280b7ab853
--- /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 000000000000..5a07a39c1735
--- /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 000000000000..6b56a0f4cb40
--- /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 000000000000..7a72d9394340
--- /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 000000000000..191447d0d252
--- /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 000000000000..eb76ffab6b0c
--- /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 000000000000..5b2ba630d913
--- /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 000000000000..eb32e99005e4
--- /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 000000000000..61becfa732e9
--- /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 000000000000..f0086de8af31
--- /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 000000000000..eb06836b69f7
--- /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 000000000000..f037a422d2f4
--- /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 000000000000..4b3578fcb7fb
--- /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 000000000000..cba67bc91390
--- /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 000000000000..347a496fcad8
--- /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 000000000000..436e9efe7ef5
--- /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 000000000000..9f59f2bf0079
--- /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 000000000000..acf818c58bf0
--- /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(&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 000000000000..168d16a9a8e9
--- /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 000000000000..f3502c961cd9
--- /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, &reg, &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, &reg, &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 000000000000..8d18fcad26e0
--- /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 000000000000..fe1ebf199ba9
--- /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 000000000000..3d2c88310f98
--- /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 = &reg },
+ { .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 = &reg },
+ { .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 000000000000..1c4c9a5c8e2e
--- /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 000000000000..4e977ff27e44
--- /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 000000000000..7120124dceac
--- /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 000000000000..1188227ca6aa
--- /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 000000000000..ba4d28b50368
--- /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 000000000000..7983d8d9b358
--- /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 000000000000..73c52ebd5932
--- /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 000000000000..27ef0891d10b
--- /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 000000000000..078a2b9d6bd6
--- /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 000000000000..de5721cfc4c2
--- /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 000000000000..23ebe477a6f0
--- /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 000000000000..397d868359ad
--- /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 000000000000..cedf33b02977
--- /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 000000000000..a001e4c4d38d
--- /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 000000000000..c2b81e30a17d
--- /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 000000000000..93e3ddf7303a
--- /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 000000000000..839ca1edc132
--- /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 000000000000..5e0be0c591ca
--- /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 000000000000..af129c2e8113
--- /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 000000000000..1674c74a76c8
--- /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 000000000000..b29237970fa0
--- /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 000000000000..e512ff0aae60
--- /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 000000000000..fcf2cfe731d6
--- /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 000000000000..f87a7a3eb4e7
--- /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 000000000000..1c3cd6abc36e
--- /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 000000000000..204282301fb1
--- /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 000000000000..5d417cc9949b
--- /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 000000000000..49976be4d73b
--- /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 000000000000..082c11b75acb
--- /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 000000000000..6adbbc9cc361
--- /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 000000000000..ec42d4bc86a6
--- /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 000000000000..0203e1e12caa
--- /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 000000000000..0ac18d05a146
--- /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 000000000000..e067f81c97b3
--- /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 000000000000..30c61e6c2017
--- /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,
+ },
+};