Support handling common TA binary for dGPUs and APUs

Signed-off-by: Mangesh Gadre <[email protected]>
Reviewed-by: Lijo Lazar <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c   | 85 ++++++++++++++++++++---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h | 16 +++++
 2 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 72ee66db182c..72796671dd2a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -3279,17 +3279,12 @@ int psp_init_sos_microcode(struct psp_context *psp, 
const char *chip_name)
 
 static int parse_ta_bin_descriptor(struct psp_context *psp,
                                   const struct psp_fw_bin_desc *desc,
-                                  const struct ta_firmware_header_v2_0 *ta_hdr)
+                                  uint8_t *ucode_start_addr)
 {
-       uint8_t *ucode_start_addr  = NULL;
 
-       if (!psp || !desc || !ta_hdr)
+       if (!psp || !desc || !ucode_start_addr)
                return -EINVAL;
 
-       ucode_start_addr  = (uint8_t *)ta_hdr +
-                           le32_to_cpu(desc->offset_bytes) +
-                           
le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
-
        switch (desc->fw_type) {
        case TA_FW_TYPE_PSP_ASD:
                psp->asd_context.bin_desc.fw_version        = 
le32_to_cpu(desc->fw_version);
@@ -3397,11 +3392,17 @@ static int parse_ta_v2_microcode(struct psp_context 
*psp)
 {
        const struct ta_firmware_header_v2_0 *ta_hdr;
        struct amdgpu_device *adev = psp->adev;
+       struct psp_fw_bin_desc *desc = NULL;
        int err = 0;
        int ta_index = 0;
+       uint8_t *ucode_array_start = NULL;
+       uint8_t *ucode_start_addr = NULL;
 
        ta_hdr = (const struct ta_firmware_header_v2_0 *)adev->psp.ta_fw->data;
 
+       ucode_array_start = (uint8_t *)ta_hdr +
+                          le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+
        if (le16_to_cpu(ta_hdr->header.header_version_major) != 2)
                return -EINVAL;
 
@@ -3411,9 +3412,13 @@ static int parse_ta_v2_microcode(struct psp_context *psp)
        }
 
        for (ta_index = 0; ta_index < le32_to_cpu(ta_hdr->ta_fw_bin_count); 
ta_index++) {
-               err = parse_ta_bin_descriptor(psp,
-                                             &ta_hdr->ta_fw_bin[ta_index],
-                                             ta_hdr);
+
+               desc = (struct psp_fw_bin_desc *)&ta_hdr->ta_fw_bin[ta_index];
+
+               ucode_start_addr  = ucode_array_start +
+                                       le32_to_cpu(desc->offset_bytes);
+
+               err = parse_ta_bin_descriptor(psp, desc, ucode_start_addr);
                if (err)
                        return err;
        }
@@ -3421,6 +3426,61 @@ static int parse_ta_v2_microcode(struct psp_context *psp)
        return 0;
 }
 
+#define FW_VALID_DGPU  0x00000002
+#define FW_VALID_APU   0x00000001
+
+static int parse_ta_v2_1_microcode(struct psp_context *psp)
+{
+       const struct ta_firmware_header_v2_1 *ta_hdr;
+       struct amdgpu_device *adev = psp->adev;
+       struct ta_fw_bin_desc_v1_1 *desc = NULL;
+       struct psp_fw_bin_desc psp_fw_bin_descriptor;
+       int err = 0;
+       int ta_index = 0;
+       uint8_t *ucode_array_start = NULL;
+       uint8_t *ucode_start_addr = NULL;
+
+       ta_hdr = (const struct ta_firmware_header_v2_1 *)adev->psp.ta_fw->data;
+
+       ucode_array_start = (uint8_t *)ta_hdr +
+                       le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+
+       if ((le16_to_cpu(ta_hdr->header.header_version_major) != 2) &&
+               (le16_to_cpu(ta_hdr->header.header_version_minor) != 1))
+               return -EINVAL;
+
+       if (le32_to_cpu(ta_hdr->ta_fw_bin_count) >= UCODE_MAX_PSP_PACKAGING) {
+               dev_err(adev->dev, "packed TA count exceeds maximum limit\n");
+               return -EINVAL;
+       }
+
+       for (ta_index = 0; ta_index < le32_to_cpu(ta_hdr->ta_fw_bin_count); 
ta_index++) {
+
+               desc = (struct ta_fw_bin_desc_v1_1 
*)&ta_hdr->ta_fw_bin[ta_index];
+
+               if (((adev->flags & AMD_IS_APU) &&
+                    (le32_to_cpu((desc->fw_valid_flags)) & FW_VALID_APU)) ||
+                    (!(adev->flags & AMD_IS_APU) &&
+                    (le32_to_cpu((desc->fw_valid_flags)) & FW_VALID_DGPU))) {
+
+                       ucode_start_addr = ucode_array_start +
+                                       le32_to_cpu(desc->offset_bytes);
+
+                       psp_fw_bin_descriptor.fw_type = desc->fw_type;
+                       psp_fw_bin_descriptor.fw_version = desc->fw_version;
+                       psp_fw_bin_descriptor.offset_bytes = desc->offset_bytes;
+                       psp_fw_bin_descriptor.size_bytes = desc->size_bytes;
+
+                       err = parse_ta_bin_descriptor(psp,
+                                                       &psp_fw_bin_descriptor,
+                                                       ucode_start_addr);
+                       if (err)
+                               return err;
+                       }
+       }
+       return 0;
+}
+
 int psp_init_ta_microcode(struct psp_context *psp, const char *chip_name)
 {
        const struct common_firmware_header *hdr;
@@ -3439,7 +3499,10 @@ int psp_init_ta_microcode(struct psp_context *psp, const 
char *chip_name)
                err = parse_ta_v1_microcode(psp);
                break;
        case 2:
-               err = parse_ta_v2_microcode(psp);
+               if (le16_to_cpu(hdr->header_version_minor) == 1)
+                       err = parse_ta_v2_1_microcode(psp);
+               else
+                       err = parse_ta_v2_microcode(psp);
                break;
        default:
                dev_err(adev->dev, "unsupported TA header version\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
index ae5fa61d2890..8c6094ee60c0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
@@ -157,6 +157,14 @@ enum ta_fw_type {
        TA_FW_TYPE_MAX_INDEX,
 };
 
+struct ta_fw_bin_desc_v1_1 {
+       uint32_t fw_type;
+       uint32_t fw_valid_flags;
+       uint32_t fw_version;
+       uint32_t offset_bytes;
+       uint32_t size_bytes;
+};
+
 /* version_major=2, version_minor=0 */
 struct ta_firmware_header_v2_0 {
        struct common_firmware_header header;
@@ -164,6 +172,13 @@ struct ta_firmware_header_v2_0 {
        struct psp_fw_bin_desc ta_fw_bin[];
 };
 
+/* version_major=2, version_minor=1 */
+struct ta_firmware_header_v2_1 {
+       struct common_firmware_header header;
+       uint32_t ta_fw_bin_count;
+       struct ta_fw_bin_desc_v1_1 ta_fw_bin[];
+};
+
 /* version_major=1, version_minor=0 */
 struct gfx_firmware_header_v1_0 {
        struct common_firmware_header header;
@@ -419,6 +434,7 @@ union amdgpu_firmware_header {
        struct psp_firmware_header_v2_0 psp_v2_0;
        struct ta_firmware_header_v1_0 ta;
        struct ta_firmware_header_v2_0 ta_v2_0;
+       struct ta_firmware_header_v2_1 ta_v2_1;
        struct gfx_firmware_header_v1_0 gfx;
        struct gfx_firmware_header_v2_0 gfx_v2_0;
        struct rlc_firmware_header_v1_0 rlc;
-- 
2.34.1

Reply via email to