aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvc0_graph.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-04-12 04:50:36 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-05-15 20:49:13 -0400
commitfe799114e2f0de37c3ddf900d15fa5e85936deba (patch)
treebf22e8163d492acbe6c5cf00551d05d862c4e589 /drivers/gpu/drm/nouveau/nvc0_graph.c
parent9548258fbce1e8d6fcd96bba299386f5666840ae (diff)
drm/nvc0/gr: better handling of fuc firmware
Allows per-chipset firmware to be installed, and keeps a copy in memory for suspend/resume purposes. 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.c111
1 files changed, 76 insertions, 35 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 31a177fa23f8..dcb8d9a12120 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -398,42 +398,22 @@ nvc0_graph_init_rop(struct drm_device *dev)
398 } 398 }
399} 399}
400 400
401static int 401static void
402nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base, 402nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
403 const char *code_fw, const char *data_fw) 403 struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
404{ 404{
405 const struct firmware *fw; 405 int i;
406 char name[32];
407 int ret, i;
408
409 snprintf(name, sizeof(name), "nouveau/%s", data_fw);
410 ret = request_firmware(&fw, name, &dev->pdev->dev);
411 if (ret) {
412 NV_ERROR(dev, "failed to load %s\n", data_fw);
413 return ret;
414 }
415 406
416 nv_wr32(dev, fuc_base + 0x01c0, 0x01000000); 407 nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
417 for (i = 0; i < fw->size / 4; i++) 408 for (i = 0; i < data->size / 4; i++)
418 nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]); 409 nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
419 release_firmware(fw);
420
421 snprintf(name, sizeof(name), "nouveau/%s", code_fw);
422 ret = request_firmware(&fw, name, &dev->pdev->dev);
423 if (ret) {
424 NV_ERROR(dev, "failed to load %s\n", code_fw);
425 return ret;
426 }
427 410
428 nv_wr32(dev, fuc_base + 0x0180, 0x01000000); 411 nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
429 for (i = 0; i < fw->size / 4; i++) { 412 for (i = 0; i < code->size / 4; i++) {
430 if ((i & 0x3f) == 0) 413 if ((i & 0x3f) == 0)
431 nv_wr32(dev, fuc_base + 0x0188, i >> 6); 414 nv_wr32(dev, fuc_base + 0x0188, i >> 6);
432 nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]); 415 nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
433 } 416 }
434 release_firmware(fw);
435
436 return 0;
437} 417}
438 418
439static int 419static int
@@ -441,18 +421,13 @@ nvc0_graph_init_ctxctl(struct drm_device *dev)
441{ 421{
442 struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); 422 struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
443 u32 r000260; 423 u32 r000260;
444 int ret;
445 424
446 /* load fuc microcode */ 425 /* load fuc microcode */
447 r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); 426 r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
448 ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d"); 427 nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
449 if (ret == 0) 428 nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
450 ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad");
451 nv_wr32(dev, 0x000260, r000260); 429 nv_wr32(dev, 0x000260, r000260);
452 430
453 if (ret)
454 return ret;
455
456 /* start both of them running */ 431 /* start both of them running */
457 nv_wr32(dev, 0x409840, 0xffffffff); 432 nv_wr32(dev, 0x409840, 0xffffffff);
458 nv_wr32(dev, 0x41a10c, 0x00000000); 433 nv_wr32(dev, 0x41a10c, 0x00000000);
@@ -636,11 +611,51 @@ nvc0_runk140_isr(struct drm_device *dev)
636 } 611 }
637} 612}
638 613
614static int
615nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
616 struct nvc0_graph_fuc *fuc)
617{
618 struct drm_nouveau_private *dev_priv = dev->dev_private;
619 const struct firmware *fw;
620 char f[32];
621 int ret;
622
623 snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
624 ret = request_firmware(&fw, f, &dev->pdev->dev);
625 if (ret) {
626 snprintf(f, sizeof(f), "nouveau/%s", fwname);
627 ret = request_firmware(&fw, f, &dev->pdev->dev);
628 if (ret) {
629 NV_ERROR(dev, "failed to load %s\n", fwname);
630 return ret;
631 }
632 }
633
634 fuc->size = fw->size;
635 fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
636 release_firmware(fw);
637 return (fuc->data != NULL) ? 0 : -ENOMEM;
638}
639
640static void
641nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
642{
643 if (fuc->data) {
644 kfree(fuc->data);
645 fuc->data = NULL;
646 }
647}
648
639static void 649static void
640nvc0_graph_destroy(struct drm_device *dev, int engine) 650nvc0_graph_destroy(struct drm_device *dev, int engine)
641{ 651{
642 struct nvc0_graph_priv *priv = nv_engine(dev, engine); 652 struct nvc0_graph_priv *priv = nv_engine(dev, engine);
643 653
654 nvc0_graph_destroy_fw(&priv->fuc409c);
655 nvc0_graph_destroy_fw(&priv->fuc409d);
656 nvc0_graph_destroy_fw(&priv->fuc41ac);
657 nvc0_graph_destroy_fw(&priv->fuc41ad);
658
644 nouveau_irq_unregister(dev, 12); 659 nouveau_irq_unregister(dev, 12);
645 nouveau_irq_unregister(dev, 25); 660 nouveau_irq_unregister(dev, 25);
646 661
@@ -686,6 +701,15 @@ nvc0_graph_create(struct drm_device *dev)
686 nouveau_irq_register(dev, 12, nvc0_graph_isr); 701 nouveau_irq_register(dev, 12, nvc0_graph_isr);
687 nouveau_irq_register(dev, 25, nvc0_runk140_isr); 702 nouveau_irq_register(dev, 25, nvc0_runk140_isr);
688 703
704 if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
705 nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
706 nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
707 nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
708 ret = 0;
709 goto error;
710 }
711
712
689 ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); 713 ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
690 if (ret) 714 if (ret)
691 goto error; 715 goto error;
@@ -777,3 +801,20 @@ error:
777 nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR); 801 nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
778 return ret; 802 return ret;
779} 803}
804
805MODULE_FIRMWARE("nouveau/nvc0_fuc409c");
806MODULE_FIRMWARE("nouveau/nvc0_fuc409d");
807MODULE_FIRMWARE("nouveau/nvc0_fuc41ac");
808MODULE_FIRMWARE("nouveau/nvc0_fuc41ad");
809MODULE_FIRMWARE("nouveau/nvc3_fuc409c");
810MODULE_FIRMWARE("nouveau/nvc3_fuc409d");
811MODULE_FIRMWARE("nouveau/nvc3_fuc41ac");
812MODULE_FIRMWARE("nouveau/nvc3_fuc41ad");
813MODULE_FIRMWARE("nouveau/nvc4_fuc409c");
814MODULE_FIRMWARE("nouveau/nvc4_fuc409d");
815MODULE_FIRMWARE("nouveau/nvc4_fuc41ac");
816MODULE_FIRMWARE("nouveau/nvc4_fuc41ad");
817MODULE_FIRMWARE("nouveau/fuc409c");
818MODULE_FIRMWARE("nouveau/fuc409d");
819MODULE_FIRMWARE("nouveau/fuc41ac");
820MODULE_FIRMWARE("nouveau/fuc41ad");