mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-29 19:48:36 -04:00
Pull drm updates from Dave Airlie:
"Highlights:
- xe: add initial CRI platform support
- amdgpu: initial HDMI 2.1 FRL support
- rust: add some new type concepts for device lifetimes
- scheduler: moves to a fair algorithm and lots of cleanups
But it's mostly the usual mountain of changes across the board.
core:
- add docbook for DRM_IOCTL_SYNCOBJ_EVENTFD
- change signature of drm_connector_attach_hdr_output_metadata_property
- dedup counter and timestamp retrieval in vblank code
- parse AMD VSDB v3 in CTA extension blocks
- add P230, Y7, XYYY2101010, T430, XVUY210101010 formats
- don't call drop master on file close if not master
- use drm_printf_indent in atomic / bridge
- fix 32b format descriptions
- docs: fix toctree
- hdmi: add common TMDS character rates
- fix drm_syncobj_find_fence leak
rust:
- introduce Higher-Ranked lifetime types
- replace drvdata with scoped registration data
- add GPUVM immediate mode abstraction for rust GPU drivers
- introduce DeviceContext type state for drm::Device
bridge:
- clarify drm_bridge_get/put
- create drm_get_bridge_by_endpoint and use it
- analogix_dp: add panel probing
- ite-it6211 - use drm audio hdmi helpers
buddy:
- add lockdep annotations
dp:
- add PR and VRR updates
- mst: fix buffer overflows
- add Adaptive Sync SDP decoding support
- fix OOB reads in dp-mst
ttm:
- bump fpfn/lpfn to 64-bit
scheduler:
- change default to fair scheduler
- map runqueue 1:1 with scheduler
dma-buf:
- port selftests to kunit
- convert dma-buf system/heap allocators to module
- add separate DMABUF_HEAPS_SYSTEM_CC_SHARED Kconfig
udmabuf:
- revert hugetlb support
- fix error with CONFIG_DMA_API_DEBUG
dma-fence:
- fix tracepoints lifetime
- remove unused signal on any support
ras:
- add clear error counter netlink command to drm ras
gpusvm:
- reject VMAs with VM_IO or VM_PFNMAP when creating SVM ranges
- use IOVA allocations
pagemap:
- use IOVA allocations
panels:
- update to use ref counts
- add support for CSW PNB601LS1-2, LGD LP116WHA-SPB1
- add support for waveshare panels
- CMN N116BCN-EA1, CMN N140HCA-EEK, IVO M140NWFQ R5,
- IVO, R140NWFW R0, BOE NT140*, BOE NV133FHM-N4F,
- AUO B140*, AUO B133HAN06.6 and AUO B116XTN02.3 eDP panels
- Surface Pro 12 Panel
xe:
- add CRI PCI-IDs
- debugfs add multi-lrc info
- engine init cleanup
- PF fair scheduling auto provisioning
- system controller support for CRI/Xe3p
- PXP state machine fixes
- Reset/wedge/unload corner case fixes
- Wedge path memory allocation fixes
- PAT type cleanups
- Reject unsafe PAT for CPU cached memory
- OA improvements for CRI device memory
- kernel doc syntax in xe headers
- xe_drm.h documentation fixes
- include guard cleanups
- VF CCS memory pool
- i915/xe step unification
- Xe3p GT tuning fixes
- forcewake cleanup in GT and GuC
- admin-only PF mode
- enable hwmon energy attributes for CRI
- enable GT_MI_USER_INTERRUPT
- refactor emit functions
- oa workarounds
- multi_queue: allow QUEUE_TIMESTAMP register
- convert stolen memory to ttm range manager
- use xe2 style blitter as a feature flag
- make drm_driver const
- add/use IRQ page to HW engine definition
- fix oops when display disabled
i915:
- enable PIPEDMC_ERROR interrupt
- more common display code refactoring
- restructure DP/HDMI sink format handling
- eliminate FB usage from lowlevel pinning code
- panel replay bw optimization
- integrate sharpness filter into the scaler
- new fb_pin abstraction for xe/i915 fb transparent handling
- skip inactive MST connectors on HDCP
- start switching to display specific registers
- use polling when irq unavailable
- Adaptive-sync SDP prep
amdgpu:
- use drm_display_info for AMD VSDB data
- Initial HDMI 2.1 FRL support
- Initial DCN 4.2.1 support
- GART fixes for non-4k pages
- GC 11.5.6/SDMA 6.4.0/and other new IPs
- GFX9/DCE6/Hawaii/SDMA4/GART/Userq fixes
- Finish support for using multiple SDMA queues for TTM operations
- SWSMU updates
- GC 12.1 updates
- SMU 15.0.8 updates
- DCN 4.2 updates
- DC type conversion fixes
- Enable DC power module
- Replay/PSR updates
- SMU 13.x updates
- Compute queue quantum MQD updates
- ASPM fix
- Align VKMS with common implementation
- DC analog support fixes
- UVD 3 fixes
- TCC harvesting fixes for SI
- GC 11 APU module reload fix
- NBIO 6.3.2 support
- IH 7.1 updates
- DC cursor fixes
- VCN/JPEG user fence fixes
- DC support for connectors without DDC
- Prefer ROM BAR for default VGA device
- DC bandwidth fixes
- Add PTL support for profiler
- Introduce dc_plane_cm and migrate surface update color path
- Add FRL registers for HDMI 2.1
- Restructure VM state machine
- Auxless ALPM support
- GEM_OP locking/warning fixes
- switch to system_dfl_wq
amdkfd:
- GPUVM TLB flush fix
- Hotplug fix
- Boundary check fixes
- SVM fixes
- CRIU fixes
- add profiler API
- MES 12.1 updates
msm:
- core:
- fix shrinker documentation
- IFPC enabled for gen8
- PERFCNTR_CONFIG ioctl support
- GPU:
- reworked UBWC handling
- a810 support
- MDSS:
- add support for Milos platform
- reworked UBWC handling
- DisplayPort:
- reworked HPD handling as prep for MST
- DPU:
- Milos platform support
- reworked UBWC handling
- DSI:
- Milos platform support
nova:
- Hopper/Blackwell enablement (GH100/GB100/GB202)
- FSP support
- 32-bit firmware support
- HAL functions
- refactor GSP boot/unload
- GA100 support
- VBIOS hardening/refactoring
- Adopt higher order lifetime types
tyr:
- define register blocks
- add shmem backed GEM objects
- adopt higher order lifetime types
- move clock cleanup into Drop
radeon:
- Hawaii SMU fixes
- CS parser fix
- use struct drm_edid instead of edid
amdxdna:
- export per-client BO memory via fdinfo
- AIE4 device support
- support medium/lower power modes
- expandable device heap support
- revert read-only user-pointer BO mappings
ivpu:
- support frequency limiting
panthor:
- enable GEM shrinker support
- add eviction and reclaim info to fdinfo
v3d:
- enable runtime PM
mgag200:
- support XRGB1555 + C8
ast:
- support XRGB1555 + C8
- use constants for lots of registers
- fix register handling
imagination:
- fence handling refactoring
nouveau:
- fix sched double call
- expose VBIOS on GSP-RM systems
- add GA100 support
virtio:
- add VIRTIO_GPU_F_BLOB_ALIGNMENT flag
- add deferred mapping support
gud:
- add RCade Display Adapter
hibmc:
- fix no connectors usage
mediatek:
- hdmi: convert error handling
- simplify mtk_crtc allocation
exynos:
- move fbdev emulation to drm client buffers
- use drm format helpers for geometry/size
- adopt core DMA tracking
- fix framebuffer offset handling
renesas:
- add RZ/T2H SOC support
versilicon:
- add cursor plane support
tegra:
- use drm client for framebuffer"
* tag 'drm-next-2026-06-17' of https://gitlab.freedesktop.org/drm/kernel: (1731 commits)
dma-buf: move system_cc_shared heap under separate Kconfig
accel/amdxdna: Clear sva pointer after unbind
agp/amd64: Fix broken error propagation in agp_amd64_probe()
accel/amdxdna: Require carveout when PASID and force_iova are disabled
drm/amdkfd: always resume_all after suspend_all
drm/amdgpu/gfx: move fault and EOP IRQ get/put to hw_init/hw_fini
drm/amd/display: Consult MCCS FreeSync cap only if requested & supported
drm/amd/pm: Use strscpy in profile mode parsing
drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length
drm/amdkfd: fix sysfs topology prop length on buffer truncation
drm/amdgpu: drop retry loop in amdgpu_hmm_range_get_pages
drm/amd/pm: bound OD parameter parsing to stack array size
drm/amd/pm: Stop pp_od_clk_voltage emit at PAGE_SIZE
drm/amdkfd: Unwind debug trap enable on copy_to_user failure
drm/amdgpu: validate the mes firmware version for gfx12.1
drm/amdgpu: validate the mes firmware version for gfx12
drm/amdgpu: compare MES firmware version ucode for gfx11
drm/amdkfd: Add bounds check for AMDKFD_IOC_WAIT_EVENTS
drm/amdgpu: restart the CS if some parts of the VM are still invalidated
drm/amd/display: use unsigned types for local pipe and REG_GET counters
...
725 lines
24 KiB
C
725 lines
24 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2020-2026 Intel Corporation
|
|
*/
|
|
|
|
#include <linux/firmware.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/pci.h>
|
|
|
|
#include "vpu_boot_api.h"
|
|
#include "ivpu_drv.h"
|
|
#include "ivpu_fw.h"
|
|
#include "ivpu_fw_log.h"
|
|
#include "ivpu_gem.h"
|
|
#include "ivpu_hw.h"
|
|
#include "ivpu_ipc.h"
|
|
#include "ivpu_pm.h"
|
|
|
|
#define FW_SHAVE_NN_MAX_SIZE SZ_2M
|
|
#define FW_FILE_IMAGE_OFFSET (VPU_FW_HEADER_SIZE + FW_VERSION_HEADER_SIZE)
|
|
#define FW_PREEMPT_BUF_MIN_SIZE SZ_4K
|
|
#define FW_PREEMPT_BUF_MAX_SIZE SZ_32M
|
|
|
|
#define WATCHDOG_MSS_REDIRECT 32
|
|
#define WATCHDOG_NCE_REDIRECT 33
|
|
|
|
#define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31)
|
|
|
|
/* Check if FW API is compatible with the driver */
|
|
#define IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, name, min_major) \
|
|
ivpu_fw_check_api(vdev, fw_hdr, #name, \
|
|
VPU_##name##_API_VER_INDEX, \
|
|
VPU_##name##_API_VER_MAJOR, \
|
|
VPU_##name##_API_VER_MINOR, min_major)
|
|
|
|
/* Check if API version is lower that the given version */
|
|
#define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \
|
|
ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor)
|
|
|
|
#define IVPU_FOCUS_PRESENT_TIMER_MS 1000
|
|
|
|
static char *ivpu_firmware;
|
|
#if IS_ENABLED(CONFIG_DRM_ACCEL_IVPU_DEBUG)
|
|
module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644);
|
|
MODULE_PARM_DESC(firmware, "NPU firmware binary in /lib/firmware/..");
|
|
#endif
|
|
|
|
static struct {
|
|
int gen;
|
|
const char *name;
|
|
} fw_names[] = {
|
|
{ IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v1.bin" },
|
|
{ IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v0.0.bin" },
|
|
{ IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v1.bin" },
|
|
{ IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v0.0.bin" },
|
|
{ IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v1.bin" },
|
|
{ IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v0.0.bin" },
|
|
{ IVPU_HW_IP_60XX, "intel/vpu/vpu_60xx_v1.bin" },
|
|
};
|
|
|
|
/* Production fw_names from the table above */
|
|
MODULE_FIRMWARE("intel/vpu/vpu_37xx_v1.bin");
|
|
MODULE_FIRMWARE("intel/vpu/vpu_40xx_v1.bin");
|
|
MODULE_FIRMWARE("intel/vpu/vpu_50xx_v1.bin");
|
|
MODULE_FIRMWARE("intel/vpu/vpu_60xx_v1.bin");
|
|
|
|
static int ivpu_fw_request(struct ivpu_device *vdev)
|
|
{
|
|
int ret = -ENOENT;
|
|
int i;
|
|
|
|
if (ivpu_firmware) {
|
|
ret = request_firmware(&vdev->fw->file, ivpu_firmware, vdev->drm.dev);
|
|
if (!ret)
|
|
vdev->fw->name = ivpu_firmware;
|
|
return ret;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fw_names); i++) {
|
|
if (fw_names[i].gen != ivpu_hw_ip_gen(vdev))
|
|
continue;
|
|
|
|
ret = firmware_request_nowarn(&vdev->fw->file, fw_names[i].name, vdev->drm.dev);
|
|
if (!ret) {
|
|
vdev->fw->name = fw_names[i].name;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ivpu_err(vdev, "Failed to request firmware: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr,
|
|
const char *str, int index, u16 expected_major, u16 expected_minor,
|
|
u16 min_major)
|
|
{
|
|
u16 major = (u16)(fw_hdr->api_version[index] >> 16);
|
|
u16 minor = (u16)(fw_hdr->api_version[index]);
|
|
|
|
if (major < min_major) {
|
|
ivpu_err(vdev, "Incompatible FW %s API version: %d.%d, required %d.0 or later\n",
|
|
str, major, minor, min_major);
|
|
return -EINVAL;
|
|
}
|
|
if (major != expected_major) {
|
|
ivpu_warn(vdev, "Major FW %s API version different: %d.%d (expected %d.%d)\n",
|
|
str, major, minor, expected_major, expected_minor);
|
|
}
|
|
ivpu_dbg(vdev, FW_BOOT, "FW %s API version: %d.%d (expected %d.%d)\n",
|
|
str, major, minor, expected_major, expected_minor);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool
|
|
ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr,
|
|
const char *str, int index, u16 major, u16 minor)
|
|
{
|
|
u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16);
|
|
u16 fw_minor = (u16)(fw_hdr->api_version[index]);
|
|
|
|
if (fw_major < major || (fw_major == major && fw_minor < minor))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ivpu_is_within_range(u64 addr, size_t size, struct ivpu_addr_range *range)
|
|
{
|
|
u64 addr_end;
|
|
|
|
if (!range || check_add_overflow(addr, size, &addr_end))
|
|
return false;
|
|
|
|
if (addr < range->start || addr_end > range->end)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static u32
|
|
ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr)
|
|
{
|
|
if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX &&
|
|
ivpu_sched_mode == VPU_SCHEDULING_MODE_OS) {
|
|
ivpu_warn(vdev, "OS sched mode is not supported, using HW mode\n");
|
|
return VPU_SCHEDULING_MODE_HW;
|
|
}
|
|
|
|
if (ivpu_sched_mode != IVPU_SCHED_MODE_AUTO)
|
|
return ivpu_sched_mode;
|
|
|
|
if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, JSM, 3, 24))
|
|
return VPU_SCHEDULING_MODE_OS;
|
|
|
|
return VPU_SCHEDULING_MODE_HW;
|
|
}
|
|
|
|
static void
|
|
ivpu_preemption_config_parse(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr)
|
|
{
|
|
struct ivpu_fw_info *fw = vdev->fw;
|
|
u32 primary_preempt_buf_size, secondary_preempt_buf_size;
|
|
|
|
if (fw_hdr->preemption_buffer_1_max_size)
|
|
primary_preempt_buf_size = fw_hdr->preemption_buffer_1_max_size;
|
|
else
|
|
primary_preempt_buf_size = fw_hdr->preemption_buffer_1_size;
|
|
|
|
if (fw_hdr->preemption_buffer_2_max_size)
|
|
secondary_preempt_buf_size = fw_hdr->preemption_buffer_2_max_size;
|
|
else
|
|
secondary_preempt_buf_size = fw_hdr->preemption_buffer_2_size;
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "Preemption buffer size, primary: %u, secondary: %u\n",
|
|
primary_preempt_buf_size, secondary_preempt_buf_size);
|
|
|
|
if (primary_preempt_buf_size < FW_PREEMPT_BUF_MIN_SIZE ||
|
|
secondary_preempt_buf_size < FW_PREEMPT_BUF_MIN_SIZE) {
|
|
ivpu_warn(vdev, "Preemption buffers size too small\n");
|
|
return;
|
|
}
|
|
|
|
if (primary_preempt_buf_size > FW_PREEMPT_BUF_MAX_SIZE ||
|
|
secondary_preempt_buf_size > FW_PREEMPT_BUF_MAX_SIZE) {
|
|
ivpu_warn(vdev, "Preemption buffers size too big\n");
|
|
return;
|
|
}
|
|
|
|
if (fw->sched_mode != VPU_SCHEDULING_MODE_HW)
|
|
return;
|
|
|
|
if (ivpu_test_mode & IVPU_TEST_MODE_MIP_DISABLE)
|
|
return;
|
|
|
|
vdev->fw->primary_preempt_buf_size = ALIGN(primary_preempt_buf_size, PAGE_SIZE);
|
|
vdev->fw->secondary_preempt_buf_size = ALIGN(secondary_preempt_buf_size, PAGE_SIZE);
|
|
}
|
|
|
|
static int ivpu_fw_parse(struct ivpu_device *vdev)
|
|
{
|
|
struct ivpu_fw_info *fw = vdev->fw;
|
|
const struct vpu_firmware_header *fw_hdr = (const void *)fw->file->data;
|
|
struct ivpu_addr_range fw_image_range;
|
|
u64 boot_params_addr, boot_params_size;
|
|
u64 fw_version_addr, fw_version_size;
|
|
u64 runtime_addr, runtime_size;
|
|
u64 image_load_addr, image_size;
|
|
|
|
if (fw->file->size <= FW_FILE_IMAGE_OFFSET) {
|
|
ivpu_err(vdev, "Firmware file is too small: %zu\n", fw->file->size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (fw_hdr->header_version != VPU_FW_HEADER_VERSION) {
|
|
ivpu_err(vdev, "Invalid firmware header version: %u\n", fw_hdr->header_version);
|
|
return -EINVAL;
|
|
}
|
|
|
|
boot_params_addr = fw_hdr->boot_params_load_address;
|
|
boot_params_size = SZ_4K;
|
|
|
|
if (!ivpu_is_within_range(boot_params_addr, boot_params_size, &vdev->hw->ranges.runtime)) {
|
|
ivpu_err(vdev, "Invalid boot params address: 0x%llx\n", boot_params_addr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
fw_version_addr = fw_hdr->firmware_version_load_address;
|
|
fw_version_size = ALIGN(fw_hdr->firmware_version_size, SZ_4K);
|
|
|
|
if (fw_version_size != SZ_4K) {
|
|
ivpu_err(vdev, "Invalid firmware version size: %u\n",
|
|
fw_hdr->firmware_version_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!ivpu_is_within_range(fw_version_addr, fw_version_size, &vdev->hw->ranges.runtime)) {
|
|
ivpu_err(vdev, "Invalid firmware version address: 0x%llx\n", fw_version_addr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
runtime_addr = fw_hdr->image_load_address;
|
|
runtime_size = fw_hdr->runtime_size - boot_params_size - fw_version_size;
|
|
|
|
image_load_addr = fw_hdr->image_load_address;
|
|
image_size = fw_hdr->image_size;
|
|
|
|
if (!ivpu_is_within_range(runtime_addr, runtime_size, &vdev->hw->ranges.runtime)) {
|
|
ivpu_err(vdev, "Invalid firmware runtime address: 0x%llx and size %llu\n",
|
|
runtime_addr, runtime_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (FW_FILE_IMAGE_OFFSET + image_size > fw->file->size) {
|
|
ivpu_err(vdev, "Invalid image size: %llu\n", image_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!PAGE_ALIGNED(runtime_addr)) {
|
|
ivpu_err(vdev, "Runtime address 0x%llx not page aligned\n", runtime_addr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!PAGE_ALIGNED(runtime_size)) {
|
|
ivpu_err(vdev, "Runtime size %llu not page aligned\n", runtime_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (runtime_size < image_size) {
|
|
ivpu_err(vdev, "Runtime size too small: %llu, image size: %llu\n",
|
|
runtime_size, image_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!ivpu_is_within_range(image_load_addr, image_size, &vdev->hw->ranges.runtime)) {
|
|
ivpu_err(vdev, "Invalid firmware load address: 0x%llx and size %llu\n",
|
|
image_load_addr, image_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (ivpu_hw_range_init(vdev, &fw_image_range, image_load_addr, image_size))
|
|
return -EINVAL;
|
|
|
|
if (!ivpu_is_within_range(fw_hdr->entry_point, SZ_4K, &fw_image_range)) {
|
|
ivpu_err(vdev, "Invalid entry point: 0x%llx\n", fw_hdr->entry_point);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (fw_hdr->shave_nn_fw_size > FW_SHAVE_NN_MAX_SIZE) {
|
|
ivpu_err(vdev, "SHAVE NN firmware is too big: %u\n", fw_hdr->shave_nn_fw_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "Header version: 0x%x, format 0x%x\n",
|
|
fw_hdr->header_version, fw_hdr->image_format);
|
|
|
|
if (!scnprintf(fw->version, sizeof(fw->version), "%s", fw->file->data + VPU_FW_HEADER_SIZE))
|
|
ivpu_warn(vdev, "Missing firmware version\n");
|
|
|
|
ivpu_info(vdev, "Firmware: %s, version: %s\n", fw->name, fw->version);
|
|
|
|
if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3))
|
|
return -EINVAL;
|
|
if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3))
|
|
return -EINVAL;
|
|
|
|
fw->boot_params_addr = boot_params_addr;
|
|
fw->boot_params_size = boot_params_size;
|
|
fw->fw_version_addr = fw_version_addr;
|
|
fw->fw_version_size = fw_version_size;
|
|
fw->runtime_addr = runtime_addr;
|
|
fw->runtime_size = runtime_size;
|
|
fw->image_load_offset = image_load_addr - runtime_addr;
|
|
fw->image_size = image_size;
|
|
fw->shave_nn_size = PAGE_ALIGN(fw_hdr->shave_nn_fw_size);
|
|
fw->cold_boot_entry_point = fw_hdr->entry_point;
|
|
|
|
fw->trace_level = min_t(u32, ivpu_fw_log_level, IVPU_FW_LOG_FATAL);
|
|
fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING;
|
|
fw->trace_hw_component_mask = -1;
|
|
|
|
fw->dvfs_mode = 0;
|
|
|
|
fw->sched_mode = ivpu_fw_sched_mode_select(vdev, fw_hdr);
|
|
ivpu_info(vdev, "Scheduler mode: %s\n", fw->sched_mode ? "HW" : "OS");
|
|
|
|
ivpu_preemption_config_parse(vdev, fw_hdr);
|
|
ivpu_dbg(vdev, FW_BOOT, "Mid-inference preemption %s supported\n",
|
|
ivpu_fw_preempt_buf_size(vdev) ? "is" : "is not");
|
|
|
|
if (fw_hdr->ro_section_start_address &&
|
|
!ivpu_is_within_range(fw_hdr->ro_section_start_address, fw_hdr->ro_section_size,
|
|
&fw_image_range)) {
|
|
ivpu_err(vdev, "Invalid read-only section: start address 0x%llx, size %u\n",
|
|
fw_hdr->ro_section_start_address, fw_hdr->ro_section_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
fw->read_only_addr = fw_hdr->ro_section_start_address;
|
|
fw->read_only_size = fw_hdr->ro_section_size;
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "Boot params: address 0x%llx, size %llu\n",
|
|
fw->boot_params_addr, fw->boot_params_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "FW version: address 0x%llx, size %llu\n",
|
|
fw->fw_version_addr, fw->fw_version_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "Runtime: address 0x%llx, size %u\n",
|
|
fw->runtime_addr, fw->runtime_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "Image load offset: 0x%llx, size %u\n",
|
|
fw->image_load_offset, fw->image_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "Read-only section: address 0x%llx, size %u\n",
|
|
fw->read_only_addr, fw->read_only_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "FW cold boot entry point: 0x%llx\n", fw->cold_boot_entry_point);
|
|
ivpu_dbg(vdev, FW_BOOT, "SHAVE NN size: %u\n", fw->shave_nn_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ivpu_fw_release(struct ivpu_device *vdev)
|
|
{
|
|
release_firmware(vdev->fw->file);
|
|
}
|
|
|
|
|
|
static int ivpu_fw_mem_init(struct ivpu_device *vdev)
|
|
{
|
|
struct ivpu_fw_info *fw = vdev->fw;
|
|
int log_verb_size;
|
|
int ret;
|
|
|
|
fw->mem_bp = ivpu_bo_create_runtime(vdev, fw->boot_params_addr, fw->boot_params_size,
|
|
DRM_IVPU_BO_WC | DRM_IVPU_BO_MAPPABLE);
|
|
if (!fw->mem_bp) {
|
|
ivpu_err(vdev, "Failed to create firmware boot params memory buffer\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
fw->mem_fw_ver = ivpu_bo_create_runtime(vdev, fw->fw_version_addr, fw->fw_version_size,
|
|
DRM_IVPU_BO_WC | DRM_IVPU_BO_MAPPABLE);
|
|
if (!fw->mem_fw_ver) {
|
|
ivpu_err(vdev, "Failed to create firmware version memory buffer\n");
|
|
ret = -ENOMEM;
|
|
goto err_free_bp;
|
|
}
|
|
|
|
fw->mem = ivpu_bo_create_runtime(vdev, fw->runtime_addr, fw->runtime_size,
|
|
DRM_IVPU_BO_WC | DRM_IVPU_BO_MAPPABLE);
|
|
if (!fw->mem) {
|
|
ivpu_err(vdev, "Failed to create firmware runtime memory buffer\n");
|
|
ret = -ENOMEM;
|
|
goto err_free_fw_ver;
|
|
}
|
|
|
|
ret = ivpu_mmu_context_set_pages_ro(vdev, &vdev->gctx, fw->read_only_addr,
|
|
fw->read_only_size);
|
|
if (ret) {
|
|
ivpu_err(vdev, "Failed to set firmware image read-only\n");
|
|
goto err_free_fw_mem;
|
|
}
|
|
|
|
fw->mem_log_crit = ivpu_bo_create_global(vdev, IVPU_FW_CRITICAL_BUFFER_SIZE,
|
|
DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
|
|
if (!fw->mem_log_crit) {
|
|
ivpu_err(vdev, "Failed to create critical log buffer\n");
|
|
ret = -ENOMEM;
|
|
goto err_free_fw_mem;
|
|
}
|
|
|
|
if (ivpu_fw_log_level <= IVPU_FW_LOG_INFO)
|
|
log_verb_size = IVPU_FW_VERBOSE_BUFFER_LARGE_SIZE;
|
|
else
|
|
log_verb_size = IVPU_FW_VERBOSE_BUFFER_SMALL_SIZE;
|
|
|
|
fw->mem_log_verb = ivpu_bo_create_global(vdev, log_verb_size,
|
|
DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
|
|
if (!fw->mem_log_verb) {
|
|
ivpu_err(vdev, "Failed to create verbose log buffer\n");
|
|
ret = -ENOMEM;
|
|
goto err_free_log_crit;
|
|
}
|
|
|
|
if (fw->shave_nn_size) {
|
|
fw->mem_shave_nn = ivpu_bo_create(vdev, &vdev->gctx, &vdev->hw->ranges.shave,
|
|
fw->shave_nn_size, DRM_IVPU_BO_WC);
|
|
if (!fw->mem_shave_nn) {
|
|
ivpu_err(vdev, "Failed to create shavenn buffer\n");
|
|
ret = -ENOMEM;
|
|
goto err_free_log_verb;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_free_log_verb:
|
|
ivpu_bo_free(fw->mem_log_verb);
|
|
err_free_log_crit:
|
|
ivpu_bo_free(fw->mem_log_crit);
|
|
err_free_fw_mem:
|
|
ivpu_bo_free(fw->mem);
|
|
err_free_fw_ver:
|
|
ivpu_bo_free(fw->mem_fw_ver);
|
|
err_free_bp:
|
|
ivpu_bo_free(fw->mem_bp);
|
|
return ret;
|
|
}
|
|
|
|
static void ivpu_fw_mem_fini(struct ivpu_device *vdev)
|
|
{
|
|
struct ivpu_fw_info *fw = vdev->fw;
|
|
|
|
if (fw->mem_shave_nn) {
|
|
ivpu_bo_free(fw->mem_shave_nn);
|
|
fw->mem_shave_nn = NULL;
|
|
}
|
|
|
|
ivpu_bo_free(fw->mem_log_verb);
|
|
ivpu_bo_free(fw->mem_log_crit);
|
|
ivpu_bo_free(fw->mem);
|
|
ivpu_bo_free(fw->mem_fw_ver);
|
|
ivpu_bo_free(fw->mem_bp);
|
|
|
|
fw->mem_log_verb = NULL;
|
|
fw->mem_log_crit = NULL;
|
|
fw->mem = NULL;
|
|
fw->mem_fw_ver = NULL;
|
|
fw->mem_bp = NULL;
|
|
}
|
|
|
|
int ivpu_fw_init(struct ivpu_device *vdev)
|
|
{
|
|
int ret;
|
|
|
|
ret = ivpu_fw_request(vdev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = ivpu_fw_parse(vdev);
|
|
if (ret)
|
|
goto err_fw_release;
|
|
|
|
ret = ivpu_fw_mem_init(vdev);
|
|
if (ret)
|
|
goto err_fw_release;
|
|
|
|
ivpu_fw_load(vdev);
|
|
|
|
return 0;
|
|
|
|
err_fw_release:
|
|
ivpu_fw_release(vdev);
|
|
return ret;
|
|
}
|
|
|
|
void ivpu_fw_fini(struct ivpu_device *vdev)
|
|
{
|
|
ivpu_fw_mem_fini(vdev);
|
|
ivpu_fw_release(vdev);
|
|
}
|
|
|
|
void ivpu_fw_load(struct ivpu_device *vdev)
|
|
{
|
|
struct ivpu_fw_info *fw = vdev->fw;
|
|
u64 image_end_offset = fw->image_load_offset + fw->image_size;
|
|
|
|
memset(ivpu_bo_vaddr(fw->mem), 0, fw->image_load_offset);
|
|
memcpy(ivpu_bo_vaddr(fw->mem) + fw->image_load_offset,
|
|
fw->file->data + FW_FILE_IMAGE_OFFSET, fw->image_size);
|
|
|
|
if (IVPU_WA(clear_runtime_mem)) {
|
|
u8 *start = ivpu_bo_vaddr(fw->mem) + image_end_offset;
|
|
u64 size = ivpu_bo_size(fw->mem) - image_end_offset;
|
|
|
|
memset(start, 0, size);
|
|
}
|
|
|
|
wmb(); /* Flush WC buffers after writing fw->mem */
|
|
}
|
|
|
|
static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
|
|
{
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.magic = 0x%x\n",
|
|
boot_params->magic);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_id = 0x%x\n",
|
|
boot_params->vpu_id);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_count = 0x%x\n",
|
|
boot_params->vpu_count);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.frequency = %u\n",
|
|
boot_params->frequency);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.perf_clk_frequency = %u\n",
|
|
boot_params->perf_clk_frequency);
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_header_area_start = 0x%llx\n",
|
|
boot_params->ipc_header_area_start);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_header_area_size = 0x%x\n",
|
|
boot_params->ipc_header_area_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.shared_region_base = 0x%llx\n",
|
|
boot_params->shared_region_base);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.shared_region_size = 0x%x\n",
|
|
boot_params->shared_region_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_payload_area_start = 0x%llx\n",
|
|
boot_params->ipc_payload_area_start);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_payload_area_size = 0x%x\n",
|
|
boot_params->ipc_payload_area_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.global_aliased_pio_base = 0x%llx\n",
|
|
boot_params->global_aliased_pio_base);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.global_aliased_pio_size = 0x%x\n",
|
|
boot_params->global_aliased_pio_size);
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.autoconfig = 0x%x\n",
|
|
boot_params->autoconfig);
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use = 0x%x\n",
|
|
boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg = 0x%x\n",
|
|
boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg);
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.shave_nn_fw_base = 0x%llx\n",
|
|
boot_params->shave_nn_fw_base);
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.watchdog_irq_mss = 0x%x\n",
|
|
boot_params->watchdog_irq_mss);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.watchdog_irq_nce = 0x%x\n",
|
|
boot_params->watchdog_irq_nce);
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.host_version_id = 0x%x\n",
|
|
boot_params->host_version_id);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.si_stepping = 0x%x\n",
|
|
boot_params->si_stepping);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.device_id = 0x%llx\n",
|
|
boot_params->device_id);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.feature_exclusion = 0x%llx\n",
|
|
boot_params->feature_exclusion);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.sku = 0x%llx\n",
|
|
boot_params->sku);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.min_freq_pll_ratio = 0x%x\n",
|
|
boot_params->min_freq_pll_ratio);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.pn_freq_pll_ratio = 0x%x\n",
|
|
boot_params->pn_freq_pll_ratio);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.max_freq_pll_ratio = 0x%x\n",
|
|
boot_params->max_freq_pll_ratio);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.default_trace_level = 0x%x\n",
|
|
boot_params->default_trace_level);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.tracing_buff_message_format_mask = 0x%llx\n",
|
|
boot_params->tracing_buff_message_format_mask);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.trace_destination_mask = 0x%x\n",
|
|
boot_params->trace_destination_mask);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.trace_hw_component_mask = 0x%llx\n",
|
|
boot_params->trace_hw_component_mask);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n",
|
|
boot_params->boot_type);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.punit_telemetry_sram_base = 0x%llx\n",
|
|
boot_params->punit_telemetry_sram_base);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.punit_telemetry_sram_size = 0x%llx\n",
|
|
boot_params->punit_telemetry_sram_size);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_telemetry_enable = 0x%x\n",
|
|
boot_params->vpu_telemetry_enable);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_scheduling_mode = 0x%x\n",
|
|
boot_params->vpu_scheduling_mode);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n",
|
|
boot_params->dvfs_mode);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_delayed_entry = %d\n",
|
|
boot_params->d0i3_delayed_entry);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n",
|
|
boot_params->d0i3_residency_time_us);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n",
|
|
boot_params->d0i3_entry_vpu_ts);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n",
|
|
boot_params->system_time_us);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.power_profile = 0x%x\n",
|
|
boot_params->power_profile);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_uses_ecc_mca_signal = 0x%x\n",
|
|
boot_params->vpu_uses_ecc_mca_signal);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type);
|
|
}
|
|
|
|
void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
|
|
{
|
|
struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx;
|
|
|
|
/* In case of warm boot only update variable params */
|
|
if (ivpu_fw_is_warm_boot(vdev)) {
|
|
boot_params->d0i3_residency_time_us =
|
|
ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts);
|
|
boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts;
|
|
boot_params->system_time_us = ktime_to_us(ktime_get_real());
|
|
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n",
|
|
boot_params->d0i3_residency_time_us);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n",
|
|
boot_params->d0i3_entry_vpu_ts);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n",
|
|
boot_params->system_time_us);
|
|
ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type);
|
|
|
|
boot_params->save_restore_ret_address = 0;
|
|
boot_params->boot_type = VPU_BOOT_TYPE_WARMBOOT;
|
|
wmb(); /* Flush WC buffers after writing save_restore_ret_address */
|
|
return;
|
|
}
|
|
|
|
memset(boot_params, 0, sizeof(*boot_params));
|
|
boot_params->boot_type = VPU_BOOT_TYPE_COLDBOOT;
|
|
boot_params->magic = VPU_BOOT_PARAMS_MAGIC;
|
|
boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number;
|
|
|
|
/*
|
|
* This param is a debug firmware feature. It switches default clock
|
|
* to higher resolution one for fine-grained and more accurate firmware
|
|
* task profiling.
|
|
*/
|
|
boot_params->perf_clk_frequency = ivpu_hw_profiling_freq_get(vdev);
|
|
|
|
/*
|
|
* Uncached region of VPU address space, covers IPC buffers, job queues
|
|
* and log buffers, programmable to L2$ Uncached by VPU MTRR
|
|
*/
|
|
boot_params->shared_region_base = vdev->hw->ranges.global.start;
|
|
boot_params->shared_region_size = vdev->hw->ranges.global.end -
|
|
vdev->hw->ranges.global.start;
|
|
|
|
boot_params->ipc_header_area_start = ipc_mem_rx->vpu_addr;
|
|
boot_params->ipc_header_area_size = ivpu_bo_size(ipc_mem_rx) / 2;
|
|
|
|
boot_params->ipc_payload_area_start = ipc_mem_rx->vpu_addr + ivpu_bo_size(ipc_mem_rx) / 2;
|
|
boot_params->ipc_payload_area_size = ivpu_bo_size(ipc_mem_rx) / 2;
|
|
|
|
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
|
|
boot_params->global_aliased_pio_base = vdev->hw->ranges.user.start;
|
|
boot_params->global_aliased_pio_size = ivpu_hw_range_size(&vdev->hw->ranges.user);
|
|
}
|
|
|
|
/* Allow configuration for L2C_PAGE_TABLE with boot param value */
|
|
boot_params->autoconfig = 1;
|
|
|
|
/* Enable L2 cache for first 2GB of high memory */
|
|
boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use = 1;
|
|
boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg =
|
|
ADDR_TO_L2_CACHE_CFG(vdev->hw->ranges.shave.start);
|
|
|
|
if (vdev->fw->mem_shave_nn)
|
|
boot_params->shave_nn_fw_base = vdev->fw->mem_shave_nn->vpu_addr;
|
|
|
|
boot_params->watchdog_irq_mss = WATCHDOG_MSS_REDIRECT;
|
|
boot_params->watchdog_irq_nce = WATCHDOG_NCE_REDIRECT;
|
|
boot_params->si_stepping = ivpu_revision(vdev);
|
|
boot_params->device_id = ivpu_device_id(vdev);
|
|
boot_params->feature_exclusion = vdev->hw->tile_fuse;
|
|
boot_params->sku = vdev->hw->sku;
|
|
|
|
boot_params->min_freq_pll_ratio = vdev->hw->pll.min_ratio;
|
|
boot_params->pn_freq_pll_ratio = vdev->hw->pll.pn_ratio;
|
|
boot_params->max_freq_pll_ratio = vdev->hw->pll.max_ratio;
|
|
|
|
boot_params->default_trace_level = vdev->fw->trace_level;
|
|
boot_params->tracing_buff_message_format_mask = BIT(VPU_TRACING_FORMAT_STRING);
|
|
boot_params->trace_destination_mask = vdev->fw->trace_destination_mask;
|
|
boot_params->trace_hw_component_mask = vdev->fw->trace_hw_component_mask;
|
|
boot_params->crit_tracing_buff_addr = vdev->fw->mem_log_crit->vpu_addr;
|
|
boot_params->crit_tracing_buff_size = ivpu_bo_size(vdev->fw->mem_log_crit);
|
|
boot_params->verbose_tracing_buff_addr = vdev->fw->mem_log_verb->vpu_addr;
|
|
boot_params->verbose_tracing_buff_size = ivpu_bo_size(vdev->fw->mem_log_verb);
|
|
|
|
boot_params->punit_telemetry_sram_base = ivpu_hw_telemetry_offset_get(vdev);
|
|
boot_params->punit_telemetry_sram_size = ivpu_hw_telemetry_size_get(vdev);
|
|
boot_params->vpu_telemetry_enable = ivpu_hw_telemetry_enable_get(vdev);
|
|
boot_params->vpu_scheduling_mode = vdev->fw->sched_mode;
|
|
if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
|
|
boot_params->vpu_focus_present_timer_ms = IVPU_FOCUS_PRESENT_TIMER_MS;
|
|
boot_params->dvfs_mode = vdev->fw->dvfs_mode;
|
|
boot_params->d0i3_delayed_entry = 1;
|
|
boot_params->d0i3_residency_time_us = 0;
|
|
boot_params->d0i3_entry_vpu_ts = 0;
|
|
if (IVPU_WA(disable_d0i2))
|
|
boot_params->power_profile |= BIT(1);
|
|
boot_params->vpu_uses_ecc_mca_signal =
|
|
ivpu_hw_uses_ecc_mca_signal(vdev) ? VPU_BOOT_MCA_ECC_BOTH : 0;
|
|
|
|
boot_params->system_time_us = ktime_to_us(ktime_get_real());
|
|
wmb(); /* Flush WC buffers after writing bootparams */
|
|
|
|
ivpu_fw_boot_params_print(vdev, boot_params);
|
|
}
|