1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2020-2023 Intel Corporation |
4 | */ |
5 | |
6 | #include <linux/firmware.h> |
7 | #include <linux/highmem.h> |
8 | #include <linux/moduleparam.h> |
9 | #include <linux/pci.h> |
10 | |
11 | #include "vpu_boot_api.h" |
12 | #include "ivpu_drv.h" |
13 | #include "ivpu_fw.h" |
14 | #include "ivpu_fw_log.h" |
15 | #include "ivpu_gem.h" |
16 | #include "ivpu_hw.h" |
17 | #include "ivpu_ipc.h" |
18 | #include "ivpu_pm.h" |
19 | |
20 | #define FW_GLOBAL_MEM_START (2ull * SZ_1G) |
21 | #define FW_GLOBAL_MEM_END (3ull * SZ_1G) |
22 | #define FW_SHARED_MEM_SIZE SZ_256M /* Must be aligned to FW_SHARED_MEM_ALIGNMENT */ |
23 | #define FW_SHARED_MEM_ALIGNMENT SZ_128K /* VPU MTRR limitation */ |
24 | #define FW_RUNTIME_MAX_SIZE SZ_512M |
25 | #define FW_SHAVE_NN_MAX_SIZE SZ_2M |
26 | #define FW_RUNTIME_MIN_ADDR (FW_GLOBAL_MEM_START) |
27 | #define FW_RUNTIME_MAX_ADDR (FW_GLOBAL_MEM_END - FW_SHARED_MEM_SIZE) |
28 | #define SZ_4K |
29 | #define FW_FILE_IMAGE_OFFSET (VPU_FW_HEADER_SIZE + FW_VERSION_HEADER_SIZE) |
30 | |
31 | #define WATCHDOG_MSS_REDIRECT 32 |
32 | #define WATCHDOG_NCE_REDIRECT 33 |
33 | |
34 | #define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31) |
35 | |
36 | /* Check if FW API is compatible with the driver */ |
37 | #define IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, name, min_major) \ |
38 | ivpu_fw_check_api(vdev, fw_hdr, #name, \ |
39 | VPU_##name##_API_VER_INDEX, \ |
40 | VPU_##name##_API_VER_MAJOR, \ |
41 | VPU_##name##_API_VER_MINOR, min_major) |
42 | |
43 | /* Check if API version is lower that the given version */ |
44 | #define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \ |
45 | ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor) |
46 | |
47 | static char *ivpu_firmware; |
48 | module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644); |
49 | MODULE_PARM_DESC(firmware, "NPU firmware binary in /lib/firmware/.." ); |
50 | |
51 | static struct { |
52 | int gen; |
53 | const char *name; |
54 | } fw_names[] = { |
55 | { IVPU_HW_37XX, "vpu_37xx.bin" }, |
56 | { IVPU_HW_37XX, "intel/vpu/vpu_37xx_v0.0.bin" }, |
57 | { IVPU_HW_40XX, "vpu_40xx.bin" }, |
58 | { IVPU_HW_40XX, "intel/vpu/vpu_40xx_v0.0.bin" }, |
59 | }; |
60 | |
61 | static int ivpu_fw_request(struct ivpu_device *vdev) |
62 | { |
63 | int ret = -ENOENT; |
64 | int i; |
65 | |
66 | if (ivpu_firmware) { |
67 | ret = request_firmware(fw: &vdev->fw->file, name: ivpu_firmware, device: vdev->drm.dev); |
68 | if (!ret) |
69 | vdev->fw->name = ivpu_firmware; |
70 | return ret; |
71 | } |
72 | |
73 | for (i = 0; i < ARRAY_SIZE(fw_names); i++) { |
74 | if (fw_names[i].gen != ivpu_hw_gen(vdev)) |
75 | continue; |
76 | |
77 | ret = firmware_request_nowarn(fw: &vdev->fw->file, name: fw_names[i].name, device: vdev->drm.dev); |
78 | if (!ret) { |
79 | vdev->fw->name = fw_names[i].name; |
80 | return 0; |
81 | } |
82 | } |
83 | |
84 | ivpu_err(vdev, "Failed to request firmware: %d\n" , ret); |
85 | return ret; |
86 | } |
87 | |
88 | static int |
89 | ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr, |
90 | const char *str, int index, u16 expected_major, u16 expected_minor, |
91 | u16 min_major) |
92 | { |
93 | u16 major = (u16)(fw_hdr->api_version[index] >> 16); |
94 | u16 minor = (u16)(fw_hdr->api_version[index]); |
95 | |
96 | if (major < min_major) { |
97 | ivpu_err(vdev, "Incompatible FW %s API version: %d.%d, required %d.0 or later\n" , |
98 | str, major, minor, min_major); |
99 | return -EINVAL; |
100 | } |
101 | if (major != expected_major) { |
102 | ivpu_warn(vdev, "Major FW %s API version different: %d.%d (expected %d.%d)\n" , |
103 | str, major, minor, expected_major, expected_minor); |
104 | } |
105 | ivpu_dbg(vdev, FW_BOOT, "FW %s API version: %d.%d (expected %d.%d)\n" , |
106 | str, major, minor, expected_major, expected_minor); |
107 | |
108 | return 0; |
109 | } |
110 | |
111 | static bool |
112 | ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr, |
113 | const char *str, int index, u16 major, u16 minor) |
114 | { |
115 | u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16); |
116 | u16 fw_minor = (u16)(fw_hdr->api_version[index]); |
117 | |
118 | if (fw_major < major || (fw_major == major && fw_minor < minor)) |
119 | return true; |
120 | |
121 | return false; |
122 | } |
123 | |
124 | static int ivpu_fw_parse(struct ivpu_device *vdev) |
125 | { |
126 | struct ivpu_fw_info *fw = vdev->fw; |
127 | const struct vpu_firmware_header *fw_hdr = (const void *)fw->file->data; |
128 | u64 runtime_addr, image_load_addr, runtime_size, image_size; |
129 | |
130 | if (fw->file->size <= FW_FILE_IMAGE_OFFSET) { |
131 | ivpu_err(vdev, "Firmware file is too small: %zu\n" , fw->file->size); |
132 | return -EINVAL; |
133 | } |
134 | |
135 | if (fw_hdr->header_version != VPU_FW_HEADER_VERSION) { |
136 | ivpu_err(vdev, "Invalid firmware header version: %u\n" , fw_hdr->header_version); |
137 | return -EINVAL; |
138 | } |
139 | |
140 | runtime_addr = fw_hdr->boot_params_load_address; |
141 | runtime_size = fw_hdr->runtime_size; |
142 | image_load_addr = fw_hdr->image_load_address; |
143 | image_size = fw_hdr->image_size; |
144 | |
145 | if (runtime_addr < FW_RUNTIME_MIN_ADDR || runtime_addr > FW_RUNTIME_MAX_ADDR) { |
146 | ivpu_err(vdev, "Invalid firmware runtime address: 0x%llx\n" , runtime_addr); |
147 | return -EINVAL; |
148 | } |
149 | |
150 | if (runtime_size < fw->file->size || runtime_size > FW_RUNTIME_MAX_SIZE) { |
151 | ivpu_err(vdev, "Invalid firmware runtime size: %llu\n" , runtime_size); |
152 | return -EINVAL; |
153 | } |
154 | |
155 | if (FW_FILE_IMAGE_OFFSET + image_size > fw->file->size) { |
156 | ivpu_err(vdev, "Invalid image size: %llu\n" , image_size); |
157 | return -EINVAL; |
158 | } |
159 | |
160 | if (image_load_addr < runtime_addr || |
161 | image_load_addr + image_size > runtime_addr + runtime_size) { |
162 | ivpu_err(vdev, "Invalid firmware load address size: 0x%llx and size %llu\n" , |
163 | image_load_addr, image_size); |
164 | return -EINVAL; |
165 | } |
166 | |
167 | if (fw_hdr->shave_nn_fw_size > FW_SHAVE_NN_MAX_SIZE) { |
168 | ivpu_err(vdev, "SHAVE NN firmware is too big: %u\n" , fw_hdr->shave_nn_fw_size); |
169 | return -EINVAL; |
170 | } |
171 | |
172 | if (fw_hdr->entry_point < image_load_addr || |
173 | fw_hdr->entry_point >= image_load_addr + image_size) { |
174 | ivpu_err(vdev, "Invalid entry point: 0x%llx\n" , fw_hdr->entry_point); |
175 | return -EINVAL; |
176 | } |
177 | ivpu_dbg(vdev, FW_BOOT, "Header version: 0x%x, format 0x%x\n" , |
178 | fw_hdr->header_version, fw_hdr->image_format); |
179 | |
180 | ivpu_info(vdev, "Firmware: %s, version: %s" , fw->name, |
181 | (const char *)fw_hdr + VPU_FW_HEADER_SIZE); |
182 | |
183 | if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3)) |
184 | return -EINVAL; |
185 | if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3)) |
186 | return -EINVAL; |
187 | |
188 | fw->runtime_addr = runtime_addr; |
189 | fw->runtime_size = runtime_size; |
190 | fw->image_load_offset = image_load_addr - runtime_addr; |
191 | fw->image_size = image_size; |
192 | fw->shave_nn_size = PAGE_ALIGN(fw_hdr->shave_nn_fw_size); |
193 | |
194 | fw->cold_boot_entry_point = fw_hdr->entry_point; |
195 | fw->entry_point = fw->cold_boot_entry_point; |
196 | |
197 | fw->trace_level = min_t(u32, ivpu_log_level, IVPU_FW_LOG_FATAL); |
198 | fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; |
199 | fw->trace_hw_component_mask = -1; |
200 | |
201 | fw->dvfs_mode = 0; |
202 | |
203 | ivpu_dbg(vdev, FW_BOOT, "Size: file %lu image %u runtime %u shavenn %u\n" , |
204 | fw->file->size, fw->image_size, fw->runtime_size, fw->shave_nn_size); |
205 | ivpu_dbg(vdev, FW_BOOT, "Address: runtime 0x%llx, load 0x%llx, entry point 0x%llx\n" , |
206 | fw->runtime_addr, image_load_addr, fw->entry_point); |
207 | |
208 | return 0; |
209 | } |
210 | |
211 | static void ivpu_fw_release(struct ivpu_device *vdev) |
212 | { |
213 | release_firmware(fw: vdev->fw->file); |
214 | } |
215 | |
216 | /* Initialize workarounds that depend on FW version */ |
217 | static void |
218 | ivpu_fw_init_wa(struct ivpu_device *vdev) |
219 | { |
220 | const struct vpu_firmware_header *fw_hdr = (const void *)vdev->fw->file->data; |
221 | |
222 | if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, BOOT, 3, 17) || |
223 | (ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_DISABLE)) |
224 | vdev->wa.disable_d0i3_msg = true; |
225 | |
226 | /* Force enable the feature for testing purposes */ |
227 | if (ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_ENABLE) |
228 | vdev->wa.disable_d0i3_msg = false; |
229 | |
230 | IVPU_PRINT_WA(disable_d0i3_msg); |
231 | } |
232 | |
233 | static int ivpu_fw_update_global_range(struct ivpu_device *vdev) |
234 | { |
235 | struct ivpu_fw_info *fw = vdev->fw; |
236 | u64 start = ALIGN(fw->runtime_addr + fw->runtime_size, FW_SHARED_MEM_ALIGNMENT); |
237 | u64 size = FW_SHARED_MEM_SIZE; |
238 | |
239 | if (start + size > FW_GLOBAL_MEM_END) { |
240 | ivpu_err(vdev, "No space for shared region, start %lld, size %lld\n" , start, size); |
241 | return -EINVAL; |
242 | } |
243 | |
244 | ivpu_hw_init_range(range: &vdev->hw->ranges.global, start, size); |
245 | return 0; |
246 | } |
247 | |
248 | static int ivpu_fw_mem_init(struct ivpu_device *vdev) |
249 | { |
250 | struct ivpu_fw_info *fw = vdev->fw; |
251 | struct ivpu_addr_range fw_range; |
252 | int log_verb_size; |
253 | int ret; |
254 | |
255 | ret = ivpu_fw_update_global_range(vdev); |
256 | if (ret) |
257 | return ret; |
258 | |
259 | fw_range.start = fw->runtime_addr; |
260 | fw_range.end = fw->runtime_addr + fw->runtime_size; |
261 | fw->mem = ivpu_bo_create(vdev, ctx: &vdev->gctx, range: &fw_range, size: fw->runtime_size, |
262 | DRM_IVPU_BO_WC | DRM_IVPU_BO_MAPPABLE); |
263 | if (!fw->mem) { |
264 | ivpu_err(vdev, "Failed to create firmware runtime memory buffer\n" ); |
265 | return -ENOMEM; |
266 | } |
267 | |
268 | fw->mem_log_crit = ivpu_bo_create_global(vdev, IVPU_FW_CRITICAL_BUFFER_SIZE, |
269 | DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE); |
270 | if (!fw->mem_log_crit) { |
271 | ivpu_err(vdev, "Failed to create critical log buffer\n" ); |
272 | ret = -ENOMEM; |
273 | goto err_free_fw_mem; |
274 | } |
275 | |
276 | if (ivpu_log_level <= IVPU_FW_LOG_INFO) |
277 | log_verb_size = IVPU_FW_VERBOSE_BUFFER_LARGE_SIZE; |
278 | else |
279 | log_verb_size = IVPU_FW_VERBOSE_BUFFER_SMALL_SIZE; |
280 | |
281 | fw->mem_log_verb = ivpu_bo_create_global(vdev, size: log_verb_size, |
282 | DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE); |
283 | if (!fw->mem_log_verb) { |
284 | ivpu_err(vdev, "Failed to create verbose log buffer\n" ); |
285 | ret = -ENOMEM; |
286 | goto err_free_log_crit; |
287 | } |
288 | |
289 | if (fw->shave_nn_size) { |
290 | fw->mem_shave_nn = ivpu_bo_create(vdev, ctx: &vdev->gctx, range: &vdev->hw->ranges.shave, |
291 | size: fw->shave_nn_size, DRM_IVPU_BO_WC); |
292 | if (!fw->mem_shave_nn) { |
293 | ivpu_err(vdev, "Failed to create shavenn buffer\n" ); |
294 | ret = -ENOMEM; |
295 | goto err_free_log_verb; |
296 | } |
297 | } |
298 | |
299 | return 0; |
300 | |
301 | err_free_log_verb: |
302 | ivpu_bo_free(bo: fw->mem_log_verb); |
303 | err_free_log_crit: |
304 | ivpu_bo_free(bo: fw->mem_log_crit); |
305 | err_free_fw_mem: |
306 | ivpu_bo_free(bo: fw->mem); |
307 | return ret; |
308 | } |
309 | |
310 | static void ivpu_fw_mem_fini(struct ivpu_device *vdev) |
311 | { |
312 | struct ivpu_fw_info *fw = vdev->fw; |
313 | |
314 | if (fw->mem_shave_nn) { |
315 | ivpu_bo_free(bo: fw->mem_shave_nn); |
316 | fw->mem_shave_nn = NULL; |
317 | } |
318 | |
319 | ivpu_bo_free(bo: fw->mem_log_verb); |
320 | ivpu_bo_free(bo: fw->mem_log_crit); |
321 | ivpu_bo_free(bo: fw->mem); |
322 | |
323 | fw->mem_log_verb = NULL; |
324 | fw->mem_log_crit = NULL; |
325 | fw->mem = NULL; |
326 | } |
327 | |
328 | int ivpu_fw_init(struct ivpu_device *vdev) |
329 | { |
330 | int ret; |
331 | |
332 | ret = ivpu_fw_request(vdev); |
333 | if (ret) |
334 | return ret; |
335 | |
336 | ret = ivpu_fw_parse(vdev); |
337 | if (ret) |
338 | goto err_fw_release; |
339 | |
340 | ivpu_fw_init_wa(vdev); |
341 | |
342 | ret = ivpu_fw_mem_init(vdev); |
343 | if (ret) |
344 | goto err_fw_release; |
345 | |
346 | ivpu_fw_load(vdev); |
347 | |
348 | return 0; |
349 | |
350 | err_fw_release: |
351 | ivpu_fw_release(vdev); |
352 | return ret; |
353 | } |
354 | |
355 | void ivpu_fw_fini(struct ivpu_device *vdev) |
356 | { |
357 | ivpu_fw_mem_fini(vdev); |
358 | ivpu_fw_release(vdev); |
359 | } |
360 | |
361 | void ivpu_fw_load(struct ivpu_device *vdev) |
362 | { |
363 | struct ivpu_fw_info *fw = vdev->fw; |
364 | u64 image_end_offset = fw->image_load_offset + fw->image_size; |
365 | |
366 | memset(ivpu_bo_vaddr(fw->mem), 0, fw->image_load_offset); |
367 | memcpy(ivpu_bo_vaddr(fw->mem) + fw->image_load_offset, |
368 | fw->file->data + FW_FILE_IMAGE_OFFSET, fw->image_size); |
369 | |
370 | if (IVPU_WA(clear_runtime_mem)) { |
371 | u8 *start = ivpu_bo_vaddr(bo: fw->mem) + image_end_offset; |
372 | u64 size = ivpu_bo_size(bo: fw->mem) - image_end_offset; |
373 | |
374 | memset(start, 0, size); |
375 | } |
376 | |
377 | wmb(); /* Flush WC buffers after writing fw->mem */ |
378 | } |
379 | |
380 | static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) |
381 | { |
382 | ivpu_dbg(vdev, FW_BOOT, "boot_params.magic = 0x%x\n" , |
383 | boot_params->magic); |
384 | ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_id = 0x%x\n" , |
385 | boot_params->vpu_id); |
386 | ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_count = 0x%x\n" , |
387 | boot_params->vpu_count); |
388 | ivpu_dbg(vdev, FW_BOOT, "boot_params.frequency = %u\n" , |
389 | boot_params->frequency); |
390 | ivpu_dbg(vdev, FW_BOOT, "boot_params.perf_clk_frequency = %u\n" , |
391 | boot_params->perf_clk_frequency); |
392 | |
393 | ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_header_area_start = 0x%llx\n" , |
394 | boot_params->ipc_header_area_start); |
395 | ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_header_area_size = 0x%x\n" , |
396 | boot_params->ipc_header_area_size); |
397 | ivpu_dbg(vdev, FW_BOOT, "boot_params.shared_region_base = 0x%llx\n" , |
398 | boot_params->shared_region_base); |
399 | ivpu_dbg(vdev, FW_BOOT, "boot_params.shared_region_size = 0x%x\n" , |
400 | boot_params->shared_region_size); |
401 | ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_payload_area_start = 0x%llx\n" , |
402 | boot_params->ipc_payload_area_start); |
403 | ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_payload_area_size = 0x%x\n" , |
404 | boot_params->ipc_payload_area_size); |
405 | ivpu_dbg(vdev, FW_BOOT, "boot_params.global_aliased_pio_base = 0x%llx\n" , |
406 | boot_params->global_aliased_pio_base); |
407 | ivpu_dbg(vdev, FW_BOOT, "boot_params.global_aliased_pio_size = 0x%x\n" , |
408 | boot_params->global_aliased_pio_size); |
409 | |
410 | ivpu_dbg(vdev, FW_BOOT, "boot_params.autoconfig = 0x%x\n" , |
411 | boot_params->autoconfig); |
412 | |
413 | ivpu_dbg(vdev, FW_BOOT, "boot_params.cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use = 0x%x\n" , |
414 | boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use); |
415 | ivpu_dbg(vdev, FW_BOOT, "boot_params.cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg = 0x%x\n" , |
416 | boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg); |
417 | |
418 | ivpu_dbg(vdev, FW_BOOT, "boot_params.global_memory_allocator_base = 0x%llx\n" , |
419 | boot_params->global_memory_allocator_base); |
420 | ivpu_dbg(vdev, FW_BOOT, "boot_params.global_memory_allocator_size = 0x%x\n" , |
421 | boot_params->global_memory_allocator_size); |
422 | |
423 | ivpu_dbg(vdev, FW_BOOT, "boot_params.shave_nn_fw_base = 0x%llx\n" , |
424 | boot_params->shave_nn_fw_base); |
425 | |
426 | ivpu_dbg(vdev, FW_BOOT, "boot_params.watchdog_irq_mss = 0x%x\n" , |
427 | boot_params->watchdog_irq_mss); |
428 | ivpu_dbg(vdev, FW_BOOT, "boot_params.watchdog_irq_nce = 0x%x\n" , |
429 | boot_params->watchdog_irq_nce); |
430 | ivpu_dbg(vdev, FW_BOOT, "boot_params.host_to_vpu_irq = 0x%x\n" , |
431 | boot_params->host_to_vpu_irq); |
432 | ivpu_dbg(vdev, FW_BOOT, "boot_params.job_done_irq = 0x%x\n" , |
433 | boot_params->job_done_irq); |
434 | |
435 | ivpu_dbg(vdev, FW_BOOT, "boot_params.host_version_id = 0x%x\n" , |
436 | boot_params->host_version_id); |
437 | ivpu_dbg(vdev, FW_BOOT, "boot_params.si_stepping = 0x%x\n" , |
438 | boot_params->si_stepping); |
439 | ivpu_dbg(vdev, FW_BOOT, "boot_params.device_id = 0x%llx\n" , |
440 | boot_params->device_id); |
441 | ivpu_dbg(vdev, FW_BOOT, "boot_params.feature_exclusion = 0x%llx\n" , |
442 | boot_params->feature_exclusion); |
443 | ivpu_dbg(vdev, FW_BOOT, "boot_params.sku = 0x%llx\n" , |
444 | boot_params->sku); |
445 | ivpu_dbg(vdev, FW_BOOT, "boot_params.min_freq_pll_ratio = 0x%x\n" , |
446 | boot_params->min_freq_pll_ratio); |
447 | ivpu_dbg(vdev, FW_BOOT, "boot_params.pn_freq_pll_ratio = 0x%x\n" , |
448 | boot_params->pn_freq_pll_ratio); |
449 | ivpu_dbg(vdev, FW_BOOT, "boot_params.max_freq_pll_ratio = 0x%x\n" , |
450 | boot_params->max_freq_pll_ratio); |
451 | ivpu_dbg(vdev, FW_BOOT, "boot_params.default_trace_level = 0x%x\n" , |
452 | boot_params->default_trace_level); |
453 | ivpu_dbg(vdev, FW_BOOT, "boot_params.tracing_buff_message_format_mask = 0x%llx\n" , |
454 | boot_params->tracing_buff_message_format_mask); |
455 | ivpu_dbg(vdev, FW_BOOT, "boot_params.trace_destination_mask = 0x%x\n" , |
456 | boot_params->trace_destination_mask); |
457 | ivpu_dbg(vdev, FW_BOOT, "boot_params.trace_hw_component_mask = 0x%llx\n" , |
458 | boot_params->trace_hw_component_mask); |
459 | ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n" , |
460 | boot_params->boot_type); |
461 | ivpu_dbg(vdev, FW_BOOT, "boot_params.punit_telemetry_sram_base = 0x%llx\n" , |
462 | boot_params->punit_telemetry_sram_base); |
463 | ivpu_dbg(vdev, FW_BOOT, "boot_params.punit_telemetry_sram_size = 0x%llx\n" , |
464 | boot_params->punit_telemetry_sram_size); |
465 | ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_telemetry_enable = 0x%x\n" , |
466 | boot_params->vpu_telemetry_enable); |
467 | ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n" , |
468 | boot_params->dvfs_mode); |
469 | ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_delayed_entry = %d\n" , |
470 | boot_params->d0i3_delayed_entry); |
471 | ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n" , |
472 | boot_params->d0i3_residency_time_us); |
473 | ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n" , |
474 | boot_params->d0i3_entry_vpu_ts); |
475 | ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n" , |
476 | boot_params->system_time_us); |
477 | } |
478 | |
479 | void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) |
480 | { |
481 | struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx; |
482 | |
483 | /* In case of warm boot only update variable params */ |
484 | if (!ivpu_fw_is_cold_boot(vdev)) { |
485 | boot_params->d0i3_residency_time_us = |
486 | ktime_us_delta(later: ktime_get_boottime(), earlier: vdev->hw->d0i3_entry_host_ts); |
487 | boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts; |
488 | boot_params->system_time_us = ktime_to_us(kt: ktime_get_real()); |
489 | |
490 | ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n" , |
491 | boot_params->d0i3_residency_time_us); |
492 | ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n" , |
493 | boot_params->d0i3_entry_vpu_ts); |
494 | ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n" , |
495 | boot_params->system_time_us); |
496 | |
497 | boot_params->save_restore_ret_address = 0; |
498 | vdev->pm->is_warmboot = true; |
499 | wmb(); /* Flush WC buffers after writing save_restore_ret_address */ |
500 | return; |
501 | } |
502 | |
503 | vdev->pm->is_warmboot = false; |
504 | |
505 | boot_params->magic = VPU_BOOT_PARAMS_MAGIC; |
506 | boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number; |
507 | boot_params->frequency = ivpu_hw_reg_pll_freq_get(vdev); |
508 | |
509 | /* |
510 | * This param is a debug firmware feature. It switches default clock |
511 | * to higher resolution one for fine-grained and more accurate firmware |
512 | * task profiling. |
513 | */ |
514 | boot_params->perf_clk_frequency = ivpu_hw_profiling_freq_get(vdev); |
515 | |
516 | /* |
517 | * Uncached region of VPU address space, covers IPC buffers, job queues |
518 | * and log buffers, programmable to L2$ Uncached by VPU MTRR |
519 | */ |
520 | boot_params->shared_region_base = vdev->hw->ranges.global.start; |
521 | boot_params->shared_region_size = vdev->hw->ranges.global.end - |
522 | vdev->hw->ranges.global.start; |
523 | |
524 | boot_params->ipc_header_area_start = ipc_mem_rx->vpu_addr; |
525 | boot_params->ipc_header_area_size = ivpu_bo_size(bo: ipc_mem_rx) / 2; |
526 | |
527 | boot_params->ipc_payload_area_start = ipc_mem_rx->vpu_addr + ivpu_bo_size(bo: ipc_mem_rx) / 2; |
528 | boot_params->ipc_payload_area_size = ivpu_bo_size(bo: ipc_mem_rx) / 2; |
529 | |
530 | boot_params->global_aliased_pio_base = vdev->hw->ranges.user.start; |
531 | boot_params->global_aliased_pio_size = ivpu_hw_range_size(range: &vdev->hw->ranges.user); |
532 | |
533 | /* Allow configuration for L2C_PAGE_TABLE with boot param value */ |
534 | boot_params->autoconfig = 1; |
535 | |
536 | /* Enable L2 cache for first 2GB of high memory */ |
537 | boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use = 1; |
538 | boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg = |
539 | ADDR_TO_L2_CACHE_CFG(vdev->hw->ranges.shave.start); |
540 | |
541 | if (vdev->fw->mem_shave_nn) |
542 | boot_params->shave_nn_fw_base = vdev->fw->mem_shave_nn->vpu_addr; |
543 | |
544 | boot_params->watchdog_irq_mss = WATCHDOG_MSS_REDIRECT; |
545 | boot_params->watchdog_irq_nce = WATCHDOG_NCE_REDIRECT; |
546 | boot_params->si_stepping = ivpu_revision(vdev); |
547 | boot_params->device_id = ivpu_device_id(vdev); |
548 | boot_params->feature_exclusion = vdev->hw->tile_fuse; |
549 | boot_params->sku = vdev->hw->sku; |
550 | |
551 | boot_params->min_freq_pll_ratio = vdev->hw->pll.min_ratio; |
552 | boot_params->pn_freq_pll_ratio = vdev->hw->pll.pn_ratio; |
553 | boot_params->max_freq_pll_ratio = vdev->hw->pll.max_ratio; |
554 | |
555 | boot_params->default_trace_level = vdev->fw->trace_level; |
556 | boot_params->tracing_buff_message_format_mask = BIT(VPU_TRACING_FORMAT_STRING); |
557 | boot_params->trace_destination_mask = vdev->fw->trace_destination_mask; |
558 | boot_params->trace_hw_component_mask = vdev->fw->trace_hw_component_mask; |
559 | boot_params->crit_tracing_buff_addr = vdev->fw->mem_log_crit->vpu_addr; |
560 | boot_params->crit_tracing_buff_size = ivpu_bo_size(bo: vdev->fw->mem_log_crit); |
561 | boot_params->verbose_tracing_buff_addr = vdev->fw->mem_log_verb->vpu_addr; |
562 | boot_params->verbose_tracing_buff_size = ivpu_bo_size(bo: vdev->fw->mem_log_verb); |
563 | |
564 | boot_params->punit_telemetry_sram_base = ivpu_hw_reg_telemetry_offset_get(vdev); |
565 | boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); |
566 | boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); |
567 | boot_params->dvfs_mode = vdev->fw->dvfs_mode; |
568 | if (!IVPU_WA(disable_d0i3_msg)) |
569 | boot_params->d0i3_delayed_entry = 1; |
570 | boot_params->d0i3_residency_time_us = 0; |
571 | boot_params->d0i3_entry_vpu_ts = 0; |
572 | |
573 | boot_params->system_time_us = ktime_to_us(kt: ktime_get_real()); |
574 | wmb(); /* Flush WC buffers after writing bootparams */ |
575 | |
576 | ivpu_fw_boot_params_print(vdev, boot_params); |
577 | } |
578 | |