Pārlūkot izejas kodu

Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

This is a major rework of the nouveau driver core, to reflect more closely
how the hw is used and to make it easier to implement newer features now
that the GPUs are more clearly understood than when nouveau started.

It also contains a few other bits:
thermal patches
nv41/44 pcie gart fixes
i2c unregistering fixes.

* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (191 commits)
  drm/nv98/crypt: fix fuc build with latest envyas
  drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering
  drm/nv41/vm: fix and enable use of "real" pciegart
  drm/nv44/vm: fix and enable use of "real" pciegart
  drm/nv04/dmaobj: fixup vm target handling in preparation for nv4x pcie
  drm/nouveau: store supported dma mask in vmmgr
  drm/nvc0/ibus: initial implementation of subdev
  drm/nouveau/therm: add support for fan-control modes
  drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules
  drm/nouveau/therm: calculate the pwm divisor on nv50+
  drm/nouveau/fan: rewrite the fan tachometer driver to get more precision, faster
  drm/nouveau/therm: move thermal-related functions to the therm subdev
  drm/nouveau/bios: parse the pwm divisor from the perf table
  drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices
  drm/nouveau/therm: rework thermal table parsing
  drm/nouveau/gpio: expose the PWM/TOGGLE parameter found in the gpio vbios table
  drm/nouveau: fix pm initialization order
  drm/nouveau/bios: check that fixed tvdac gpio data is valid before using it
  drm/nouveau: log channel debug/error messages from client object rather than drm client
  drm/nouveau: have drm debugging macros build on top of core macros
  ...

Conflicts:
	drivers/gpu/drm/nouveau/nouveau_dp.c
Dave Airlie 12 gadi atpakaļ
vecāks
revīzija
268d28371c
100 mainītis faili ar 22090 papildinājumiem un 610 dzēšanām
  1. 1 1
      Documentation/vfio.txt
  2. 6 3
      MAINTAINERS
  3. 1 1
      Makefile
  4. 1 1
      arch/arm/mach-mxs/mach-mxs.c
  5. 7 0
      arch/arm/mach-orion5x/common.c
  6. 2 0
      arch/arm/mm/dma-mapping.c
  7. 1 0
      arch/c6x/include/asm/Kbuild
  8. 0 27
      arch/c6x/include/asm/barrier.h
  9. 13 11
      arch/tile/include/gxio/iorpc_trio.h
  10. 0 9
      arch/um/include/asm/processor-generic.h
  11. 0 10
      arch/um/include/shared/common-offsets.h
  12. 11 0
      arch/um/include/shared/user.h
  13. 6 19
      arch/um/kernel/exec.c
  14. 4 4
      arch/um/kernel/process.c
  15. 5 1
      arch/um/kernel/signal.c
  16. 12 12
      arch/um/kernel/syscall.c
  17. 1 1
      arch/um/scripts/Makefile.rules
  18. 1 0
      arch/x86/um/Kconfig
  19. 0 3
      arch/x86/um/shared/sysdep/kernel-offsets.h
  20. 2 0
      arch/x86/um/shared/sysdep/syscalls.h
  21. 0 6
      arch/x86/um/signal.c
  22. 1 1
      arch/x86/um/sys_call_table_32.c
  23. 7 20
      arch/x86/um/syscalls_32.c
  24. 3 20
      arch/x86/um/syscalls_64.c
  25. 4 0
      arch/x86/xen/setup.c
  26. 103 50
      drivers/block/nvme.c
  27. 3 4
      drivers/block/rbd.c
  28. 1 1
      drivers/edac/i3200_edac.c
  29. 4 0
      drivers/edac/i5000_edac.c
  30. 4 3
      drivers/edac/sb_edac.c
  31. 5 0
      drivers/gpio/gpio-lpc32xx.c
  32. 28 8
      drivers/gpu/drm/nouveau/Kconfig
  33. 183 42
      drivers/gpu/drm/nouveau/Makefile
  34. 103 0
      drivers/gpu/drm/nouveau/core/core/client.c
  35. 236 0
      drivers/gpu/drm/nouveau/core/core/engctx.c
  36. 55 0
      drivers/gpu/drm/nouveau/core/core/engine.c
  37. 18 29
      drivers/gpu/drm/nouveau/core/core/enum.c
  38. 318 0
      drivers/gpu/drm/nouveau/core/core/gpuobj.c
  39. 223 0
      drivers/gpu/drm/nouveau/core/core/handle.c
  40. 122 52
      drivers/gpu/drm/nouveau/core/core/mm.c
  41. 203 0
      drivers/gpu/drm/nouveau/core/core/namedb.c
  42. 468 0
      drivers/gpu/drm/nouveau/core/core/object.c
  43. 131 0
      drivers/gpu/drm/nouveau/core/core/option.c
  44. 139 0
      drivers/gpu/drm/nouveau/core/core/parent.c
  45. 74 0
      drivers/gpu/drm/nouveau/core/core/printk.c
  46. 109 0
      drivers/gpu/drm/nouveau/core/core/ramht.c
  47. 115 0
      drivers/gpu/drm/nouveau/core/core/subdev.c
  48. 175 0
      drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
  49. 0 0
      drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc
  50. 2 2
      drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
  51. 2 2
      drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
  52. 222 0
      drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
  53. 265 0
      drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
  54. 156 0
      drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
  55. 1 1
      drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc
  56. 2 2
      drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
  57. 217 0
      drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
  58. 208 0
      drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
  59. 90 0
      drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
  60. 125 0
      drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
  61. 118 0
      drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
  62. 215 0
      drivers/gpu/drm/nouveau/core/engine/disp/vga.c
  63. 87 0
      drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
  64. 185 0
      drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
  65. 173 0
      drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
  66. 99 0
      drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
  67. 181 0
      drivers/gpu/drm/nouveau/core/engine/fifo/base.c
  68. 630 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
  69. 178 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h
  70. 171 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
  71. 208 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
  72. 349 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
  73. 502 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
  74. 36 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h
  75. 420 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
  76. 647 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
  77. 628 0
      drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
  78. 13 13
      drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
  79. 66 67
      drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
  80. 157 176
      drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
  81. 3039 0
      drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
  82. 2788 0
      drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
  83. 4 4
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
  84. 66 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
  85. 451 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
  86. 530 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
  87. 4 4
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
  88. 89 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
  89. 780 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
  90. 857 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
  91. 0 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc
  92. 400 0
      drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc
  93. 1387 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
  94. 1314 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
  95. 381 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
  96. 31 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
  97. 167 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
  98. 134 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
  99. 238 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
  100. 168 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv34.c

+ 1 - 1
Documentation/vfio.txt

@@ -133,7 +133,7 @@ character devices for this group:
 $ lspci -n -s 0000:06:0d.0
 06:0d.0 0401: 1102:0002 (rev 08)
 # echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind
-# echo 1102 0002 > /sys/bus/pci/drivers/vfio/new_id
+# echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id
 
 Now we need to look at what other devices are in the group to free
 it for use by VFIO:

+ 6 - 3
MAINTAINERS

@@ -3552,11 +3552,12 @@ K:	\b(ABS|SYN)_MT_
 
 INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:	Intel SCU Linux support <intel-linux-scu@intel.com>
+M:	Lukasz Dorau <lukasz.dorau@intel.com>
+M:	Maciej Patelczyk <maciej.patelczyk@intel.com>
 M:	Dave Jiang <dave.jiang@intel.com>
-M:	Ed Nadolski <edmund.nadolski@intel.com>
 L:	linux-scsi@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git
-S:	Maintained
+T:	git git://git.code.sf.net/p/intel-sas/isci
+S:	Supported
 F:	drivers/scsi/isci/
 F:	firmware/isci/
 
@@ -5544,6 +5545,8 @@ F:	Documentation/devicetree/bindings/pwm/
 F:	include/linux/pwm.h
 F:	include/linux/of_pwm.h
 F:	drivers/pwm/
+F:	drivers/video/backlight/pwm_bl.c
+F:	include/linux/pwm_backlight.h
 
 PXA2xx/PXA3xx SUPPORT
 M:	Eric Miao <eric.y.miao@gmail.com>

+ 1 - 1
Makefile

@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Terrified Chipmunk
 
 # *DOCUMENTATION*

+ 1 - 1
arch/arm/mach-mxs/mach-mxs.c

@@ -261,7 +261,7 @@ static void __init apx4devkit_init(void)
 	enable_clk_enet_out();
 
 	if (IS_BUILTIN(CONFIG_PHYLIB))
-		phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
+		phy_register_fixup_for_uid(PHY_ID_KSZ8051, MICREL_PHY_ID_MASK,
 					   apx4devkit_phy_fixup);
 
 	mxsfb_pdata.mode_list = apx4devkit_video_modes;

+ 7 - 0
arch/arm/mach-orion5x/common.c

@@ -204,6 +204,13 @@ void __init orion5x_wdt_init(void)
 void __init orion5x_init_early(void)
 {
 	orion_time_set_base(TIMER_VIRT_BASE);
+
+	/*
+	 * Some Orion5x devices allocate their coherent buffers from atomic
+	 * context. Increase size of atomic coherent pool to make sure such
+	 * the allocations won't fail.
+	 */
+	init_dma_coherent_pool_size(SZ_1M);
 }
 
 int orion5x_tclk;

+ 2 - 0
arch/arm/mm/dma-mapping.c

@@ -346,6 +346,8 @@ static int __init atomic_pool_init(void)
 		       (unsigned)pool->size / 1024);
 		return 0;
 	}
+
+	kfree(pages);
 no_pages:
 	kfree(bitmap);
 no_bitmap:

+ 1 - 0
arch/c6x/include/asm/Kbuild

@@ -2,6 +2,7 @@ include include/asm-generic/Kbuild.asm
 
 generic-y += atomic.h
 generic-y += auxvec.h
+generic-y += barrier.h
 generic-y += bitsperlong.h
 generic-y += bugs.h
 generic-y += cputime.h

+ 0 - 27
arch/c6x/include/asm/barrier.h

@@ -1,27 +0,0 @@
-/*
- *  Port on Texas Instruments TMS320C6x architecture
- *
- *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
- *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-#ifndef _ASM_C6X_BARRIER_H
-#define _ASM_C6X_BARRIER_H
-
-#define nop()                    asm("NOP\n");
-
-#define mb()                     barrier()
-#define rmb()                    barrier()
-#define wmb()                    barrier()
-#define set_mb(var, value)       do { var = value;  mb(); } while (0)
-#define set_wmb(var, value)      do { var = value; wmb(); } while (0)
-
-#define smp_mb()	         barrier()
-#define smp_rmb()	         barrier()
-#define smp_wmb()	         barrier()
-#define smp_read_barrier_depends()	do { } while (0)
-
-#endif /* _ASM_C6X_BARRIER_H */

+ 13 - 11
arch/tile/include/gxio/iorpc_trio.h

@@ -25,21 +25,23 @@
 #include <linux/module.h>
 #include <asm/pgtable.h>
 
-#define GXIO_TRIO_OP_ALLOC_ASIDS       IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400)
+#define GXIO_TRIO_OP_DEALLOC_ASID      IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400)
+#define GXIO_TRIO_OP_ALLOC_ASIDS       IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1401)
 
-#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1402)
+#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404)
 
-#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e)
-#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140f)
+#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412)
 
-#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1417)
-#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1418)
-#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1419)
-#define GXIO_TRIO_OP_CONFIG_MSI_INTR   IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x141a)
+#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414)
 
-#define GXIO_TRIO_OP_SET_MPS_MRS       IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141c)
-#define GXIO_TRIO_OP_FORCE_RC_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141d)
-#define GXIO_TRIO_OP_FORCE_EP_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e)
+#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e)
+#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141f)
+#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1420)
+#define GXIO_TRIO_OP_CONFIG_MSI_INTR   IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1421)
+
+#define GXIO_TRIO_OP_SET_MPS_MRS       IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1423)
+#define GXIO_TRIO_OP_FORCE_RC_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1424)
+#define GXIO_TRIO_OP_FORCE_EP_LINK_UP  IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1425)
 #define GXIO_TRIO_OP_GET_MMIO_BASE     IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
 #define GXIO_TRIO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
 

