]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drm/amdgpu: psp HDCP init
[linux.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_psp.c
index c027e5e7713ef821297d78127e035fff8e3732d8..678ffe2662f80c431f35bf2876599eadcc034e55 100644 (file)
@@ -32,6 +32,7 @@
 #include "psp_v3_1.h"
 #include "psp_v10_0.h"
 #include "psp_v11_0.h"
+#include "psp_v12_0.h"
 
 static void psp_set_funcs(struct amdgpu_device *adev);
 
@@ -53,13 +54,19 @@ static int psp_early_init(void *handle)
                psp->autoload_supported = false;
                break;
        case CHIP_VEGA20:
+       case CHIP_ARCTURUS:
                psp_v11_0_set_psp_funcs(psp);
                psp->autoload_supported = false;
                break;
        case CHIP_NAVI10:
+       case CHIP_NAVI14:
+       case CHIP_NAVI12:
                psp_v11_0_set_psp_funcs(psp);
                psp->autoload_supported = true;
                break;
+       case CHIP_RENOIR:
+               psp_v12_0_set_psp_funcs(psp);
+               break;
        default:
                return -EINVAL;
        }
@@ -137,8 +144,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
        memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp));
 
        index = atomic_inc_return(&psp->fence_value);
-       ret = psp_cmd_submit(psp, ucode, psp->cmd_buf_mc_addr,
-                            fence_mc_addr, index);
+       ret = psp_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index);
        if (ret) {
                atomic_dec(&psp->fence_value);
                mutex_unlock(&psp->mutex);
@@ -162,8 +168,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
                if (ucode)
                        DRM_WARN("failed to load ucode id (%d) ",
                                  ucode->ucode_id);
-               DRM_WARN("psp command failed and response status is (%d)\n",
-                         psp->cmd_buf_mem->resp.status);
+               DRM_WARN("psp command failed and response status is (0x%X)\n",
+                         psp->cmd_buf_mem->resp.status & GFX_CMD_STATUS_MASK);
                if (!timeout) {
                        mutex_unlock(&psp->mutex);
                        return -EINVAL;
@@ -233,6 +239,8 @@ static int psp_tmr_init(struct psp_context *psp)
 {
        int ret;
        int tmr_size;
+       void *tmr_buf;
+       void **pptr;
 
        /*
         * According to HW engineer, they prefer the TMR address be "naturally
@@ -245,7 +253,8 @@ static int psp_tmr_init(struct psp_context *psp)
 
        /* For ASICs support RLC autoload, psp will parse the toc
         * and calculate the total size of TMR needed */
-       if (psp->toc_start_addr &&
+       if (!amdgpu_sriov_vf(psp->adev) &&
+           psp->toc_start_addr &&
            psp->toc_bin_size &&
            psp->fw_pri_buf) {
                ret = psp_load_toc(psp, &tmr_size);
@@ -255,9 +264,10 @@ static int psp_tmr_init(struct psp_context *psp)
                }
        }
 
+       pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
        ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_SIZE,
                                      AMDGPU_GEM_DOMAIN_VRAM,
-                                     &psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
+                                     &psp->tmr_bo, &psp->tmr_mc_addr, pptr);
 
        return ret;
 }
@@ -278,15 +288,9 @@ static int psp_tmr_load(struct psp_context *psp)
 
        ret = psp_cmd_submit_buf(psp, NULL, cmd,
                                 psp->fence_buf_mc_addr);
-       if (ret)
-               goto failed;
 
        kfree(cmd);
 
-       return 0;
-
-failed:
-       kfree(cmd);
        return ret;
 }
 
@@ -763,6 +767,181 @@ static int psp_ras_initialize(struct psp_context *psp)
 }
 // ras end
 
