summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gp106/bios_gp106.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gp106/bios_gp106.c')
-rw-r--r--drivers/gpu/nvgpu/gp106/bios_gp106.c240
1 files changed, 240 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gp106/bios_gp106.c b/drivers/gpu/nvgpu/gp106/bios_gp106.c
new file mode 100644
index 00000000..f772e267
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/bios_gp106.c
@@ -0,0 +1,240 @@
1/*
2 * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include <nvgpu/bios.h>
15#include <nvgpu/kmem.h>
16#include <nvgpu/nvgpu_common.h>
17#include <nvgpu/timers.h>
18#include <nvgpu/falcon.h>
19#include <nvgpu/enabled.h>
20
21#include "gk20a/gk20a.h"
22#include "gm20b/fifo_gm20b.h"
23#include "bios_gp106.h"
24#include "gp106/mclk_gp106.h"
25#ifdef CONFIG_DEBUG_FS
26#include "common/linux/os_linux.h"
27#endif
28
29#include <nvgpu/hw/gp106/hw_pwr_gp106.h>
30#include <nvgpu/hw/gp106/hw_mc_gp106.h>
31#include <nvgpu/hw/gp106/hw_top_gp106.h>
32
33#define PMU_BOOT_TIMEOUT_DEFAULT 100 /* usec */
34#define PMU_BOOT_TIMEOUT_MAX 2000000 /* usec */
35#define BIOS_OVERLAY_NAME "bios-%04x.rom"
36#define BIOS_OVERLAY_NAME_FORMATTED "bios-xxxx.rom"
37#define ROM_FILE_PAYLOAD_OFFSET 0xa00
38#define BIOS_SIZE 0x40000
39
40static void upload_code(struct gk20a *g, u32 dst,
41 u8 *src, u32 size, u8 port, bool sec)
42{
43 nvgpu_flcn_copy_to_imem(g->pmu.flcn, dst, src, size, port, sec,
44 dst >> 8);
45}
46
47static void upload_data(struct gk20a *g, u32 dst, u8 *src, u32 size, u8 port)
48{
49 u32 i, words;
50 u32 *src_u32 = (u32 *)src;
51 u32 blk;
52
53 gk20a_dbg_info("upload %d bytes to %x", size, dst);
54
55 words = DIV_ROUND_UP(size, 4);
56
57 blk = dst >> 8;
58
59 gk20a_dbg_info("upload %d words to %x blk %d",
60 words, dst, blk);
61 gk20a_writel(g, pwr_falcon_dmemc_r(port),
62 pwr_falcon_dmemc_offs_f(dst >> 2) |
63 pwr_falcon_dmemc_blk_f(blk) |
64 pwr_falcon_dmemc_aincw_f(1));
65
66 for (i = 0; i < words; i++)
67 gk20a_writel(g, pwr_falcon_dmemd_r(port), src_u32[i]);
68}
69
70static int gp106_bios_devinit(struct gk20a *g)
71{
72 int err = 0;
73 int devinit_completed;
74 struct nvgpu_timeout timeout;
75
76 gk20a_dbg_fn("");
77
78 if (nvgpu_flcn_reset(g->pmu.flcn)) {
79 err = -ETIMEDOUT;
80 goto out;
81 }
82
83 upload_code(g, g->bios.devinit.bootloader_phys_base,
84 g->bios.devinit.bootloader,
85 g->bios.devinit.bootloader_size,
86 0, 0);
87 upload_code(g, g->bios.devinit.phys_base,
88 g->bios.devinit.ucode,
89 g->bios.devinit.size,
90 0, 1);
91 upload_data(g, g->bios.devinit.dmem_phys_base,
92 g->bios.devinit.dmem,
93 g->bios.devinit.dmem_size,
94 0);
95 upload_data(g, g->bios.devinit_tables_phys_base,
96 g->bios.devinit_tables,
97 g->bios.devinit_tables_size,
98 0);
99 upload_data(g, g->bios.devinit_script_phys_base,
100 g->bios.bootscripts,
101 g->bios.bootscripts_size,
102 0);
103
104 nvgpu_flcn_bootstrap(g->pmu.flcn, g->bios.devinit.code_entry_point);
105
106 nvgpu_timeout_init(g, &timeout,
107 PMU_BOOT_TIMEOUT_MAX /
108 PMU_BOOT_TIMEOUT_DEFAULT,
109 NVGPU_TIMER_RETRY_TIMER);
110 do {
111 devinit_completed = pwr_falcon_cpuctl_halt_intr_v(
112 gk20a_readl(g, pwr_falcon_cpuctl_r())) &&
113 top_scratch1_devinit_completed_v(
114 gk20a_readl(g, top_scratch1_r()));
115 nvgpu_udelay(PMU_BOOT_TIMEOUT_DEFAULT);
116 } while (!devinit_completed && !nvgpu_timeout_expired(&timeout));
117
118 if (nvgpu_timeout_peek_expired(&timeout))
119 err = -ETIMEDOUT;
120
121 nvgpu_flcn_clear_halt_intr_status(g->pmu.flcn,
122 gk20a_get_gr_idle_timeout(g));
123
124out:
125 gk20a_dbg_fn("done");
126 return err;
127}
128
129static int gp106_bios_preos(struct gk20a *g)
130{
131 int err = 0;
132
133 gk20a_dbg_fn("");
134
135 if (nvgpu_flcn_reset(g->pmu.flcn)) {
136 err = -ETIMEDOUT;
137 goto out;
138 }
139
140 upload_code(g, g->bios.preos.bootloader_phys_base,
141 g->bios.preos.bootloader,
142 g->bios.preos.bootloader_size,
143 0, 0);
144 upload_code(g, g->bios.preos.phys_base,
145 g->bios.preos.ucode,
146 g->bios.preos.size,
147 0, 1);
148 upload_data(g, g->bios.preos.dmem_phys_base,
149 g->bios.preos.dmem,
150 g->bios.preos.dmem_size,
151 0);
152
153 nvgpu_flcn_bootstrap(g->pmu.flcn, g->bios.preos.code_entry_point);
154
155 if (nvgpu_flcn_wait_for_halt(g->pmu.flcn,
156 PMU_BOOT_TIMEOUT_MAX / 1000)) {
157 err = -ETIMEDOUT;
158 goto out;
159 }
160
161 nvgpu_flcn_clear_halt_intr_status(g->pmu.flcn,
162 gk20a_get_gr_idle_timeout(g));
163
164out:
165 gk20a_dbg_fn("done");
166 return err;
167}
168
169int gp106_bios_init(struct gk20a *g)
170{
171 unsigned int i;
172#ifdef CONFIG_DEBUG_FS
173 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
174 struct dentry *d;
175#endif
176 int err;
177
178 gk20a_dbg_fn("");
179
180 gk20a_dbg_info("reading bios from EEPROM");
181 g->bios.size = BIOS_SIZE;
182 g->bios.data = nvgpu_vmalloc(g, BIOS_SIZE);
183 if (!g->bios.data)
184 return -ENOMEM;
185 g->ops.xve.disable_shadow_rom(g);
186 for (i = 0; i < g->bios.size/4; i++) {
187 u32 val = be32_to_cpu(gk20a_readl(g, 0x300000 + i*4));
188
189 g->bios.data[(i*4)] = (val >> 24) & 0xff;
190 g->bios.data[(i*4)+1] = (val >> 16) & 0xff;
191 g->bios.data[(i*4)+2] = (val >> 8) & 0xff;
192 g->bios.data[(i*4)+3] = val & 0xff;
193 }
194 g->ops.xve.enable_shadow_rom(g);
195
196 err = nvgpu_bios_parse_rom(g);
197 if (err)
198 return err;
199
200 if (g->gpu_characteristics.vbios_version < g->vbios_min_version) {
201 nvgpu_err(g, "unsupported VBIOS version %08x",
202 g->gpu_characteristics.vbios_version);
203 return -EINVAL;
204 }
205
206 /* WAR for HW2.5 RevA (INA3221 is missing) */
207 if ((g->pci_vendor_id == PCI_VENDOR_ID_NVIDIA) &&
208 (g->pci_device_id == 0x1c75) &&
209 (g->gpu_characteristics.vbios_version == 0x86065300)) {
210 g->power_sensor_missing = true;
211 }
212
213#ifdef CONFIG_DEBUG_FS
214 g->bios_blob.data = g->bios.data;
215 g->bios_blob.size = g->bios.size;
216
217 d = debugfs_create_blob("bios", S_IRUGO, l->debugfs,
218 &g->bios_blob);
219 if (!d)
220 nvgpu_err(g, "No debugfs?");
221#endif
222
223 gk20a_dbg_fn("done");
224
225 err = gp106_bios_devinit(g);
226 if (err) {
227 nvgpu_err(g, "devinit failed");
228 return err;
229 }
230
231 if (nvgpu_is_enabled(g, NVGPU_PMU_RUN_PREOS)) {
232 err = gp106_bios_preos(g);
233 if (err) {
234 nvgpu_err(g, "pre-os failed");
235 return err;
236 }
237 }
238
239 return 0;
240}