drm/radeon: add new firmware header definitions (v3)
authorAlex Deucher <alexander.deucher@amd.com>
Wed, 25 Jun 2014 19:54:46 +0000 (15:54 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 5 Aug 2014 12:53:22 +0000 (08:53 -0400)
These are needed to properly handle more frequently
updated firmware.

v2: add new firmware helper functions as well.
v3: update to latest format

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/radeon_ucode.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_ucode.h

index dbcbfe80aac0293892259f5602256d2f559453cf..1b0400213756655e30600b1e1b008f933e002504 100644 (file)
@@ -80,7 +80,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
        rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
-       ci_dpm.o dce6_afmt.o radeon_vm.o
+       ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o
 
 # add async DMA block
 radeon-y += \
diff --git a/drivers/gpu/drm/radeon/radeon_ucode.c b/drivers/gpu/drm/radeon/radeon_ucode.c
new file mode 100644 (file)
index 0000000..6beec68
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "radeon_ucode.h"
+
+static void radeon_ucode_print_common_hdr(const struct common_firmware_header *hdr)
+{
+       DRM_DEBUG("size_bytes: %u\n", le32_to_cpu(hdr->size_bytes));
+       DRM_DEBUG("header_size_bytes: %u\n", le32_to_cpu(hdr->header_size_bytes));
+       DRM_DEBUG("header_version_major: %u\n", le16_to_cpu(hdr->header_version_major));
+       DRM_DEBUG("header_version_minor: %u\n", le16_to_cpu(hdr->header_version_minor));
+       DRM_DEBUG("ip_version_major: %u\n", le16_to_cpu(hdr->ip_version_major));
+       DRM_DEBUG("ip_version_minor: %u\n", le16_to_cpu(hdr->ip_version_minor));
+       DRM_DEBUG("ucode_version: 0x%08x\n", le32_to_cpu(hdr->ucode_version));
+       DRM_DEBUG("ucode_size_bytes: %u\n", le32_to_cpu(hdr->ucode_size_bytes));
+       DRM_DEBUG("ucode_array_offset_bytes: %u\n",
+                 le32_to_cpu(hdr->ucode_array_offset_bytes));
+       DRM_DEBUG("crc32: 0x%08x\n", le32_to_cpu(hdr->crc32));
+}
+
+void radeon_ucode_print_mc_hdr(const struct common_firmware_header *hdr)
+{
+       uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+       uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+       DRM_DEBUG("MC\n");
+       radeon_ucode_print_common_hdr(hdr);
+
+       if (version_major == 1) {
+               const struct mc_firmware_header_v1_0 *mc_hdr =
+                       container_of(hdr, struct mc_firmware_header_v1_0, header);
+
+               DRM_DEBUG("io_debug_size_bytes: %u\n",
+                         le32_to_cpu(mc_hdr->io_debug_size_bytes));
+               DRM_DEBUG("io_debug_array_offset_bytes: %u\n",
+                         le32_to_cpu(mc_hdr->io_debug_array_offset_bytes));
+       } else {
+               DRM_ERROR("Unknown MC ucode version: %u.%u\n", version_major, version_minor);
+       }
+}
+
+void radeon_ucode_print_smc_hdr(const struct common_firmware_header *hdr)
+{
+       uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+       uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+       DRM_DEBUG("SMC\n");
+       radeon_ucode_print_common_hdr(hdr);
+
+       if (version_major == 1) {
+               const struct smc_firmware_header_v1_0 *smc_hdr =
+                       container_of(hdr, struct smc_firmware_header_v1_0, header);
+
+               DRM_DEBUG("ucode_start_addr: %u\n", le32_to_cpu(smc_hdr->ucode_start_addr));
+       } else {
+               DRM_ERROR("Unknown SMC ucode version: %u.%u\n", version_major, version_minor);
+       }
+}
+
+void radeon_ucode_print_gfx_hdr(const struct common_firmware_header *hdr)
+{
+       uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+       uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+       DRM_DEBUG("GFX\n");
+       radeon_ucode_print_common_hdr(hdr);
+
+       if (version_major == 1) {
+               const struct gfx_firmware_header_v1_0 *gfx_hdr =
+                       container_of(hdr, struct gfx_firmware_header_v1_0, header);
+
+               DRM_DEBUG("ucode_feature_version: %u\n",
+                         le32_to_cpu(gfx_hdr->ucode_feature_version));
+               DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(gfx_hdr->jt_offset));
+               DRM_DEBUG("jt_size: %u\n", le32_to_cpu(gfx_hdr->jt_size));
+       } else {
+               DRM_ERROR("Unknown GFX ucode version: %u.%u\n", version_major, version_minor);
+       }
+}
+
+void radeon_ucode_print_rlc_hdr(const struct common_firmware_header *hdr)
+{
+       uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+       uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+       DRM_DEBUG("RLC\n");
+       radeon_ucode_print_common_hdr(hdr);
+
+       if (version_major == 1) {
+               const struct rlc_firmware_header_v1_0 *rlc_hdr =
+                       container_of(hdr, struct rlc_firmware_header_v1_0, header);
+
+               DRM_DEBUG("ucode_feature_version: %u\n",
+                         le32_to_cpu(rlc_hdr->ucode_feature_version));
+               DRM_DEBUG("save_and_restore_offset: %u\n",
+                         le32_to_cpu(rlc_hdr->save_and_restore_offset));
+               DRM_DEBUG("clear_state_descriptor_offset: %u\n",
+                         le32_to_cpu(rlc_hdr->clear_state_descriptor_offset));
+               DRM_DEBUG("avail_scratch_ram_locations: %u\n",
+                         le32_to_cpu(rlc_hdr->avail_scratch_ram_locations));
+               DRM_DEBUG("master_pkt_description_offset: %u\n",
+                         le32_to_cpu(rlc_hdr->master_pkt_description_offset));
+       } else {
+               DRM_ERROR("Unknown RLC ucode version: %u.%u\n", version_major, version_minor);
+       }
+}
+
+void radeon_ucode_print_sdma_hdr(const struct common_firmware_header *hdr)
+{
+       uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+       uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+       DRM_DEBUG("SDMA\n");
+       radeon_ucode_print_common_hdr(hdr);
+
+       if (version_major == 1) {
+               const struct sdma_firmware_header_v1_0 *sdma_hdr =
+                       container_of(hdr, struct sdma_firmware_header_v1_0, header);
+
+               DRM_DEBUG("ucode_feature_version: %u\n",
+                         le32_to_cpu(sdma_hdr->ucode_feature_version));
+               DRM_DEBUG("ucode_change_version: %u\n",
+                         le32_to_cpu(sdma_hdr->ucode_change_version));
+               DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(sdma_hdr->jt_offset));
+               DRM_DEBUG("jt_size: %u\n", le32_to_cpu(sdma_hdr->jt_size));
+       } else {
+               DRM_ERROR("Unknown SDMA ucode version: %u.%u\n",
+                         version_major, version_minor);
+       }
+}
+
+int radeon_ucode_validate(const struct firmware *fw)
+{
+       const struct common_firmware_header *hdr =
+               (const struct common_firmware_header *)fw->data;
+
+       if (fw->size == le32_to_cpu(hdr->size_bytes))
+               return 0;
+
+       return -EINVAL;
+}
+
index 4e7c3269b183644ea87c4879d764eac7fb246e80..dc4576e4d8ad161e7a4d59866ac4be9b244ec5c7 100644 (file)
 #define HAWAII_SMC_UCODE_START       0x20000
 #define HAWAII_SMC_UCODE_SIZE        0x1FDEC
 
