drm/amdgpu: load mc firware in driver for Polaris.
authorRex Zhu <Rex.Zhu@amd.com>
Tue, 21 Mar 2017 04:51:48 +0000 (12:51 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 30 Mar 2017 03:54:08 +0000 (23:54 -0400)
load mc ucode in driver if VBIOS not loaded
a full version of MC ucode,

Signed-off-by: Rex Zhu <Rex.Zhu@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: jimqu <Jim.Qu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c

index 5fcb64e..ead889a 100644 (file)
@@ -253,14 +253,14 @@ out:
 }
 
 /**
- * gmc_v8_0_mc_load_microcode - load MC ucode into the hw
+ * gmc_v8_0_tonga_mc_load_microcode - load tonga MC ucode into the hw
  *
  * @adev: amdgpu_device pointer
  *
  * Load the GDDR MC ucode into the hw (CIK).
  * Returns 0 on success, error on failure.
  */
-static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
+static int gmc_v8_0_tonga_mc_load_microcode(struct amdgpu_device *adev)
 {
        const struct mc_firmware_header_v1_0 *hdr;
        const __le32 *fw_data = NULL;
@@ -268,9 +268,6 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
        u32 running;
        int i, ucode_size, regs_size;
 
-       if (!adev->mc.fw)
-               return -EINVAL;
-
        /* Skip MC ucode loading on SR-IOV capable boards.
         * vbios does this for us in asic_init in that case.
         * Skip MC ucode loading on VF, because hypervisor will do that
@@ -279,6 +276,9 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
        if (amdgpu_sriov_bios(adev))
                return 0;
 
+       if (!adev->mc.fw)
+               return -EINVAL;
+
        hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data;
        amdgpu_ucode_print_mc_hdr(&hdr->header);
 
@@ -329,6 +329,76 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
        return 0;
 }
 
+static int gmc_v8_0_polaris_mc_load_microcode(struct amdgpu_device *adev)
+{
+       const struct mc_firmware_header_v1_0 *hdr;
+       const __le32 *fw_data = NULL;
+       const __le32 *io_mc_regs = NULL;
+       u32 data, vbios_version;
+       int i, ucode_size, regs_size;
+
+       /* Skip MC ucode loading on SR-IOV capable boards.
+        * vbios does this for us in asic_init in that case.
+        * Skip MC ucode loading on VF, because hypervisor will do that
+        * for this adaptor.
+        */
+       if (amdgpu_sriov_bios(adev))
+               return 0;
+
+       WREG32(mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
+       data = RREG32(mmMC_SEQ_IO_DEBUG_DATA);
+       vbios_version = data & 0xf;
+
+       if (vbios_version == 0)
+               return 0;
+
+       if (!adev->mc.fw)
+               return -EINVAL;
+
+       hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data;
+       amdgpu_ucode_print_mc_hdr(&hdr->header);
+
+       adev->mc.fw_version = le32_to_cpu(hdr->header.ucode_version);
+       regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2);
+       io_mc_regs = (const __le32 *)
+               (adev->mc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes));
+       ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
+       fw_data = (const __le32 *)
+               (adev->mc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+
+       data = RREG32(mmMC_SEQ_MISC0);
+       data &= ~(0x40);
+       WREG32(mmMC_SEQ_MISC0, data);
+
+       /* load mc io regs */
+       for (i = 0; i < regs_size; i++) {
+               WREG32(mmMC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(io_mc_regs++));
+               WREG32(mmMC_SEQ_IO_DEBUG_DATA, le32_to_cpup(io_mc_regs++));
+       }
+
+       WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008);
+       WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010);
+
+       /* load the MC ucode */
+       for (i = 0; i < ucode_size; i++)
+               WREG32(mmMC_SEQ_SUP_PGM, le32_to_cpup(fw_data++));
+
+       /* put the engine back into the active state */
+       WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008);
+       WREG32(mmMC_SEQ_SUP_CNTL, 0x00000004);
+       WREG32(mmMC_SEQ_SUP_CNTL, 0x00000001);
+
+       /* wait for training to complete */
+       for (i = 0; i < adev->usec_timeout; i++) {
+               data = RREG32(mmMC_SEQ_MISC0);
+               if (data & 0x80)
+                       break;
+               udelay(1);
+       }
+
+       return 0;
+}
+
 static void gmc_v8_0_vram_gtt_location(struct amdgpu_device *adev,
                                       struct amdgpu_mc *mc)
 {
@@ -1095,7 +1165,15 @@ static int gmc_v8_0_hw_init(void *handle)
        gmc_v8_0_mc_program(adev);
 
        if (adev->asic_type == CHIP_TONGA) {
-               r = gmc_v8_0_mc_load_microcode(adev);
+               r = gmc_v8_0_tonga_mc_load_microcode(adev);
+               if (r) {
+                       DRM_ERROR("Failed to load MC firmware!\n");
+                       return r;
+               }
+       } else if (adev->asic_type == CHIP_POLARIS11 ||
+                       adev->asic_type == CHIP_POLARIS10 ||
+                       adev->asic_type == CHIP_POLARIS12) {
+               r = gmc_v8_0_polaris_mc_load_microcode(adev);
                if (r) {
                        DRM_ERROR("Failed to load MC firmware!\n");
                        return r;