Support handling common TA binary for dGPUs and APUs Signed-off-by: Mangesh Gadre <Mangesh.Gadre@xxxxxxx> Reviewed-by: Lijo Lazar <lijo.lazar@xxxxxxx> --- 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