+ 0 - 9
arch/um/include/asm/processor-generic.h

@@ -20,14 +20,6 @@ struct mm_struct;
 
 struct thread_struct {
 	struct task_struct *saved_task;
-	/*
-	 * This flag is set to 1 before calling do_fork (and analyzed in
-	 * copy_thread) to mark that we are begin called from userspace (fork /
-	 * vfork / clone), and reset to 0 after. It is left to 0 when called
-	 * from kernelspace (i.e. kernel_thread() or fork_idle(),
-	 * as of 2.6.11).
-	 */
-	int forking;
 	struct pt_regs regs;
 	int singlestep_syscall;
 	void *fault_addr;
@@ -58,7 +50,6 @@ struct thread_struct {
 
 #define INIT_THREAD \
 { \
-	.forking		= 0, \
 	.regs		   	= EMPTY_REGS,	\
 	.fault_addr		= NULL, \
 	.prev_sched		= NULL, \

+ 0 - 10
arch/um/include/shared/common-offsets.h

@@ -7,16 +7,6 @@ DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK);
 DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT);
 DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC);
 
-DEFINE_STR(UM_KERN_EMERG, KERN_EMERG);
-DEFINE_STR(UM_KERN_ALERT, KERN_ALERT);
-DEFINE_STR(UM_KERN_CRIT, KERN_CRIT);
-DEFINE_STR(UM_KERN_ERR, KERN_ERR);
-DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
-DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
-DEFINE_STR(UM_KERN_INFO, KERN_INFO);
-DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
-DEFINE_STR(UM_KERN_CONT, KERN_CONT);
-
 DEFINE(UM_ELF_CLASS, ELF_CLASS);
 DEFINE(UM_ELFCLASS32, ELFCLASS32);
 DEFINE(UM_ELFCLASS64, ELFCLASS64);

+ 11 - 0
arch/um/include/shared/user.h

@@ -26,6 +26,17 @@
 extern void panic(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
 
+/* Requires preincluding include/linux/kern_levels.h */
+#define UM_KERN_EMERG	KERN_EMERG
+#define UM_KERN_ALERT	KERN_ALERT
+#define UM_KERN_CRIT	KERN_CRIT
+#define UM_KERN_ERR	KERN_ERR
+#define UM_KERN_WARNING	KERN_WARNING
+#define UM_KERN_NOTICE	KERN_NOTICE
+#define UM_KERN_INFO	KERN_INFO
+#define UM_KERN_DEBUG	KERN_DEBUG
+#define UM_KERN_CONT	KERN_CONT
+
 #ifdef UML_CONFIG_PRINTK
 extern int printk(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));

+ 6 - 19
arch/um/kernel/exec.c

@@ -39,34 +39,21 @@ void flush_thread(void)
 
 void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
 {
+	get_safe_registers(regs->regs.gp, regs->regs.fp);
 	PT_REGS_IP(regs) = eip;
 	PT_REGS_SP(regs) = esp;
-}
-EXPORT_SYMBOL(start_thread);
-
-static long execve1(const char *file,
-		    const char __user *const __user *argv,
-		    const char __user *const __user *env)
-{
-	long error;
-
-	error = do_execve(file, argv, env, &current->thread.regs);
-	if (error == 0) {
-		task_lock(current);
-		current->ptrace &= ~PT_DTRACE;
+	current->ptrace &= ~PT_DTRACE;
 #ifdef SUBARCH_EXECVE1
-		SUBARCH_EXECVE1(&current->thread.regs.regs);
+	SUBARCH_EXECVE1(regs->regs);
 #endif
-		task_unlock(current);
-	}
-	return error;
 }
+EXPORT_SYMBOL(start_thread);
 
 long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env)
 {
 	long err;
 
-	err = execve1(file, argv, env);
+	err = do_execve(file, argv, env, &current->thread.regs);
 	if (!err)
 		UML_LONGJMP(current->thread.exec_buf, 1);
 	return err;
@@ -81,7 +68,7 @@ long sys_execve(const char __user *file, const char __user *const __user *argv,
 	filename = getname(file);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename)) goto out;
-	error = execve1(filename, argv, env);
+	error = do_execve(filename, argv, env, &current->thread.regs);
 	putname(filename);
  out:
 	return error;

+ 4 - 4
arch/um/kernel/process.c

@@ -181,11 +181,12 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		struct pt_regs *regs)
 {
 	void (*handler)(void);
+	int kthread = current->flags & PF_KTHREAD;
 	int ret = 0;
 
 	p->thread = (struct thread_struct) INIT_THREAD;
 
-	if (current->thread.forking) {
+	if (!kthread) {
 	  	memcpy(&p->thread.regs.regs, &regs->regs,
 		       sizeof(p->thread.regs.regs));
 		PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
@@ -195,8 +196,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		handler = fork_handler;
 
 		arch_copy_thread(&current->thread.arch, &p->thread.arch);
-	}
-	else {
+	} else {
 		get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp);
 		p->thread.request.u.thread = current->thread.request.u.thread;
 		handler = new_thread_handler;
@@ -204,7 +204,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 
 	new_thread(task_stack_page(p), &p->thread.switch_buf, handler);
 
-	if (current->thread.forking) {
+	if (!kthread) {
 		clear_flushed_tls(p);
 
 		/*

+ 5 - 1
arch/um/kernel/signal.c

@@ -22,9 +22,13 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
 			 struct k_sigaction *ka, siginfo_t *info)
 {
 	sigset_t *oldset = sigmask_to_save();
+	int singlestep = 0;
 	unsigned long sp;
 	int err;
 
+	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+		singlestep = 1;
+
 	/* Did we come from a system call? */
 	if (PT_REGS_SYSCALL_NR(regs) >= 0) {
 		/* If so, check system call restarting.. */
@@ -61,7 +65,7 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
 	if (err)
 		force_sigsegv(signr, current);
 	else
-		signal_delivered(signr, info, ka, regs, 0);
+		signal_delivered(signr, info, ka, regs, singlestep);
 }
 
 static int kern_do_signal(struct pt_regs *regs)

+ 12 - 12
arch/um/kernel/syscall.c

@@ -17,25 +17,25 @@
 
 long sys_fork(void)
 {
-	long ret;
-
-	current->thread.forking = 1;
-	ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
+	return do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
 		      &current->thread.regs, 0, NULL, NULL);
-	current->thread.forking = 0;
-	return ret;
 }
 
 long sys_vfork(void)
 {
-	long ret;
-
-	current->thread.forking = 1;
-	ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
 		      UPT_SP(&current->thread.regs.regs),
 		      &current->thread.regs, 0, NULL, NULL);
-	current->thread.forking = 0;
-	return ret;
+}
+
+long sys_clone(unsigned long clone_flags, unsigned long newsp,
+	       void __user *parent_tid, void __user *child_tid)
+{
+	if (!newsp)
+		newsp = UPT_SP(&current->thread.regs.regs);
+
+	return do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+		      child_tid);
 }
 
 long old_mmap(unsigned long addr, unsigned long len,

+ 1 - 1
arch/um/scripts/Makefile.rules

@@ -8,7 +8,7 @@ USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m)  $(USER_SINGLE_OBJS))
 USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
 
 $(USER_OBJS:.o=.%): \
-	c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include user.h $(CFLAGS_$(basetarget).o)
+	c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include $(srctree)/include/linux/kern_levels.h -include user.h $(CFLAGS_$(basetarget).o)
 
 # These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of
 # using it directly.

+ 1 - 0
arch/x86/um/Kconfig

@@ -21,6 +21,7 @@ config 64BIT
 config X86_32
 	def_bool !64BIT
 	select HAVE_AOUT
+	select ARCH_WANT_IPC_PARSE_VERSION
 
 config X86_64
 	def_bool 64BIT

+ 0 - 3
arch/x86/um/shared/sysdep/kernel-offsets.h

@@ -7,9 +7,6 @@
 #define DEFINE(sym, val) \
 	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
-#define STR(x) #x
-#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : )
-
 #define BLANK() asm volatile("\n->" : : )
 
 #define OFFSET(sym, str, mem) \

+ 2 - 0
arch/x86/um/shared/sysdep/syscalls.h

@@ -1,3 +1,5 @@
+extern long sys_clone(unsigned long clone_flags, unsigned long newsp,
+	       void __user *parent_tid, void __user *child_tid);
 #ifdef __i386__
 #include "syscalls_32.h"
 #else

+ 0 - 6
arch/x86/um/signal.c

@@ -416,9 +416,6 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
 	PT_REGS_AX(regs) = (unsigned long) sig;
 	PT_REGS_DX(regs) = (unsigned long) 0;
 	PT_REGS_CX(regs) = (unsigned long) 0;
-
-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
-		ptrace_notify(SIGTRAP);
 	return 0;
 }
 
@@ -466,9 +463,6 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
 	PT_REGS_AX(regs) = (unsigned long) sig;
 	PT_REGS_DX(regs) = (unsigned long) &frame->info;
 	PT_REGS_CX(regs) = (unsigned long) &frame->uc;
-
-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
-		ptrace_notify(SIGTRAP);
 	return 0;
 }
 

+ 1 - 1
arch/x86/um/sys_call_table_32.c

@@ -28,7 +28,7 @@
 #define ptregs_execve sys_execve
 #define ptregs_iopl sys_iopl
 #define ptregs_vm86old sys_vm86old
-#define ptregs_clone sys_clone
+#define ptregs_clone i386_clone
 #define ptregs_vm86 sys_vm86
 #define ptregs_sigaltstack sys_sigaltstack
 #define ptregs_vfork sys_vfork

+ 7 - 20
arch/x86/um/syscalls_32.c

@@ -3,37 +3,24 @@
  * Licensed under the GPL
  */
 
-#include "linux/sched.h"
-#include "linux/shm.h"
-#include "linux/ipc.h"
-#include "linux/syscalls.h"
-#include "asm/mman.h"
-#include "asm/uaccess.h"
-#include "asm/unistd.h"
+#include <linux/syscalls.h>
+#include <sysdep/syscalls.h>
 
 /*
  * The prototype on i386 is:
  *
- *     int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr)
+ *     int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls
  *
  * and the "newtls" arg. on i386 is read by copy_thread directly from the
  * register saved on the stack.
  */
-long sys_clone(unsigned long clone_flags, unsigned long newsp,
-	       int __user *parent_tid, void *newtls, int __user *child_tid)
+long i386_clone(unsigned long clone_flags, unsigned long newsp,
+		int __user *parent_tid, void *newtls, int __user *child_tid)
 {
-	long ret;
-
-	if (!newsp)
-		newsp = UPT_SP(&current->thread.regs.regs);
-
-	current->thread.forking = 1;
-	ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
-		      child_tid);
-	current->thread.forking = 0;
-	return ret;
+	return sys_clone(clone_flags, newsp, parent_tid, child_tid);
 }
 
+
 long sys_sigaction(int sig, const struct old_sigaction __user *act,
 			 struct old_sigaction __user *oact)
 {

+ 3 - 20
arch/x86/um/syscalls_64.c

@@ -5,12 +5,9 @@
  * Licensed under the GPL
  */
 
-#include "linux/linkage.h"
-#include "linux/personality.h"
-#include "linux/utsname.h"
-#include "asm/prctl.h" /* XXX This should get the constants from libc */
-#include "asm/uaccess.h"
-#include "os.h"
+#include <linux/sched.h>
+#include <asm/prctl.h> /* XXX This should get the constants from libc */
+#include <os.h>
 
 long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
 {
@@ -79,20 +76,6 @@ long sys_arch_prctl(int code, unsigned long addr)
 	return arch_prctl(current, code, (unsigned long __user *) addr);
 }
 
-long sys_clone(unsigned long clone_flags, unsigned long newsp,
-	       void __user *parent_tid, void __user *child_tid)
-{
-	long ret;
-
-	if (!newsp)
-		newsp = UPT_SP(&current->thread.regs.regs);
-	current->thread.forking = 1;
-	ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
-		      child_tid);
-	current->thread.forking = 0;
-	return ret;
-}
-
 void arch_switch_to(struct task_struct *to)
 {
 	if ((to->thread.arch.fs == 0) || (to->mm == NULL))

+ 4 - 0
arch/x86/xen/setup.c

@@ -17,6 +17,7 @@
 #include <asm/e820.h>
 #include <asm/setup.h>
 #include <asm/acpi.h>
+#include <asm/numa.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 
@@ -544,4 +545,7 @@ void __init xen_arch_setup(void)
 	disable_cpufreq();
 	WARN_ON(set_pm_idle_to_default());
 	fiddle_vdso();
+#ifdef CONFIG_NUMA
+	numa_off = 1;
+#endif
 }

