]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm/amdgpu: psp HDCP init
authorBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Wed, 19 Jun 2019 18:37:29 +0000 (14:37 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 3 Oct 2019 14:10:58 +0000 (09:10 -0500)
This patch adds
-Loading the firmware
-The functions and definitions for communication with the firmware

v2: Fix formatting

Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
drivers/gpu/drm/amd/amdgpu/psp_v10_0.c

index 7d8998481246ca1c12697533d91f3042dbc9cc3d..678ffe2662f80c431f35bf2876599eadcc034e55 100644 (file)
@@ -767,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;
@@ -840,6 +1015,11 @@ static int psp_hw_start(struct psp_context *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;
@@ -1205,8 +1385,10 @@ static int psp_hw_fini(void *handle)
            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);
 
@@ -1248,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);
index bc0947f6bc8a929226e64303bfe8be6cd434be9a..6788e160194578bf40bf21e48dc5cf9119d2d447 100644 (file)
@@ -37,6 +37,8 @@
 #define PSP_RAS_SHARED_MEM_SIZE 0x4000
 #define PSP_1_MEG              0x100000
 #define PSP_TMR_SIZE   0x400000
+#define PSP_HDCP_SHARED_MEM_SIZE       0x4000
+#define PSP_SHARED_MEM_SIZE            0x4000
 
 struct psp_context;
 struct psp_xgmi_node_info;
@@ -142,6 +144,14 @@ struct psp_ras_context {
        struct amdgpu_ras       *ras;
 };
 
+struct psp_hdcp_context {
+       bool                    hdcp_initialized;
+       uint32_t                session_id;
+       struct amdgpu_bo        *hdcp_shared_bo;
+       uint64_t                hdcp_shared_mc_addr;
+       void                    *hdcp_shared_buf;
+};
+
 struct psp_context
 {
        struct amdgpu_device            *adev;
@@ -206,8 +216,14 @@ struct psp_context
        uint32_t                        ta_ras_ucode_version;
        uint32_t                        ta_ras_ucode_size;
        uint8_t                         *ta_ras_start_addr;
+
+       uint32_t                        ta_hdcp_ucode_version;
+       uint32_t                        ta_hdcp_ucode_size;
+       uint8_t                         *ta_hdcp_start_addr;
+
        struct psp_xgmi_context         xgmi_context;
        struct psp_ras_context          ras;
+       struct psp_hdcp_context         hdcp_context;
        struct mutex                    mutex;
 };
 
@@ -279,6 +295,7 @@ int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
 int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
 int psp_ras_enable_features(struct psp_context *psp,
                union ta_ras_cmd_input *info, bool enable);
+int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
 
 int psp_rlc_autoload_start(struct psp_context *psp);
 
index b34f00d420499d447ceb26464b687247edd891d6..c2b593ab749510f462cc54df42c88df97a73529e 100644 (file)
@@ -108,6 +108,9 @@ struct ta_firmware_header_v1_0 {
        uint32_t ta_ras_ucode_version;
        uint32_t ta_ras_offset_bytes;
        uint32_t ta_ras_size_bytes;
+       uint32_t ta_hdcp_ucode_version;
+       uint32_t ta_hdcp_offset_bytes;
+       uint32_t ta_hdcp_size_bytes;
 };
 
 /* version_major=1, version_minor=0 */
index 5d95e614369aaf3c3614a52f26c6ec8e94c1439b..85db478fb600ae34ada857a04124f505b90204be 100644 (file)
@@ -48,7 +48,7 @@ static int psp_v10_0_init_microcode(struct psp_context *psp)
        char fw_name[30];
        int err = 0;
        const struct psp_firmware_header_v1_0 *hdr;
-
+       const struct ta_firmware_header_v1_0 *ta_hdr;
        DRM_DEBUG("\n");
 
        switch (adev->asic_type) {
@@ -79,7 +79,38 @@ static int psp_v10_0_init_microcode(struct psp_context *psp)
        adev->psp.asd_start_addr = (uint8_t *)hdr +
                                le32_to_cpu(hdr->header.ucode_array_offset_bytes);
 
+       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) {
+               release_firmware(adev->psp.ta_fw);
+               adev->psp.ta_fw = NULL;
+               dev_info(adev->dev,
+                        "psp v10.0: Failed to load firmware \"%s\"\n",
+                        fw_name);
+       } else {
+               err = amdgpu_ucode_validate(adev->psp.ta_fw);
+               if (err)
+                       goto out2;
+
+               ta_hdr = (const struct ta_firmware_header_v1_0 *)
+                                adev->psp.ta_fw->data;
+               adev->psp.ta_hdcp_ucode_version =
+                       le32_to_cpu(ta_hdr->ta_hdcp_ucode_version);
+               adev->psp.ta_hdcp_ucode_size =
+                       le32_to_cpu(ta_hdr->ta_hdcp_size_bytes);
+               adev->psp.ta_hdcp_start_addr =
+                       (uint8_t *)ta_hdr +
+                       le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+
+               adev->psp.ta_fw_version =
+                       le32_to_cpu(ta_hdr->header.ucode_version);
+       }
+
        return 0;
+
+out2:
+       release_firmware(adev->psp.ta_fw);
+       adev->psp.ta_fw = NULL;
 out:
        if (err) {
                dev_err(adev->dev,