DMCU (Display Microcontroller Unit) is a GPU chip involved in
eDP features like Adaptive Backlight Modulation and Panel Self
Refresh.

DMCU has two pieces of firmware: the ERAM and the interrupt
vectors, which must be loaded seperately.

To this end, the DMCU firmware has a custom header and parsing
logic similar to MEC, to extract the two ucodes from a single
struct firmware.

Signed-off-by: David Francis <david.fran...@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c | 21 +++++++++++++++++++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h | 10 ++++++++++
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
index a942fd28dae8..1fa8bc337859 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
@@ -322,6 +322,7 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device 
*adev,
 {
        const struct common_firmware_header *header = NULL;
        const struct gfx_firmware_header_v1_0 *cp_hdr = NULL;
+       const struct dmcu_firmware_header_v1_0 *dmcu_hdr = NULL;
 
        if (NULL == ucode->fw)
                return 0;
@@ -333,8 +334,8 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device 
*adev,
                return 0;
 
        header = (const struct common_firmware_header *)ucode->fw->data;
-
        cp_hdr = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
+       dmcu_hdr = (const struct dmcu_firmware_header_v1_0 *)ucode->fw->data;
 
        if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP ||
            (ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC1 &&
@@ -343,7 +344,9 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device 
*adev,
             ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC2_JT &&
             ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL &&
             ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM &&
-            ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM)) {
+            ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM &&
+                ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_ERAM &&
+                ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_INTV)) {
                ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes);
 
                memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
@@ -365,6 +368,20 @@ static int amdgpu_ucode_init_single_fw(struct 
amdgpu_device *adev,
                                              
le32_to_cpu(header->ucode_array_offset_bytes) +
                                              le32_to_cpu(cp_hdr->jt_offset) * 
4),
                       ucode->ucode_size);
+       } else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCU_ERAM) {
+               ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes) -
+                               le32_to_cpu(dmcu_hdr->intv_size_bytes);
+
+               memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
+                                             
le32_to_cpu(header->ucode_array_offset_bytes)),
+                      ucode->ucode_size);
+       } else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCU_INTV) {
+               ucode->ucode_size = le32_to_cpu(dmcu_hdr->intv_size_bytes);
+
+               memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
+                                             
le32_to_cpu(header->ucode_array_offset_bytes) +
+                                             
le32_to_cpu(dmcu_hdr->intv_offset_bytes)),
+                      ucode->ucode_size);
        } else if (ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL) {
                ucode->ucode_size = 
adev->gfx.rlc.save_restore_list_cntl_size_bytes;
                memcpy(ucode->kaddr, adev->gfx.rlc.save_restore_list_cntl,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
index b358e7519987..8f3f1117728c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
@@ -157,6 +157,13 @@ struct gpu_info_firmware_header_v1_0 {
        uint16_t version_minor; /* version */
 };
 
+/* version_major=1, version_minor=0 */
+struct dmcu_firmware_header_v1_0 {
+       struct common_firmware_header header;
+       uint32_t intv_offset_bytes; /* interrupt vectors offset from end of 
header, in bytes */
+       uint32_t intv_size_bytes;  /* size of interrupt vectors, in bytes */
+};
+
 /* header is fixed size */
 union amdgpu_firmware_header {
        struct common_firmware_header common;
@@ -170,6 +177,7 @@ union amdgpu_firmware_header {
        struct sdma_firmware_header_v1_0 sdma;
        struct sdma_firmware_header_v1_1 sdma_v1_1;
        struct gpu_info_firmware_header_v1_0 gpu_info;
+       struct dmcu_firmware_header_v1_0 dmcu;
        uint8_t raw[0x100];
 };
 
@@ -196,6 +204,8 @@ enum AMDGPU_UCODE_ID {
        AMDGPU_UCODE_ID_UVD1,
        AMDGPU_UCODE_ID_VCE,
        AMDGPU_UCODE_ID_VCN,
+       AMDGPU_UCODE_ID_DMCU_ERAM,
+       AMDGPU_UCODE_ID_DMCU_INTV,
        AMDGPU_UCODE_ID_MAXIMUM,
 };
 
-- 
2.17.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to