+ 103 - 50
drivers/block/nvme.c

@@ -79,6 +79,7 @@ struct nvme_dev {
 	char serial[20];
 	char model[40];
 	char firmware_rev[8];
+	u32 max_hw_sectors;
 };
 
 /*
@@ -835,15 +836,15 @@ static int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns,
 }
 
 static int nvme_get_features(struct nvme_dev *dev, unsigned fid,
-				unsigned dword11, dma_addr_t dma_addr)
+				unsigned nsid, dma_addr_t dma_addr)
 {
 	struct nvme_command c;
 
 	memset(&c, 0, sizeof(c));
 	c.features.opcode = nvme_admin_get_features;
+	c.features.nsid = cpu_to_le32(nsid);
 	c.features.prp1 = cpu_to_le64(dma_addr);
 	c.features.fid = cpu_to_le32(fid);
-	c.features.dword11 = cpu_to_le32(dword11);
 
 	return nvme_submit_admin_cmd(dev, &c, NULL);
 }
@@ -862,11 +863,51 @@ static int nvme_set_features(struct nvme_dev *dev, unsigned fid,
 	return nvme_submit_admin_cmd(dev, &c, result);
 }
 
+/**
+ * nvme_cancel_ios - Cancel outstanding I/Os
+ * @queue: The queue to cancel I/Os on
+ * @timeout: True to only cancel I/Os which have timed out
+ */
+static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout)
+{
+	int depth = nvmeq->q_depth - 1;
+	struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
+	unsigned long now = jiffies;
+	int cmdid;
+
+	for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) {
+		void *ctx;
+		nvme_completion_fn fn;
+		static struct nvme_completion cqe = {
+			.status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1,
+		};
+
+		if (timeout && !time_after(now, info[cmdid].timeout))
+			continue;
+		dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid);
+		ctx = cancel_cmdid(nvmeq, cmdid, &fn);
+		fn(nvmeq->dev, ctx, &cqe);
+	}
+}
+
+static void nvme_free_queue_mem(struct nvme_queue *nvmeq)
+{
+	dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
+				(void *)nvmeq->cqes, nvmeq->cq_dma_addr);
+	dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
+					nvmeq->sq_cmds, nvmeq->sq_dma_addr);
+	kfree(nvmeq);
+}
+
 static void nvme_free_queue(struct nvme_dev *dev, int qid)
 {
 	struct nvme_queue *nvmeq = dev->queues[qid];
 	int vector = dev->entry[nvmeq->cq_vector].vector;
 
+	spin_lock_irq(&nvmeq->q_lock);
+	nvme_cancel_ios(nvmeq, false);
+	spin_unlock_irq(&nvmeq->q_lock);
+
 	irq_set_affinity_hint(vector, NULL);
 	free_irq(vector, nvmeq);
 
@@ -876,18 +917,15 @@ static void nvme_free_queue(struct nvme_dev *dev, int qid)
 		adapter_delete_cq(dev, qid);
 	}
 
-	dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
-				(void *)nvmeq->cqes, nvmeq->cq_dma_addr);
-	dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
-					nvmeq->sq_cmds, nvmeq->sq_dma_addr);
-	kfree(nvmeq);
+	nvme_free_queue_mem(nvmeq);
 }
 
 static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
 							int depth, int vector)
 {
 	struct device *dmadev = &dev->pci_dev->dev;
-	unsigned extra = (depth / 8) + (depth * sizeof(struct nvme_cmd_info));
+	unsigned extra = DIV_ROUND_UP(depth, 8) + (depth *
+						sizeof(struct nvme_cmd_info));
 	struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL);
 	if (!nvmeq)
 		return NULL;
@@ -975,7 +1013,7 @@ static __devinit struct nvme_queue *nvme_create_queue(struct nvme_dev *dev,
 
 static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
 {
-	int result;
+	int result = 0;
 	u32 aqa;
 	u64 cap;
 	unsigned long timeout;
@@ -1005,17 +1043,22 @@ static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
 	timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies;
 	dev->db_stride = NVME_CAP_STRIDE(cap);
 
-	while (!(readl(&dev->bar->csts) & NVME_CSTS_RDY)) {
+	while (!result && !(readl(&dev->bar->csts) & NVME_CSTS_RDY)) {
 		msleep(100);
 		if (fatal_signal_pending(current))
-			return -EINTR;
+			result = -EINTR;
 		if (time_after(jiffies, timeout)) {
 			dev_err(&dev->pci_dev->dev,
 				"Device not ready; aborting initialisation\n");
-			return -ENODEV;
+			result = -ENODEV;
 		}
 	}
 
+	if (result) {
+		nvme_free_queue_mem(nvmeq);
+		return result;
+	}
+
 	result = queue_request_irq(dev, nvmeq, "nvme admin");
 	dev->queues[0] = nvmeq;
 	return result;
@@ -1037,6 +1080,8 @@ static struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
 	offset = offset_in_page(addr);
 	count = DIV_ROUND_UP(offset + length, PAGE_SIZE);
 	pages = kcalloc(count, sizeof(*pages), GFP_KERNEL);
+	if (!pages)
+		return ERR_PTR(-ENOMEM);
 
 	err = get_user_pages_fast(addr, count, 1, pages);
 	if (err < count) {
@@ -1146,14 +1191,13 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 	return status;
 }
 
-static int nvme_user_admin_cmd(struct nvme_ns *ns,
+static int nvme_user_admin_cmd(struct nvme_dev *dev,
 					struct nvme_admin_cmd __user *ucmd)
 {
-	struct nvme_dev *dev = ns->dev;
 	struct nvme_admin_cmd cmd;
 	struct nvme_command c;
 	int status, length;
-	struct nvme_iod *iod;
+	struct nvme_iod *uninitialized_var(iod);
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -1204,7 +1248,7 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
 	case NVME_IOCTL_ID:
 		return ns->ns_id;
 	case NVME_IOCTL_ADMIN_CMD:
-		return nvme_user_admin_cmd(ns, (void __user *)arg);
+		return nvme_user_admin_cmd(ns->dev, (void __user *)arg);
 	case NVME_IOCTL_SUBMIT_IO:
 		return nvme_submit_io(ns, (void __user *)arg);
 	default:
@@ -1218,26 +1262,6 @@ static const struct block_device_operations nvme_fops = {
 	.compat_ioctl	= nvme_ioctl,
 };
 
-static void nvme_timeout_ios(struct nvme_queue *nvmeq)
-{
-	int depth = nvmeq->q_depth - 1;
-	struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
-	unsigned long now = jiffies;
-	int cmdid;
-
-	for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) {
-		void *ctx;
-		nvme_completion_fn fn;
-		static struct nvme_completion cqe = { .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, };
-
-		if (!time_after(now, info[cmdid].timeout))
-			continue;
-		dev_warn(nvmeq->q_dmadev, "Timing out I/O %d\n", cmdid);
-		ctx = cancel_cmdid(nvmeq, cmdid, &fn);
-		fn(nvmeq->dev, ctx, &cqe);
-	}
-}
-
 static void nvme_resubmit_bios(struct nvme_queue *nvmeq)
 {
 	while (bio_list_peek(&nvmeq->sq_cong)) {
@@ -1269,7 +1293,7 @@ static int nvme_kthread(void *data)
 				spin_lock_irq(&nvmeq->q_lock);
 				if (nvme_process_cq(nvmeq))
 					printk("process_cq did something\n");
-				nvme_timeout_ios(nvmeq);
+				nvme_cancel_ios(nvmeq, true);
 				nvme_resubmit_bios(nvmeq);
 				spin_unlock_irq(&nvmeq->q_lock);
 			}
@@ -1339,6 +1363,9 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid,
 	ns->disk = disk;
 	lbaf = id->flbas & 0xf;
 	ns->lba_shift = id->lbaf[lbaf].ds;
+	blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
+	if (dev->max_hw_sectors)
+		blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors);
 
 	disk->major = nvme_major;
 	disk->minors = NVME_MINORS;
@@ -1383,7 +1410,7 @@ static int set_queue_count(struct nvme_dev *dev, int count)
 
 static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
 {
-	int result, cpu, i, nr_io_queues, db_bar_size;
+	int result, cpu, i, nr_io_queues, db_bar_size, q_depth;
 
 	nr_io_queues = num_online_cpus();
 	result = set_queue_count(dev, nr_io_queues);
@@ -1429,9 +1456,10 @@ static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
 		cpu = cpumask_next(cpu, cpu_online_mask);
 	}
 
+	q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1,
+								NVME_Q_DEPTH);
 	for (i = 0; i < nr_io_queues; i++) {
-		dev->queues[i + 1] = nvme_create_queue(dev, i + 1,
-							NVME_Q_DEPTH, i);
+		dev->queues[i + 1] = nvme_create_queue(dev, i + 1, q_depth, i);
 		if (IS_ERR(dev->queues[i + 1]))
 			return PTR_ERR(dev->queues[i + 1]);
 		dev->queue_count++;
@@ -1480,6 +1508,10 @@ static int __devinit nvme_dev_add(struct nvme_dev *dev)
 	memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn));
 	memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn));
 	memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr));
+	if (ctrl->mdts) {
+		int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;
+		dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9);
+	}
 
 	id_ns = mem;
 	for (i = 1; i <= nn; i++) {
@@ -1523,8 +1555,6 @@ static int nvme_dev_remove(struct nvme_dev *dev)
 	list_del(&dev->node);
 	spin_unlock(&dev_list_lock);
 
-	/* TODO: wait all I/O finished or cancel them */
-
 	list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
 		list_del(&ns->list);
 		del_gendisk(ns->disk);
@@ -1560,15 +1590,33 @@ static void nvme_release_prp_pools(struct nvme_dev *dev)
 	dma_pool_destroy(dev->prp_small_pool);
 }
 
