aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nv20_graph.c
diff options
context:
space:
mode:
authorBen Skeggs2009-12-11 19:24:15 +1000
committerDave Airlie2009-12-11 21:29:34 +1000
commit6ee738610f41b59733f63718f0bdbcba7d3a3f12 (patch)
treeeccb9f07671998c50a1bc606a54cd6f82ba43e0a /drivers/gpu/drm/nouveau/nv20_graph.c
parentd1ede145cea25c5b6d2ebb19b167af14e374bb45 (diff)
drm/nouveau: Add DRM driver for NVIDIA GPUs
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA. This driver is a KMS-based driver and requires a compatible nouveau userspace libdrm and nouveau X.org driver. This driver requires firmware files not available in this kernel tree, interested parties can find them via the nouveau project git archive. This driver is reverse engineered, and is in no way supported by nVidia. Support for nearly the complete range of nvidia hw from nv04->g80 (nv50) is available, and the kms driver should support driving nearly all output types (displayport is under development still) along with supporting suspend/resume. This work is all from the upstream nouveau project found at nouveau.freedesktop.org. The original authors list from nouveau git tree is: Anssi Hannula <anssi.hannula@iki.fi> Ben Skeggs <bskeggs@redhat.com> Francisco Jerez <currojerez@riseup.net> Maarten Maathuis <madman2003@gmail.com> Marcin Koƛcielnicki <koriakin@0x04.net> Matthew Garrett <mjg@redhat.com> Matt Parnell <mparnell@gmail.com> Patrice Mandin <patmandin@gmail.com> Pekka Paalanen <pq@iki.fi> Xavier Chantry <shiningxc@gmail.com> along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv20_graph.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c780
1 files changed, 780 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
new file mode 100644
index 000000000000..18ba74f19703
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -0,0 +1,780 @@
+#include "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+
+/*
+ * NV20
+ * -----
+ * There are 3 families :
+ * NV20 is 0x10de:0x020*
+ * NV25/28 is 0x10de:0x025* / 0x10de:0x028*
+ * NV2A is 0x10de:0x02A0
+ *
+ * NV30
+ * -----
+ * There are 3 families :
+ * NV30/31 is 0x10de:0x030* / 0x10de:0x031*
+ * NV34 is 0x10de:0x032*
+ * NV35/36 is 0x10de:0x033* / 0x10de:0x034*
+ *
+ * Not seen in the wild, no dumps (probably NV35) :
+ * NV37 is 0x10de:0x00fc, 0x10de:0x00fd
+ * NV38 is 0x10de:0x0333, 0x10de:0x00fe
+ *
+ */
+
+#define NV20_GRCTX_SIZE (3580*4)
+#define NV25_GRCTX_SIZE (3529*4)
+#define NV2A_GRCTX_SIZE (3500*4)
+
+#define NV30_31_GRCTX_SIZE (24392)
+#define NV34_GRCTX_SIZE (18140)
+#define NV35_36_GRCTX_SIZE (22396)
+
+static void
+nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+ int i;
+
+ nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
+ nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
+ nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
+ nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+ for (i = 0x04d4; i <= 0x04e0; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00030303);
+ for (i = 0x04f4; i <= 0x0500; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080000);
+ for (i = 0x050c; i <= 0x0518; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x01012000);
+ for (i = 0x051c; i <= 0x0528; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x000105b8);
+ for (i = 0x052c; i <= 0x0538; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080008);
+ for (i = 0x055c; i <= 0x0598; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x07ff0000);
+ nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
+ nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
+ nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
+ nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+ for (i = 0x1c1c; i <= 0x248c; i += 16) {
+ nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
+ nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
+ nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+ }
+ nv_wo32(dev, ctx, 0x281c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2830/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x285c/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x2860/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2864/4, 0x3f000000);
+ nv_wo32(dev, ctx, 0x286c/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x2870/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2878/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x2880/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x34a4/4, 0x000fe000);
+ nv_wo32(dev, ctx, 0x3530/4, 0x000003f8);
+ nv_wo32(dev, ctx, 0x3540/4, 0x002fe000);
+ for (i = 0x355c; i <= 0x3578; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x001c527c);
+}
+
+static void
+nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+ int i;
+
+ nv_wo32(dev, ctx, 0x035c/4, 0xffff0000);
+ nv_wo32(dev, ctx, 0x03c0/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x03c4/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x049c/4, 0x00000101);
+ nv_wo32(dev, ctx, 0x04b0/4, 0x00000111);
+ nv_wo32(dev, ctx, 0x04c8/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x04cc/4, 0xffff0000);
+ nv_wo32(dev, ctx, 0x04d0/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x04e4/4, 0x44400000);
+ nv_wo32(dev, ctx, 0x04fc/4, 0x4b800000);
+ for (i = 0x0510; i <= 0x051c; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00030303);
+ for (i = 0x0530; i <= 0x053c; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080000);
+ for (i = 0x0548; i <= 0x0554; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x01012000);
+ for (i = 0x0558; i <= 0x0564; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x000105b8);
+ for (i = 0x0568; i <= 0x0574; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080008);
+ for (i = 0x0598; i <= 0x05d4; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x07ff0000);
+ nv_wo32(dev, ctx, 0x05e0/4, 0x4b7fffff);
+ nv_wo32(dev, ctx, 0x0620/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x0624/4, 0x30201000);
+ nv_wo32(dev, ctx, 0x0628/4, 0x70605040);
+ nv_wo32(dev, ctx, 0x062c/4, 0xb0a09080);
+ nv_wo32(dev, ctx, 0x0630/4, 0xf0e0d0c0);
+ nv_wo32(dev, ctx, 0x0664/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x066c/4, 0x00004000);
+ nv_wo32(dev, ctx, 0x0678/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x0680/4, 0x00040000);
+ nv_wo32(dev, ctx, 0x0684/4, 0x00010000);
+ for (i = 0x1b04; i <= 0x2374; i += 16) {
+ nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
+ nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
+ nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+ }
+ nv_wo32(dev, ctx, 0x2704/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2718/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2744/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x2748/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x274c/4, 0x3f000000);
+ nv_wo32(dev, ctx, 0x2754/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x2758/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2760/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x2768/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x308c/4, 0x000fe000);
+ nv_wo32(dev, ctx, 0x3108/4, 0x000003f8);
+ nv_wo32(dev, ctx, 0x3468/4, 0x002fe000);
+ for (i = 0x3484; i <= 0x34a0; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x001c527c);
+}
+
+static void
+nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+ int i;
+
+ nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
+ nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
+ nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
+ nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+ for (i = 0x04d4; i <= 0x04e0; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00030303);
+ for (i = 0x04f4; i <= 0x0500; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080000);
+ for (i = 0x050c; i <= 0x0518; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x01012000);
+ for (i = 0x051c; i <= 0x0528; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x000105b8);
+ for (i = 0x052c; i <= 0x0538; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080008);
+ for (i = 0x055c; i <= 0x0598; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x07ff0000);
+ nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
+ nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
+ nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
+ nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+ for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
+ nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
+ nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
+ nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+ }
+ nv_wo32(dev, ctx, 0x269c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x26b0/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x26dc/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x26e0/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x26e4/4, 0x3f000000);
+ nv_wo32(dev, ctx, 0x26ec/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x26f0/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x26f8/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x2700/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x3024/4, 0x000fe000);
+ nv_wo32(dev, ctx, 0x30a0/4, 0x000003f8);
+ nv_wo32(dev, ctx, 0x33fc/4, 0x002fe000);
+ for (i = 0x341c; i <= 0x3438; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x001c527c);
+}
+
+static void
+nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+ int i;
+
+ nv_wo32(dev, ctx, 0x0410/4, 0x00000101);
+ nv_wo32(dev, ctx, 0x0424/4, 0x00000111);
+ nv_wo32(dev, ctx, 0x0428/4, 0x00000060);
+ nv_wo32(dev, ctx, 0x0444/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x0448/4, 0xffff0000);
+ nv_wo32(dev, ctx, 0x044c/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x0460/4, 0x44400000);
+ nv_wo32(dev, ctx, 0x048c/4, 0xffff0000);
+ for (i = 0x04e0; i < 0x04e8; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x04ec/4, 0x00011100);
+ for (i = 0x0508; i < 0x0548; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x07ff0000);
+ nv_wo32(dev, ctx, 0x0550/4, 0x4b7fffff);
+ nv_wo32(dev, ctx, 0x058c/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x0590/4, 0x30201000);
+ nv_wo32(dev, ctx, 0x0594/4, 0x70605040);
+ nv_wo32(dev, ctx, 0x0598/4, 0xb8a89888);
+ nv_wo32(dev, ctx, 0x059c/4, 0xf8e8d8c8);
+ nv_wo32(dev, ctx, 0x05b0/4, 0xb0000000);
+ for (i = 0x0600; i < 0x0640; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00010588);
+ for (i = 0x0640; i < 0x0680; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00030303);
+ for (i = 0x06c0; i < 0x0700; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0008aae4);
+ for (i = 0x0700; i < 0x0740; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x01012000);
+ for (i = 0x0740; i < 0x0780; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080008);
+ nv_wo32(dev, ctx, 0x085c/4, 0x00040000);
+ nv_wo32(dev, ctx, 0x0860/4, 0x00010000);
+ for (i = 0x0864; i < 0x0874; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00040004);
+ for (i = 0x1f18; i <= 0x3088 ; i += 16) {
+ nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
+ nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
+ nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+ }
+ for (i = 0x30b8; i < 0x30c8; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0000ffff);
+ nv_wo32(dev, ctx, 0x344c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x3808/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x381c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x3848/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x384c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x3850/4, 0x3f000000);
+ nv_wo32(dev, ctx, 0x3858/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x385c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x3864/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x386c/4, 0xbf800000);
+}
+
+static void
+nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+ int i;
+
+ nv_wo32(dev, ctx, 0x040c/4, 0x01000101);
+ nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
+ nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
+ nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
+ nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
+ nv_wo32(dev, ctx, 0x0480/4, 0xffff0000);
+ for (i = 0x04d4; i < 0x04dc; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x04e0/4, 0x00011100);
+ for (i = 0x04fc; i < 0x053c; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x07ff0000);
+ nv_wo32(dev, ctx, 0x0544/4, 0x4b7fffff);
+ nv_wo32(dev, ctx, 0x057c/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x0580/4, 0x30201000);
+ nv_wo32(dev, ctx, 0x0584/4, 0x70605040);
+ nv_wo32(dev, ctx, 0x0588/4, 0xb8a89888);
+ nv_wo32(dev, ctx, 0x058c/4, 0xf8e8d8c8);
+ nv_wo32(dev, ctx, 0x05a0/4, 0xb0000000);
+ for (i = 0x05f0; i < 0x0630; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00010588);
+ for (i = 0x0630; i < 0x0670; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00030303);
+ for (i = 0x06b0; i < 0x06f0; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0008aae4);
+ for (i = 0x06f0; i < 0x0730; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x01012000);
+ for (i = 0x0730; i < 0x0770; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080008);
+ nv_wo32(dev, ctx, 0x0850/4, 0x00040000);
+ nv_wo32(dev, ctx, 0x0854/4, 0x00010000);
+ for (i = 0x0858; i < 0x0868; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00040004);
+ for (i = 0x15ac; i <= 0x271c ; i += 16) {
+ nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
+ nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
+ nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+ }
+ for (i = 0x274c; i < 0x275c; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0000ffff);
+ nv_wo32(dev, ctx, 0x2ae0/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2e9c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2eb0/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2edc/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x2ee0/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2ee4/4, 0x3f000000);
+ nv_wo32(dev, ctx, 0x2eec/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x2ef0/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x2ef8/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x2f00/4, 0xbf800000);
+}
+
+static void
+nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+ int i;
+
+ nv_wo32(dev, ctx, 0x040c/4, 0x00000101);
+ nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
+ nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
+ nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
+ nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
+ nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
+ nv_wo32(dev, ctx, 0x0488/4, 0xffff0000);
+ for (i = 0x04dc; i < 0x04e4; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0fff0000);
+ nv_wo32(dev, ctx, 0x04e8/4, 0x00011100);
+ for (i = 0x0504; i < 0x0544; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x07ff0000);
+ nv_wo32(dev, ctx, 0x054c/4, 0x4b7fffff);
+ nv_wo32(dev, ctx, 0x0588/4, 0x00000080);
+ nv_wo32(dev, ctx, 0x058c/4, 0x30201000);
+ nv_wo32(dev, ctx, 0x0590/4, 0x70605040);
+ nv_wo32(dev, ctx, 0x0594/4, 0xb8a89888);
+ nv_wo32(dev, ctx, 0x0598/4, 0xf8e8d8c8);
+ nv_wo32(dev, ctx, 0x05ac/4, 0xb0000000);
+ for (i = 0x0604; i < 0x0644; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00010588);
+ for (i = 0x0644; i < 0x0684; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00030303);
+ for (i = 0x06c4; i < 0x0704; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0008aae4);
+ for (i = 0x0704; i < 0x0744; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x01012000);
+ for (i = 0x0744; i < 0x0784; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00080008);
+ nv_wo32(dev, ctx, 0x0860/4, 0x00040000);
+ nv_wo32(dev, ctx, 0x0864/4, 0x00010000);
+ for (i = 0x0868; i < 0x0878; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x00040004);
+ for (i = 0x1f1c; i <= 0x308c ; i += 16) {
+ nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
+ nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
+ nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+ }
+ for (i = 0x30bc; i < 0x30cc; i += 4)
+ nv_wo32(dev, ctx, i/4, 0x0000ffff);
+ nv_wo32(dev, ctx, 0x3450/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x380c/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x3820/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x384c/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x3850/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x3854/4, 0x3f000000);
+ nv_wo32(dev, ctx, 0x385c/4, 0x40000000);
+ nv_wo32(dev, ctx, 0x3860/4, 0x3f800000);
+ nv_wo32(dev, ctx, 0x3868/4, 0xbf800000);
+ nv_wo32(dev, ctx, 0x3870/4, 0xbf800000);
+}
+
+int
+nv20_graph_create_context(struct nouveau_channel *chan)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
+ unsigned int ctx_size;
+ unsigned int idoffs = 0x28/4;
+ int ret;
+
+ switch (dev_priv->chipset) {
+ case 0x20:
+ ctx_size = NV20_GRCTX_SIZE;
+ ctx_init = nv20_graph_context_init;
+ idoffs = 0;
+ break;
+ case 0x25:
+ case 0x28:
+ ctx_size = NV25_GRCTX_SIZE;
+ ctx_init = nv25_graph_context_init;
+ break;
+ case 0x2a:
+ ctx_size = NV2A_GRCTX_SIZE;
+ ctx_init = nv2a_graph_context_init;
+ idoffs = 0;
+ break;
+ case 0x30:
+ case 0x31:
+ ctx_size = NV30_31_GRCTX_SIZE;
+ ctx_init = nv30_31_graph_context_init;
+ break;
+ case 0x34:
+ ctx_size = NV34_GRCTX_SIZE;
+ ctx_init = nv34_graph_context_init;
+ break;
+ case 0x35:
+ case 0x36:
+ ctx_size = NV35_36_GRCTX_SIZE;
+ ctx_init = nv35_36_graph_context_init;
+ break;
+ default:
+ ctx_size = 0;
+ ctx_init = nv35_36_graph_context_init;
+ NV_ERROR(dev, "Please contact the devs if you want your NV%x"
+ " card to work\n", dev_priv->chipset);
+ return -ENOSYS;
+ break;
+ }
+
+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramin_grctx);
+ if (ret)
+ return ret;
+
+ /* Initialise default context values */
+ dev_priv->engine.instmem.prepare_access(dev, true);
+ ctx_init(dev, chan->ramin_grctx->gpuobj);
+
+ /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
+ nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
+ (chan->id << 24) | 0x1); /* CTX_USER */
+
+ nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id,
+ chan->ramin_grctx->instance >> 4);
+
+ dev_priv->engine.instmem.finish_access(dev);
+ return 0;
+}
+
+void
+nv20_graph_destroy_context(struct nouveau_channel *chan)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (chan->ramin_grctx)
+ nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+
+ dev_priv->engine.instmem.prepare_access(dev, true);
+ nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0);
+ dev_priv->engine.instmem.finish_access(dev);
+}
+
+int
+nv20_graph_load_context(struct nouveau_channel *chan)
+{
+ struct drm_device *dev = chan->dev;
+ uint32_t inst;
+
+ if (!chan->ramin_grctx)
+ return -EINVAL;
+ inst = chan->ramin_grctx->instance >> 4;
+
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+ NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD);
+ nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+
+ nouveau_wait_for_idle(dev);
+ return 0;
+}
+
+int
+nv20_graph_unload_context(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_channel *chan;
+ uint32_t inst, tmp;
+
+ chan = pgraph->channel(dev);
+ if (!chan)
+ return 0;
+ inst = chan->ramin_grctx->instance >> 4;
+
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+ NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
+
+ nouveau_wait_for_idle(dev);
+
+ nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+ tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
+ tmp |= (pfifo->channels - 1) << 24;
+ nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+ return 0;
+}
+
+static void
+nv20_graph_rdi(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int i, writecount = 32;
+ uint32_t rdi_index = 0x2c80000;
+
+ if (dev_priv->chipset == 0x20) {
+ rdi_index = 0x3d0000;
+ writecount = 15;
+ }
+
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
+ for (i = 0; i < writecount; i++)
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
+
+ nouveau_wait_for_idle(dev);
+}
+
+int
+nv20_graph_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv =
+ (struct drm_nouveau_private *)dev->dev_private;
+ uint32_t tmp, vramsz;
+ int ret, i;
+
+ nv_wr32(dev, NV03_PMC_ENABLE,
+ nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
+ nv_wr32(dev, NV03_PMC_ENABLE,
+ nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
+
+ if (!dev_priv->ctx_table) {
+ /* Create Context Pointer Table */
+ dev_priv->ctx_table_size = 32 * 4;
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
+ dev_priv->ctx_table_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &dev_priv->ctx_table);
+ if (ret)
+ return ret;
+ }
+
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
+ dev_priv->ctx_table->instance >> 4);
+
+ nv20_graph_rdi(dev);
+
+ nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700);
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
+ nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
+ nv_wr32(dev, 0x40009C , 0x00000040);
+
+ if (dev_priv->chipset >= 0x25) {
+ nv_wr32(dev, 0x400890, 0x00080000);
+ nv_wr32(dev, 0x400610, 0x304B1FB6);
+ nv_wr32(dev, 0x400B80, 0x18B82880);
+ nv_wr32(dev, 0x400B84, 0x44000000);
+ nv_wr32(dev, 0x400098, 0x40000080);
+ nv_wr32(dev, 0x400B88, 0x000000ff);
+ } else {
+ nv_wr32(dev, 0x400880, 0x00080000); /* 0x0008c7df */
+ nv_wr32(dev, 0x400094, 0x00000005);
+ nv_wr32(dev, 0x400B80, 0x45CAA208); /* 0x45eae20e */
+ nv_wr32(dev, 0x400B84, 0x24000000);
+ nv_wr32(dev, 0x400098, 0x00000040);
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030);
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030);
+ }
+
+ /* copy tile info from PFB */
+ for (i = 0; i < NV10_PFB_TILE__SIZE; i++) {
+ nv_wr32(dev, 0x00400904 + i * 0x10,
+ nv_rd32(dev, NV10_PFB_TLIMIT(i)));
+ /* which is NV40_PGRAPH_TLIMIT0(i) ?? */
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + i * 4);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
+ nv_rd32(dev, NV10_PFB_TLIMIT(i)));
+ nv_wr32(dev, 0x00400908 + i * 0x10,
+ nv_rd32(dev, NV10_PFB_TSIZE(i)));
+ /* which is NV40_PGRAPH_TSIZE0(i) ?? */
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + i * 4);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
+ nv_rd32(dev, NV10_PFB_TSIZE(i)));
+ nv_wr32(dev, 0x00400900 + i * 0x10,
+ nv_rd32(dev, NV10_PFB_TILE(i)));
+ /* which is NV40_PGRAPH_TILE0(i) ?? */
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + i * 4);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
+ nv_rd32(dev, NV10_PFB_TILE(i)));
+ }
+ for (i = 0; i < 8; i++) {
+ nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4));
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0090 + i * 4);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
+ nv_rd32(dev, 0x100300 + i * 4));
+ }
+ nv_wr32(dev, 0x4009a0, nv_rd32(dev, 0x100324));
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, nv_rd32(dev, 0x100324));
+
+ nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+ nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF);
+
+ tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) & 0x0007ff00;
+ nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
+ tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) | 0x00020100;
+ nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
+
+ /* begin RAM config */
+ vramsz = drm_get_resource_len(dev, 0) - 1;
+ nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
+ nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG0));
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG1));
+ nv_wr32(dev, 0x400820, 0);
+ nv_wr32(dev, 0x400824, 0);
+ nv_wr32(dev, 0x400864, vramsz - 1);
+ nv_wr32(dev, 0x400868, vramsz - 1);
+
+ /* interesting.. the below overwrites some of the tile setup above.. */
+ nv_wr32(dev, 0x400B20, 0x00000000);
+ nv_wr32(dev, 0x400B04, 0xFFFFFFFF);
+
+ nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
+ nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
+ nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
+ nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
+
+ return 0;
+}
+
+void
+nv20_graph_takedown(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table);
+}
+
+int
+nv30_graph_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int ret, i;
+
+ nv_wr32(dev, NV03_PMC_ENABLE,
+ nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
+ nv_wr32(dev, NV03_PMC_ENABLE,
+ nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
+
+ if (!dev_priv->ctx_table) {
+ /* Create Context Pointer Table */
+ dev_priv->ctx_table_size = 32 * 4;
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
+ dev_priv->ctx_table_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &dev_priv->ctx_table);
+ if (ret)
+ return ret;
+ }
+
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
+ dev_priv->ctx_table->instance >> 4);
+
+ nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+ nv_wr32(dev, 0x400890, 0x01b463ff);
+ nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
+ nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000);
+ nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
+ nv_wr32(dev, 0x400B80, 0x1003d888);
+ nv_wr32(dev, 0x400B84, 0x0c000000);
+ nv_wr32(dev, 0x400098, 0x00000000);
+ nv_wr32(dev, 0x40009C, 0x0005ad00);
+ nv_wr32(dev, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
+ nv_wr32(dev, 0x4000a0, 0x00000000);
+ nv_wr32(dev, 0x4000a4, 0x00000008);
+ nv_wr32(dev, 0x4008a8, 0xb784a400);
+ nv_wr32(dev, 0x400ba0, 0x002f8685);
+ nv_wr32(dev, 0x400ba4, 0x00231f3f);
+ nv_wr32(dev, 0x4008a4, 0x40000020);
+
+ if (dev_priv->chipset == 0x34) {
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00200201);
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000008);
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000032);
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000002);
+ }
+
+ nv_wr32(dev, 0x4000c0, 0x00000016);
+
+ /* copy tile info from PFB */
+ for (i = 0; i < NV10_PFB_TILE__SIZE; i++) {
+ nv_wr32(dev, 0x00400904 + i * 0x10,
+ nv_rd32(dev, NV10_PFB_TLIMIT(i)));
+ /* which is NV40_PGRAPH_TLIMIT0(i) ?? */
+ nv_wr32(dev, 0x00400908 + i * 0x10,
+ nv_rd32(dev, NV10_PFB_TSIZE(i)));
+ /* which is NV40_PGRAPH_TSIZE0(i) ?? */
+ nv_wr32(dev, 0x00400900 + i * 0x10,
+ nv_rd32(dev, NV10_PFB_TILE(i)));
+ /* which is NV40_PGRAPH_TILE0(i) ?? */
+ }
+
+ nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+ nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF);
+ nv_wr32(dev, 0x0040075c , 0x00000001);
+
+ /* begin RAM config */
+ /* vramsz = drm_get_resource_len(dev, 0) - 1; */
+ nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
+ nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
+ if (dev_priv->chipset != 0x34) {
+ nv_wr32(dev, 0x400750, 0x00EA0000);
+ nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG0));
+ nv_wr32(dev, 0x400750, 0x00EA0004);
+ nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG1));
+ }
+
+ return 0;
+}
+
+struct nouveau_pgraph_object_class nv20_graph_grclass[] = {
+ { 0x0030, false, NULL }, /* null */
+ { 0x0039, false, NULL }, /* m2mf */
+ { 0x004a, false, NULL }, /* gdirect */
+ { 0x009f, false, NULL }, /* imageblit (nv12) */
+ { 0x008a, false, NULL }, /* ifc */
+ { 0x0089, false, NULL }, /* sifm */
+ { 0x0062, false, NULL }, /* surf2d */
+ { 0x0043, false, NULL }, /* rop */
+ { 0x0012, false, NULL }, /* beta1 */
+ { 0x0072, false, NULL }, /* beta4 */
+ { 0x0019, false, NULL }, /* cliprect */
+ { 0x0044, false, NULL }, /* pattern */
+ { 0x009e, false, NULL }, /* swzsurf */
+ { 0x0096, false, NULL }, /* celcius */
+ { 0x0097, false, NULL }, /* kelvin (nv20) */
+ { 0x0597, false, NULL }, /* kelvin (nv25) */
+ {}
+};
+
+struct nouveau_pgraph_object_class nv30_graph_grclass[] = {
+ { 0x0030, false, NULL }, /* null */
+ { 0x0039, false, NULL }, /* m2mf */
+ { 0x004a, false, NULL }, /* gdirect */
+ { 0x009f, false, NULL }, /* imageblit (nv12) */
+ { 0x008a, false, NULL }, /* ifc */
+ { 0x038a, false, NULL }, /* ifc (nv30) */
+ { 0x0089, false, NULL }, /* sifm */
+ { 0x0389, false, NULL }, /* sifm (nv30) */
+ { 0x0062, false, NULL }, /* surf2d */
+ { 0x0362, false, NULL }, /* surf2d (nv30) */
+ { 0x0043, false, NULL }, /* rop */
+ { 0x0012, false, NULL }, /* beta1 */
+ { 0x0072, false, NULL }, /* beta4 */
+ { 0x0019, false, NULL }, /* cliprect */
+ { 0x0044, false, NULL }, /* pattern */
+ { 0x039e, false, NULL }, /* swzsurf */
+ { 0x0397, false, NULL }, /* rankine (nv30) */
+ { 0x0497, false, NULL }, /* rankine (nv35) */
+ { 0x0697, false, NULL }, /* rankine (nv34) */
+ {}
+};
+