aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvc0_graph.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-05-25 04:32:44 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-06-23 01:57:38 -0400
commit0411de854898a2402cf4bd915bed7ec9a6b76f9a (patch)
tree52678d0557377674a78b95211adb36dba1ecde9b /drivers/gpu/drm/nouveau/nvc0_graph.c
parentf8522fc80f2e0392fc44b069f61721bd25907270 (diff)
drm/nvc0/gr: import and use our own fuc by default
The ability to use NVIDIA's fuc has been retained *temporarily* in order to better debug any issues that may be lingering in our initial attempt at writing this ucode. Once I'm fairly confident we're okay, it'll be removed. There's a number of things not implemented by this fuc currently, but most of it is sets of state that our context setup would not have used anyway. No doubt we'll find out what they're for at some point, and implement it if required. This has been tested on 0xc0/0xc4 thus far, and from what I could tell it worked as well as NVIDIA's. It's also been tested on 0xc1, but even with NVIDIA's fuc that chipset doesn't work correctly with nouveau yet. 0xc3/0xc8/0xce should in theory be supported too, but I don't have the hardware to check that. There's no doubt numerous bugs to squash yet, please report any! Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvc0_graph.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c185
1 files changed, 149 insertions, 36 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 6c06d6636a3c..c5aa7e7aea0d 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -28,7 +28,34 @@
28 28
29#include "nouveau_drv.h" 29#include "nouveau_drv.h"
30#include "nouveau_mm.h" 30#include "nouveau_mm.h"
31
31#include "nvc0_graph.h" 32#include "nvc0_graph.h"
33#include "nvc0_grhub.fuc.h"
34#include "nvc0_grgpc.fuc.h"
35
36static void
37nvc0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
38{
39 NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
40 nv_rd32(dev, base + 0x400));
41 NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
42 nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
43 nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
44 NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
45 nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
46 nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
47}
48
49static void
50nvc0_graph_ctxctl_debug(struct drm_device *dev)
51{
52 u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
53 u32 gpc;
54
55 nvc0_graph_ctxctl_debug_unit(dev, 0x409000);
56 for (gpc = 0; gpc < gpcnr; gpc++)
57 nvc0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
58}
32 59
33static int 60static int
34nvc0_graph_load_context(struct nouveau_channel *chan) 61nvc0_graph_load_context(struct nouveau_channel *chan)
@@ -72,13 +99,24 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
72 if (!ctx) 99 if (!ctx)
73 return -ENOMEM; 100 return -ENOMEM;
74 101
75 nvc0_graph_load_context(chan); 102 if (!nouveau_ctxfw) {
76 103 nv_wr32(dev, 0x409840, 0x80000000);
77 nv_wo32(grch->grctx, 0x1c, 1); 104 nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
78 nv_wo32(grch->grctx, 0x20, 0); 105 nv_wr32(dev, 0x409504, 0x00000001);
79 nv_wo32(grch->grctx, 0x28, 0); 106 if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
80 nv_wo32(grch->grctx, 0x2c, 0); 107 NV_ERROR(dev, "PGRAPH: HUB_SET_CHAN timeout\n");
81 dev_priv->engine.instmem.flush(dev); 108 nvc0_graph_ctxctl_debug(dev);
109 return -EBUSY;
110 }
111 } else {
112 nvc0_graph_load_context(chan);
113
114 nv_wo32(grch->grctx, 0x1c, 1);
115 nv_wo32(grch->grctx, 0x20, 0);
116 nv_wo32(grch->grctx, 0x28, 0);
117 nv_wo32(grch->grctx, 0x2c, 0);
118 dev_priv->engine.instmem.flush(dev);
119 }
82 120
83 ret = nvc0_grctx_generate(chan); 121 ret = nvc0_grctx_generate(chan);
84 if (ret) { 122 if (ret) {
@@ -86,10 +124,21 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
86 return ret; 124 return ret;
87 } 125 }
88 126
89 ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst); 127 if (!nouveau_ctxfw) {
90 if (ret) { 128 nv_wr32(dev, 0x409840, 0x80000000);
91 kfree(ctx); 129 nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
92 return ret; 130 nv_wr32(dev, 0x409504, 0x00000002);
131 if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
132 NV_ERROR(dev, "PGRAPH: HUB_CTX_SAVE timeout\n");
133 nvc0_graph_ctxctl_debug(dev);
134 return -EBUSY;
135 }
136 } else {
137 ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst);
138 if (ret) {
139 kfree(ctx);
140 return ret;
141 }
93 } 142 }
94 143
95 for (i = 0; i < priv->grctx_size; i += 4) 144 for (i = 0; i < priv->grctx_size; i += 4)
@@ -210,15 +259,20 @@ nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
210 for (i = 0; i < priv->grctx_size; i += 4) 259 for (i = 0; i < priv->grctx_size; i += 4)
211 nv_wo32(grctx, i, priv->grctx_vals[i / 4]); 260 nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
212 261
213 nv_wo32(grctx, 0xf4, 0); 262 if (!nouveau_ctxfw) {
214 nv_wo32(grctx, 0xf8, 0); 263 nv_wo32(grctx, 0x00, grch->mmio_nr);
215 nv_wo32(grctx, 0x10, grch->mmio_nr); 264 nv_wo32(grctx, 0x04, grch->mmio->linst >> 8);
216 nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->linst)); 265 } else {
217 nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->linst)); 266 nv_wo32(grctx, 0xf4, 0);
218 nv_wo32(grctx, 0x1c, 1); 267 nv_wo32(grctx, 0xf8, 0);
219 nv_wo32(grctx, 0x20, 0); 268 nv_wo32(grctx, 0x10, grch->mmio_nr);
220 nv_wo32(grctx, 0x28, 0); 269 nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->linst));
221 nv_wo32(grctx, 0x2c, 0); 270 nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->linst));
271 nv_wo32(grctx, 0x1c, 1);
272 nv_wo32(grctx, 0x20, 0);
273 nv_wo32(grctx, 0x28, 0);
274 nv_wo32(grctx, 0x2c, 0);
275 }
222 pinstmem->flush(dev); 276 pinstmem->flush(dev);
223 return 0; 277 return 0;
224 278
@@ -419,8 +473,51 @@ nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
419static int 473static int
420nvc0_graph_init_ctxctl(struct drm_device *dev) 474nvc0_graph_init_ctxctl(struct drm_device *dev)
421{ 475{
476 struct drm_nouveau_private *dev_priv = dev->dev_private;
422 struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); 477 struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
423 u32 r000260; 478 u32 r000260;
479 int i;
480
481 if (!nouveau_ctxfw) {
482 /* load HUB microcode */
483 r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
484 nv_wr32(dev, 0x4091c0, 0x01000000);
485 for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++)
486 nv_wr32(dev, 0x4091c4, nvc0_grhub_data[i]);
487
488 nv_wr32(dev, 0x409180, 0x01000000);
489 for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) {
490 if ((i & 0x3f) == 0)
491 nv_wr32(dev, 0x409188, i >> 6);
492 nv_wr32(dev, 0x409184, nvc0_grhub_code[i]);
493 }
494
495 /* load GPC microcode */
496 nv_wr32(dev, 0x41a1c0, 0x01000000);
497 for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++)
498 nv_wr32(dev, 0x41a1c4, nvc0_grgpc_data[i]);
499
500 nv_wr32(dev, 0x41a180, 0x01000000);
501 for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) {
502 if ((i & 0x3f) == 0)
503 nv_wr32(dev, 0x41a188, i >> 6);
504 nv_wr32(dev, 0x41a184, nvc0_grgpc_code[i]);
505 }
506 nv_wr32(dev, 0x000260, r000260);
507
508 /* start HUB ucode running, it'll init the GPCs */
509 nv_wr32(dev, 0x409800, dev_priv->chipset);
510 nv_wr32(dev, 0x40910c, 0x00000000);
511 nv_wr32(dev, 0x409100, 0x00000002);
512 if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
513 NV_ERROR(dev, "PGRAPH: HUB_INIT timed out\n");
514 nvc0_graph_ctxctl_debug(dev);
515 return -EBUSY;
516 }
517
518 priv->grctx_size = nv_rd32(dev, 0x409804);
519 return 0;
520 }
424 521
425 /* load fuc microcode */ 522 /* load fuc microcode */
426 r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); 523 r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
@@ -528,6 +625,22 @@ nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
528} 625}
529 626
530static void 627static void
628nvc0_graph_ctxctl_isr(struct drm_device *dev)
629{
630 u32 ustat = nv_rd32(dev, 0x409c18);
631
632 if (ustat & 0x00000001)
633 NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
634 if (ustat & 0x00080000)
635 NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
636 if (ustat & ~0x00080001)
637 NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
638
639 nvc0_graph_ctxctl_debug(dev);
640 nv_wr32(dev, 0x409c20, ustat);
641}
642
643static void
531nvc0_graph_isr(struct drm_device *dev) 644nvc0_graph_isr(struct drm_device *dev)
532{ 645{
533 u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; 646 u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
@@ -578,11 +691,7 @@ nvc0_graph_isr(struct drm_device *dev)
578 } 691 }
579 692
580 if (stat & 0x00080000) { 693 if (stat & 0x00080000) {
581 u32 ustat = nv_rd32(dev, 0x409c18); 694 nvc0_graph_ctxctl_isr(dev);
582
583 NV_INFO(dev, "PGRAPH: CTXCTRL ustat 0x%08x\n", ustat);
584
585 nv_wr32(dev, 0x409c20, ustat);
586 nv_wr32(dev, 0x400100, 0x00080000); 695 nv_wr32(dev, 0x400100, 0x00080000);
587 stat &= ~0x00080000; 696 stat &= ~0x00080000;
588 } 697 }
@@ -651,10 +760,12 @@ nvc0_graph_destroy(struct drm_device *dev, int engine)
651{ 760{
652 struct nvc0_graph_priv *priv = nv_engine(dev, engine); 761 struct nvc0_graph_priv *priv = nv_engine(dev, engine);
653 762
654 nvc0_graph_destroy_fw(&priv->fuc409c); 763 if (nouveau_ctxfw) {
655 nvc0_graph_destroy_fw(&priv->fuc409d); 764 nvc0_graph_destroy_fw(&priv->fuc409c);
656 nvc0_graph_destroy_fw(&priv->fuc41ac); 765 nvc0_graph_destroy_fw(&priv->fuc409d);
657 nvc0_graph_destroy_fw(&priv->fuc41ad); 766 nvc0_graph_destroy_fw(&priv->fuc41ac);
767 nvc0_graph_destroy_fw(&priv->fuc41ad);
768 }
658 769
659 nouveau_irq_unregister(dev, 12); 770 nouveau_irq_unregister(dev, 12);
660 nouveau_irq_unregister(dev, 25); 771 nouveau_irq_unregister(dev, 25);
@@ -698,15 +809,17 @@ nvc0_graph_create(struct drm_device *dev)
698 nouveau_irq_register(dev, 12, nvc0_graph_isr); 809 nouveau_irq_register(dev, 12, nvc0_graph_isr);
699 nouveau_irq_register(dev, 25, nvc0_runk140_isr); 810 nouveau_irq_register(dev, 25, nvc0_runk140_isr);
700 811
701 if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) || 812 if (nouveau_ctxfw) {
702 nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) || 813 NV_INFO(dev, "PGRAPH: using external firmware\n");
703 nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) || 814 if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
704 nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) { 815 nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
705 ret = 0; 816 nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
706 goto error; 817 nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
818 ret = 0;
819 goto error;
820 }
707 } 821 }
708 822
709
710 ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); 823 ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
711 if (ret) 824 if (ret)
712 goto error; 825 goto error;