-/* XXX: Use an ida or something to let remove / add work correctly */
-static void nvme_set_instance(struct nvme_dev *dev)
+static DEFINE_IDA(nvme_instance_ida);
+
+static int nvme_set_instance(struct nvme_dev *dev)
 {
-	static int instance;
-	dev->instance = instance++;
+	int instance, error;
+
+	do {
+		if (!ida_pre_get(&nvme_instance_ida, GFP_KERNEL))
+			return -ENODEV;
+
+		spin_lock(&dev_list_lock);
+		error = ida_get_new(&nvme_instance_ida, &instance);
+		spin_unlock(&dev_list_lock);
+	} while (error == -EAGAIN);
+
+	if (error)
+		return -ENODEV;
+
+	dev->instance = instance;
+	return 0;
 }
 
 static void nvme_release_instance(struct nvme_dev *dev)
 {
+	spin_lock(&dev_list_lock);
+	ida_remove(&nvme_instance_ida, dev->instance);
+	spin_unlock(&dev_list_lock);
 }
 
 static int __devinit nvme_probe(struct pci_dev *pdev,
@@ -1601,7 +1649,10 @@ static int __devinit nvme_probe(struct pci_dev *pdev,
 	pci_set_drvdata(pdev, dev);
 	dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
 	dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-	nvme_set_instance(dev);
+	result = nvme_set_instance(dev);
+	if (result)
+		goto disable;
+
 	dev->entry[0].vector = pdev->irq;
 
 	result = nvme_setup_prp_pools(dev);
@@ -1704,15 +1755,17 @@ static struct pci_driver nvme_driver = {
 
 static int __init nvme_init(void)
 {
-	int result = -EBUSY;
+	int result;
 
 	nvme_thread = kthread_run(nvme_kthread, NULL, "nvme");
 	if (IS_ERR(nvme_thread))
 		return PTR_ERR(nvme_thread);
 
-	nvme_major = register_blkdev(nvme_major, "nvme");
-	if (nvme_major <= 0)
+	result = register_blkdev(nvme_major, "nvme");
+	if (result < 0)
 		goto kill_kthread;
+	else if (result > 0)
+		nvme_major = result;
 
 	result = pci_register_driver(&nvme_driver);
 	if (result)

+ 3 - 4
drivers/block/rbd.c

@@ -246,13 +246,12 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
 	struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
 
-	rbd_get_dev(rbd_dev);
-
-	set_device_ro(bdev, rbd_dev->read_only);
-
 	if ((mode & FMODE_WRITE) && rbd_dev->read_only)
 		return -EROFS;
 
+	rbd_get_dev(rbd_dev);
+	set_device_ro(bdev, rbd_dev->read_only);
+
 	return 0;
 }
 

+ 1 - 1
drivers/edac/i3200_edac.c

@@ -391,7 +391,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 		for (j = 0; j < nr_channels; j++) {
 			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
-			dimm->nr_pages = nr_pages / nr_channels;
+			dimm->nr_pages = nr_pages;
 			dimm->grain = nr_pages << PAGE_SHIFT;
 			dimm->mtype = MEM_DDR2;
 			dimm->dtype = DEV_UNKNOWN;

+ 4 - 0
drivers/edac/i5000_edac.c

@@ -1012,6 +1012,10 @@ static void handle_channel(struct i5000_pvt *pvt, int slot, int channel,
 			/* add the number of COLUMN bits */
 			addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
 
+			/* Dual-rank memories have twice the size */
+			if (dinfo->dual_rank)
+				addrBits++;
+
 			addrBits += 6;	/* add 64 bits per DIMM */
 			addrBits -= 20;	/* divide by 2^^20 */
 			addrBits -= 3;	/* 8 bits per bytes */

+ 4 - 3
drivers/edac/sb_edac.c

@@ -513,7 +513,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 {
 	struct sbridge_pvt *pvt = mci->pvt_info;
 	struct dimm_info *dimm;
-	int i, j, banks, ranks, rows, cols, size, npages;
+	unsigned i, j, banks, ranks, rows, cols, npages;
+	u64 size;
 	u32 reg;
 	enum edac_type mode;
 	enum mem_type mtype;
@@ -585,10 +586,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 				cols = numcol(mtr);
 
 				/* DDR3 has 8 I/O banks */
-				size = (rows * cols * banks * ranks) >> (20 - 3);
+				size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
 				npages = MiB_TO_PAGES(size);
 
-				edac_dbg(0, "mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+				edac_dbg(0, "mc#%d: channel %d, dimm %d, %Ld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
 					 pvt->sbridge_dev->mc, i, j,
 					 size, npages,
 					 banks, ranks, rows, cols);

+ 5 - 0
drivers/gpio/gpio-lpc32xx.c

@@ -308,6 +308,7 @@ static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
 {
 	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
 
+	__set_gpio_level_p012(group, pin, value);
 	__set_gpio_dir_p012(group, pin, 0);
 
 	return 0;
@@ -318,6 +319,7 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
 {
 	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
 
+	__set_gpio_level_p3(group, pin, value);
 	__set_gpio_dir_p3(group, pin, 0);
 
 	return 0;
@@ -326,6 +328,9 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
 static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpo_level_p3(group, pin, value);
 	return 0;
 }
 

+ 28 - 8
drivers/gpu/drm/nouveau/Kconfig

@@ -17,6 +17,34 @@ config DRM_NOUVEAU
 	help
 	  Choose this option for open-source nVidia support.
 
+config NOUVEAU_DEBUG
+	int "Maximum debug level"
+	depends on DRM_NOUVEAU
+	range 0 7
+	default 5
+	help
+	  Selects the maximum debug level to compile support for.
+
+	  0 - fatal
+	  1 - error
+	  2 - warning
+	  3 - info
+	  4 - debug
+	  5 - trace (recommended)
+	  6 - paranoia
+	  7 - spam
+
+	  The paranoia and spam levels will add a lot of extra checks which
+	  may potentially slow down driver operation.
+
+config NOUVEAU_DEBUG_DEFAULT
+	int "Default debug level"
+	depends on DRM_NOUVEAU
+	range 0 7
+	default 3
+	help
+	  Selects the default debug level
+
 config DRM_NOUVEAU_BACKLIGHT
 	bool "Support for backlight control"
 	depends on DRM_NOUVEAU
@@ -25,14 +53,6 @@ config DRM_NOUVEAU_BACKLIGHT
 	  Say Y here if you want to control the backlight of your display
 	  (e.g. a laptop panel).
 
-config DRM_NOUVEAU_DEBUG
-	bool "Build in Nouveau's debugfs support"
-	depends on DRM_NOUVEAU && DEBUG_FS
-	default y
-	help
-	  Say Y here if you want Nouveau to output debugging information
-	  via debugfs.
-
 menu "I2C encoder or helper chips"
      depends on DRM && DRM_KMS_HELPER && I2C
 

+ 183 - 42
drivers/gpu/drm/nouveau/Makefile

@@ -3,49 +3,190 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm
-nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
-             nouveau_gpuobj.o nouveau_irq.o nouveau_notifier.o \
-             nouveau_sgdma.o nouveau_dma.o nouveau_util.o \
-             nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
-             nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
-             nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
-             nouveau_hdmi.o nouveau_dp.o nouveau_ramht.o \
-	     nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
-	     nouveau_mm.o nouveau_vm.o nouveau_mxm.o nouveau_gpio.o \
-	     nouveau_abi16.o \
-             nv04_timer.o \
-             nv04_mc.o nv40_mc.o nv50_mc.o \
-             nv04_fb.o nv10_fb.o nv20_fb.o nv30_fb.o nv40_fb.o \
-             nv50_fb.o nvc0_fb.o \
-             nv04_fifo.o nv10_fifo.o nv17_fifo.o nv40_fifo.o nv50_fifo.o \
-             nv84_fifo.o nvc0_fifo.o nve0_fifo.o \
-             nv04_fence.o nv10_fence.o nv84_fence.o nvc0_fence.o \
-             nv04_software.o nv50_software.o nvc0_software.o \
-             nv04_graph.o nv10_graph.o nv20_graph.o \
-             nv40_graph.o nv50_graph.o nvc0_graph.o nve0_graph.o \
-             nv40_grctx.o nv50_grctx.o nvc0_grctx.o nve0_grctx.o \
-             nv84_crypt.o nv98_crypt.o \
-             nva3_copy.o nvc0_copy.o \
-             nv31_mpeg.o nv50_mpeg.o \
-             nv84_bsp.o \
-             nv84_vp.o \
-             nv98_ppp.o \
-             nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
-             nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
-             nv04_crtc.o nv04_display.o nv04_cursor.o \
-             nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
-             nv50_cursor.o nv50_display.o \
-             nvd0_display.o \
-             nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \
-             nv10_gpio.o nv50_gpio.o \
-	     nv50_calc.o \
-	     nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
-	     nv50_vram.o nvc0_vram.o \
-	     nv50_vm.o nvc0_vm.o nouveau_prime.o
-
-nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
+ccflags-y += -I$(src)/core/include
+ccflags-y += -I$(src)/core
+ccflags-y += -I$(src)
+
+nouveau-y := core/core/client.o
+nouveau-y += core/core/engctx.o
+nouveau-y += core/core/engine.o
+nouveau-y += core/core/enum.o
+nouveau-y += core/core/gpuobj.o
+nouveau-y += core/core/handle.o
+nouveau-y += core/core/mm.o
+nouveau-y += core/core/namedb.o
+nouveau-y += core/core/object.o
+nouveau-y += core/core/option.o
+nouveau-y += core/core/parent.o
+nouveau-y += core/core/printk.o
+nouveau-y += core/core/ramht.o
+nouveau-y += core/core/subdev.o
+
+nouveau-y += core/subdev/bar/base.o
+nouveau-y += core/subdev/bar/nv50.o
+nouveau-y += core/subdev/bar/nvc0.o
+nouveau-y += core/subdev/bios/base.o
+nouveau-y += core/subdev/bios/bit.o
+nouveau-y += core/subdev/bios/conn.o
+nouveau-y += core/subdev/bios/dcb.o
+nouveau-y += core/subdev/bios/dp.o
+nouveau-y += core/subdev/bios/extdev.o
+nouveau-y += core/subdev/bios/gpio.o
+nouveau-y += core/subdev/bios/i2c.o
+nouveau-y += core/subdev/bios/init.o
+nouveau-y += core/subdev/bios/mxm.o
+nouveau-y += core/subdev/bios/perf.o
+nouveau-y += core/subdev/bios/pll.o
+nouveau-y += core/subdev/bios/therm.o
+nouveau-y += core/subdev/clock/nv04.o
+nouveau-y += core/subdev/clock/nv40.o
+nouveau-y += core/subdev/clock/nv50.o
+nouveau-y += core/subdev/clock/nva3.o
+nouveau-y += core/subdev/clock/nvc0.o
+nouveau-y += core/subdev/clock/pllnv04.o
+nouveau-y += core/subdev/clock/pllnva3.o
+nouveau-y += core/subdev/device/base.o
+nouveau-y += core/subdev/device/nv04.o
+nouveau-y += core/subdev/device/nv10.o
+nouveau-y += core/subdev/device/nv20.o
+nouveau-y += core/subdev/device/nv30.o
+nouveau-y += core/subdev/device/nv40.o
+nouveau-y += core/subdev/device/nv50.o
+nouveau-y += core/subdev/device/nvc0.o
+nouveau-y += core/subdev/device/nve0.o
+nouveau-y += core/subdev/devinit/base.o
+nouveau-y += core/subdev/devinit/nv04.o
+nouveau-y += core/subdev/devinit/nv05.o
+nouveau-y += core/subdev/devinit/nv10.o
+nouveau-y += core/subdev/devinit/nv1a.o
+nouveau-y += core/subdev/devinit/nv20.o
+nouveau-y += core/subdev/devinit/nv50.o
+nouveau-y += core/subdev/fb/base.o
+nouveau-y += core/subdev/fb/nv04.o
+nouveau-y += core/subdev/fb/nv10.o
+nouveau-y += core/subdev/fb/nv20.o
+nouveau-y += core/subdev/fb/nv30.o
+nouveau-y += core/subdev/fb/nv40.o
+nouveau-y += core/subdev/fb/nv50.o
+nouveau-y += core/subdev/fb/nvc0.o
+nouveau-y += core/subdev/gpio/base.o
+nouveau-y += core/subdev/gpio/nv10.o
+nouveau-y += core/subdev/gpio/nv50.o
+nouveau-y += core/subdev/gpio/nvd0.o
+nouveau-y += core/subdev/i2c/base.o
+nouveau-y += core/subdev/i2c/aux.o
+nouveau-y += core/subdev/i2c/bit.o
+nouveau-y += core/subdev/ibus/nvc0.o
+nouveau-y += core/subdev/ibus/nve0.o
+nouveau-y += core/subdev/instmem/base.o
+nouveau-y += core/subdev/instmem/nv04.o
+nouveau-y += core/subdev/instmem/nv40.o
+nouveau-y += core/subdev/instmem/nv50.o
+nouveau-y += core/subdev/ltcg/nvc0.o
+nouveau-y += core/subdev/mc/base.o
+nouveau-y += core/subdev/mc/nv04.o
+nouveau-y += core/subdev/mc/nv44.o
+nouveau-y += core/subdev/mc/nv50.o
+nouveau-y += core/subdev/mc/nv98.o
+nouveau-y += core/subdev/mc/nvc0.o
+nouveau-y += core/subdev/mxm/base.o
+nouveau-y += core/subdev/mxm/mxms.o
+nouveau-y += core/subdev/mxm/nv50.o
+nouveau-y += core/subdev/therm/base.o
+nouveau-y += core/subdev/therm/fan.o
+nouveau-y += core/subdev/therm/ic.o
+nouveau-y += core/subdev/therm/nv40.o
+nouveau-y += core/subdev/therm/nv50.o
+nouveau-y += core/subdev/therm/temp.o
+nouveau-y += core/subdev/timer/base.o
+nouveau-y += core/subdev/timer/nv04.o
+nouveau-y += core/subdev/vm/base.o
+nouveau-y += core/subdev/vm/nv04.o
+nouveau-y += core/subdev/vm/nv41.o
+nouveau-y += core/subdev/vm/nv44.o
+nouveau-y += core/subdev/vm/nv50.o
+nouveau-y += core/subdev/vm/nvc0.o
+
+nouveau-y += core/engine/dmaobj/base.o
+nouveau-y += core/engine/dmaobj/nv04.o
+nouveau-y += core/engine/dmaobj/nv50.o
+nouveau-y += core/engine/dmaobj/nvc0.o
+nouveau-y += core/engine/bsp/nv84.o
+nouveau-y += core/engine/copy/nva3.o
+nouveau-y += core/engine/copy/nvc0.o
+nouveau-y += core/engine/copy/nve0.o
+nouveau-y += core/engine/crypt/nv84.o
+nouveau-y += core/engine/crypt/nv98.o
+nouveau-y += core/engine/disp/nv04.o
+nouveau-y += core/engine/disp/nv50.o
+nouveau-y += core/engine/disp/nvd0.o
+nouveau-y += core/engine/disp/vga.o
+nouveau-y += core/engine/fifo/base.o
+nouveau-y += core/engine/fifo/nv04.o
+nouveau-y += core/engine/fifo/nv10.o
+nouveau-y += core/engine/fifo/nv17.o
+nouveau-y += core/engine/fifo/nv40.o
+nouveau-y += core/engine/fifo/nv50.o
+nouveau-y += core/engine/fifo/nv84.o
+nouveau-y += core/engine/fifo/nvc0.o
+nouveau-y += core/engine/fifo/nve0.o
+nouveau-y += core/engine/graph/ctxnv40.o
+nouveau-y += core/engine/graph/ctxnv50.o
+nouveau-y += core/engine/graph/ctxnvc0.o
+nouveau-y += core/engine/graph/ctxnve0.o
+nouveau-y += core/engine/graph/nv04.o
+nouveau-y += core/engine/graph/nv10.o
+nouveau-y += core/engine/graph/nv20.o
+nouveau-y += core/engine/graph/nv25.o
+nouveau-y += core/engine/graph/nv2a.o
+nouveau-y += core/engine/graph/nv30.o
+nouveau-y += core/engine/graph/nv34.o
+nouveau-y += core/engine/graph/nv35.o
+nouveau-y += core/engine/graph/nv40.o
+nouveau-y += core/engine/graph/nv50.o
+nouveau-y += core/engine/graph/nvc0.o
+nouveau-y += core/engine/graph/nve0.o
+nouveau-y += core/engine/mpeg/nv31.o
+nouveau-y += core/engine/mpeg/nv40.o
+nouveau-y += core/engine/mpeg/nv50.o
+nouveau-y += core/engine/mpeg/nv84.o
+nouveau-y += core/engine/ppp/nv98.o
+nouveau-y += core/engine/software/nv04.o
+nouveau-y += core/engine/software/nv10.o
+nouveau-y += core/engine/software/nv50.o
+nouveau-y += core/engine/software/nvc0.o
+nouveau-y += core/engine/vp/nv84.o
+
+# drm/core
+nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
+nouveau-y += nouveau_irq.o nouveau_vga.o nouveau_agp.o
+nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
+nouveau-y += nouveau_prime.o nouveau_abi16.o
+nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
+
+# drm/kms
+nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
+nouveau-y += nouveau_connector.o nouveau_hdmi.o nouveau_dp.o
+nouveau-y += nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o
+
+# drm/kms/nv04:nv50
+nouveau-y += nouveau_hw.o nouveau_calc.o
+nouveau-y += nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o
+nouveau-y += nv04_crtc.o nv04_display.o nv04_cursor.o
+
+# drm/kms/nv50-
+nouveau-y += nv50_display.o nvd0_display.o
+nouveau-y += nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
+nouveau-y += nv50_evo.o
+
+# drm/pm
+nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o
+nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o
+nouveau-y += nouveau_mem.o
+
+# other random bits
 nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
-nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
 nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
+nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
 
 obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o

+ 103 - 0
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;
+}

+ 236 - 0
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);
+	}
+}

+ 55 - 0
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;
+}

+ 18 - 29
drivers/gpu/drm/nouveau/nouveau_util.c → drivers/gpu/drm/nouveau/core/core/enum.c

@@ -25,27 +25,8 @@
  *
  */
 
-#include <linux/ratelimit.h>
-
-#include "nouveau_util.h"
-
-static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
-
-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);
-}
+#include <core/os.h>
+#include <core/enum.h>
 
 const struct nouveau_enum *
 nouveau_enum_find(const struct nouveau_enum *en, u32 value)