+struct common_firmware_header {
+       uint32_t size_bytes; /* size of the entire header+image(s) in bytes */
+       uint32_t header_size_bytes; /* size of just the header in bytes */
+       uint16_t header_version_major; /* header version */
+       uint16_t header_version_minor; /* header version */
+       uint16_t ip_version_major; /* IP version */
+       uint16_t ip_version_minor; /* IP version */
+       uint32_t ucode_version;
+       uint32_t ucode_size_bytes; /* size of ucode in bytes */
+       uint32_t ucode_array_offset_bytes; /* payload offset from the start of the header */
+       uint32_t crc32;  /* crc32 checksum of the payload */
+};
+
+/* version_major=1, version_minor=0 */
+struct mc_firmware_header_v1_0 {
+       struct common_firmware_header header;
+       uint32_t io_debug_size_bytes; /* size of debug array in dwords */
+       uint32_t io_debug_array_offset_bytes; /* payload offset from the start of the header */
+};
+
+/* version_major=1, version_minor=0 */
+struct smc_firmware_header_v1_0 {
+       struct common_firmware_header header;
+       uint32_t ucode_start_addr;
+};
+
+/* version_major=1, version_minor=0 */
+struct gfx_firmware_header_v1_0 {
+       struct common_firmware_header header;
+       uint32_t ucode_feature_version;
+       uint32_t jt_offset; /* jt location */
+       uint32_t jt_size;  /* size of jt */
+};
+
+/* version_major=1, version_minor=0 */
+struct rlc_firmware_header_v1_0 {
+       struct common_firmware_header header;
+       uint32_t ucode_feature_version;
+       uint32_t save_and_restore_offset;
+       uint32_t clear_state_descriptor_offset;
+       uint32_t avail_scratch_ram_locations;
+       uint32_t master_pkt_description_offset;
+};
+
+/* version_major=1, version_minor=0 */
+struct sdma_firmware_header_v1_0 {
+       struct common_firmware_header header;
+       uint32_t ucode_feature_version;
+       uint32_t ucode_change_version;
+       uint32_t jt_offset; /* jt location */
+       uint32_t jt_size; /* size of jt */
+};
+
+/* header is fixed size */
+union radeon_firmware_header {
+       struct common_firmware_header common;
+       struct mc_firmware_header_v1_0 mc;
+       struct smc_firmware_header_v1_0 smc;
+       struct gfx_firmware_header_v1_0 gfx;
+       struct rlc_firmware_header_v1_0 rlc;
+       struct sdma_firmware_header_v1_0 sdma;
+       uint8_t raw[0x100];
+};
+
+void radeon_ucode_print_mc_hdr(const struct common_firmware_header *hdr);
+void radeon_ucode_print_smc_hdr(const struct common_firmware_header *hdr);
+void radeon_ucode_print_gfx_hdr(const struct common_firmware_header *hdr);
+void radeon_ucode_print_rlc_hdr(const struct common_firmware_header *hdr);
+void radeon_ucode_print_sdma_hdr(const struct common_firmware_header *hdr);
+int radeon_ucode_validate(const struct firmware *fw);
+
 #endif