+// HDCP start
+static void psp_prep_hdcp_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+                                         uint64_t hdcp_ta_mc,
+                                         uint64_t hdcp_mc_shared,
+                                         uint32_t hdcp_ta_size,
+                                         uint32_t shared_size)
+{
+       cmd->cmd_id = GFX_CMD_ID_LOAD_TA;
+       cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(hdcp_ta_mc);
+       cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(hdcp_ta_mc);
+       cmd->cmd.cmd_load_ta.app_len = hdcp_ta_size;
+
+       cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo =
+               lower_32_bits(hdcp_mc_shared);
+       cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi =
+               upper_32_bits(hdcp_mc_shared);
+       cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size;
+}
+
+static int psp_hdcp_init_shared_buf(struct psp_context *psp)
+{
+       int ret;
+
+       /*
+        * Allocate 16k memory aligned to 4k from Frame Buffer (local
+        * physical) for hdcp ta <-> Driver
+        */
+       ret = amdgpu_bo_create_kernel(psp->adev, PSP_HDCP_SHARED_MEM_SIZE,
+                                     PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+                                     &psp->hdcp_context.hdcp_shared_bo,
+                                     &psp->hdcp_context.hdcp_shared_mc_addr,
+                                     &psp->hdcp_context.hdcp_shared_buf);
+
+       return ret;
+}
+
+static int psp_hdcp_load(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the loading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       memset(psp->fw_pri_buf, 0, PSP_1_MEG);
+       memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
+              psp->ta_hdcp_ucode_size);
+
+       psp_prep_hdcp_ta_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
+                                     psp->hdcp_context.hdcp_shared_mc_addr,
+                                     psp->ta_hdcp_ucode_size,
+                                     PSP_HDCP_SHARED_MEM_SIZE);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
+
+       if (!ret) {
+               psp->hdcp_context.hdcp_initialized = 1;
+               psp->hdcp_context.session_id = cmd->resp.session_id;
+       }
+
+       kfree(cmd);
+
+       return ret;
+}
+static int psp_hdcp_initialize(struct psp_context *psp)
+{
+       int ret;
+
+       if (!psp->hdcp_context.hdcp_initialized) {
+               ret = psp_hdcp_init_shared_buf(psp);
+               if (ret)
+                       return ret;
+       }
+
+       ret = psp_hdcp_load(psp);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+static void psp_prep_hdcp_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+                                           uint32_t hdcp_session_id)
+{
+       cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA;
+       cmd->cmd.cmd_unload_ta.session_id = hdcp_session_id;
+}
+
+static int psp_hdcp_unload(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the unloading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       psp_prep_hdcp_ta_unload_cmd_buf(cmd, psp->hdcp_context.session_id);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static void psp_prep_hdcp_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+                                           uint32_t ta_cmd_id,
+                                           uint32_t hdcp_session_id)
+{
+       cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD;
+       cmd->cmd.cmd_invoke_cmd.session_id = hdcp_session_id;
+       cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id;
+       /* Note: cmd_invoke_cmd.buf is not used for now */
+}
+
+int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the loading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       psp_prep_hdcp_ta_invoke_cmd_buf(cmd, ta_cmd_id,
+                                       psp->hdcp_context.session_id);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static int psp_hdcp_terminate(struct psp_context *psp)
+{
+       int ret;
+
+       if (!psp->hdcp_context.hdcp_initialized)
+               return 0;
+
+       ret = psp_hdcp_unload(psp);
+       if (ret)
+               return ret;
+
+       psp->hdcp_context.hdcp_initialized = 0;
+
+       /* free hdcp shared memory */
+       amdgpu_bo_free_kernel(&psp->hdcp_context.hdcp_shared_bo,
+                             &psp->hdcp_context.hdcp_shared_mc_addr,
+                             &psp->hdcp_context.hdcp_shared_buf);
+
+       return 0;
+}
+// HDCP end
+
 static int psp_hw_start(struct psp_context *psp)
 {
        struct amdgpu_device *adev = psp->adev;
@@ -831,12 +1010,16 @@ static int psp_hw_start(struct psp_context *psp)
                                "XGMI: Failed to initialize XGMI session\n");
        }
 
