1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
2 /* Copyright (c) 2023 Imagination Technologies Ltd. */
4 #include "pvr_device.h"
5 #include "pvr_device_info.h"
8 #include <drm/drm_drv.h>
9 #include <linux/firmware.h>
10 #include <linux/sizes.h>
12 #define FW_MAX_SUPPORTED_MAJOR_VERSION 1
15 * pvr_fw_validate() - Parse firmware header and check compatibility
16 * @pvr_dev: Device pointer.
20 * * -EINVAL if firmware is incompatible.
23 pvr_fw_validate(struct pvr_device *pvr_dev)
25 struct drm_device *drm_dev = from_pvr_device(pvr_dev);
26 const struct firmware *firmware = pvr_dev->fw_dev.firmware;
27 const struct pvr_fw_layout_entry *layout_entries;
28 const struct pvr_fw_info_header *header;
29 const u8 *fw = firmware->data;
30 u32 fw_offset = firmware->size - SZ_4K;
31 u32 layout_table_size;
34 if (firmware->size < SZ_4K || (firmware->size % FW_BLOCK_SIZE))
37 header = (const struct pvr_fw_info_header *)&fw[fw_offset];
39 if (header->info_version != PVR_FW_INFO_VERSION) {
40 drm_err(drm_dev, "Unsupported fw info version %u\n",
41 header->info_version);
45 if (header->header_len != sizeof(struct pvr_fw_info_header) ||
46 header->layout_entry_size != sizeof(struct pvr_fw_layout_entry) ||
47 header->layout_entry_num > PVR_FW_INFO_MAX_NUM_ENTRIES) {
48 drm_err(drm_dev, "FW info format mismatch\n");
52 if (!(header->flags & PVR_FW_FLAGS_OPEN_SOURCE) ||
53 header->fw_version_major > FW_MAX_SUPPORTED_MAJOR_VERSION ||
54 header->fw_version_major == 0) {
55 drm_err(drm_dev, "Unsupported FW version %u.%u (build: %u%s)\n",
56 header->fw_version_major, header->fw_version_minor,
57 header->fw_version_build,
58 (header->flags & PVR_FW_FLAGS_OPEN_SOURCE) ? " OS" : "");
62 if (pvr_gpu_id_to_packed_bvnc(&pvr_dev->gpu_id) != header->bvnc) {
63 struct pvr_gpu_id fw_gpu_id;
65 packed_bvnc_to_pvr_gpu_id(header->bvnc, &fw_gpu_id);
66 drm_err(drm_dev, "FW built for incorrect GPU ID %i.%i.%i.%i (expected %i.%i.%i.%i)\n",
67 fw_gpu_id.b, fw_gpu_id.v, fw_gpu_id.n, fw_gpu_id.c,
68 pvr_dev->gpu_id.b, pvr_dev->gpu_id.v, pvr_dev->gpu_id.n, pvr_dev->gpu_id.c);
72 fw_offset += header->header_len;
74 header->layout_entry_size * header->layout_entry_num;
75 if ((fw_offset + layout_table_size) > firmware->size)
78 layout_entries = (const struct pvr_fw_layout_entry *)&fw[fw_offset];
79 for (entry = 0; entry < header->layout_entry_num; entry++) {
80 u32 start_addr = layout_entries[entry].base_addr;
81 u32 end_addr = start_addr + layout_entries[entry].alloc_size;
83 if (start_addr >= end_addr)
87 fw_offset = (firmware->size - SZ_4K) - header->device_info_size;
89 drm_info(drm_dev, "FW version v%u.%u (build %u OS)\n", header->fw_version_major,
90 header->fw_version_minor, header->fw_version_build);
92 pvr_dev->fw_version.major = header->fw_version_major;
93 pvr_dev->fw_version.minor = header->fw_version_minor;
95 pvr_dev->fw_dev.header = header;
96 pvr_dev->fw_dev.layout_entries = layout_entries;
102 pvr_fw_get_device_info(struct pvr_device *pvr_dev)
104 const struct firmware *firmware = pvr_dev->fw_dev.firmware;
105 struct pvr_fw_device_info_header *header;
106 const u8 *fw = firmware->data;
110 fw_offset = (firmware->size - SZ_4K) - pvr_dev->fw_dev.header->device_info_size;
112 header = (struct pvr_fw_device_info_header *)&fw[fw_offset];
113 dev_info = (u64 *)(header + 1);
115 pvr_device_info_set_quirks(pvr_dev, dev_info, header->brn_mask_size);
116 dev_info += header->brn_mask_size;
118 pvr_device_info_set_enhancements(pvr_dev, dev_info, header->ern_mask_size);
119 dev_info += header->ern_mask_size;
121 return pvr_device_info_set_features(pvr_dev, dev_info, header->feature_mask_size,
122 header->feature_param_size);
126 * pvr_fw_validate_init_device_info() - Validate firmware and initialise device information
127 * @pvr_dev: Target PowerVR device.
129 * This function must be called before querying device information.
133 * * -%EINVAL if firmware validation fails.
136 pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev)
140 err = pvr_fw_validate(pvr_dev);
144 return pvr_fw_get_device_info(pvr_dev);