diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gp106/bios_gp106.c')
-rw-r--r-- | drivers/gpu/nvgpu/gp106/bios_gp106.c | 243 |
1 files changed, 243 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..8511d3c2 --- /dev/null +++ b/drivers/gpu/nvgpu/gp106/bios_gp106.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <nvgpu/bios.h> | ||
24 | #include <nvgpu/kmem.h> | ||
25 | #include <nvgpu/nvgpu_common.h> | ||
26 | #include <nvgpu/timers.h> | ||
27 | #include <nvgpu/falcon.h> | ||
28 | #include <nvgpu/enabled.h> | ||
29 | |||
30 | #include "gk20a/gk20a.h" | ||
31 | #include "gm20b/fifo_gm20b.h" | ||
32 | #include "bios_gp106.h" | ||
33 | #include "gp106/mclk_gp106.h" | ||
34 | |||
35 | #include <nvgpu/hw/gp106/hw_pwr_gp106.h> | ||
36 | #include <nvgpu/hw/gp106/hw_mc_gp106.h> | ||
37 | #include <nvgpu/hw/gp106/hw_top_gp106.h> | ||
38 | |||
39 | #define PMU_BOOT_TIMEOUT_DEFAULT 100 /* usec */ | ||
40 | #define PMU_BOOT_TIMEOUT_MAX 2000000 /* usec */ | ||
41 | #define BIOS_OVERLAY_NAME "bios-%04x.rom" | ||
42 | #define BIOS_OVERLAY_NAME_FORMATTED "bios-xxxx.rom" | ||
43 | #define ROM_FILE_PAYLOAD_OFFSET 0xa00 | ||
44 | #define BIOS_SIZE 0x40000 | ||
45 | |||
46 | static void upload_code(struct gk20a *g, u32 dst, | ||
47 | u8 *src, u32 size, u8 port, bool sec) | ||
48 | { | ||
49 | nvgpu_flcn_copy_to_imem(g->pmu.flcn, dst, src, size, port, sec, | ||
50 | dst >> 8); | ||
51 | } | ||
52 | |||
53 | static void upload_data(struct gk20a *g, u32 dst, u8 *src, u32 size, u8 port) | ||
54 | { | ||
55 | u32 i, words; | ||
56 | u32 *src_u32 = (u32 *)src; | ||
57 | u32 blk; | ||
58 | |||
59 | gk20a_dbg_info("upload %d bytes to %x", size, dst); | ||
60 | |||
61 | words = DIV_ROUND_UP(size, 4); | ||
62 | |||
63 | blk = dst >> 8; | ||
64 | |||
65 | gk20a_dbg_info("upload %d words to %x blk %d", | ||
66 | words, dst, blk); | ||
67 | gk20a_writel(g, pwr_falcon_dmemc_r(port), | ||
68 | pwr_falcon_dmemc_offs_f(dst >> 2) | | ||
69 | pwr_falcon_dmemc_blk_f(blk) | | ||
70 | pwr_falcon_dmemc_aincw_f(1)); | ||
71 | |||
72 | for (i = 0; i < words; i++) | ||
73 | gk20a_writel(g, pwr_falcon_dmemd_r(port), src_u32[i]); | ||
74 | } | ||
75 | |||
76 | static int gp106_bios_devinit(struct gk20a *g) | ||
77 | { | ||
78 | int err = 0; | ||
79 | int devinit_completed; | ||
80 | struct nvgpu_timeout timeout; | ||
81 | |||
82 | gk20a_dbg_fn(""); | ||
83 | |||
84 | if (nvgpu_flcn_reset(g->pmu.flcn)) { | ||
85 | err = -ETIMEDOUT; | ||
86 | goto out; | ||
87 | } | ||
88 | |||
89 | upload_code(g, g->bios.devinit.bootloader_phys_base, | ||
90 | g->bios.devinit.bootloader, | ||
91 | g->bios.devinit.bootloader_size, | ||
92 | 0, 0); | ||
93 | upload_code(g, g->bios.devinit.phys_base, | ||
94 | g->bios.devinit.ucode, | ||
95 | g->bios.devinit.size, | ||
96 | 0, 1); | ||
97 | upload_data(g, g->bios.devinit.dmem_phys_base, | ||
98 | g->bios.devinit.dmem, | ||
99 | g->bios.devinit.dmem_size, | ||
100 | 0); | ||
101 | upload_data(g, g->bios.devinit_tables_phys_base, | ||
102 | g->bios.devinit_tables, | ||
103 | g->bios.devinit_tables_size, | ||
104 | 0); | ||
105 | upload_data(g, g->bios.devinit_script_phys_base, | ||
106 | g->bios.bootscripts, | ||
107 | g->bios.bootscripts_size, | ||
108 | 0); | ||
109 | |||
110 | nvgpu_flcn_bootstrap(g->pmu.flcn, g->bios.devinit.code_entry_point); | ||
111 | |||
112 | nvgpu_timeout_init(g, &timeout, | ||
113 | PMU_BOOT_TIMEOUT_MAX / | ||
114 | PMU_BOOT_TIMEOUT_DEFAULT, | ||
115 | NVGPU_TIMER_RETRY_TIMER); | ||
116 | do { | ||
117 | devinit_completed = pwr_falcon_cpuctl_halt_intr_v( | ||
118 | gk20a_readl(g, pwr_falcon_cpuctl_r())) && | ||
119 | top_scratch1_devinit_completed_v( | ||
120 | gk20a_readl(g, top_scratch1_r())); | ||
121 | nvgpu_udelay(PMU_BOOT_TIMEOUT_DEFAULT); | ||
122 | } while (!devinit_completed && !nvgpu_timeout_expired(&timeout)); | ||
123 | |||
124 | if (nvgpu_timeout_peek_expired(&timeout)) | ||
125 | err = -ETIMEDOUT; | ||
126 | |||
127 | nvgpu_flcn_clear_halt_intr_status(g->pmu.flcn, | ||
128 | gk20a_get_gr_idle_timeout(g)); | ||
129 | |||
130 | out: | ||
131 | gk20a_dbg_fn("done"); | ||
132 | return err; | ||
133 | } | ||
134 | |||
135 | int gp106_bios_preos_wait_for_halt(struct gk20a *g) | ||
136 | { | ||
137 | int err = 0; | ||
138 | |||
139 | if (nvgpu_flcn_wait_for_halt(g->pmu.flcn, PMU_BOOT_TIMEOUT_MAX / 1000)) | ||
140 | err = -ETIMEDOUT; | ||
141 | |||
142 | return err; | ||
143 | } | ||
144 | |||
145 | static int gp106_bios_preos(struct gk20a *g) | ||
146 | { | ||
147 | int err = 0; | ||
148 | |||
149 | gk20a_dbg_fn(""); | ||
150 | |||
151 | if (nvgpu_flcn_reset(g->pmu.flcn)) { | ||
152 | err = -ETIMEDOUT; | ||
153 | goto out; | ||
154 | } | ||
155 | |||
156 | if (g->ops.bios.preos_reload_check) | ||
157 | g->ops.bios.preos_reload_check(g); | ||
158 | |||
159 | upload_code(g, g->bios.preos.bootloader_phys_base, | ||
160 | g->bios.preos.bootloader, | ||
161 | g->bios.preos.bootloader_size, | ||
162 | 0, 0); | ||
163 | upload_code(g, g->bios.preos.phys_base, | ||
164 | g->bios.preos.ucode, | ||
165 | g->bios.preos.size, | ||
166 | 0, 1); | ||
167 | upload_data(g, g->bios.preos.dmem_phys_base, | ||
168 | g->bios.preos.dmem, | ||
169 | g->bios.preos.dmem_size, | ||
170 | 0); | ||
171 | |||
172 | nvgpu_flcn_bootstrap(g->pmu.flcn, g->bios.preos.code_entry_point); | ||
173 | |||
174 | err = g->ops.bios.preos_wait_for_halt(g); | ||
175 | |||
176 | nvgpu_flcn_clear_halt_intr_status(g->pmu.flcn, | ||
177 | gk20a_get_gr_idle_timeout(g)); | ||
178 | |||
179 | out: | ||
180 | gk20a_dbg_fn("done"); | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | int gp106_bios_init(struct gk20a *g) | ||
185 | { | ||
186 | unsigned int i; | ||
187 | int err; | ||
188 | |||
189 | gk20a_dbg_fn(""); | ||
190 | |||
191 | if (g->bios_is_init) | ||
192 | return 0; | ||
193 | |||
194 | gk20a_dbg_info("reading bios from EEPROM"); | ||
195 | g->bios.size = BIOS_SIZE; | ||
196 | g->bios.data = nvgpu_vmalloc(g, BIOS_SIZE); | ||
197 | if (!g->bios.data) | ||
198 | return -ENOMEM; | ||
199 | g->ops.xve.disable_shadow_rom(g); | ||
200 | for (i = 0; i < g->bios.size/4; i++) { | ||
201 | u32 val = be32_to_cpu(gk20a_readl(g, 0x300000 + i*4)); | ||
202 | |||
203 | g->bios.data[(i*4)] = (val >> 24) & 0xff; | ||
204 | g->bios.data[(i*4)+1] = (val >> 16) & 0xff; | ||
205 | g->bios.data[(i*4)+2] = (val >> 8) & 0xff; | ||
206 | g->bios.data[(i*4)+3] = val & 0xff; | ||
207 | } | ||
208 | g->ops.xve.enable_shadow_rom(g); | ||
209 | |||
210 | err = nvgpu_bios_parse_rom(g); | ||
211 | if (err) | ||
212 | goto free_firmware; | ||
213 | |||
214 | if (g->bios.vbios_version < g->vbios_min_version) { | ||
215 | nvgpu_err(g, "unsupported VBIOS version %08x", | ||
216 | g->bios.vbios_version); | ||
217 | err = -EINVAL; | ||
218 | goto free_firmware; | ||
219 | } | ||
220 | |||
221 | gk20a_dbg_fn("done"); | ||
222 | |||
223 | err = gp106_bios_devinit(g); | ||
224 | if (err) { | ||
225 | nvgpu_err(g, "devinit failed"); | ||
226 | goto free_firmware; | ||
227 | } | ||
228 | |||
229 | if (nvgpu_is_enabled(g, NVGPU_PMU_RUN_PREOS)) { | ||
230 | err = gp106_bios_preos(g); | ||
231 | if (err) { | ||
232 | nvgpu_err(g, "pre-os failed"); | ||
233 | goto free_firmware; | ||
234 | } | ||
235 | } | ||
236 | g->bios_is_init = true; | ||
237 | |||
238 | return 0; | ||
239 | free_firmware: | ||
240 | if (g->bios.data) | ||
241 | nvgpu_vfree(g, g->bios.data); | ||
242 | return err; | ||
243 | } | ||