fw_info->ver = adev->psp.toc.fw_version;
                fw_info->feature = adev->psp.toc.feature_version;
                break;
+       case AMDGPU_INFO_FW_CAP:
+               fw_info->ver = adev->psp.cap_fw_version;
+               fw_info->feature = adev->psp.cap_feature_version;
+               break;
        default:
                return -EINVAL;
        }
        seq_printf(m, "TOC feature version: %u, firmware version: 0x%08x\n",
                   fw_info.feature, fw_info.ver);
 
+       /* CAP */
+       if (adev->psp.cap_fw) {
+               query_fw.fw_type = AMDGPU_INFO_FW_CAP;
+               ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
+               if (ret)
+                       return ret;
+               seq_printf(m, "CAP feature version: %u, firmware version: 0x%08x\n",
+                               fw_info.feature, fw_info.ver);
+       }
+
        seq_printf(m, "VBIOS version: %s\n", ctx->vbios_version);
 
        return 0;
 
        return ret;
 }
 
+static int psp_init_sriov_microcode(struct psp_context *psp)
+{
+       struct amdgpu_device *adev = psp->adev;
+       int ret = 0;
+
+       switch (adev->ip_versions[MP0_HWIP][0]) {
+       case IP_VERSION(9, 0, 0):
+               ret = psp_init_cap_microcode(psp, "vega10");
+               break;
+       case IP_VERSION(11, 0, 9):
+               ret = psp_init_cap_microcode(psp, "navi12");
+               break;
+       case IP_VERSION(11, 0, 7):
+               ret = psp_init_cap_microcode(psp, "sienna_cichlid");
+               break;
+       case IP_VERSION(13, 0, 2):
+               ret = psp_init_ta_microcode(psp, "aldebaran");
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       return ret;
+}
+
 static int psp_sw_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
                ret = -ENOMEM;
        }
 
-       if (!amdgpu_sriov_vf(adev)) {
+       if (amdgpu_sriov_vf(adev))
+               ret = psp_init_sriov_microcode(psp);
+       else
                ret = psp_init_microcode(psp);
-               if (ret) {
-                       DRM_ERROR("Failed to load psp firmware!\n");
-                       return ret;
-               }
-       } else if (amdgpu_sriov_vf(adev) &&
-                  adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 2)) {
-               ret = psp_init_ta_microcode(psp, "aldebaran");
-               if (ret) {
-                       DRM_ERROR("Failed to initialize ta microcode!\n");
-                       return ret;
-               }
+       if (ret) {
+               DRM_ERROR("Failed to load psp firmware!\n");
+               return ret;
        }
 
        memset(&boot_cfg_entry, 0, sizeof(boot_cfg_entry));
                release_firmware(psp->ta_fw);
                psp->ta_fw = NULL;
        }
+       if (adev->psp.cap_fw) {
+               release_firmware(psp->cap_fw);
+               psp->cap_fw = NULL;
+       }
 
        if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 0) ||
            adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 7))
                DRM_WARN("psp gfx command %s(0x%X) failed and response status is (0x%X)\n",
                         psp_gfx_cmd_name(psp->cmd_buf_mem->cmd_id), psp->cmd_buf_mem->cmd_id,
                         psp->cmd_buf_mem->resp.status);
-               if (!timeout) {
+               /* If we load CAP FW, PSP must return 0 under SRIOV
+                * also return failure in case of timeout
+                */
+               if ((ucode && (ucode->ucode_id == AMDGPU_UCODE_ID_CAP)) || !timeout) {
                        ret = -EINVAL;
                        goto exit;
                }
                           enum psp_gfx_fw_type *type)
 {
        switch (ucode->ucode_id) {
+       case AMDGPU_UCODE_ID_CAP:
+               *type = GFX_FW_TYPE_CAP;
+               break;
        case AMDGPU_UCODE_ID_SDMA0:
                *type = GFX_FW_TYPE_SDMA0;
                break;
        return err;
 }
 
+int psp_init_cap_microcode(struct psp_context *psp,
+                         const char *chip_name)
+{
+       struct amdgpu_device *adev = psp->adev;
+       char fw_name[PSP_FW_NAME_LEN];
+       const struct psp_firmware_header_v1_0 *cap_hdr_v1_0;
+       struct amdgpu_firmware_info *info = NULL;
+       int err = 0;
+
+       if (!chip_name) {
+               dev_err(adev->dev, "invalid chip name for cap microcode\n");
+               return -EINVAL;
+       }
+
+       if (!amdgpu_sriov_vf(adev)) {
+               dev_err(adev->dev, "cap microcode should only be loaded under SRIOV\n");
+               return -EINVAL;
+       }
+
+       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_cap.bin", chip_name);
+       err = request_firmware(&adev->psp.cap_fw, fw_name, adev->dev);
+       if (err) {
+               dev_warn(adev->dev, "cap microcode does not exist, skip\n");
+               err = 0;
+               goto out;
+       }
+
+       err = amdgpu_ucode_validate(adev->psp.cap_fw);
+       if (err) {
+               dev_err(adev->dev, "fail to initialize cap microcode\n");
+               goto out;
+       }
+
+       info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CAP];
+       info->ucode_id = AMDGPU_UCODE_ID_CAP;
+       info->fw = adev->psp.cap_fw;
+       cap_hdr_v1_0 = (const struct psp_firmware_header_v1_0 *)
+               adev->psp.cap_fw->data;
+       adev->firmware.fw_size += ALIGN(
+                       le32_to_cpu(cap_hdr_v1_0->header.ucode_size_bytes), PAGE_SIZE);
+       adev->psp.cap_fw_version = le32_to_cpu(cap_hdr_v1_0->header.ucode_version);
+       adev->psp.cap_feature_version = le32_to_cpu(cap_hdr_v1_0->sos.fw_version);
+       adev->psp.cap_ucode_size = le32_to_cpu(cap_hdr_v1_0->header.ucode_size_bytes);
+
+       return 0;
+
+out:
+       release_firmware(adev->psp.cap_fw);
+       adev->psp.cap_fw = NULL;
+       return err;
+}
+
 static int psp_set_clockgating_state(void *handle,
                                     enum amd_clockgating_state state)
 {
 
 MODULE_FIRMWARE("amdgpu/navi12_sos.bin");
 MODULE_FIRMWARE("amdgpu/navi12_asd.bin");
 MODULE_FIRMWARE("amdgpu/navi12_ta.bin");
+MODULE_FIRMWARE("amdgpu/navi12_cap.bin");
 MODULE_FIRMWARE("amdgpu/arcturus_sos.bin");
 MODULE_FIRMWARE("amdgpu/arcturus_asd.bin");
 MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
 MODULE_FIRMWARE("amdgpu/sienna_cichlid_sos.bin");
 MODULE_FIRMWARE("amdgpu/sienna_cichlid_ta.bin");
+MODULE_FIRMWARE("amdgpu/sienna_cichlid_cap.bin");
 MODULE_FIRMWARE("amdgpu/navy_flounder_sos.bin");
 MODULE_FIRMWARE("amdgpu/navy_flounder_ta.bin");
 MODULE_FIRMWARE("amdgpu/vangogh_asd.bin");
                err = psp_init_asd_microcode(psp, chip_name);
                if (err)
                        return err;
-               if (amdgpu_sriov_vf(adev))
-                       break;
                snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
                err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
                if (err) {