diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 459 | 
1 files changed, 439 insertions, 20 deletions
| diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index a46090071034..e1b8d8daeafc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -34,6 +34,8 @@  #include "psp_v11_0.h"  #include "psp_v12_0.h" +#include "amdgpu_ras.h" +  static void psp_set_funcs(struct amdgpu_device *adev);  static int psp_early_init(void *handle) @@ -88,6 +90,17 @@ static int psp_sw_init(void *handle)  		return ret;  	} +	ret = psp_mem_training_init(psp); +	if (ret) { +		DRM_ERROR("Failed to initialize memory training!\n"); +		return ret; +	} +	ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT); +	if (ret) { +		DRM_ERROR("Failed to process memory training!\n"); +		return ret; +	} +  	return 0;  } @@ -95,6 +108,7 @@ static int psp_sw_fini(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	psp_mem_training_fini(&adev->psp);  	release_firmware(adev->psp.sos_fw);  	adev->psp.sos_fw = NULL;  	release_firmware(adev->psp.asd_fw); @@ -151,10 +165,19 @@ psp_cmd_submit_buf(struct psp_context *psp,  		return ret;  	} +	amdgpu_asic_invalidate_hdp(psp->adev, NULL);  	while (*((unsigned int *)psp->fence_buf) != index) {  		if (--timeout == 0)  			break; +		/* +		 * Shouldn't wait for timeout when err_event_athub occurs, +		 * because gpu reset thread triggered and lock resource should +		 * be released for psp resume sequence. +		 */ +		if (amdgpu_ras_intr_triggered()) +			break;  		msleep(1); +		amdgpu_asic_invalidate_hdp(psp->adev, NULL);  	}  	/* In some cases, psp response status is not 0 even there is no @@ -168,8 +191,9 @@ 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 (0x%X)\n", -			  psp->cmd_buf_mem->resp.status & GFX_CMD_STATUS_MASK); +		DRM_DEBUG_DRIVER("psp command (0x%X) failed and response status is (0x%X)\n", +			 psp->cmd_buf_mem->cmd_id, +			 psp->cmd_buf_mem->resp.status & GFX_CMD_STATUS_MASK);  		if (!timeout) {  			mutex_unlock(&psp->mutex);  			return -EINVAL; @@ -253,7 +277,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); @@ -287,15 +312,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;  } @@ -548,7 +567,9 @@ static int psp_xgmi_initialize(struct psp_context *psp)  	struct ta_xgmi_shared_memory *xgmi_cmd;  	int ret; -	if (!psp->adev->psp.ta_fw) +	if (!psp->adev->psp.ta_fw || +	    !psp->adev->psp.ta_xgmi_ucode_size || +	    !psp->adev->psp.ta_xgmi_start_addr)  		return -ENOENT;  	if (!psp->xgmi_context.initialized) { @@ -737,6 +758,12 @@ static int psp_ras_terminate(struct psp_context *psp)  {  	int ret; +	/* +	 * TODO: bypass the terminate in sriov for now +	 */ +	if (amdgpu_sriov_vf(psp->adev)) +		return 0; +  	if (!psp->ras.ras_initialized)  		return 0; @@ -758,6 +785,18 @@ static int psp_ras_initialize(struct psp_context *psp)  {  	int ret; +	/* +	 * TODO: bypass the initialize in sriov for now +	 */ +	if (amdgpu_sriov_vf(psp->adev)) +		return 0; + +	if (!psp->adev->psp.ta_ras_ucode_size || +	    !psp->adev->psp.ta_ras_start_addr) { +		dev_warn(psp->adev->dev, "RAS: ras ta ucode is not available\n"); +		return 0; +	} +  	if (!psp->ras.ras_initialized) {  		ret = psp_ras_init_shared_buf(psp);  		if (ret) @@ -772,6 +811,360 @@ 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; + +	/* +	 * TODO: bypass the initialize in sriov for now +	 */ +	if (amdgpu_sriov_vf(psp->adev)) +		return 0; + +	if (!psp->adev->psp.ta_hdcp_ucode_size || +	    !psp->adev->psp.ta_hdcp_start_addr) { +		dev_warn(psp->adev->dev, "HDCP: hdcp ta ucode is not available\n"); +		return 0; +	} + +	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; + +	/* +	 * TODO: bypass the terminate in sriov for now +	 */ +	if (amdgpu_sriov_vf(psp->adev)) +		return 0; + +	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 + +// DTM start +static void psp_prep_dtm_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd, +					 uint64_t dtm_ta_mc, +					 uint64_t dtm_mc_shared, +					 uint32_t dtm_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(dtm_ta_mc); +	cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(dtm_ta_mc); +	cmd->cmd.cmd_load_ta.app_len = dtm_ta_size; + +	cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(dtm_mc_shared); +	cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(dtm_mc_shared); +	cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size; +} + +static int psp_dtm_init_shared_buf(struct psp_context *psp) +{ +	int ret; + +	/* +	 * Allocate 16k memory aligned to 4k from Frame Buffer (local +	 * physical) for dtm ta <-> Driver +	 */ +	ret = amdgpu_bo_create_kernel(psp->adev, PSP_DTM_SHARED_MEM_SIZE, +				      PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, +				      &psp->dtm_context.dtm_shared_bo, +				      &psp->dtm_context.dtm_shared_mc_addr, +				      &psp->dtm_context.dtm_shared_buf); + +	return ret; +} + +static int psp_dtm_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_dtm_start_addr, psp->ta_dtm_ucode_size); + +	psp_prep_dtm_ta_load_cmd_buf(cmd, psp->fw_pri_mc_addr, +				     psp->dtm_context.dtm_shared_mc_addr, +				     psp->ta_dtm_ucode_size, +				     PSP_DTM_SHARED_MEM_SIZE); + +	ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + +	if (!ret) { +		psp->dtm_context.dtm_initialized = 1; +		psp->dtm_context.session_id = cmd->resp.session_id; +	} + +	kfree(cmd); + +	return ret; +} + +static int psp_dtm_initialize(struct psp_context *psp) +{ +	int ret; + +	/* +	 * TODO: bypass the initialize in sriov for now +	 */ +	if (amdgpu_sriov_vf(psp->adev)) +		return 0; + +	if (!psp->adev->psp.ta_dtm_ucode_size || +	    !psp->adev->psp.ta_dtm_start_addr) { +		dev_warn(psp->adev->dev, "DTM: dtm ta ucode is not available\n"); +		return 0; +	} + +	if (!psp->dtm_context.dtm_initialized) { +		ret = psp_dtm_init_shared_buf(psp); +		if (ret) +			return ret; +	} + +	ret = psp_dtm_load(psp); +	if (ret) +		return ret; + +	return 0; +} + +static void psp_prep_dtm_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd, +					   uint32_t ta_cmd_id, +					   uint32_t dtm_session_id) +{ +	cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD; +	cmd->cmd.cmd_invoke_cmd.session_id = dtm_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_dtm_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_dtm_ta_invoke_cmd_buf(cmd, ta_cmd_id, +				       psp->dtm_context.session_id); + +	ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + +	kfree(cmd); + +	return ret; +} + +static int psp_dtm_terminate(struct psp_context *psp) +{ +	int ret; + +	/* +	 * TODO: bypass the terminate in sriov for now +	 */ +	if (amdgpu_sriov_vf(psp->adev)) +		return 0; + +	if (!psp->dtm_context.dtm_initialized) +		return 0; + +	ret = psp_hdcp_unload(psp); +	if (ret) +		return ret; + +	psp->dtm_context.dtm_initialized = 0; + +	/* free hdcp shared memory */ +	amdgpu_bo_free_kernel(&psp->dtm_context.dtm_shared_bo, +			      &psp->dtm_context.dtm_shared_mc_addr, +			      &psp->dtm_context.dtm_shared_buf); + +	return 0; +} +// DTM end +  static int psp_hw_start(struct psp_context *psp)  {  	struct amdgpu_device *adev = psp->adev; @@ -845,6 +1238,16 @@ 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"); + +		ret = psp_dtm_initialize(psp); +		if (ret) +			dev_err(psp->adev->dev, +				"DTM: Failed to initialize DTM\n");  	}  	return 0; @@ -1064,7 +1467,10 @@ out:  		    || 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)) +                    || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_G +	            || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL +	            || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM +	            || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM))  			/*skip ucode loading in SRIOV VF */  			continue; @@ -1073,10 +1479,6 @@ out:  		     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); @@ -1085,7 +1487,8 @@ out:  			return ret;  		/* Start rlc autoload after psp recieved all the gfx firmware */ -		if (ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM) { +		if (psp->autoload_supported && ucode->ucode_id == (amdgpu_sriov_vf(adev) ? +		    AMDGPU_UCODE_ID_CP_MEC2 : AMDGPU_UCODE_ID_RLC_G)) {  			ret = psp_rlc_autoload(psp);  			if (ret) {  				DRM_ERROR("Failed to start rlc autoload\n"); @@ -1210,8 +1613,11 @@ 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_dtm_terminate(psp); +		psp_hdcp_terminate(psp); +	}  	psp_ring_destroy(psp, PSP_RING_TYPE__KM); @@ -1253,6 +1659,16 @@ 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_dtm_terminate(psp); +		if (ret) { +			DRM_ERROR("Failed to terminate dtm ta\n"); +			return ret; +		}  	}  	ret = psp_ring_stop(psp, PSP_RING_TYPE__KM); @@ -1272,6 +1688,12 @@ static int psp_resume(void *handle)  	DRM_INFO("PSP is resuming...\n"); +	ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME); +	if (ret) { +		DRM_ERROR("Failed to process memory training!\n"); +		return ret; +	} +  	mutex_lock(&adev->firmware.mutex);  	ret = psp_hw_start(psp); @@ -1311,9 +1733,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; | 