@@ -63,16 +44,24 @@ void
 nouveau_enum_print(const struct nouveau_enum *en, u32 value)
 {
 	en = nouveau_enum_find(en, value);
-	if (en) {
+	if (en)
 		printk("%s", en->name);
-		return;
-	}
-
-	printk("(unknown enum 0x%08x)", value);
+	else
+		printk("(unknown enum 0x%08x)", value);
 }
 
-int
-nouveau_ratelimit(void)
+void
+nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
 {
-	return __ratelimit(&nouveau_ratelimit_state);
+	while (bf->name) {
+		if (value & bf->mask) {
+			printk(" %s", bf->name);
+			value &= ~bf->mask;
+		}
+
+		bf++;
+	}
+
+	if (value)
+		printk(" (unknown bits 0x%08x)", value);
 }

+ 318 - 0
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;
+}

+ 223 - 0
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);
+}

+ 122 - 52
drivers/gpu/drm/nouveau/nouveau_mm.c → drivers/gpu/drm/nouveau/core/core/mm.c

@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * Copyright 2012 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -22,20 +22,52 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_mm.h"
+#include "core/os.h"
+#include "core/mm.h"
 
-static inline void
-region_put(struct nouveau_mm *mm, struct nouveau_mm_node *a)
+#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)
 {
-	list_del(&a->nl_entry);
-	list_del(&a->fl_entry);
-	kfree(a);
+	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_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
+region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
 {
 	struct nouveau_mm_node *b;
 
@@ -57,38 +89,12 @@ region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
 	return b;
 }
 
-#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_put(struct nouveau_mm *mm, struct nouveau_mm_node *this)
-{
-	struct nouveau_mm_node *prev = node(this, prev);
-	struct nouveau_mm_node *next = node(this, next);
-
-	list_add(&this->fl_entry, &mm->free);
-	this->type = 0;
-
-	if (prev && prev->type == 0) {
-		prev->length += this->length;
-		region_put(mm, this);
-		this = prev;
-	}
-
-	if (next && next->type == 0) {
-		next->offset  = this->offset;
-		next->length += this->length;
-		region_put(mm, this);
-	}
-}
-
 int
-nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc,
-	       u32 align, struct nouveau_mm_node **pnode)
+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 min = size_nc ? size_nc : size;
-	u32 align_mask = align - 1;
+	u32 mask = align - 1;
 	u32 splitoff;
 	u32 s, e;
 
@@ -104,16 +110,86 @@ nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc,
 		if (next && next->type != type)
 			e = rounddown(e, mm->block_size);
 
-		s  = (s + align_mask) & ~align_mask;
-		e &= ~align_mask;
-		if (s > e || e - s < min)
+		s  = (s + mask) & ~mask;
+		e &= ~mask;
+		if (s > e || e - s < size_min)
 			continue;
 
 		splitoff = s - this->offset;
-		if (splitoff && !region_split(mm, this, splitoff))
+		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_split(mm, this, min(size, e - s));
+		this = region_tail(mm, this, a);
 		if (!this)
 			return -ENOMEM;
 
@@ -148,6 +224,7 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
 	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;
 }
 
@@ -159,15 +236,8 @@ nouveau_mm_fini(struct nouveau_mm *mm)
 	int nodes = 0;
 
 	list_for_each_entry(node, &mm->nodes, nl_entry) {
-		if (nodes++ == mm->heap_nodes) {
-			printk(KERN_ERR "nouveau_mm in use at destroy time!\n");
-			list_for_each_entry(node, &mm->nodes, nl_entry) {
-				printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n",
-				       node->type, node->offset, node->length);
-			}
-			WARN_ON(1);
+		if (nodes++ == mm->heap_nodes)
 			return -EBUSY;
-		}
 	}
 
 	kfree(heap);

+ 203 - 0
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;
+}

+ 468 - 0
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
+}

+ 131 - 0
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;
+}

+ 139 - 0
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));
+}

+ 74 - 0
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);
+}

+ 109 - 0
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;
+}

+ 115 - 0
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;
+}

+ 175 - 0
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,
+	},
+};

+ 0 - 0
drivers/gpu/drm/nouveau/nva3_copy.fuc → drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc


+ 2 - 2
drivers/gpu/drm/nouveau/nva3_copy.fuc.h → drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h

@@ -1,4 +1,4 @@
-u32 nva3_pcopy_data[] = {
+static u32 nva3_pcopy_data[] = {
 /* 0x0000: ctx_object */
 	0x00000000,
 /* 0x0004: ctx_dma */
@@ -183,7 +183,7 @@ u32 nva3_pcopy_data[] = {
 	0x00000800,
 };
 
-u32 nva3_pcopy_code[] = {
+static u32 nva3_pcopy_code[] = {
 /* 0x0000: main */
 	0x04fe04bd,
 	0x3517f000,

+ 2 - 2
drivers/gpu/drm/nouveau/nvc0_copy.fuc.h → drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h

@@ -1,4 +1,4 @@
-u32 nvc0_pcopy_data[] = {
+static u32 nvc0_pcopy_data[] = {
 /* 0x0000: ctx_object */
 	0x00000000,
 /* 0x0004: ctx_query_address_high */
@@ -171,7 +171,7 @@ u32 nvc0_pcopy_data[] = {
 	0x00000800,
 };
 
-u32 nvc0_pcopy_code[] = {
+static u32 nvc0_pcopy_code[] = {
 /* 0x0000: main */
 	0x04fe04bd,
 	0x3517f000,

+ 222 - 0
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,
+	},
+};

+ 265 - 0
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,
+	},
+};

+ 156 - 0
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,
+	},
+};

+ 1 - 1
drivers/gpu/drm/nouveau/nv98_crypt.fuc → drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc

@@ -238,7 +238,7 @@ ih:
 			cmpu b32 $r4 0x60+#dma_count
 			bra nc #illegal_mthd
 			shl b32 $r5 $r4 2
-			add b32 $r5 (#ctx_dma - 0x60 * 4) & 0xffff
+			add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
 			bset $r3 0x1e
 			st b32 D[$r5] $r3
 			add b32 $r4 0x180 - 0x60

+ 2 - 2
drivers/gpu/drm/nouveau/nv98_crypt.fuc.h → drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h

@@ -1,4 +1,4 @@
-uint32_t nv98_pcrypt_data[] = {
+static uint32_t nv98_pcrypt_data[] = {
 /* 0x0000: ctx_dma */
 /* 0x0000: ctx_dma_query */
 	0x00000000,
@@ -150,7 +150,7 @@ uint32_t nv98_pcrypt_data[] = {
 	0x00000000,
 };
 
-uint32_t nv98_pcrypt_code[] = {
+static uint32_t nv98_pcrypt_code[] = {
 	0x17f004bd,
 	0x0010fe35,
 	0xf10004fe,

+ 217 - 0
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,
+	},
+};

+ 208 - 0
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,
+	},
+};

+ 90 - 0
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,
+	},
+};

+ 125 - 0
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,
+	},
+};

