Commit ed19a9a2 authored by Bhawanpreet Lakha's avatar Bhawanpreet Lakha Committed by Alex Deucher
Browse files

drm/amdgpu: psp HDCP init



This patch adds
-Loading the firmware
-The functions and definitions for communication with the firmware

v2: Fix formatting

Signed-off-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Reviewed-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent bb2746ac
Loading
Loading
Loading
Loading
+188 −1
Original line number Diff line number Diff line
@@ -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);
+17 −0
Original line number Diff line number Diff line
@@ -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);

+3 −0
Original line number Diff line number Diff line
@@ -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 */
+32 −1
Original line number Diff line number Diff line
@@ -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,