diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gm206')
-rw-r--r-- | drivers/gpu/nvgpu/gm206/bios_gm206.c | 61 |
1 files changed, 43 insertions, 18 deletions
diff --git a/drivers/gpu/nvgpu/gm206/bios_gm206.c b/drivers/gpu/nvgpu/gm206/bios_gm206.c index 21c852a5..6a509b04 100644 --- a/drivers/gpu/nvgpu/gm206/bios_gm206.c +++ b/drivers/gpu/nvgpu/gm206/bios_gm206.c | |||
@@ -13,6 +13,8 @@ | |||
13 | 13 | ||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/firmware.h> | ||
17 | #include <linux/pci.h> | ||
16 | 18 | ||
17 | #include "gk20a/gk20a.h" | 19 | #include "gk20a/gk20a.h" |
18 | #include "gm20b/fifo_gm20b.h" | 20 | #include "gm20b/fifo_gm20b.h" |
@@ -29,8 +31,11 @@ | |||
29 | #define NV_PCFG 0x88000 | 31 | #define NV_PCFG 0x88000 |
30 | #define PCI_EXP_ROM_SIG 0xaa55 | 32 | #define PCI_EXP_ROM_SIG 0xaa55 |
31 | #define PCI_EXP_ROM_SIG_NV 0x4e56 | 33 | #define PCI_EXP_ROM_SIG_NV 0x4e56 |
34 | #define ROM_FILE_PAYLOAD_OFFSET 0xa00 | ||
32 | #define PMU_BOOT_TIMEOUT_DEFAULT 100 /* usec */ | 35 | #define PMU_BOOT_TIMEOUT_DEFAULT 100 /* usec */ |
33 | #define PMU_BOOT_TIMEOUT_MAX 2000000 /* usec */ | 36 | #define PMU_BOOT_TIMEOUT_MAX 2000000 /* usec */ |
37 | #define BIOS_OVERLAY_NAME "bios-%04x.rom" | ||
38 | #define BIOS_OVERLAY_NAME_FORMATTED "bios-xxxx.rom" | ||
34 | 39 | ||
35 | static u16 gm206_bios_rdu16(struct gk20a *g, int offset) | 40 | static u16 gm206_bios_rdu16(struct gk20a *g, int offset) |
36 | { | 41 | { |
@@ -724,34 +729,54 @@ static int gm206_bios_init(struct gk20a *g) | |||
724 | int i; | 729 | int i; |
725 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); | 730 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); |
726 | struct dentry *d; | 731 | struct dentry *d; |
732 | const struct firmware *bios_fw; | ||
727 | int err; | 733 | int err; |
728 | bool found = 0; | 734 | bool found = 0; |
735 | struct pci_dev *pdev = to_pci_dev(g->dev); | ||
736 | char rom_name[sizeof(BIOS_OVERLAY_NAME_FORMATTED)]; | ||
729 | 737 | ||
730 | gk20a_dbg_fn(""); | 738 | gk20a_dbg_fn(""); |
731 | g->bios.data = kzalloc(BIOS_SIZE, GFP_KERNEL); | 739 | |
732 | if (!g->bios.data) | 740 | snprintf(rom_name, sizeof(rom_name), BIOS_OVERLAY_NAME, pdev->device); |
733 | return -ENOMEM; | 741 | gk20a_dbg_info("checking for VBIOS overlay %s", rom_name); |
734 | 742 | bios_fw = gk20a_request_firmware(g, rom_name); | |
735 | gk20a_dbg_info("reading bios"); | 743 | if (bios_fw) { |
736 | gk20a_writel(g, NV_PCFG + xve_rom_ctrl_r(), | 744 | gk20a_dbg_info("using VBIOS overlay"); |
737 | xve_rom_ctrl_rom_shadow_disabled_f()); | 745 | g->bios.size = bios_fw->size - ROM_FILE_PAYLOAD_OFFSET; |
738 | for (i = 0; i < BIOS_SIZE/4; i++) { | 746 | g->bios.data = vmalloc(g->bios.size); |
739 | u32 val = be32_to_cpu(gk20a_readl(g, 0x300000 + i*4)); | 747 | if (!g->bios.data) |
740 | 748 | return -ENOMEM; | |
741 | g->bios.data[(i*4)] = (val >> 24) & 0xff; | 749 | |
742 | g->bios.data[(i*4)+1] = (val >> 16) & 0xff; | 750 | memcpy(g->bios.data, &bios_fw->data[ROM_FILE_PAYLOAD_OFFSET], |
743 | g->bios.data[(i*4)+2] = (val >> 8) & 0xff; | 751 | g->bios.size); |
744 | g->bios.data[(i*4)+3] = val & 0xff; | 752 | |
753 | release_firmware(bios_fw); | ||
754 | } else { | ||
755 | gk20a_dbg_info("reading bios from EEPROM"); | ||
756 | g->bios.size = BIOS_SIZE; | ||
757 | g->bios.data = vmalloc(BIOS_SIZE); | ||
758 | if (!g->bios.data) | ||
759 | return -ENOMEM; | ||
760 | gk20a_writel(g, NV_PCFG + xve_rom_ctrl_r(), | ||
761 | xve_rom_ctrl_rom_shadow_disabled_f()); | ||
762 | for (i = 0; i < g->bios.size/4; i++) { | ||
763 | u32 val = be32_to_cpu(gk20a_readl(g, 0x300000 + i*4)); | ||
764 | |||
765 | g->bios.data[(i*4)] = (val >> 24) & 0xff; | ||
766 | g->bios.data[(i*4)+1] = (val >> 16) & 0xff; | ||
767 | g->bios.data[(i*4)+2] = (val >> 8) & 0xff; | ||
768 | g->bios.data[(i*4)+3] = val & 0xff; | ||
769 | } | ||
770 | gk20a_writel(g, NV_PCFG + xve_rom_ctrl_r(), | ||
771 | xve_rom_ctrl_rom_shadow_enabled_f()); | ||
745 | } | 772 | } |
746 | gk20a_writel(g, NV_PCFG + xve_rom_ctrl_r(), | ||
747 | xve_rom_ctrl_rom_shadow_enabled_f()); | ||
748 | 773 | ||
749 | err = gm206_bios_parse_rom(g); | 774 | err = gm206_bios_parse_rom(g); |
750 | if (err) | 775 | if (err) |
751 | return err; | 776 | return err; |
752 | 777 | ||
753 | gk20a_dbg_info("read bios"); | 778 | gk20a_dbg_info("read bios"); |
754 | for (i = 0; i < BIOS_SIZE; i++) { | 779 | for (i = 0; i < g->bios.size; i++) { |
755 | if (gm206_bios_rdu16(g, i) == BIT_HEADER_ID && | 780 | if (gm206_bios_rdu16(g, i) == BIT_HEADER_ID && |
756 | gm206_bios_rdu32(g, i+2) == BIT_HEADER_SIGNATURE) { | 781 | gm206_bios_rdu32(g, i+2) == BIT_HEADER_SIGNATURE) { |
757 | gm206_bios_parse_bit(g, i); | 782 | gm206_bios_parse_bit(g, i); |
@@ -764,7 +789,7 @@ static int gm206_bios_init(struct gk20a *g) | |||
764 | return -EINVAL; | 789 | return -EINVAL; |
765 | } | 790 | } |
766 | g->bios_blob.data = g->bios.data; | 791 | g->bios_blob.data = g->bios.data; |
767 | g->bios_blob.size = BIOS_SIZE; | 792 | g->bios_blob.size = g->bios.size; |
768 | 793 | ||
769 | d = debugfs_create_blob("bios", S_IRUGO, platform->debugfs, | 794 | d = debugfs_create_blob("bios", S_IRUGO, platform->debugfs, |
770 | &g->bios_blob); | 795 | &g->bios_blob); |