+ 118 - 0
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,
+	},
+};

+ 215 - 0
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");
+}

+ 87 - 0
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;
+}

+ 185 - 0
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,
+	},
+};

+ 173 - 0
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,
+	},
+};

+ 99 - 0
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,
+	},
+};

+ 181 - 0
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;
+}

+ 630 - 0
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,
+	},
+};

+ 178 - 0
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

+ 171 - 0
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,
+	},
+};

+ 208 - 0
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,
+	},
+};

+ 349 - 0
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,
+	},
+};

+ 502 - 0
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,
+	},
+};

+ 36 - 0
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

+ 420 - 0
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,
+	},
+};

+ 647 - 0
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,
+	},
+};

+ 628 - 0
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,
+	},
+};

+ 13 - 13
drivers/gpu/drm/nouveau/nouveau_grctx.h → drivers/gpu/drm/nouveau/core/engine/graph/ctx.h

@@ -2,7 +2,7 @@
 #define __NOUVEAU_GRCTX_H__
 
 struct nouveau_grctx {
-	struct drm_device *dev;
+	struct nouveau_device *device;
 
 	enum {
 		NOUVEAU_GRCTX_PROG,
@@ -10,18 +10,18 @@ struct nouveau_grctx {
 	} mode;
 	void *data;
 
-	uint32_t ctxprog_max;
-	uint32_t ctxprog_len;
-	uint32_t ctxprog_reg;
-	int      ctxprog_label[32];
-	uint32_t ctxvals_pos;
-	uint32_t ctxvals_base;
+	u32 ctxprog_max;
+	u32 ctxprog_len;
+	u32 ctxprog_reg;
+	int ctxprog_label[32];
+	u32 ctxvals_pos;
+	u32 ctxvals_base;
 };
 
 static inline void
-cp_out(struct nouveau_grctx *ctx, uint32_t inst)
+cp_out(struct nouveau_grctx *ctx, u32 inst)
 {
-	uint32_t *ctxprog = ctx->data;
+	u32 *ctxprog = ctx->data;
 
 	if (ctx->mode != NOUVEAU_GRCTX_PROG)
 		return;
@@ -31,13 +31,13 @@ cp_out(struct nouveau_grctx *ctx, uint32_t inst)
 }
 
 static inline void
-cp_lsr(struct nouveau_grctx *ctx, uint32_t val)
+cp_lsr(struct nouveau_grctx *ctx, u32 val)
 {
 	cp_out(ctx, CP_LOAD_SR | val);
 }
 
 static inline void
-cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
+cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length)
 {
 	ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
 
@@ -55,7 +55,7 @@ cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
 static inline void
 cp_name(struct nouveau_grctx *ctx, int name)
 {
-	uint32_t *ctxprog = ctx->data;
+	u32 *ctxprog = ctx->data;
 	int i;
 
 	if (ctx->mode != NOUVEAU_GRCTX_PROG)
@@ -115,7 +115,7 @@ cp_pos(struct nouveau_grctx *ctx, int offset)
 }
 
 static inline void
-gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
+gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val)
 {
 	if (ctx->mode != NOUVEAU_GRCTX_VALS)
 		return;

+ 66 - 67
drivers/gpu/drm/nouveau/nv40_grctx.c → drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c

@@ -22,6 +22,8 @@
  * Authors: Ben Skeggs
  */
 
+#include <core/gpuobj.h>
+
 /* NVIDIA context programs handle a number of other conditions which are
  * not implemented in our versions.  It's not clear why NVIDIA context
  * programs have this code, nor whether it's strictly necessary for
@@ -109,20 +111,18 @@
 #define CP_LOAD_MAGIC_NV44TCL    0x00800029 /* per-vs state (0x4497) */
 #define CP_LOAD_MAGIC_NV40TCL    0x00800041 /* per-vs state (0x4097) */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_grctx.h"
+#include "nv40.h"
+#include "ctx.h"
 
 /* TODO:
  *  - get vs count from 0x1540
  */
 
 static int
-nv40_graph_vs_count(struct drm_device *dev)
+nv40_graph_vs_count(struct nouveau_device *device)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -160,7 +160,7 @@ enum cp_label {
 static void
 nv40_graph_construct_general(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
 	cp_ctx(ctx, 0x4000a4, 1);
@@ -187,7 +187,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
 	cp_ctx(ctx, 0x400724, 1);
 	gr_def(ctx, 0x400724, 0x02008821);
 	cp_ctx(ctx, 0x400770, 3);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x400814, 4);
 		cp_ctx(ctx, 0x400828, 5);
 		cp_ctx(ctx, 0x400840, 5);
@@ -208,7 +208,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
 		gr_def(ctx, 0x4009dc, 0x80000000);
 	} else {
 		cp_ctx(ctx, 0x400840, 20);
-		if (nv44_graph_class(ctx->dev)) {
+		if (nv44_graph_class(ctx->device)) {
 			for (i = 0; i < 8; i++)
 				gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
 		}
@@ -217,21 +217,21 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
 		gr_def(ctx, 0x400888, 0x00000040);
 		cp_ctx(ctx, 0x400894, 11);
 		gr_def(ctx, 0x400894, 0x00000040);
-		if (!nv44_graph_class(ctx->dev)) {
+		if (!nv44_graph_class(ctx->device)) {
 			for (i = 0; i < 8; i++)
 				gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
 		}
 		cp_ctx(ctx, 0x4008e0, 2);
 		cp_ctx(ctx, 0x4008f8, 2);
-		if (dev_priv->chipset == 0x4c ||
-		    (dev_priv->chipset & 0xf0) == 0x60)
+		if (device->chipset == 0x4c ||
+		    (device->chipset & 0xf0) == 0x60)
 			cp_ctx(ctx, 0x4009f8, 1);
 	}
 	cp_ctx(ctx, 0x400a00, 73);
 	gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
 	cp_ctx(ctx, 0x401000, 4);
 	cp_ctx(ctx, 0x405004, 1);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -240,7 +240,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
 		break;
 	default:
 		cp_ctx(ctx, 0x403440, 1);
-		switch (dev_priv->chipset) {
+		switch (device->chipset) {
 		case 0x40:
 			gr_def(ctx, 0x403440, 0x00000010);
 			break;
@@ -266,19 +266,19 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
 static void
 nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x401880, 51);
 		gr_def(ctx, 0x401940, 0x00000100);
 	} else
-	if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 ||
-	    dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
+	if (device->chipset == 0x46 || device->chipset == 0x47 ||
+	    device->chipset == 0x49 || device->chipset == 0x4b) {
 		cp_ctx(ctx, 0x401880, 32);
 		for (i = 0; i < 16; i++)
 			gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
-		if (dev_priv->chipset == 0x46)
+		if (device->chipset == 0x46)
 			cp_ctx(ctx, 0x401900, 16);
 		cp_ctx(ctx, 0x401940, 3);
 	}
@@ -289,7 +289,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 	gr_def(ctx, 0x401978, 0xffff0000);
 	gr_def(ctx, 0x40197c, 0x00000001);
 	gr_def(ctx, 0x401990, 0x46400000);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x4019a0, 2);
 		cp_ctx(ctx, 0x4019ac, 5);
 	} else {
@@ -297,7 +297,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 		cp_ctx(ctx, 0x4019b4, 3);
 	}
 	gr_def(ctx, 0x4019bc, 0xffff0000);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x46:
 	case 0x47:
 	case 0x49:
@@ -316,7 +316,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 	for (i = 0; i < 16; i++)
 		gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
 	gr_def(ctx, 0x401a8c, 0x4b7fffff);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x401ab8, 3);
 	} else {
 		cp_ctx(ctx, 0x401ab8, 1);
@@ -327,10 +327,10 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 	gr_def(ctx, 0x401ad4, 0x70605040);
 	gr_def(ctx, 0x401ad8, 0xb8a89888);
 	gr_def(ctx, 0x401adc, 0xf8e8d8c8);
-	cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1);
+	cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
 	gr_def(ctx, 0x401b10, 0x40100000);
-	cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5);
-	gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ?
+	cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
+	gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
 			      0x00000004 : 0x00000000);
 	cp_ctx(ctx, 0x401b30, 25);
 	gr_def(ctx, 0x401b34, 0x0000ffff);
@@ -341,8 +341,8 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 	gr_def(ctx, 0x401b84, 0xffffffff);
 	gr_def(ctx, 0x401b88, 0x00ff7000);
 	gr_def(ctx, 0x401b8c, 0x0000ffff);
-	if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a &&
-	    dev_priv->chipset != 0x4e)
+	if (device->chipset != 0x44 && device->chipset != 0x4a &&
+	    device->chipset != 0x4e)
 		cp_ctx(ctx, 0x401b94, 1);
 	cp_ctx(ctx, 0x401b98, 8);
 	gr_def(ctx, 0x401b9c, 0x00ff0000);
@@ -371,12 +371,12 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 static void
 nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
 	cp_ctx(ctx, 0x402000, 1);
-	cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2);
-	switch (dev_priv->chipset) {
+	cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
+	switch (device->chipset) {
 	case 0x40:
 		gr_def(ctx, 0x402404, 0x00000001);
 		break;
@@ -393,9 +393,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 	default:
 		gr_def(ctx, 0x402404, 0x00000021);
 	}
-	if (dev_priv->chipset != 0x40)
+	if (device->chipset != 0x40)
 		gr_def(ctx, 0x402408, 0x030c30c3);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x44:
 	case 0x46:
 	case 0x4a:
@@ -408,10 +408,10 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 	default:
 		break;
 	}
-	cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9);
+	cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
 	gr_def(ctx, 0x402488, 0x3e020200);
 	gr_def(ctx, 0x40248c, 0x00ffffff);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x40:
 		gr_def(ctx, 0x402490, 0x60103f00);
 		break;
@@ -428,16 +428,16 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 		gr_def(ctx, 0x402490, 0x0c103f00);
 		break;
 	}
-	gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ?
+	gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
 			      0x00020000 : 0x00040000);
 	cp_ctx(ctx, 0x402500, 31);
 	gr_def(ctx, 0x402530, 0x00008100);
-	if (dev_priv->chipset == 0x40)
+	if (device->chipset == 0x40)
 		cp_ctx(ctx, 0x40257c, 6);
 	cp_ctx(ctx, 0x402594, 16);
 	cp_ctx(ctx, 0x402800, 17);
 	gr_def(ctx, 0x402800, 0x00000001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -445,7 +445,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 		gr_def(ctx, 0x402864, 0x00001001);
 		cp_ctx(ctx, 0x402870, 3);
 		gr_def(ctx, 0x402878, 0x00000003);
-		if (dev_priv->chipset != 0x47) { /* belong at end!! */
+		if (device->chipset != 0x47) { /* belong at end!! */
 			cp_ctx(ctx, 0x402900, 1);
 			cp_ctx(ctx, 0x402940, 1);
 			cp_ctx(ctx, 0x402980, 1);
@@ -470,9 +470,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 	}
 
 	cp_ctx(ctx, 0x402c00, 4);
-	gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ?
+	gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
 			      0x80800001 : 0x00888001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -485,30 +485,30 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 		break;
 	default:
 		cp_ctx(ctx, 0x402c10, 4);
-		if (dev_priv->chipset == 0x40)
+		if (device->chipset == 0x40)
 			cp_ctx(ctx, 0x402c20, 36);
 		else
-		if (dev_priv->chipset <= 0x42)
+		if (device->chipset <= 0x42)
 			cp_ctx(ctx, 0x402c20, 24);
 		else
-		if (dev_priv->chipset <= 0x4a)
+		if (device->chipset <= 0x4a)
 			cp_ctx(ctx, 0x402c20, 16);
 		else
 			cp_ctx(ctx, 0x402c20, 8);
-		cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13);
+		cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
 		gr_def(ctx, 0x402cd4, 0x00000005);
-		if (dev_priv->chipset != 0x40)
+		if (device->chipset != 0x40)
 			gr_def(ctx, 0x402ce0, 0x0000ffff);
 		break;
 	}
 
