[PATCH] drm/amdgpu:common ta binary handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux