diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-04-12 04:50:36 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-05-15 20:49:13 -0400 |
commit | fe799114e2f0de37c3ddf900d15fa5e85936deba (patch) | |
tree | bf22e8163d492acbe6c5cf00551d05d862c4e589 /drivers/gpu | |
parent | 9548258fbce1e8d6fcd96bba299386f5666840ae (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')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_graph.c | 111 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_graph.h | 10 |
2 files changed, 86 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 | ||
401 | static int | 401 | static void |
402 | nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base, | 402 | nvc0_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 | ||
439 | static int | 419 | static 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 | ||
614 | static int | ||
615 | nvc0_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 | |||
640 | static void | ||
641 | nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc) | ||
642 | { | ||
643 | if (fuc->data) { | ||
644 | kfree(fuc->data); | ||
645 | fuc->data = NULL; | ||
646 | } | ||
647 | } | ||
648 | |||
639 | static void | 649 | static void |
640 | nvc0_graph_destroy(struct drm_device *dev, int engine) | 650 | nvc0_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 | |||
805 | MODULE_FIRMWARE("nouveau/nvc0_fuc409c"); | ||
806 | MODULE_FIRMWARE("nouveau/nvc0_fuc409d"); | ||
807 | MODULE_FIRMWARE("nouveau/nvc0_fuc41ac"); | ||
808 | MODULE_FIRMWARE("nouveau/nvc0_fuc41ad"); | ||
809 | MODULE_FIRMWARE("nouveau/nvc3_fuc409c"); | ||
810 | MODULE_FIRMWARE("nouveau/nvc3_fuc409d"); | ||
811 | MODULE_FIRMWARE("nouveau/nvc3_fuc41ac"); | ||
812 | MODULE_FIRMWARE("nouveau/nvc3_fuc41ad"); | ||
813 | MODULE_FIRMWARE("nouveau/nvc4_fuc409c"); | ||
814 | MODULE_FIRMWARE("nouveau/nvc4_fuc409d"); | ||
815 | MODULE_FIRMWARE("nouveau/nvc4_fuc41ac"); | ||
816 | MODULE_FIRMWARE("nouveau/nvc4_fuc41ad"); | ||
817 | MODULE_FIRMWARE("nouveau/fuc409c"); | ||
818 | MODULE_FIRMWARE("nouveau/fuc409d"); | ||
819 | MODULE_FIRMWARE("nouveau/fuc41ac"); | ||
820 | MODULE_FIRMWARE("nouveau/fuc41ad"); | ||
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h index fecc187d724c..f59d848b52eb 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.h +++ b/drivers/gpu/drm/nouveau/nvc0_graph.h | |||
@@ -34,9 +34,19 @@ | |||
34 | #define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r)) | 34 | #define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r)) |
35 | #define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) | 35 | #define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) |
36 | 36 | ||
37 | struct nvc0_graph_fuc { | ||
38 | u32 *data; | ||
39 | u32 size; | ||
40 | }; | ||
41 | |||
37 | struct nvc0_graph_priv { | 42 | struct nvc0_graph_priv { |
38 | struct nouveau_exec_engine base; | 43 | struct nouveau_exec_engine base; |
39 | 44 | ||
45 | struct nvc0_graph_fuc fuc409c; | ||
46 | struct nvc0_graph_fuc fuc409d; | ||
47 | struct nvc0_graph_fuc fuc41ac; | ||
48 | struct nvc0_graph_fuc fuc41ad; | ||
49 | |||
40 | u8 gpc_nr; | 50 | u8 gpc_nr; |
41 | u8 rop_nr; | 51 | u8 rop_nr; |
42 | u8 tp_nr[GPC_MAX]; | 52 | u8 tp_nr[GPC_MAX]; |