-	cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev));
-	for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++)
+	cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device));
+	for (i = 0; i < nv40_graph_vs_count(ctx->device); i++)
 		gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
 
-	if (dev_priv->chipset != 0x40) {
+	if (device->chipset != 0x40) {
 		cp_ctx(ctx, 0x403600, 1);
 		gr_def(ctx, 0x403600, 0x00000001);
 	}
@@ -516,7 +516,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 
 	cp_ctx(ctx, 0x403c18, 1);
 	gr_def(ctx, 0x403c18, 0x00000001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x46:
 	case 0x47:
 	case 0x49:
@@ -527,7 +527,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 		gr_def(ctx, 0x405c24, 0x000e3000);
 		break;
 	}
-	if (dev_priv->chipset != 0x4e)
+	if (device->chipset != 0x4e)
 		cp_ctx(ctx, 0x405800, 11);
 	cp_ctx(ctx, 0x407000, 1);
 }
@@ -535,7 +535,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 static void
 nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
 {
-	int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;
+	int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684;
 
 	cp_out (ctx, 0x300000);
 	cp_lsr (ctx, len - 4);
@@ -550,32 +550,31 @@ nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
 static void
 nv40_graph_construct_shader(struct nouveau_grctx *ctx)
 {
-	struct drm_device *dev = ctx->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	struct nouveau_gpuobj *obj = ctx->data;
 	int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
 	int offset, i;
 
-	vs_nr    = nv40_graph_vs_count(ctx->dev);
+	vs_nr    = nv40_graph_vs_count(ctx->device);
 	vs_nr_b0 = 363;
-	vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
-	if (dev_priv->chipset == 0x40) {
+	vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
+	if (device->chipset == 0x40) {
 		b0_offset = 0x2200/4; /* 33a0 */
 		b1_offset = 0x55a0/4; /* 1500 */
 		vs_len = 0x6aa0/4;
 	} else
-	if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
+	if (device->chipset == 0x41 || device->chipset == 0x42) {
 		b0_offset = 0x2200/4; /* 2200 */
 		b1_offset = 0x4400/4; /* 0b00 */
 		vs_len = 0x4f00/4;
 	} else {
 		b0_offset = 0x1d40/4; /* 2200 */
 		b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
-		vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
+		vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4;
 	}
 
 	cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
-	cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);
+	cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041);
 
 	offset = ctx->ctxvals_pos;
 	ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
@@ -661,21 +660,21 @@ nv40_grctx_generate(struct nouveau_grctx *ctx)
 }
 
 void
-nv40_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
+nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
 {
 	nv40_grctx_generate(&(struct nouveau_grctx) {
-			     .dev = dev,
+			     .device = device,
 			     .mode = NOUVEAU_GRCTX_VALS,
 			     .data = mem,
 			   });
 }
 
 void
-nv40_grctx_init(struct drm_device *dev, u32 *size)
+nv40_grctx_init(struct nouveau_device *device, u32 *size)
 {
 	u32 ctxprog[256], i;
 	struct nouveau_grctx ctx = {
-		.dev = dev,
+		.device = device,
 		.mode = NOUVEAU_GRCTX_PROG,
 		.data = ctxprog,
 		.ctxprog_max = ARRAY_SIZE(ctxprog)
@@ -683,8 +682,8 @@ nv40_grctx_init(struct drm_device *dev, u32 *size)
 
 	nv40_grctx_generate(&ctx);
 
-	nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+	nv_wr32(device, 0x400324, 0);
 	for (i = 0; i < ctx.ctxprog_len; i++)
-		nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, ctxprog[i]);
+		nv_wr32(device, 0x400328, ctxprog[i]);
 	*size = ctx.ctxvals_pos * 4;
 }

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 157 - 176
drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c


+ 3039 - 0
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);
+}

+ 2788 - 0
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);
+}

+ 4 - 4
drivers/gpu/drm/nouveau/nvc0_grgpc.fuc → drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc

@@ -24,7 +24,7 @@
  */
 
 /* To build:
- *    m4 nvc0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grgpc.fuc.h
+ *    m4 gpcnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o gpcnvc0.fuc.h
  */
 
 /* TODO
@@ -33,7 +33,7 @@
  */
 
 .section #nvc0_grgpc_data