-
        if (psp->adev->psp.ta_fw) {
                ret = psp_ras_initialize(psp);
                if (ret)
                        dev_err(psp->adev->dev,
                                        "RAS: Failed to initialize RAS\n");
+
+               ret = psp_hdcp_initialize(psp);
+               if (ret)
+                       dev_err(psp->adev->dev,
+                               "HDCP: Failed to initialize HDCP\n");
        }
 
        return 0;
@@ -852,6 +1035,24 @@ static int psp_get_fw_type(struct amdgpu_firmware_info *ucode,
        case AMDGPU_UCODE_ID_SDMA1:
                *type = GFX_FW_TYPE_SDMA1;
                break;
+       case AMDGPU_UCODE_ID_SDMA2:
+               *type = GFX_FW_TYPE_SDMA2;
+               break;
+       case AMDGPU_UCODE_ID_SDMA3:
+               *type = GFX_FW_TYPE_SDMA3;
+               break;
+       case AMDGPU_UCODE_ID_SDMA4:
+               *type = GFX_FW_TYPE_SDMA4;
+               break;
+       case AMDGPU_UCODE_ID_SDMA5:
+               *type = GFX_FW_TYPE_SDMA5;
+               break;
+       case AMDGPU_UCODE_ID_SDMA6:
+               *type = GFX_FW_TYPE_SDMA6;
+               break;
+       case AMDGPU_UCODE_ID_SDMA7:
+               *type = GFX_FW_TYPE_SDMA7;
+               break;
        case AMDGPU_UCODE_ID_CP_CE:
                *type = GFX_FW_TYPE_CP_CE;
                break;
@@ -920,6 +1121,54 @@ static int psp_get_fw_type(struct amdgpu_firmware_info *ucode,
        return 0;
 }
 
+static void psp_print_fw_hdr(struct psp_context *psp,
+                            struct amdgpu_firmware_info *ucode)
+{
+       struct amdgpu_device *adev = psp->adev;
+       struct common_firmware_header *hdr;
+
+       switch (ucode->ucode_id) {
+       case AMDGPU_UCODE_ID_SDMA0:
+       case AMDGPU_UCODE_ID_SDMA1:
+       case AMDGPU_UCODE_ID_SDMA2:
+       case AMDGPU_UCODE_ID_SDMA3:
+       case AMDGPU_UCODE_ID_SDMA4:
+       case AMDGPU_UCODE_ID_SDMA5:
+       case AMDGPU_UCODE_ID_SDMA6:
+       case AMDGPU_UCODE_ID_SDMA7:
+               hdr = (struct common_firmware_header *)
+                       adev->sdma.instance[ucode->ucode_id - AMDGPU_UCODE_ID_SDMA0].fw->data;
+               amdgpu_ucode_print_sdma_hdr(hdr);
+               break;
+       case AMDGPU_UCODE_ID_CP_CE:
+               hdr = (struct common_firmware_header *)adev->gfx.ce_fw->data;
+               amdgpu_ucode_print_gfx_hdr(hdr);
+               break;
+       case AMDGPU_UCODE_ID_CP_PFP:
+               hdr = (struct common_firmware_header *)adev->gfx.pfp_fw->data;
+               amdgpu_ucode_print_gfx_hdr(hdr);
+               break;
+       case AMDGPU_UCODE_ID_CP_ME:
+               hdr = (struct common_firmware_header *)adev->gfx.me_fw->data;
+               amdgpu_ucode_print_gfx_hdr(hdr);
+               break;
+       case AMDGPU_UCODE_ID_CP_MEC1:
+               hdr = (struct common_firmware_header *)adev->gfx.mec_fw->data;
+               amdgpu_ucode_print_gfx_hdr(hdr);
+               break;
+       case AMDGPU_UCODE_ID_RLC_G:
+               hdr = (struct common_firmware_header *)adev->gfx.rlc_fw->data;
+               amdgpu_ucode_print_rlc_hdr(hdr);
+               break;
+       case AMDGPU_UCODE_ID_SMC:
+               hdr = (struct common_firmware_header *)adev->pm.fw->data;
+               amdgpu_ucode_print_smc_hdr(hdr);
+               break;
+       default:
+               break;
+       }
+}
+
 static int psp_prep_load_ip_fw_cmd_buf(struct amdgpu_firmware_info *ucode,
                                       struct psp_gfx_cmd_resp *cmd)
 {
@@ -980,17 +1229,31 @@ static int psp_np_fw_load(struct psp_context *psp)
                if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC &&
                    (psp_smu_reload_quirk(psp) || psp->autoload_supported))
                        continue;
+
                if (amdgpu_sriov_vf(adev) &&
                   (ucode->ucode_id == AMDGPU_UCODE_ID_SDMA0
                    || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1
+                   || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2
+                   || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3
+                   || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA4
+                   || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA5
+                   || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA6
+                   || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA7
                    || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_G))
                        /*skip ucode loading in SRIOV VF */
                        continue;
+
                if (psp->autoload_supported &&
                    (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1_JT ||
                     ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT))
                        /* skip mec JT when autoload is enabled */
                        continue;
+               /* Renoir only needs to load mec jump table one time */
+               if (adev->asic_type == CHIP_RENOIR &&
+                   ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT)
+                       continue;
+
+               psp_print_fw_hdr(psp, ucode);
 
                ret = psp_execute_np_fw_load(psp, ucode);
                if (ret)
@@ -1115,17 +1378,22 @@ static int psp_hw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        struct psp_context *psp = &adev->psp;
+       void *tmr_buf;
+       void **pptr;
 
        if (adev->gmc.xgmi.num_physical_nodes > 1 &&
            psp->xgmi_context.initialized == 1)
                 psp_xgmi_terminate(psp);
 
-       if (psp->adev->psp.ta_fw)
+       if (psp->adev->psp.ta_fw) {
                psp_ras_terminate(psp);
+               psp_hdcp_terminate(psp);
+       }
 
        psp_ring_destroy(psp, PSP_RING_TYPE__KM);
 
-       amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
+       pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
+       amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, pptr);
        amdgpu_bo_free_kernel(&psp->fw_pri_bo,
                              &psp->fw_pri_mc_addr, &psp->fw_pri_buf);
        amdgpu_bo_free_kernel(&psp->fence_buf_bo,
@@ -1162,6 +1430,11 @@ static int psp_suspend(void *handle)
                        DRM_ERROR("Failed to terminate ras ta\n");
                        return ret;
                }
+               ret = psp_hdcp_terminate(psp);
+               if (ret) {
+                       DRM_ERROR("Failed to terminate hdcp ta\n");
+                       return ret;
+               }
        }
 
        ret = psp_ring_stop(psp, PSP_RING_TYPE__KM);
@@ -1220,9 +1493,6 @@ int psp_rlc_autoload_start(struct psp_context *psp)
        int ret;
        struct psp_gfx_cmd_resp *cmd;
 
-       if (amdgpu_sriov_vf(psp->adev))
-               return 0;
-
        cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
        if (!cmd)
                return -ENOMEM;
@@ -1329,3 +1599,12 @@ const struct amdgpu_ip_block_version psp_v11_0_ip_block =
        .rev = 0,
        .funcs = &psp_ip_funcs,
 };
+
+const struct amdgpu_ip_block_version psp_v12_0_ip_block =
+{
+       .type = AMD_IP_BLOCK_TYPE_PSP,
+       .major = 12,
+       .minor = 0,
+       .rev = 0,
+       .funcs = &psp_ip_funcs,
+};