-include(`nvc0_graph.fuc')
+include(`nvc0.fuc')
 gpc_id:			.b32 0
 gpc_mmio_list_head:	.b32 0
 gpc_mmio_list_tail:	.b32 0
@@ -209,11 +209,11 @@ nvd9_tpc_mmio_tail:
 .section #nvc0_grgpc_code
 bra #init
 define(`include_code')
-include(`nvc0_graph.fuc')
+include(`nvc0.fuc')
 
 // reports an exception to the host
 //
-// In: $r15 error code (see nvc0_graph.fuc)
+// In: $r15 error code (see nvc0.fuc)
 //
 error:
 	push $r14

+ 66 - 0
drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h → drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h

@@ -1,11 +1,19 @@
 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,
@@ -24,6 +32,7 @@ uint32_t nvc0_grgpc_data[] = {
 	0x00000000,
 	0x00000000,
 	0x00000000,
+/* 0x0064: chipsets */
 	0x000000c0,
 	0x012800c8,
 	0x01e40194,
@@ -49,6 +58,7 @@ uint32_t nvc0_grgpc_data[] = {
 	0x0194012c,
 	0x025401f8,
 	0x00000000,
+/* 0x00c8: nvc0_gpc_mmio_head */
 	0x00000380,
 	0x14000400,
 	0x20000450,
@@ -73,7 +83,10 @@ uint32_t nvc0_grgpc_data[] = {
 	0x00000c8c,
 	0x08001000,
 	0x00001014,
+/* 0x0128: nvc0_gpc_mmio_tail */
 	0x00000c6c,
+/* 0x012c: nvc1_gpc_mmio_tail */
+/* 0x012c: nvd9_gpc_mmio_head */
 	0x00000380,
 	0x04000400,
 	0x0800040c,
@@ -100,6 +113,8 @@ uint32_t nvc0_grgpc_data[] = {
 	0x00000c8c,
 	0x08001000,
 	0x00001014,
+/* 0x0194: nvd9_gpc_mmio_tail */
+/* 0x0194: nvc0_tpc_mmio_head */
 	0x00000018,
 	0x0000003c,
 	0x00000048,
@@ -120,11 +135,16 @@ uint32_t nvc0_grgpc_data[] = {
 	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,
@@ -152,12 +172,14 @@ uint32_t nvc0_grgpc_data[] = {
 
 uint32_t nvc0_grgpc_code[] = {
 	0x03060ef5,
+/* 0x0004: queue_put */
 	0x9800d898,
 	0x86f001d9,
 	0x0489b808,
 	0xf00c1bf4,
 	0x21f502f7,
 	0x00f802ec,
+/* 0x001c: queue_put_next */
 	0xb60798c4,
 	0x8dbb0384,
 	0x0880b600,
@@ -165,6 +187,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x90b6018f,
 	0x0f94f001,
 	0xf801d980,
+/* 0x0039: queue_get */
 	0x0131f400,
 	0x9800d898,
 	0x89b801d9,
@@ -176,37 +199,46 @@ uint32_t nvc0_grgpc_code[] = {
 	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,
@@ -215,6 +247,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x84b6085c,
 	0xf094bd06,
 	0x89d00099,
+/* 0x0103: wait_doneo */
 	0xf100f800,
 	0xb6083c87,
 	0x94bd0684,
@@ -222,6 +255,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x87f10089,
 	0x84b60818,
 	0x008ad006,
+/* 0x011c: wait_done_wait_doneo */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
@@ -230,6 +264,8 @@ uint32_t nvc0_grgpc_code[] = {
 	0xbd0684b6,
 	0x0099f094,
 	0xf80089d0,
+/* 0x013d: mmctx_size */
+/* 0x013f: nv_mmctx_size_loop */
 	0x9894bd00,
 	0x85b600e8,
 	0x0180b61a,
@@ -238,6 +274,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x04efb804,
 	0xb9eb1bf4,
 	0x00f8029f,
+/* 0x015c: mmctx_xfer */
 	0x083c87f1,
 	0xbd0684b6,
 	0x0199f094,
@@ -247,9 +284,11 @@ uint32_t nvc0_grgpc_code[] = {
 	0xf405bbfd,
 	0x8bd0090b,
 	0x0099f000,
+/* 0x0180: mmctx_base_disabled */
 	0xf405eefd,
 	0x8ed00c0b,
 	0xc08fd080,
+/* 0x018f: mmctx_multi_disabled */
 	0xb70199f0,
 	0xc8010080,
 	0xb4b600ab,
@@ -257,6 +296,8 @@ uint32_t nvc0_grgpc_code[] = {
 	0xb601aec8,
 	0xbefd11e4,
 	0x008bd005,
+/* 0x01a8: mmctx_exec_loop */
+/* 0x01a8: mmctx_wait_free */
 	0xf0008ecf,
 	0x0bf41fe4,
 	0x00ce98fa,
@@ -265,34 +306,42 @@ uint32_t nvc0_grgpc_code[] = {
 	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,
@@ -303,6 +352,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0xf000aed0,
 	0xbcd00ac7,
 	0x0721f500,
+/* 0x0263: strand_ctx_init */
 	0xf100f802,
 	0xb6083c87,
 	0x94bd0684,
@@ -325,6 +375,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x0684b608,
 	0xb70089cf,
 	0x95220080,
+/* 0x02ba: ctx_init_strand_loop */
 	0x8ed008fe,
 	0x408ed000,
 	0xb6808acf,
@@ -338,12 +389,14 @@ uint32_t nvc0_grgpc_code[] = {
 	0x94bd0684,
 	0xd00399f0,
 	0x00f80089,
+/* 0x02ec: error */
 	0xe7f1e0f9,
 	0xe3f09814,
 	0x8d21f440,
 	0x041ce0b7,
 	0xf401f7f0,
 	0xe0fc8d21,
+/* 0x0306: init */
 	0x04bd00f8,
 	0xf10004fe,
 	0xf0120017,
@@ -366,11 +419,13 @@ uint32_t nvc0_grgpc_code[] = {
 	0x27f10002,
 	0x24b60800,
 	0x0022cf06,
+/* 0x035f: init_find_chipset */
 	0xb65817f0,
 	0x13980c10,
 	0x0432b800,
 	0xb00b0bf4,
 	0x1bf40034,
+/* 0x0373: init_context */
 	0xf100f8f1,
 	0xb6080027,
 	0x22cf0624,
@@ -407,6 +462,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x0010b740,
 	0xf024bd08,
 	0x12d01f29,
+/* 0x0401: main */
 	0x0031f400,
 	0xf00028f4,
 	0x21f41cd7,
@@ -419,9 +475,11 @@ uint32_t nvc0_grgpc_code[] = {
 	0xfe051efd,
 	0x21f50018,
 	0x0ef404c3,
+/* 0x0431: main_not_ctx_xfer */
 	0x10ef94d3,
 	0xf501f5f0,
 	0xf402ec21,
+/* 0x043e: ih */
 	0x80f9c60e,
 	0xf90188fe,
 	0xf990f980,
@@ -436,30 +494,36 @@ uint32_t nvc0_grgpc_code[] = {
 	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,
@@ -489,11 +553,13 @@ uint32_t nvc0_grgpc_code[] = {
 	0x5c21f508,
 	0x0721f501,
 	0x0601f402,
+/* 0x054b: ctx_xfer_post */
 	0xf11412f4,
 	0xf04afc17,
 	0x27f00213,
 	0x0012d00d,
 	0x020721f5,
+/* 0x055c: ctx_xfer_done */
 	0x048f21f5,
 	0x000000f8,
 	0x00000000,

+ 451 - 0
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

+ 530 - 0
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,
+};

+ 4 - 4
drivers/gpu/drm/nouveau/nvc0_grhub.fuc → drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc

@@ -24,11 +24,11 @@
  */
 
 /* To build:
- *    m4 nvc0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grhub.fuc.h
+ *    m4 hubnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o hubnvc0.fuc.h
  */
 
 .section #nvc0_grhub_data
-include(`nvc0_graph.fuc')
+include(`nvc0.fuc')
 gpc_count:		.b32 0
 rop_count:		.b32 0
 cmd_queue:		queue_init
@@ -161,11 +161,11 @@ xfer_data: 		.b32 0
 .section #nvc0_grhub_code
 bra #init
 define(`include_code')
-include(`nvc0_graph.fuc')
+include(`nvc0.fuc')
 
 // reports an exception to the host
 //
-// In: $r15 error code (see nvc0_graph.fuc)
+// In: $r15 error code (see nvc0.fuc)
 //
 error:
 	push $r14

+ 89 - 0
drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h → drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h

@@ -1,6 +1,9 @@
 uint32_t nvc0_grhub_data[] = {
+/* 0x0000: gpc_count */
 	0x00000000,
+/* 0x0004: rop_count */
 	0x00000000,
+/* 0x0008: cmd_queue */
 	0x00000000,
 	0x00000000,
 	0x00000000,
@@ -19,9 +22,13 @@ uint32_t nvc0_grhub_data[] = {
 	0x00000000,
 	0x00000000,
 	0x00000000,
+/* 0x0050: hub_mmio_list_head */
 	0x00000000,
+/* 0x0054: hub_mmio_list_tail */
 	0x00000000,
+/* 0x0058: ctx_current */
 	0x00000000,
+/* 0x005c: chipsets */
 	0x000000c0,
 	0x013c00a0,
 	0x000000c1,
@@ -39,6 +46,7 @@ uint32_t nvc0_grhub_data[] = {
 	0x000000d9,
 	0x01dc0140,
 	0x00000000,
+/* 0x00a0: nvc0_hub_mmio_head */
 	0x0417e91c,
 	0x04400204,
 	0x28404004,
@@ -78,7 +86,10 @@ uint32_t nvc0_grhub_data[] = {
 	0x08408800,
 	0x0c408900,
 	0x00408980,
+/* 0x013c: nvc0_hub_mmio_tail */
 	0x044064c0,
+/* 0x0140: nvc1_hub_mmio_tail */
+/* 0x0140: nvd9_hub_mmio_head */
 	0x0417e91c,
 	0x04400204,
 	0x24404004,
@@ -118,6 +129,7 @@ uint32_t nvc0_grhub_data[] = {
 	0x08408800,
 	0x0c408900,
 	0x00408980,
+/* 0x01dc: nvd9_hub_mmio_tail */
 	0x00000000,
 	0x00000000,
 	0x00000000,
@@ -127,7 +139,10 @@ uint32_t nvc0_grhub_data[] = {
 	0x00000000,
 	0x00000000,
 	0x00000000,
+/* 0x0200: chan_data */
+/* 0x0200: chan_mmio_count */
 	0x00000000,
+/* 0x0204: chan_mmio_address */
 	0x00000000,
 	0x00000000,
 	0x00000000,
@@ -191,17 +206,20 @@ uint32_t nvc0_grhub_data[] = {
 	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,
@@ -209,6 +227,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x90b6018f,
 	0x0f94f001,
 	0xf801d980,
+/* 0x0039: queue_get */
 	0x0131f400,
 	0x9800d898,
 	0x89b801d9,
@@ -220,37 +239,46 @@ uint32_t nvc0_grhub_code[] = {
 	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,
@@ -259,6 +287,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x84b6085c,
 	0xf094bd06,
 	0x89d00099,
+/* 0x0103: wait_doneo */
 	0xf100f800,
 	0xb6083c87,
 	0x94bd0684,
@@ -266,6 +295,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x87f10089,
 	0x84b60818,
 	0x008ad006,
+/* 0x011c: wait_done_wait_doneo */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
@@ -274,6 +304,8 @@ uint32_t nvc0_grhub_code[] = {
 	0xbd0684b6,
 	0x0099f094,
 	0xf80089d0,
+/* 0x013d: mmctx_size */
+/* 0x013f: nv_mmctx_size_loop */
 	0x9894bd00,
 	0x85b600e8,
 	0x0180b61a,
@@ -282,6 +314,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x04efb804,
 	0xb9eb1bf4,
 	0x00f8029f,
+/* 0x015c: mmctx_xfer */
 	0x083c87f1,
 	0xbd0684b6,
 	0x0199f094,
@@ -291,9 +324,11 @@ uint32_t nvc0_grhub_code[] = {
 	0xf405bbfd,
 	0x8bd0090b,
 	0x0099f000,
+/* 0x0180: mmctx_base_disabled */
 	0xf405eefd,
 	0x8ed00c0b,
 	0xc08fd080,
+/* 0x018f: mmctx_multi_disabled */
 	0xb70199f0,
 	0xc8010080,
 	0xb4b600ab,
@@ -301,6 +336,8 @@ uint32_t nvc0_grhub_code[] = {
 	0xb601aec8,
 	0xbefd11e4,
 	0x008bd005,
+/* 0x01a8: mmctx_exec_loop */
+/* 0x01a8: mmctx_wait_free */
 	0xf0008ecf,
 	0x0bf41fe4,
 	0x00ce98fa,
@@ -309,34 +346,42 @@ uint32_t nvc0_grhub_code[] = {
 	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,
@@ -347,6 +392,7 @@ uint32_t nvc0_grhub_code[] = {
 	0xf000aed0,
 	0xbcd00ac7,
 	0x0721f500,
+/* 0x0263: strand_ctx_init */
 	0xf100f802,
 	0xb6083c87,
 	0x94bd0684,
@@ -369,6 +415,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x0684b608,
 	0xb70089cf,
 	0x95220080,
+/* 0x02ba: ctx_init_strand_loop */
 	0x8ed008fe,
 	0x408ed000,
 	0xb6808acf,
@@ -382,6 +429,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x94bd0684,
 	0xd00399f0,
 	0x00f80089,
+/* 0x02ec: error */
 	0xe7f1e0f9,
 	0xe4b60814,
 	0x00efd006,
@@ -389,6 +437,7 @@ uint32_t nvc0_grhub_code[] = {
 	0xf006e4b6,
 	0xefd001f7,
 	0xf8e0fc00,
+/* 0x0309: init */
 	0xfe04bd00,
 	0x07fe0004,
 	0x0017f100,
@@ -429,11 +478,13 @@ uint32_t nvc0_grhub_code[] = {
 	0x080027f1,
 	0xcf0624b6,
 	0xf7f00022,
+/* 0x03a9: init_find_chipset */
 	0x08f0b654,
 	0xb800f398,
 	0x0bf40432,
 	0x0034b00b,
 	0xf8f11bf4,
+/* 0x03bd: init_context */
 	0x0017f100,
 	0x02fe5801,
 	0xf003ff58,
@@ -454,6 +505,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x001fbb02,
 	0xf1000398,
 	0xf0200047,
+/* 0x040e: init_gpc */
 	0x4ea05043,
 	0x1fb90804,
 	0x8d21f402,
@@ -467,6 +519,7 @@ uint32_t nvc0_grhub_code[] = {
 	0xf7f00100,
 	0x8d21f402,
 	0x08004ea0,
+/* 0x0440: init_gpc_wait */
 	0xc86821f4,
 	0x0bf41fff,
 	0x044ea0fa,
@@ -479,6 +532,7 @@ uint32_t nvc0_grhub_code[] = {
 	0xb74021d0,
 	0xbd080020,
 	0x1f19f014,
+/* 0x0473: main */
 	0xf40021d0,
 	0x28f40031,
 	0x08d7f000,
@@ -517,6 +571,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x94bd0684,
 	0xd00699f0,
 	0x0ef40089,
+/* 0x0509: chsw_prev_no_next */
 	0xb920f931,
 	0x32f40212,
 	0x0232f401,
@@ -524,10 +579,12 @@ uint32_t nvc0_grhub_code[] = {
 	0x17f120fc,
 	0x14b60b00,
 	0x0012d006,
+/* 0x0527: chsw_no_prev */
 	0xc8130ef4,
 	0x0bf41f23,
 	0x0131f40d,
 	0xf50232f4,
+/* 0x0537: chsw_done */
 	0xf1082921,
 	0xb60b0c17,
 	0x27f00614,
@@ -536,10 +593,12 @@ uint32_t nvc0_grhub_code[] = {
 	0xbd0684b6,
 	0x0499f094,
 	0xf50089d0,
+/* 0x0557: main_not_ctx_switch */
 	0xb0ff200e,
 	0x1bf401e4,
 	0x02f2b90d,
 	0x07b521f5,
+/* 0x0567: main_not_ctx_chan */
 	0xb0420ef4,
 	0x1bf402e4,
 	0x3c87f12e,
@@ -553,14 +612,17 @@ uint32_t nvc0_grhub_code[] = {
 	0xf094bd06,
 	0x89d00799,
 	0x110ef400,
+/* 0x0598: main_not_ctx_save */
 	0xf010ef94,
 	0x21f501f5,
 	0x0ef502ec,
+/* 0x05a6: main_done */
 	0x17f1fed1,
 	0x14b60820,
 	0xf024bd06,
 	0x12d01f29,
 	0xbe0ef500,
+/* 0x05b9: ih */
 	0xfe80f9fe,
 	0x80f90188,
 	0xa0f990f9,
@@ -574,16 +636,19 @@ uint32_t nvc0_grhub_code[] = {
 	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,
@@ -591,32 +656,40 @@ uint32_t nvc0_grhub_code[] = {
 	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,
@@ -625,6 +698,7 @@ uint32_t nvc0_grhub_code[] = {
 	0xa86ce7f1,
 	0xf441e3f0,
 	0x00f88d21,
+/* 0x06b8: ctx_load */
 	0x083c87f1,
 	0xbd0684b6,
 	0x0599f094,
@@ -639,6 +713,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x0614b60a,
 	0xd00747f0,
 	0x14d00012,
+/* 0x06f1: ctx_chan_wait_0 */
 	0x4014cf40,
 	0xf41f44f0,
 	0x32d0fa1b,
@@ -688,6 +763,7 @@ uint32_t nvc0_grhub_code[] = {
 	0xbd0684b6,
 	0x0599f094,
 	0xf80089d0,
+/* 0x07b5: ctx_chan */
 	0x3121f500,
 	0xb821f506,
 	0x0ca7f006,
@@ -695,39 +771,48 @@ uint32_t nvc0_grhub_code[] = {
 	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,
@@ -762,9 +847,11 @@ uint32_t nvc0_grhub_code[] = {
 	0x0a1017f1,
 	0xf00614b6,
 	0x12d00527,
+/* 0x08dd: ctx_xfer_post_save_wait */
 	0x0012cf00,
 	0xf40522fd,
 	0x02f4fa1b,
+/* 0x08e9: ctx_xfer_post */
 	0x02f7f032,
 	0x065721f5,
 	0x21f5f4bd,
@@ -776,7 +863,9 @@ uint32_t nvc0_grhub_code[] = {
 	0x11fd8001,
 	0x070bf405,
 	0x07df21f5,
+/* 0x0914: ctx_xfer_no_post_mmio */
 	0x064921f5,
+/* 0x0918: ctx_xfer_done */
 	0x000000f8,
 	0x00000000,
 	0x00000000,

+ 780 - 0
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

+ 857 - 0
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,
+};

+ 0 - 0
drivers/gpu/drm/nouveau/nvc0_graph.fuc → drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc


+ 400 - 0
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
+')

+ 1387 - 0
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,
+	},
+};

+ 1314 - 0
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,
+	},
+};

+ 381 - 0
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,
+	},
+};

+ 31 - 0
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

+ 167 - 0
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,
+	},
+};

+ 134 - 0
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,
+	},
+};

+ 238 - 0
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,
+	},
+};

+ 168 - 0
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,
+	},
+};

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels