10e5ca0d1SHuang Rui /* 20e5ca0d1SHuang Rui * Copyright 2016 Advanced Micro Devices, Inc. 30e5ca0d1SHuang Rui * 40e5ca0d1SHuang Rui * Permission is hereby granted, free of charge, to any person obtaining a 50e5ca0d1SHuang Rui * copy of this software and associated documentation files (the "Software"), 60e5ca0d1SHuang Rui * to deal in the Software without restriction, including without limitation 70e5ca0d1SHuang Rui * the rights to use, copy, modify, merge, publish, distribute, sublicense, 80e5ca0d1SHuang Rui * and/or sell copies of the Software, and to permit persons to whom the 90e5ca0d1SHuang Rui * Software is furnished to do so, subject to the following conditions: 100e5ca0d1SHuang Rui * 110e5ca0d1SHuang Rui * The above copyright notice and this permission notice shall be included in 120e5ca0d1SHuang Rui * all copies or substantial portions of the Software. 130e5ca0d1SHuang Rui * 140e5ca0d1SHuang Rui * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 150e5ca0d1SHuang Rui * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 160e5ca0d1SHuang Rui * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 170e5ca0d1SHuang Rui * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 180e5ca0d1SHuang Rui * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 190e5ca0d1SHuang Rui * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 200e5ca0d1SHuang Rui * OTHER DEALINGS IN THE SOFTWARE. 210e5ca0d1SHuang Rui * 220e5ca0d1SHuang Rui * Author: Huang Rui 230e5ca0d1SHuang Rui * 240e5ca0d1SHuang Rui */ 250e5ca0d1SHuang Rui 260e5ca0d1SHuang Rui #include <linux/firmware.h> 2757430471SAndrey Grodzovsky #include <linux/dma-mapping.h> 28fdf2f6c5SSam Ravnborg 290e5ca0d1SHuang Rui #include "amdgpu.h" 300e5ca0d1SHuang Rui #include "amdgpu_psp.h" 310e5ca0d1SHuang Rui #include "amdgpu_ucode.h" 320e5ca0d1SHuang Rui #include "soc15_common.h" 330e5ca0d1SHuang Rui #include "psp_v3_1.h" 34c1798b54SHuang Rui #include "psp_v10_0.h" 35654f761cSFeifei Xu #include "psp_v11_0.h" 366a7a0bdbSAaron Liu #include "psp_v12_0.h" 370e5ca0d1SHuang Rui 38bff77e86SLe Ma #include "amdgpu_ras.h" 39bff77e86SLe Ma 4057430471SAndrey Grodzovsky static int psp_sysfs_init(struct amdgpu_device *adev); 4157430471SAndrey Grodzovsky static void psp_sysfs_fini(struct amdgpu_device *adev); 4257430471SAndrey Grodzovsky 4340e611bdSJohn Clements static int psp_load_smu_fw(struct psp_context *psp); 4440e611bdSJohn Clements 45995da6ccSEvan Quan /* 46995da6ccSEvan Quan * Due to DF Cstate management centralized to PMFW, the firmware 47995da6ccSEvan Quan * loading sequence will be updated as below: 48995da6ccSEvan Quan * - Load KDB 49995da6ccSEvan Quan * - Load SYS_DRV 50995da6ccSEvan Quan * - Load tOS 51995da6ccSEvan Quan * - Load PMFW 52995da6ccSEvan Quan * - Setup TMR 53995da6ccSEvan Quan * - Load other non-psp fw 54995da6ccSEvan Quan * - Load ASD 55995da6ccSEvan Quan * - Load XGMI/RAS/HDCP/DTM TA if any 56995da6ccSEvan Quan * 57995da6ccSEvan Quan * This new sequence is required for 58995da6ccSEvan Quan * - Arcturus 59995da6ccSEvan Quan * - Navi12 and onwards 60995da6ccSEvan Quan */ 61995da6ccSEvan Quan static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp) 62995da6ccSEvan Quan { 63995da6ccSEvan Quan struct amdgpu_device *adev = psp->adev; 64995da6ccSEvan Quan 65995da6ccSEvan Quan psp->pmfw_centralized_cstate_management = false; 66995da6ccSEvan Quan 67995da6ccSEvan Quan if (amdgpu_sriov_vf(adev)) 68995da6ccSEvan Quan return; 69995da6ccSEvan Quan 70995da6ccSEvan Quan if (adev->flags & AMD_IS_APU) 71995da6ccSEvan Quan return; 72995da6ccSEvan Quan 73995da6ccSEvan Quan if ((adev->asic_type == CHIP_ARCTURUS) || 74995da6ccSEvan Quan (adev->asic_type >= CHIP_NAVI12)) 75995da6ccSEvan Quan psp->pmfw_centralized_cstate_management = true; 76995da6ccSEvan Quan } 77995da6ccSEvan Quan 780e5ca0d1SHuang Rui static int psp_early_init(void *handle) 790e5ca0d1SHuang Rui { 800e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 819d6fea57SAlex Deucher struct psp_context *psp = &adev->psp; 820e5ca0d1SHuang Rui 830e5ca0d1SHuang Rui switch (adev->asic_type) { 840e5ca0d1SHuang Rui case CHIP_VEGA10: 85ff13dc67SAlex Deucher case CHIP_VEGA12: 86e7f9ccb4SAlex Deucher psp_v3_1_set_psp_funcs(psp); 871d1f41cfSHawking Zhang psp->autoload_supported = false; 880e5ca0d1SHuang Rui break; 89c1798b54SHuang Rui case CHIP_RAVEN: 90e7f9ccb4SAlex Deucher psp_v10_0_set_psp_funcs(psp); 911d1f41cfSHawking Zhang psp->autoload_supported = false; 92c1798b54SHuang Rui break; 93654f761cSFeifei Xu case CHIP_VEGA20: 94f36d9ab9SJohn Clements case CHIP_ARCTURUS: 951d1f41cfSHawking Zhang psp_v11_0_set_psp_funcs(psp); 961d1f41cfSHawking Zhang psp->autoload_supported = false; 971d1f41cfSHawking Zhang break; 98bc290fe5STao Zhou case CHIP_NAVI10: 9982522b2dSXiaojie Yuan case CHIP_NAVI14: 100739cdbd6SXiaojie Yuan case CHIP_NAVI12: 101654f761cSFeifei Xu psp_v11_0_set_psp_funcs(psp); 1021d1f41cfSHawking Zhang psp->autoload_supported = true; 103654f761cSFeifei Xu break; 1046a7a0bdbSAaron Liu case CHIP_RENOIR: 1056a7a0bdbSAaron Liu psp_v12_0_set_psp_funcs(psp); 1066a7a0bdbSAaron Liu break; 1070e5ca0d1SHuang Rui default: 1080e5ca0d1SHuang Rui return -EINVAL; 1090e5ca0d1SHuang Rui } 1100e5ca0d1SHuang Rui 1110e5ca0d1SHuang Rui psp->adev = adev; 1120e5ca0d1SHuang Rui 113995da6ccSEvan Quan psp_check_pmfw_centralized_cstate_management(psp); 114995da6ccSEvan Quan 1159d6fea57SAlex Deucher return 0; 1169d6fea57SAlex Deucher } 1179d6fea57SAlex Deucher 1189d6fea57SAlex Deucher static int psp_sw_init(void *handle) 1199d6fea57SAlex Deucher { 1209d6fea57SAlex Deucher struct amdgpu_device *adev = (struct amdgpu_device *)handle; 1219d6fea57SAlex Deucher struct psp_context *psp = &adev->psp; 1229d6fea57SAlex Deucher int ret; 1239d6fea57SAlex Deucher 1240e5ca0d1SHuang Rui ret = psp_init_microcode(psp); 1250e5ca0d1SHuang Rui if (ret) { 1260e5ca0d1SHuang Rui DRM_ERROR("Failed to load psp firmware!\n"); 1270e5ca0d1SHuang Rui return ret; 1280e5ca0d1SHuang Rui } 1290e5ca0d1SHuang Rui 1300586a059STianci.Yin ret = psp_mem_training_init(psp); 1310586a059STianci.Yin if (ret) { 132d5e5c1bcSColin Ian King DRM_ERROR("Failed to initialize memory training!\n"); 1330586a059STianci.Yin return ret; 1340586a059STianci.Yin } 1350586a059STianci.Yin ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT); 1360586a059STianci.Yin if (ret) { 1370586a059STianci.Yin DRM_ERROR("Failed to process memory training!\n"); 1380586a059STianci.Yin return ret; 1390586a059STianci.Yin } 1400586a059STianci.Yin 14190f88cddSAndrey Grodzovsky if (adev->asic_type == CHIP_NAVI10) { 14290f88cddSAndrey Grodzovsky ret= psp_sysfs_init(adev); 14390f88cddSAndrey Grodzovsky if (ret) { 14490f88cddSAndrey Grodzovsky return ret; 14590f88cddSAndrey Grodzovsky } 14690f88cddSAndrey Grodzovsky } 14790f88cddSAndrey Grodzovsky 1480e5ca0d1SHuang Rui return 0; 1490e5ca0d1SHuang Rui } 1500e5ca0d1SHuang Rui 1510e5ca0d1SHuang Rui static int psp_sw_fini(void *handle) 1520e5ca0d1SHuang Rui { 153c833d8aaSMonk Liu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 154c833d8aaSMonk Liu 1550586a059STianci.Yin psp_mem_training_fini(&adev->psp); 156c833d8aaSMonk Liu release_firmware(adev->psp.sos_fw); 157c833d8aaSMonk Liu adev->psp.sos_fw = NULL; 158c833d8aaSMonk Liu release_firmware(adev->psp.asd_fw); 159c833d8aaSMonk Liu adev->psp.asd_fw = NULL; 1601d69511eSAlex Deucher if (adev->psp.ta_fw) { 16151e7177fSHawking Zhang release_firmware(adev->psp.ta_fw); 16251e7177fSHawking Zhang adev->psp.ta_fw = NULL; 1631d69511eSAlex Deucher } 16457430471SAndrey Grodzovsky 16557430471SAndrey Grodzovsky if (adev->asic_type == CHIP_NAVI10) 16657430471SAndrey Grodzovsky psp_sysfs_fini(adev); 16757430471SAndrey Grodzovsky 1680e5ca0d1SHuang Rui return 0; 1690e5ca0d1SHuang Rui } 1700e5ca0d1SHuang Rui 1710e5ca0d1SHuang Rui int psp_wait_for(struct psp_context *psp, uint32_t reg_index, 1720e5ca0d1SHuang Rui uint32_t reg_val, uint32_t mask, bool check_changed) 1730e5ca0d1SHuang Rui { 1740e5ca0d1SHuang Rui uint32_t val; 1750e5ca0d1SHuang Rui int i; 1760e5ca0d1SHuang Rui struct amdgpu_device *adev = psp->adev; 1770e5ca0d1SHuang Rui 1780e5ca0d1SHuang Rui for (i = 0; i < adev->usec_timeout; i++) { 1792890decfSZhang, Jerry val = RREG32(reg_index); 1800e5ca0d1SHuang Rui if (check_changed) { 1810e5ca0d1SHuang Rui if (val != reg_val) 1820e5ca0d1SHuang Rui return 0; 1830e5ca0d1SHuang Rui } else { 1840e5ca0d1SHuang Rui if ((val & mask) == reg_val) 1850e5ca0d1SHuang Rui return 0; 1860e5ca0d1SHuang Rui } 1870e5ca0d1SHuang Rui udelay(1); 1880e5ca0d1SHuang Rui } 1890e5ca0d1SHuang Rui 1900e5ca0d1SHuang Rui return -ETIME; 1910e5ca0d1SHuang Rui } 1920e5ca0d1SHuang Rui 1930e5ca0d1SHuang Rui static int 1940e5ca0d1SHuang Rui psp_cmd_submit_buf(struct psp_context *psp, 1950e5ca0d1SHuang Rui struct amdgpu_firmware_info *ucode, 1960b25cbf9SHawking Zhang struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr) 1970e5ca0d1SHuang Rui { 1980e5ca0d1SHuang Rui int ret; 1990b25cbf9SHawking Zhang int index; 200ea114213Sxinhui pan int timeout = 2000; 201c2c6f816SJohn Clements bool ras_intr = false; 202d73cd701SEmily Deng bool skip_unsupport = false; 2030e5ca0d1SHuang Rui 20432eaeae0SAlex Deucher mutex_lock(&psp->mutex); 20532eaeae0SAlex Deucher 206a1952da7SHuang Rui memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE); 2070e5ca0d1SHuang Rui 208a1952da7SHuang Rui memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp)); 2090e5ca0d1SHuang Rui 2100b25cbf9SHawking Zhang index = atomic_inc_return(&psp->fence_value); 2115bdd0b72SHawking Zhang ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index); 2120b25cbf9SHawking Zhang if (ret) { 2130b25cbf9SHawking Zhang atomic_dec(&psp->fence_value); 21432eaeae0SAlex Deucher mutex_unlock(&psp->mutex); 2150b25cbf9SHawking Zhang return ret; 216ca7f65c7Skbuild test robot } 2170e5ca0d1SHuang Rui 21801b40c98SAlex Deucher amdgpu_asic_invalidate_hdp(psp->adev, NULL); 219ea114213Sxinhui pan while (*((unsigned int *)psp->fence_buf) != index) { 220ea114213Sxinhui pan if (--timeout == 0) 2217a3d7bf6SEvan Quan break; 222bff77e86SLe Ma /* 223bff77e86SLe Ma * Shouldn't wait for timeout when err_event_athub occurs, 224bff77e86SLe Ma * because gpu reset thread triggered and lock resource should 225bff77e86SLe Ma * be released for psp resume sequence. 226bff77e86SLe Ma */ 227c2c6f816SJohn Clements ras_intr = amdgpu_ras_intr_triggered(); 228c2c6f816SJohn Clements if (ras_intr) 229bff77e86SLe Ma break; 2300b25cbf9SHawking Zhang msleep(1); 23101b40c98SAlex Deucher amdgpu_asic_invalidate_hdp(psp->adev, NULL); 232ea114213Sxinhui pan } 2330b25cbf9SHawking Zhang 234d73cd701SEmily Deng /* We allow TEE_ERROR_NOT_SUPPORTED for VMR command in SRIOV */ 235d73cd701SEmily Deng skip_unsupport = (psp->cmd_buf_mem->resp.status == 0xffff000a) && amdgpu_sriov_vf(psp->adev); 236d73cd701SEmily Deng 237466bcb75SAaron Liu /* In some cases, psp response status is not 0 even there is no 238466bcb75SAaron Liu * problem while the command is submitted. Some version of PSP FW 239466bcb75SAaron Liu * doesn't write 0 to that field. 240466bcb75SAaron Liu * So here we would like to only print a warning instead of an error 241466bcb75SAaron Liu * during psp initialization to avoid breaking hw_init and it doesn't 242466bcb75SAaron Liu * return -EINVAL. 243466bcb75SAaron Liu */ 244d73cd701SEmily Deng if (!skip_unsupport && (psp->cmd_buf_mem->resp.status || !timeout) && !ras_intr) { 24576223c54SXiangliang Yu if (ucode) 246466bcb75SAaron Liu DRM_WARN("failed to load ucode id (%d) ", 24776223c54SXiangliang Yu ucode->ucode_id); 248e6e193c0SJohn Clements DRM_WARN("psp command (0x%X) failed and response status is (0x%X)\n", 2491f01cd99SHawking Zhang psp->cmd_buf_mem->cmd_id, 250e6e193c0SJohn Clements psp->cmd_buf_mem->resp.status); 251728b3d05SZhigang Luo if (!timeout) { 25232eaeae0SAlex Deucher mutex_unlock(&psp->mutex); 2537a3d7bf6SEvan Quan return -EINVAL; 25428a16027SHuang Rui } 25532eaeae0SAlex Deucher } 25628a16027SHuang Rui 257a363553cSXiangliang Yu /* get xGMI session id from response buffer */ 258a363553cSXiangliang Yu cmd->resp.session_id = psp->cmd_buf_mem->resp.session_id; 259a363553cSXiangliang Yu 260435198f3SJames Zhu if (ucode) { 261435198f3SJames Zhu ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo; 262435198f3SJames Zhu ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi; 263435198f3SJames Zhu } 26432eaeae0SAlex Deucher mutex_unlock(&psp->mutex); 265435198f3SJames Zhu 2660e5ca0d1SHuang Rui return ret; 2670e5ca0d1SHuang Rui } 2680e5ca0d1SHuang Rui 2695ec996dfSXiangliang Yu static void psp_prep_tmr_cmd_buf(struct psp_context *psp, 2705ec996dfSXiangliang Yu struct psp_gfx_cmd_resp *cmd, 2710e5ca0d1SHuang Rui uint64_t tmr_mc, uint32_t size) 2720e5ca0d1SHuang Rui { 273a2676149SHawking Zhang if (amdgpu_sriov_vf(psp->adev)) 2745ec996dfSXiangliang Yu cmd->cmd_id = GFX_CMD_ID_SETUP_VMR; 2755ec996dfSXiangliang Yu else 2760e5ca0d1SHuang Rui cmd->cmd_id = GFX_CMD_ID_SETUP_TMR; 277f03defe0SAlex Deucher cmd->cmd.cmd_setup_tmr.buf_phy_addr_lo = lower_32_bits(tmr_mc); 278f03defe0SAlex Deucher cmd->cmd.cmd_setup_tmr.buf_phy_addr_hi = upper_32_bits(tmr_mc); 2790e5ca0d1SHuang Rui cmd->cmd.cmd_setup_tmr.buf_size = size; 2800e5ca0d1SHuang Rui } 2810e5ca0d1SHuang Rui 2827ea49e76SHawking Zhang static void psp_prep_load_toc_cmd_buf(struct psp_gfx_cmd_resp *cmd, 2837ea49e76SHawking Zhang uint64_t pri_buf_mc, uint32_t size) 2847ea49e76SHawking Zhang { 2857ea49e76SHawking Zhang cmd->cmd_id = GFX_CMD_ID_LOAD_TOC; 2867ea49e76SHawking Zhang cmd->cmd.cmd_load_toc.toc_phy_addr_lo = lower_32_bits(pri_buf_mc); 2877ea49e76SHawking Zhang cmd->cmd.cmd_load_toc.toc_phy_addr_hi = upper_32_bits(pri_buf_mc); 2887ea49e76SHawking Zhang cmd->cmd.cmd_load_toc.toc_size = size; 2897ea49e76SHawking Zhang } 2907ea49e76SHawking Zhang 2917ea49e76SHawking Zhang /* Issue LOAD TOC cmd to PSP to part toc and calculate tmr size needed */ 2927ea49e76SHawking Zhang static int psp_load_toc(struct psp_context *psp, 2937ea49e76SHawking Zhang uint32_t *tmr_size) 2947ea49e76SHawking Zhang { 2957ea49e76SHawking Zhang int ret; 2967ea49e76SHawking Zhang struct psp_gfx_cmd_resp *cmd; 2977ea49e76SHawking Zhang 2987ea49e76SHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 2997ea49e76SHawking Zhang if (!cmd) 3007ea49e76SHawking Zhang return -ENOMEM; 3017ea49e76SHawking Zhang /* Copy toc to psp firmware private buffer */ 3027ea49e76SHawking Zhang memset(psp->fw_pri_buf, 0, PSP_1_MEG); 3037ea49e76SHawking Zhang memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size); 3047ea49e76SHawking Zhang 3057ea49e76SHawking Zhang psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size); 3067ea49e76SHawking Zhang 3077ea49e76SHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 3087ea49e76SHawking Zhang psp->fence_buf_mc_addr); 3097ea49e76SHawking Zhang if (!ret) 3107ea49e76SHawking Zhang *tmr_size = psp->cmd_buf_mem->resp.tmr_size; 3117ea49e76SHawking Zhang kfree(cmd); 3127ea49e76SHawking Zhang return ret; 3137ea49e76SHawking Zhang } 3147ea49e76SHawking Zhang 3150e5ca0d1SHuang Rui /* Set up Trusted Memory Region */ 3160e5ca0d1SHuang Rui static int psp_tmr_init(struct psp_context *psp) 3170e5ca0d1SHuang Rui { 3180e5ca0d1SHuang Rui int ret; 3197ea49e76SHawking Zhang int tmr_size; 32012842d02STianci.Yin void *tmr_buf; 32112842d02STianci.Yin void **pptr; 3220e5ca0d1SHuang Rui 3230e5ca0d1SHuang Rui /* 324795c1b8dSshaoyunl * According to HW engineer, they prefer the TMR address be "naturally 325795c1b8dSshaoyunl * aligned" , e.g. the start address be an integer divide of TMR size. 3260e5ca0d1SHuang Rui * 3270e5ca0d1SHuang Rui * Note: this memory need be reserved till the driver 3280e5ca0d1SHuang Rui * uninitializes. 3290e5ca0d1SHuang Rui */ 3307ea49e76SHawking Zhang tmr_size = PSP_TMR_SIZE; 3317ea49e76SHawking Zhang 3327ea49e76SHawking Zhang /* For ASICs support RLC autoload, psp will parse the toc 3337ea49e76SHawking Zhang * and calculate the total size of TMR needed */ 3341b657824SJiange Zhao if (!amdgpu_sriov_vf(psp->adev) && 3351b657824SJiange Zhao psp->toc_start_addr && 3367ea49e76SHawking Zhang psp->toc_bin_size && 3377ea49e76SHawking Zhang psp->fw_pri_buf) { 3387ea49e76SHawking Zhang ret = psp_load_toc(psp, &tmr_size); 3397ea49e76SHawking Zhang if (ret) { 3407ea49e76SHawking Zhang DRM_ERROR("Failed to load toc\n"); 3417ea49e76SHawking Zhang return ret; 3427ea49e76SHawking Zhang } 3437ea49e76SHawking Zhang } 3447ea49e76SHawking Zhang 34512842d02STianci.Yin pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; 3467ea49e76SHawking Zhang ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_SIZE, 3470e5ca0d1SHuang Rui AMDGPU_GEM_DOMAIN_VRAM, 34812842d02STianci.Yin &psp->tmr_bo, &psp->tmr_mc_addr, pptr); 3496f2b1fccSHuang Rui 3506f2b1fccSHuang Rui return ret; 3516f2b1fccSHuang Rui } 3526f2b1fccSHuang Rui 3536f2b1fccSHuang Rui static int psp_tmr_load(struct psp_context *psp) 3546f2b1fccSHuang Rui { 3556f2b1fccSHuang Rui int ret; 3566f2b1fccSHuang Rui struct psp_gfx_cmd_resp *cmd; 3576f2b1fccSHuang Rui 3586f2b1fccSHuang Rui cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 3596f2b1fccSHuang Rui if (!cmd) 3606f2b1fccSHuang Rui return -ENOMEM; 3610e5ca0d1SHuang Rui 3627ea49e76SHawking Zhang psp_prep_tmr_cmd_buf(psp, cmd, psp->tmr_mc_addr, 3637ea49e76SHawking Zhang amdgpu_bo_size(psp->tmr_bo)); 3647ea49e76SHawking Zhang DRM_INFO("reserve 0x%lx from 0x%llx for PSP TMR\n", 3657ea49e76SHawking Zhang amdgpu_bo_size(psp->tmr_bo), psp->tmr_mc_addr); 3660e5ca0d1SHuang Rui 3670e5ca0d1SHuang Rui ret = psp_cmd_submit_buf(psp, NULL, cmd, 3680b25cbf9SHawking Zhang psp->fence_buf_mc_addr); 3690e5ca0d1SHuang Rui 3700e5ca0d1SHuang Rui kfree(cmd); 3710e5ca0d1SHuang Rui 3720e5ca0d1SHuang Rui return ret; 3730e5ca0d1SHuang Rui } 3740e5ca0d1SHuang Rui 375c64ab828SHawking Zhang static void psp_prep_asd_load_cmd_buf(struct psp_gfx_cmd_resp *cmd, 376c64ab828SHawking Zhang uint64_t asd_mc, uint32_t size) 3770e5ca0d1SHuang Rui { 3780e5ca0d1SHuang Rui cmd->cmd_id = GFX_CMD_ID_LOAD_ASD; 3790e5ca0d1SHuang Rui cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(asd_mc); 3800e5ca0d1SHuang Rui cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(asd_mc); 3810e5ca0d1SHuang Rui cmd->cmd.cmd_load_ta.app_len = size; 3820e5ca0d1SHuang Rui 383c64ab828SHawking Zhang cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = 0; 384c64ab828SHawking Zhang cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = 0; 385c64ab828SHawking Zhang cmd->cmd.cmd_load_ta.cmd_buf_len = 0; 3860e5ca0d1SHuang Rui } 3870e5ca0d1SHuang Rui 3880e5ca0d1SHuang Rui static int psp_asd_load(struct psp_context *psp) 3890e5ca0d1SHuang Rui { 3900e5ca0d1SHuang Rui int ret; 3910e5ca0d1SHuang Rui struct psp_gfx_cmd_resp *cmd; 3920e5ca0d1SHuang Rui 393943cafb8SXiangliang Yu /* If PSP version doesn't match ASD version, asd loading will be failed. 394943cafb8SXiangliang Yu * add workaround to bypass it for sriov now. 395943cafb8SXiangliang Yu * TODO: add version check to make it common 396943cafb8SXiangliang Yu */ 397943cafb8SXiangliang Yu if (amdgpu_sriov_vf(psp->adev)) 398943cafb8SXiangliang Yu return 0; 399943cafb8SXiangliang Yu 4000e5ca0d1SHuang Rui cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 4010e5ca0d1SHuang Rui if (!cmd) 4020e5ca0d1SHuang Rui return -ENOMEM; 4030e5ca0d1SHuang Rui 4042b0c3aeeSHuang Rui memset(psp->fw_pri_buf, 0, PSP_1_MEG); 4052b0c3aeeSHuang Rui memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size); 4060e5ca0d1SHuang Rui 407c64ab828SHawking Zhang psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr, 408c64ab828SHawking Zhang psp->asd_ucode_size); 4090e5ca0d1SHuang Rui 4100e5ca0d1SHuang Rui ret = psp_cmd_submit_buf(psp, NULL, cmd, 4110b25cbf9SHawking Zhang psp->fence_buf_mc_addr); 412c64ab828SHawking Zhang if (!ret) { 413c64ab828SHawking Zhang psp->asd_context.asd_initialized = true; 414c64ab828SHawking Zhang psp->asd_context.session_id = cmd->resp.session_id; 415c64ab828SHawking Zhang } 4160e5ca0d1SHuang Rui 4170e5ca0d1SHuang Rui kfree(cmd); 4180e5ca0d1SHuang Rui 4190e5ca0d1SHuang Rui return ret; 4200e5ca0d1SHuang Rui } 4210e5ca0d1SHuang Rui 4221f455f25SJohn Clements static void psp_prep_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd, 4231f455f25SJohn Clements uint32_t session_id) 42471e5f0cbSHawking Zhang { 42571e5f0cbSHawking Zhang cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA; 4261f455f25SJohn Clements cmd->cmd.cmd_unload_ta.session_id = session_id; 42771e5f0cbSHawking Zhang } 42871e5f0cbSHawking Zhang 42971e5f0cbSHawking Zhang static int psp_asd_unload(struct psp_context *psp) 43071e5f0cbSHawking Zhang { 43171e5f0cbSHawking Zhang int ret; 43271e5f0cbSHawking Zhang struct psp_gfx_cmd_resp *cmd; 43371e5f0cbSHawking Zhang 43471e5f0cbSHawking Zhang if (amdgpu_sriov_vf(psp->adev)) 43571e5f0cbSHawking Zhang return 0; 43671e5f0cbSHawking Zhang 43771e5f0cbSHawking Zhang if (!psp->asd_context.asd_initialized) 43871e5f0cbSHawking Zhang return 0; 43971e5f0cbSHawking Zhang 44071e5f0cbSHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 44171e5f0cbSHawking Zhang if (!cmd) 44271e5f0cbSHawking Zhang return -ENOMEM; 44371e5f0cbSHawking Zhang 4441f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->asd_context.session_id); 44571e5f0cbSHawking Zhang 44671e5f0cbSHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 44771e5f0cbSHawking Zhang psp->fence_buf_mc_addr); 44871e5f0cbSHawking Zhang if (!ret) 44971e5f0cbSHawking Zhang psp->asd_context.asd_initialized = false; 45071e5f0cbSHawking Zhang 45171e5f0cbSHawking Zhang kfree(cmd); 45271e5f0cbSHawking Zhang 45371e5f0cbSHawking Zhang return ret; 45471e5f0cbSHawking Zhang } 45571e5f0cbSHawking Zhang 456c5d19419STrigger Huang static void psp_prep_reg_prog_cmd_buf(struct psp_gfx_cmd_resp *cmd, 457c5d19419STrigger Huang uint32_t id, uint32_t value) 458c5d19419STrigger Huang { 459c5d19419STrigger Huang cmd->cmd_id = GFX_CMD_ID_PROG_REG; 460c5d19419STrigger Huang cmd->cmd.cmd_setup_reg_prog.reg_value = value; 461c5d19419STrigger Huang cmd->cmd.cmd_setup_reg_prog.reg_id = id; 462c5d19419STrigger Huang } 463c5d19419STrigger Huang 464c5d19419STrigger Huang int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg, 465c5d19419STrigger Huang uint32_t value) 466c5d19419STrigger Huang { 467c5d19419STrigger Huang struct psp_gfx_cmd_resp *cmd = NULL; 468c5d19419STrigger Huang int ret = 0; 469c5d19419STrigger Huang 470c5d19419STrigger Huang if (reg >= PSP_REG_LAST) 471c5d19419STrigger Huang return -EINVAL; 472c5d19419STrigger Huang 473c5d19419STrigger Huang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 474c5d19419STrigger Huang if (!cmd) 475c5d19419STrigger Huang return -ENOMEM; 476c5d19419STrigger Huang 477c5d19419STrigger Huang psp_prep_reg_prog_cmd_buf(cmd, reg, value); 478c5d19419STrigger Huang ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 479c5d19419STrigger Huang 480c5d19419STrigger Huang kfree(cmd); 481c5d19419STrigger Huang return ret; 482c5d19419STrigger Huang } 483c5d19419STrigger Huang 4841f455f25SJohn Clements static void psp_prep_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd, 4851f455f25SJohn Clements uint64_t ta_bin_mc, 4861f455f25SJohn Clements uint32_t ta_bin_size, 4871f455f25SJohn Clements uint64_t ta_shared_mc, 4881f455f25SJohn Clements uint32_t ta_shared_size) 48997c8d171SHawking Zhang { 49097c8d171SHawking Zhang cmd->cmd_id = GFX_CMD_ID_LOAD_TA; 4911f455f25SJohn Clements cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(ta_bin_mc); 4921f455f25SJohn Clements cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(ta_bin_mc); 4931f455f25SJohn Clements cmd->cmd.cmd_load_ta.app_len = ta_bin_size; 49497c8d171SHawking Zhang 4951f455f25SJohn Clements cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(ta_shared_mc); 4961f455f25SJohn Clements cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(ta_shared_mc); 4971f455f25SJohn Clements cmd->cmd.cmd_load_ta.cmd_buf_len = ta_shared_size; 49897c8d171SHawking Zhang } 49997c8d171SHawking Zhang 50097c8d171SHawking Zhang static int psp_xgmi_init_shared_buf(struct psp_context *psp) 50197c8d171SHawking Zhang { 50297c8d171SHawking Zhang int ret; 50397c8d171SHawking Zhang 50497c8d171SHawking Zhang /* 50597c8d171SHawking Zhang * Allocate 16k memory aligned to 4k from Frame Buffer (local 50697c8d171SHawking Zhang * physical) for xgmi ta <-> Driver 50797c8d171SHawking Zhang */ 50897c8d171SHawking Zhang ret = amdgpu_bo_create_kernel(psp->adev, PSP_XGMI_SHARED_MEM_SIZE, 50997c8d171SHawking Zhang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 51097c8d171SHawking Zhang &psp->xgmi_context.xgmi_shared_bo, 51197c8d171SHawking Zhang &psp->xgmi_context.xgmi_shared_mc_addr, 51297c8d171SHawking Zhang &psp->xgmi_context.xgmi_shared_buf); 51397c8d171SHawking Zhang 51497c8d171SHawking Zhang return ret; 51597c8d171SHawking Zhang } 51697c8d171SHawking Zhang 51734e48caeSJohn Clements static void psp_prep_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd, 51834e48caeSJohn Clements uint32_t ta_cmd_id, 51934e48caeSJohn Clements uint32_t session_id) 52034e48caeSJohn Clements { 52134e48caeSJohn Clements cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD; 52234e48caeSJohn Clements cmd->cmd.cmd_invoke_cmd.session_id = session_id; 52334e48caeSJohn Clements cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id; 52434e48caeSJohn Clements } 52534e48caeSJohn Clements 52634e48caeSJohn Clements int psp_ta_invoke(struct psp_context *psp, 52734e48caeSJohn Clements uint32_t ta_cmd_id, 52834e48caeSJohn Clements uint32_t session_id) 52934e48caeSJohn Clements { 53034e48caeSJohn Clements int ret; 53134e48caeSJohn Clements struct psp_gfx_cmd_resp *cmd; 53234e48caeSJohn Clements 53334e48caeSJohn Clements cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 53434e48caeSJohn Clements if (!cmd) 53534e48caeSJohn Clements return -ENOMEM; 53634e48caeSJohn Clements 53734e48caeSJohn Clements psp_prep_ta_invoke_cmd_buf(cmd, ta_cmd_id, session_id); 53834e48caeSJohn Clements 53934e48caeSJohn Clements ret = psp_cmd_submit_buf(psp, NULL, cmd, 54034e48caeSJohn Clements psp->fence_buf_mc_addr); 54134e48caeSJohn Clements 54234e48caeSJohn Clements kfree(cmd); 54334e48caeSJohn Clements 54434e48caeSJohn Clements return ret; 54534e48caeSJohn Clements } 54634e48caeSJohn Clements 54797c8d171SHawking Zhang static int psp_xgmi_load(struct psp_context *psp) 54897c8d171SHawking Zhang { 54997c8d171SHawking Zhang int ret; 55097c8d171SHawking Zhang struct psp_gfx_cmd_resp *cmd; 55197c8d171SHawking Zhang 55297c8d171SHawking Zhang /* 55397c8d171SHawking Zhang * TODO: bypass the loading in sriov for now 55497c8d171SHawking Zhang */ 55597c8d171SHawking Zhang 55697c8d171SHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 55797c8d171SHawking Zhang if (!cmd) 55897c8d171SHawking Zhang return -ENOMEM; 55997c8d171SHawking Zhang 56097c8d171SHawking Zhang memset(psp->fw_pri_buf, 0, PSP_1_MEG); 56197c8d171SHawking Zhang memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size); 56297c8d171SHawking Zhang 5631f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 5641f455f25SJohn Clements psp->fw_pri_mc_addr, 5651f455f25SJohn Clements psp->ta_xgmi_ucode_size, 56697c8d171SHawking Zhang psp->xgmi_context.xgmi_shared_mc_addr, 5671f455f25SJohn Clements PSP_XGMI_SHARED_MEM_SIZE); 56897c8d171SHawking Zhang 56997c8d171SHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 57097c8d171SHawking Zhang psp->fence_buf_mc_addr); 57197c8d171SHawking Zhang 57297c8d171SHawking Zhang if (!ret) { 57397c8d171SHawking Zhang psp->xgmi_context.initialized = 1; 57497c8d171SHawking Zhang psp->xgmi_context.session_id = cmd->resp.session_id; 57597c8d171SHawking Zhang } 57697c8d171SHawking Zhang 57797c8d171SHawking Zhang kfree(cmd); 57897c8d171SHawking Zhang 57997c8d171SHawking Zhang return ret; 58097c8d171SHawking Zhang } 58197c8d171SHawking Zhang 58297c8d171SHawking Zhang static int psp_xgmi_unload(struct psp_context *psp) 58397c8d171SHawking Zhang { 58497c8d171SHawking Zhang int ret; 58597c8d171SHawking Zhang struct psp_gfx_cmd_resp *cmd; 5869c8c81feSJohn Clements struct amdgpu_device *adev = psp->adev; 5879c8c81feSJohn Clements 5889c8c81feSJohn Clements /* XGMI TA unload currently is not supported on Arcturus */ 5899c8c81feSJohn Clements if (adev->asic_type == CHIP_ARCTURUS) 5909c8c81feSJohn Clements return 0; 59197c8d171SHawking Zhang 59297c8d171SHawking Zhang /* 59397c8d171SHawking Zhang * TODO: bypass the unloading in sriov for now 59497c8d171SHawking Zhang */ 59597c8d171SHawking Zhang 59697c8d171SHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 59797c8d171SHawking Zhang if (!cmd) 59897c8d171SHawking Zhang return -ENOMEM; 59997c8d171SHawking Zhang 6001f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->xgmi_context.session_id); 60197c8d171SHawking Zhang 60297c8d171SHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 60397c8d171SHawking Zhang psp->fence_buf_mc_addr); 60497c8d171SHawking Zhang 60597c8d171SHawking Zhang kfree(cmd); 60697c8d171SHawking Zhang 60797c8d171SHawking Zhang return ret; 60897c8d171SHawking Zhang } 60997c8d171SHawking Zhang 610ca6e1e59SHawking Zhang int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 611ca6e1e59SHawking Zhang { 61234e48caeSJohn Clements return psp_ta_invoke(psp, ta_cmd_id, psp->xgmi_context.session_id); 613ca6e1e59SHawking Zhang } 614ca6e1e59SHawking Zhang 6150b9d3760SHawking Zhang int psp_xgmi_terminate(struct psp_context *psp) 6163e2e2ab5SHawking Zhang { 6173e2e2ab5SHawking Zhang int ret; 6183e2e2ab5SHawking Zhang 6193e2e2ab5SHawking Zhang if (!psp->xgmi_context.initialized) 6203e2e2ab5SHawking Zhang return 0; 6213e2e2ab5SHawking Zhang 6223e2e2ab5SHawking Zhang ret = psp_xgmi_unload(psp); 6233e2e2ab5SHawking Zhang if (ret) 6243e2e2ab5SHawking Zhang return ret; 6253e2e2ab5SHawking Zhang 6263e2e2ab5SHawking Zhang psp->xgmi_context.initialized = 0; 6273e2e2ab5SHawking Zhang 6283e2e2ab5SHawking Zhang /* free xgmi shared memory */ 6293e2e2ab5SHawking Zhang amdgpu_bo_free_kernel(&psp->xgmi_context.xgmi_shared_bo, 6303e2e2ab5SHawking Zhang &psp->xgmi_context.xgmi_shared_mc_addr, 6313e2e2ab5SHawking Zhang &psp->xgmi_context.xgmi_shared_buf); 6323e2e2ab5SHawking Zhang 6333e2e2ab5SHawking Zhang return 0; 6343e2e2ab5SHawking Zhang } 6353e2e2ab5SHawking Zhang 6360b9d3760SHawking Zhang int psp_xgmi_initialize(struct psp_context *psp) 6373e2e2ab5SHawking Zhang { 6383e2e2ab5SHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 6393e2e2ab5SHawking Zhang int ret; 6403e2e2ab5SHawking Zhang 64151bd3638SHawking Zhang if (!psp->adev->psp.ta_fw || 64251bd3638SHawking Zhang !psp->adev->psp.ta_xgmi_ucode_size || 64351bd3638SHawking Zhang !psp->adev->psp.ta_xgmi_start_addr) 6441d69511eSAlex Deucher return -ENOENT; 6451d69511eSAlex Deucher 6463e2e2ab5SHawking Zhang if (!psp->xgmi_context.initialized) { 6473e2e2ab5SHawking Zhang ret = psp_xgmi_init_shared_buf(psp); 6483e2e2ab5SHawking Zhang if (ret) 6493e2e2ab5SHawking Zhang return ret; 6503e2e2ab5SHawking Zhang } 6513e2e2ab5SHawking Zhang 6523e2e2ab5SHawking Zhang /* Load XGMI TA */ 6533e2e2ab5SHawking Zhang ret = psp_xgmi_load(psp); 6543e2e2ab5SHawking Zhang if (ret) 6553e2e2ab5SHawking Zhang return ret; 6563e2e2ab5SHawking Zhang 6573e2e2ab5SHawking Zhang /* Initialize XGMI session */ 6583e2e2ab5SHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory *)(psp->xgmi_context.xgmi_shared_buf); 6593e2e2ab5SHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 6603e2e2ab5SHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__INITIALIZE; 6613e2e2ab5SHawking Zhang 6623e2e2ab5SHawking Zhang ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id); 6633e2e2ab5SHawking Zhang 6643e2e2ab5SHawking Zhang return ret; 6653e2e2ab5SHawking Zhang } 6663e2e2ab5SHawking Zhang 667*35ccba4eSHawking Zhang int psp_xgmi_get_hive_id(struct psp_context *psp, uint64_t *hive_id) 668*35ccba4eSHawking Zhang { 669*35ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 670*35ccba4eSHawking Zhang int ret; 671*35ccba4eSHawking Zhang 672*35ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf; 673*35ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 674*35ccba4eSHawking Zhang 675*35ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_HIVE_ID; 676*35ccba4eSHawking Zhang 677*35ccba4eSHawking Zhang /* Invoke xgmi ta to get hive id */ 678*35ccba4eSHawking Zhang ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id); 679*35ccba4eSHawking Zhang if (ret) 680*35ccba4eSHawking Zhang return ret; 681*35ccba4eSHawking Zhang 682*35ccba4eSHawking Zhang *hive_id = xgmi_cmd->xgmi_out_message.get_hive_id.hive_id; 683*35ccba4eSHawking Zhang 684*35ccba4eSHawking Zhang return 0; 685*35ccba4eSHawking Zhang } 686*35ccba4eSHawking Zhang 687*35ccba4eSHawking Zhang int psp_xgmi_get_node_id(struct psp_context *psp, uint64_t *node_id) 688*35ccba4eSHawking Zhang { 689*35ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 690*35ccba4eSHawking Zhang int ret; 691*35ccba4eSHawking Zhang 692*35ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf; 693*35ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 694*35ccba4eSHawking Zhang 695*35ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_NODE_ID; 696*35ccba4eSHawking Zhang 697*35ccba4eSHawking Zhang /* Invoke xgmi ta to get the node id */ 698*35ccba4eSHawking Zhang ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id); 699*35ccba4eSHawking Zhang if (ret) 700*35ccba4eSHawking Zhang return ret; 701*35ccba4eSHawking Zhang 702*35ccba4eSHawking Zhang *node_id = xgmi_cmd->xgmi_out_message.get_node_id.node_id; 703*35ccba4eSHawking Zhang 704*35ccba4eSHawking Zhang return 0; 705*35ccba4eSHawking Zhang } 706*35ccba4eSHawking Zhang 707*35ccba4eSHawking Zhang int psp_xgmi_get_topology_info(struct psp_context *psp, 708*35ccba4eSHawking Zhang int number_devices, 709*35ccba4eSHawking Zhang struct psp_xgmi_topology_info *topology) 710*35ccba4eSHawking Zhang { 711*35ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 712*35ccba4eSHawking Zhang struct ta_xgmi_cmd_get_topology_info_input *topology_info_input; 713*35ccba4eSHawking Zhang struct ta_xgmi_cmd_get_topology_info_output *topology_info_output; 714*35ccba4eSHawking Zhang int i; 715*35ccba4eSHawking Zhang int ret; 716*35ccba4eSHawking Zhang 717*35ccba4eSHawking Zhang if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES) 718*35ccba4eSHawking Zhang return -EINVAL; 719*35ccba4eSHawking Zhang 720*35ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf; 721*35ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 722*35ccba4eSHawking Zhang 723*35ccba4eSHawking Zhang /* Fill in the shared memory with topology information as input */ 724*35ccba4eSHawking Zhang topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info; 725*35ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO; 726*35ccba4eSHawking Zhang topology_info_input->num_nodes = number_devices; 727*35ccba4eSHawking Zhang 728*35ccba4eSHawking Zhang for (i = 0; i < topology_info_input->num_nodes; i++) { 729*35ccba4eSHawking Zhang topology_info_input->nodes[i].node_id = topology->nodes[i].node_id; 730*35ccba4eSHawking Zhang topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops; 731*35ccba4eSHawking Zhang topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled; 732*35ccba4eSHawking Zhang topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine; 733*35ccba4eSHawking Zhang } 734*35ccba4eSHawking Zhang 735*35ccba4eSHawking Zhang /* Invoke xgmi ta to get the topology information */ 736*35ccba4eSHawking Zhang ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO); 737*35ccba4eSHawking Zhang if (ret) 738*35ccba4eSHawking Zhang return ret; 739*35ccba4eSHawking Zhang 740*35ccba4eSHawking Zhang /* Read the output topology information from the shared memory */ 741*35ccba4eSHawking Zhang topology_info_output = &xgmi_cmd->xgmi_out_message.get_topology_info; 742*35ccba4eSHawking Zhang topology->num_nodes = xgmi_cmd->xgmi_out_message.get_topology_info.num_nodes; 743*35ccba4eSHawking Zhang for (i = 0; i < topology->num_nodes; i++) { 744*35ccba4eSHawking Zhang topology->nodes[i].node_id = topology_info_output->nodes[i].node_id; 745*35ccba4eSHawking Zhang topology->nodes[i].num_hops = topology_info_output->nodes[i].num_hops; 746*35ccba4eSHawking Zhang topology->nodes[i].is_sharing_enabled = topology_info_output->nodes[i].is_sharing_enabled; 747*35ccba4eSHawking Zhang topology->nodes[i].sdma_engine = topology_info_output->nodes[i].sdma_engine; 748*35ccba4eSHawking Zhang } 749*35ccba4eSHawking Zhang 750*35ccba4eSHawking Zhang return 0; 751*35ccba4eSHawking Zhang } 752*35ccba4eSHawking Zhang 753*35ccba4eSHawking Zhang int psp_xgmi_set_topology_info(struct psp_context *psp, 754*35ccba4eSHawking Zhang int number_devices, 755*35ccba4eSHawking Zhang struct psp_xgmi_topology_info *topology) 756*35ccba4eSHawking Zhang { 757*35ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 758*35ccba4eSHawking Zhang struct ta_xgmi_cmd_get_topology_info_input *topology_info_input; 759*35ccba4eSHawking Zhang int i; 760*35ccba4eSHawking Zhang 761*35ccba4eSHawking Zhang if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES) 762*35ccba4eSHawking Zhang return -EINVAL; 763*35ccba4eSHawking Zhang 764*35ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf; 765*35ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 766*35ccba4eSHawking Zhang 767*35ccba4eSHawking Zhang topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info; 768*35ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__SET_TOPOLOGY_INFO; 769*35ccba4eSHawking Zhang topology_info_input->num_nodes = number_devices; 770*35ccba4eSHawking Zhang 771*35ccba4eSHawking Zhang for (i = 0; i < topology_info_input->num_nodes; i++) { 772*35ccba4eSHawking Zhang topology_info_input->nodes[i].node_id = topology->nodes[i].node_id; 773*35ccba4eSHawking Zhang topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops; 774*35ccba4eSHawking Zhang topology_info_input->nodes[i].is_sharing_enabled = 1; 775*35ccba4eSHawking Zhang topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine; 776*35ccba4eSHawking Zhang } 777*35ccba4eSHawking Zhang 778*35ccba4eSHawking Zhang /* Invoke xgmi ta to set topology information */ 779*35ccba4eSHawking Zhang return psp_xgmi_invoke(psp, TA_COMMAND_XGMI__SET_TOPOLOGY_INFO); 780*35ccba4eSHawking Zhang } 781*35ccba4eSHawking Zhang 7825e5d3154Sxinhui pan // ras begin 7835e5d3154Sxinhui pan static int psp_ras_init_shared_buf(struct psp_context *psp) 7845e5d3154Sxinhui pan { 7855e5d3154Sxinhui pan int ret; 7865e5d3154Sxinhui pan 7875e5d3154Sxinhui pan /* 7885e5d3154Sxinhui pan * Allocate 16k memory aligned to 4k from Frame Buffer (local 7895e5d3154Sxinhui pan * physical) for ras ta <-> Driver 7905e5d3154Sxinhui pan */ 7915e5d3154Sxinhui pan ret = amdgpu_bo_create_kernel(psp->adev, PSP_RAS_SHARED_MEM_SIZE, 7925e5d3154Sxinhui pan PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 7935e5d3154Sxinhui pan &psp->ras.ras_shared_bo, 7945e5d3154Sxinhui pan &psp->ras.ras_shared_mc_addr, 7955e5d3154Sxinhui pan &psp->ras.ras_shared_buf); 7965e5d3154Sxinhui pan 7975e5d3154Sxinhui pan return ret; 7985e5d3154Sxinhui pan } 7995e5d3154Sxinhui pan 8005e5d3154Sxinhui pan static int psp_ras_load(struct psp_context *psp) 8015e5d3154Sxinhui pan { 8025e5d3154Sxinhui pan int ret; 8035e5d3154Sxinhui pan struct psp_gfx_cmd_resp *cmd; 8045e5d3154Sxinhui pan 8055e5d3154Sxinhui pan /* 8065e5d3154Sxinhui pan * TODO: bypass the loading in sriov for now 8075e5d3154Sxinhui pan */ 8085e5d3154Sxinhui pan if (amdgpu_sriov_vf(psp->adev)) 8095e5d3154Sxinhui pan return 0; 8105e5d3154Sxinhui pan 8115e5d3154Sxinhui pan cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 8125e5d3154Sxinhui pan if (!cmd) 8135e5d3154Sxinhui pan return -ENOMEM; 8145e5d3154Sxinhui pan 8155e5d3154Sxinhui pan memset(psp->fw_pri_buf, 0, PSP_1_MEG); 8165e5d3154Sxinhui pan memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size); 8175e5d3154Sxinhui pan 8181f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 8191f455f25SJohn Clements psp->fw_pri_mc_addr, 8201f455f25SJohn Clements psp->ta_ras_ucode_size, 8215e5d3154Sxinhui pan psp->ras.ras_shared_mc_addr, 8221f455f25SJohn Clements PSP_RAS_SHARED_MEM_SIZE); 8235e5d3154Sxinhui pan 8245e5d3154Sxinhui pan ret = psp_cmd_submit_buf(psp, NULL, cmd, 8255e5d3154Sxinhui pan psp->fence_buf_mc_addr); 8265e5d3154Sxinhui pan 8275e5d3154Sxinhui pan if (!ret) { 828e95cd6b2Szhengbin psp->ras.ras_initialized = true; 8295e5d3154Sxinhui pan psp->ras.session_id = cmd->resp.session_id; 8305e5d3154Sxinhui pan } 8315e5d3154Sxinhui pan 8325e5d3154Sxinhui pan kfree(cmd); 8335e5d3154Sxinhui pan 8345e5d3154Sxinhui pan return ret; 8355e5d3154Sxinhui pan } 8365e5d3154Sxinhui pan 8375e5d3154Sxinhui pan static int psp_ras_unload(struct psp_context *psp) 8385e5d3154Sxinhui pan { 8395e5d3154Sxinhui pan int ret; 8405e5d3154Sxinhui pan struct psp_gfx_cmd_resp *cmd; 8415e5d3154Sxinhui pan 8425e5d3154Sxinhui pan /* 8435e5d3154Sxinhui pan * TODO: bypass the unloading in sriov for now 8445e5d3154Sxinhui pan */ 8455e5d3154Sxinhui pan if (amdgpu_sriov_vf(psp->adev)) 8465e5d3154Sxinhui pan return 0; 8475e5d3154Sxinhui pan 8485e5d3154Sxinhui pan cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 8495e5d3154Sxinhui pan if (!cmd) 8505e5d3154Sxinhui pan return -ENOMEM; 8515e5d3154Sxinhui pan 8521f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->ras.session_id); 8535e5d3154Sxinhui pan 8545e5d3154Sxinhui pan ret = psp_cmd_submit_buf(psp, NULL, cmd, 8555e5d3154Sxinhui pan psp->fence_buf_mc_addr); 8565e5d3154Sxinhui pan 8575e5d3154Sxinhui pan kfree(cmd); 8585e5d3154Sxinhui pan 8595e5d3154Sxinhui pan return ret; 8605e5d3154Sxinhui pan } 8615e5d3154Sxinhui pan 8625e5d3154Sxinhui pan int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 8635e5d3154Sxinhui pan { 86443965797SJohn Clements struct ta_ras_shared_memory *ras_cmd; 86543965797SJohn Clements int ret; 86643965797SJohn Clements 86743965797SJohn Clements ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; 86843965797SJohn Clements 8695e5d3154Sxinhui pan /* 8705e5d3154Sxinhui pan * TODO: bypass the loading in sriov for now 8715e5d3154Sxinhui pan */ 8725e5d3154Sxinhui pan if (amdgpu_sriov_vf(psp->adev)) 8735e5d3154Sxinhui pan return 0; 8745e5d3154Sxinhui pan 87543965797SJohn Clements ret = psp_ta_invoke(psp, ta_cmd_id, psp->ras.session_id); 87643965797SJohn Clements 877624e8c87SJohn Clements if (amdgpu_ras_intr_triggered()) 878624e8c87SJohn Clements return ret; 879624e8c87SJohn Clements 88043965797SJohn Clements if (ras_cmd->if_version > RAS_TA_HOST_IF_VER) 88143965797SJohn Clements { 88243965797SJohn Clements DRM_WARN("RAS: Unsupported Interface"); 88343965797SJohn Clements return -EINVAL; 88443965797SJohn Clements } 88543965797SJohn Clements 88643965797SJohn Clements if (!ret) { 88743965797SJohn Clements if (ras_cmd->ras_out_message.flags.err_inject_switch_disable_flag) { 88843965797SJohn Clements dev_warn(psp->adev->dev, "ECC switch disabled\n"); 88943965797SJohn Clements 89043965797SJohn Clements ras_cmd->ras_status = TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE; 89143965797SJohn Clements } 89243965797SJohn Clements else if (ras_cmd->ras_out_message.flags.reg_access_failure_flag) 89343965797SJohn Clements dev_warn(psp->adev->dev, 89443965797SJohn Clements "RAS internal register access blocked\n"); 89543965797SJohn Clements } 89643965797SJohn Clements 89743965797SJohn Clements return ret; 8985e5d3154Sxinhui pan } 8995e5d3154Sxinhui pan 9005e5d3154Sxinhui pan int psp_ras_enable_features(struct psp_context *psp, 9015e5d3154Sxinhui pan union ta_ras_cmd_input *info, bool enable) 9025e5d3154Sxinhui pan { 9035e5d3154Sxinhui pan struct ta_ras_shared_memory *ras_cmd; 9045e5d3154Sxinhui pan int ret; 9055e5d3154Sxinhui pan 9065e5d3154Sxinhui pan if (!psp->ras.ras_initialized) 9075e5d3154Sxinhui pan return -EINVAL; 9085e5d3154Sxinhui pan 9095e5d3154Sxinhui pan ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; 9105e5d3154Sxinhui pan memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory)); 9115e5d3154Sxinhui pan 9125e5d3154Sxinhui pan if (enable) 9135e5d3154Sxinhui pan ras_cmd->cmd_id = TA_RAS_COMMAND__ENABLE_FEATURES; 9145e5d3154Sxinhui pan else 9155e5d3154Sxinhui pan ras_cmd->cmd_id = TA_RAS_COMMAND__DISABLE_FEATURES; 9165e5d3154Sxinhui pan 9175e5d3154Sxinhui pan ras_cmd->ras_in_message = *info; 9185e5d3154Sxinhui pan 9195e5d3154Sxinhui pan ret = psp_ras_invoke(psp, ras_cmd->cmd_id); 9205e5d3154Sxinhui pan if (ret) 9215e5d3154Sxinhui pan return -EINVAL; 9225e5d3154Sxinhui pan 9235e5d3154Sxinhui pan return ras_cmd->ras_status; 9245e5d3154Sxinhui pan } 9255e5d3154Sxinhui pan 9265e5d3154Sxinhui pan static int psp_ras_terminate(struct psp_context *psp) 9275e5d3154Sxinhui pan { 9285e5d3154Sxinhui pan int ret; 9295e5d3154Sxinhui pan 930edc2176dSJack Zhang /* 931edc2176dSJack Zhang * TODO: bypass the terminate in sriov for now 932edc2176dSJack Zhang */ 933edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 934edc2176dSJack Zhang return 0; 935edc2176dSJack Zhang 9365e5d3154Sxinhui pan if (!psp->ras.ras_initialized) 9375e5d3154Sxinhui pan return 0; 9385e5d3154Sxinhui pan 9395e5d3154Sxinhui pan ret = psp_ras_unload(psp); 9405e5d3154Sxinhui pan if (ret) 9415e5d3154Sxinhui pan return ret; 9425e5d3154Sxinhui pan 943e95cd6b2Szhengbin psp->ras.ras_initialized = false; 9445e5d3154Sxinhui pan 9455e5d3154Sxinhui pan /* free ras shared memory */ 9465e5d3154Sxinhui pan amdgpu_bo_free_kernel(&psp->ras.ras_shared_bo, 9475e5d3154Sxinhui pan &psp->ras.ras_shared_mc_addr, 9485e5d3154Sxinhui pan &psp->ras.ras_shared_buf); 9495e5d3154Sxinhui pan 9505e5d3154Sxinhui pan return 0; 9515e5d3154Sxinhui pan } 9525e5d3154Sxinhui pan 9535e5d3154Sxinhui pan static int psp_ras_initialize(struct psp_context *psp) 9545e5d3154Sxinhui pan { 9555e5d3154Sxinhui pan int ret; 9565e5d3154Sxinhui pan 957edc2176dSJack Zhang /* 958edc2176dSJack Zhang * TODO: bypass the initialize in sriov for now 959edc2176dSJack Zhang */ 960edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 961edc2176dSJack Zhang return 0; 962edc2176dSJack Zhang 96351bd3638SHawking Zhang if (!psp->adev->psp.ta_ras_ucode_size || 96451bd3638SHawking Zhang !psp->adev->psp.ta_ras_start_addr) { 965a45a9e5eSAlex Deucher dev_info(psp->adev->dev, "RAS: optional ras ta ucode is not available\n"); 96651bd3638SHawking Zhang return 0; 96751bd3638SHawking Zhang } 96851bd3638SHawking Zhang 9695e5d3154Sxinhui pan if (!psp->ras.ras_initialized) { 9705e5d3154Sxinhui pan ret = psp_ras_init_shared_buf(psp); 9715e5d3154Sxinhui pan if (ret) 9725e5d3154Sxinhui pan return ret; 9735e5d3154Sxinhui pan } 9745e5d3154Sxinhui pan 9755e5d3154Sxinhui pan ret = psp_ras_load(psp); 9765e5d3154Sxinhui pan if (ret) 9775e5d3154Sxinhui pan return ret; 9785e5d3154Sxinhui pan 9795e5d3154Sxinhui pan return 0; 9805e5d3154Sxinhui pan } 9815e5d3154Sxinhui pan // ras end 9825e5d3154Sxinhui pan 983ed19a9a2SBhawanpreet Lakha // HDCP start 984ed19a9a2SBhawanpreet Lakha static int psp_hdcp_init_shared_buf(struct psp_context *psp) 985ed19a9a2SBhawanpreet Lakha { 986ed19a9a2SBhawanpreet Lakha int ret; 987ed19a9a2SBhawanpreet Lakha 988ed19a9a2SBhawanpreet Lakha /* 989ed19a9a2SBhawanpreet Lakha * Allocate 16k memory aligned to 4k from Frame Buffer (local 990ed19a9a2SBhawanpreet Lakha * physical) for hdcp ta <-> Driver 991ed19a9a2SBhawanpreet Lakha */ 992ed19a9a2SBhawanpreet Lakha ret = amdgpu_bo_create_kernel(psp->adev, PSP_HDCP_SHARED_MEM_SIZE, 993ed19a9a2SBhawanpreet Lakha PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 994ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_bo, 995ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_mc_addr, 996ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_buf); 997ed19a9a2SBhawanpreet Lakha 998ed19a9a2SBhawanpreet Lakha return ret; 999ed19a9a2SBhawanpreet Lakha } 1000ed19a9a2SBhawanpreet Lakha 1001ed19a9a2SBhawanpreet Lakha static int psp_hdcp_load(struct psp_context *psp) 1002ed19a9a2SBhawanpreet Lakha { 1003ed19a9a2SBhawanpreet Lakha int ret; 1004ed19a9a2SBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1005ed19a9a2SBhawanpreet Lakha 1006ed19a9a2SBhawanpreet Lakha /* 1007ed19a9a2SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1008ed19a9a2SBhawanpreet Lakha */ 1009ed19a9a2SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1010ed19a9a2SBhawanpreet Lakha return 0; 1011ed19a9a2SBhawanpreet Lakha 1012ed19a9a2SBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1013ed19a9a2SBhawanpreet Lakha if (!cmd) 1014ed19a9a2SBhawanpreet Lakha return -ENOMEM; 1015ed19a9a2SBhawanpreet Lakha 1016ed19a9a2SBhawanpreet Lakha memset(psp->fw_pri_buf, 0, PSP_1_MEG); 1017ed19a9a2SBhawanpreet Lakha memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr, 1018ed19a9a2SBhawanpreet Lakha psp->ta_hdcp_ucode_size); 1019ed19a9a2SBhawanpreet Lakha 10201f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 10211f455f25SJohn Clements psp->fw_pri_mc_addr, 1022ed19a9a2SBhawanpreet Lakha psp->ta_hdcp_ucode_size, 10231f455f25SJohn Clements psp->hdcp_context.hdcp_shared_mc_addr, 1024ed19a9a2SBhawanpreet Lakha PSP_HDCP_SHARED_MEM_SIZE); 1025ed19a9a2SBhawanpreet Lakha 1026ed19a9a2SBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1027ed19a9a2SBhawanpreet Lakha 1028ed19a9a2SBhawanpreet Lakha if (!ret) { 1029e95cd6b2Szhengbin psp->hdcp_context.hdcp_initialized = true; 1030ed19a9a2SBhawanpreet Lakha psp->hdcp_context.session_id = cmd->resp.session_id; 10318913f7ffSBhawanpreet Lakha mutex_init(&psp->hdcp_context.mutex); 1032ed19a9a2SBhawanpreet Lakha } 1033ed19a9a2SBhawanpreet Lakha 1034ed19a9a2SBhawanpreet Lakha kfree(cmd); 1035ed19a9a2SBhawanpreet Lakha 1036ed19a9a2SBhawanpreet Lakha return ret; 1037ed19a9a2SBhawanpreet Lakha } 1038ed19a9a2SBhawanpreet Lakha static int psp_hdcp_initialize(struct psp_context *psp) 1039ed19a9a2SBhawanpreet Lakha { 1040ed19a9a2SBhawanpreet Lakha int ret; 1041ed19a9a2SBhawanpreet Lakha 1042edc2176dSJack Zhang /* 1043edc2176dSJack Zhang * TODO: bypass the initialize in sriov for now 1044edc2176dSJack Zhang */ 1045edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1046edc2176dSJack Zhang return 0; 1047edc2176dSJack Zhang 104851bd3638SHawking Zhang if (!psp->adev->psp.ta_hdcp_ucode_size || 104951bd3638SHawking Zhang !psp->adev->psp.ta_hdcp_start_addr) { 1050a45a9e5eSAlex Deucher dev_info(psp->adev->dev, "HDCP: optional hdcp ta ucode is not available\n"); 105151bd3638SHawking Zhang return 0; 105251bd3638SHawking Zhang } 105351bd3638SHawking Zhang 1054ed19a9a2SBhawanpreet Lakha if (!psp->hdcp_context.hdcp_initialized) { 1055ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_init_shared_buf(psp); 1056ed19a9a2SBhawanpreet Lakha if (ret) 1057ed19a9a2SBhawanpreet Lakha return ret; 1058ed19a9a2SBhawanpreet Lakha } 1059ed19a9a2SBhawanpreet Lakha 1060ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_load(psp); 1061ed19a9a2SBhawanpreet Lakha if (ret) 1062ed19a9a2SBhawanpreet Lakha return ret; 1063ed19a9a2SBhawanpreet Lakha 1064ed19a9a2SBhawanpreet Lakha return 0; 1065ed19a9a2SBhawanpreet Lakha } 1066ed19a9a2SBhawanpreet Lakha 1067ed19a9a2SBhawanpreet Lakha static int psp_hdcp_unload(struct psp_context *psp) 1068ed19a9a2SBhawanpreet Lakha { 1069ed19a9a2SBhawanpreet Lakha int ret; 1070ed19a9a2SBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1071ed19a9a2SBhawanpreet Lakha 1072ed19a9a2SBhawanpreet Lakha /* 1073ed19a9a2SBhawanpreet Lakha * TODO: bypass the unloading in sriov for now 1074ed19a9a2SBhawanpreet Lakha */ 1075ed19a9a2SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1076ed19a9a2SBhawanpreet Lakha return 0; 1077ed19a9a2SBhawanpreet Lakha 1078ed19a9a2SBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1079ed19a9a2SBhawanpreet Lakha if (!cmd) 1080ed19a9a2SBhawanpreet Lakha return -ENOMEM; 1081ed19a9a2SBhawanpreet Lakha 10821f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->hdcp_context.session_id); 1083ed19a9a2SBhawanpreet Lakha 1084ed19a9a2SBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1085ed19a9a2SBhawanpreet Lakha 1086ed19a9a2SBhawanpreet Lakha kfree(cmd); 1087ed19a9a2SBhawanpreet Lakha 1088ed19a9a2SBhawanpreet Lakha return ret; 1089ed19a9a2SBhawanpreet Lakha } 1090ed19a9a2SBhawanpreet Lakha 1091ed19a9a2SBhawanpreet Lakha int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 1092ed19a9a2SBhawanpreet Lakha { 1093ed19a9a2SBhawanpreet Lakha /* 1094ed19a9a2SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1095ed19a9a2SBhawanpreet Lakha */ 1096ed19a9a2SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1097ed19a9a2SBhawanpreet Lakha return 0; 1098ed19a9a2SBhawanpreet Lakha 109934e48caeSJohn Clements return psp_ta_invoke(psp, ta_cmd_id, psp->hdcp_context.session_id); 1100ed19a9a2SBhawanpreet Lakha } 1101ed19a9a2SBhawanpreet Lakha 1102ed19a9a2SBhawanpreet Lakha static int psp_hdcp_terminate(struct psp_context *psp) 1103ed19a9a2SBhawanpreet Lakha { 1104ed19a9a2SBhawanpreet Lakha int ret; 1105ed19a9a2SBhawanpreet Lakha 1106edc2176dSJack Zhang /* 1107edc2176dSJack Zhang * TODO: bypass the terminate in sriov for now 1108edc2176dSJack Zhang */ 1109edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1110edc2176dSJack Zhang return 0; 1111edc2176dSJack Zhang 1112ed19a9a2SBhawanpreet Lakha if (!psp->hdcp_context.hdcp_initialized) 1113ed19a9a2SBhawanpreet Lakha return 0; 1114ed19a9a2SBhawanpreet Lakha 1115ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_unload(psp); 1116ed19a9a2SBhawanpreet Lakha if (ret) 1117ed19a9a2SBhawanpreet Lakha return ret; 1118ed19a9a2SBhawanpreet Lakha 1119e95cd6b2Szhengbin psp->hdcp_context.hdcp_initialized = false; 1120ed19a9a2SBhawanpreet Lakha 1121ed19a9a2SBhawanpreet Lakha /* free hdcp shared memory */ 1122ed19a9a2SBhawanpreet Lakha amdgpu_bo_free_kernel(&psp->hdcp_context.hdcp_shared_bo, 1123ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_mc_addr, 1124ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_buf); 1125ed19a9a2SBhawanpreet Lakha 1126ed19a9a2SBhawanpreet Lakha return 0; 1127ed19a9a2SBhawanpreet Lakha } 1128ed19a9a2SBhawanpreet Lakha // HDCP end 1129ed19a9a2SBhawanpreet Lakha 1130143f2305SBhawanpreet Lakha // DTM start 1131143f2305SBhawanpreet Lakha static int psp_dtm_init_shared_buf(struct psp_context *psp) 1132143f2305SBhawanpreet Lakha { 1133143f2305SBhawanpreet Lakha int ret; 1134143f2305SBhawanpreet Lakha 1135143f2305SBhawanpreet Lakha /* 1136143f2305SBhawanpreet Lakha * Allocate 16k memory aligned to 4k from Frame Buffer (local 1137143f2305SBhawanpreet Lakha * physical) for dtm ta <-> Driver 1138143f2305SBhawanpreet Lakha */ 1139143f2305SBhawanpreet Lakha ret = amdgpu_bo_create_kernel(psp->adev, PSP_DTM_SHARED_MEM_SIZE, 1140143f2305SBhawanpreet Lakha PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 1141143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_bo, 1142143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_mc_addr, 1143143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_buf); 1144143f2305SBhawanpreet Lakha 1145143f2305SBhawanpreet Lakha return ret; 1146143f2305SBhawanpreet Lakha } 1147143f2305SBhawanpreet Lakha 1148143f2305SBhawanpreet Lakha static int psp_dtm_load(struct psp_context *psp) 1149143f2305SBhawanpreet Lakha { 1150143f2305SBhawanpreet Lakha int ret; 1151143f2305SBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1152143f2305SBhawanpreet Lakha 1153143f2305SBhawanpreet Lakha /* 1154143f2305SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1155143f2305SBhawanpreet Lakha */ 1156143f2305SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1157143f2305SBhawanpreet Lakha return 0; 1158143f2305SBhawanpreet Lakha 1159143f2305SBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1160143f2305SBhawanpreet Lakha if (!cmd) 1161143f2305SBhawanpreet Lakha return -ENOMEM; 1162143f2305SBhawanpreet Lakha 1163143f2305SBhawanpreet Lakha memset(psp->fw_pri_buf, 0, PSP_1_MEG); 1164143f2305SBhawanpreet Lakha memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size); 1165143f2305SBhawanpreet Lakha 11661f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 11671f455f25SJohn Clements psp->fw_pri_mc_addr, 1168143f2305SBhawanpreet Lakha psp->ta_dtm_ucode_size, 11691f455f25SJohn Clements psp->dtm_context.dtm_shared_mc_addr, 1170143f2305SBhawanpreet Lakha PSP_DTM_SHARED_MEM_SIZE); 1171143f2305SBhawanpreet Lakha 1172143f2305SBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1173143f2305SBhawanpreet Lakha 1174143f2305SBhawanpreet Lakha if (!ret) { 1175e95cd6b2Szhengbin psp->dtm_context.dtm_initialized = true; 1176143f2305SBhawanpreet Lakha psp->dtm_context.session_id = cmd->resp.session_id; 11778913f7ffSBhawanpreet Lakha mutex_init(&psp->dtm_context.mutex); 1178143f2305SBhawanpreet Lakha } 1179143f2305SBhawanpreet Lakha 1180143f2305SBhawanpreet Lakha kfree(cmd); 1181143f2305SBhawanpreet Lakha 1182143f2305SBhawanpreet Lakha return ret; 1183143f2305SBhawanpreet Lakha } 1184143f2305SBhawanpreet Lakha 1185143f2305SBhawanpreet Lakha static int psp_dtm_initialize(struct psp_context *psp) 1186143f2305SBhawanpreet Lakha { 1187143f2305SBhawanpreet Lakha int ret; 1188143f2305SBhawanpreet Lakha 1189edc2176dSJack Zhang /* 1190edc2176dSJack Zhang * TODO: bypass the initialize in sriov for now 1191edc2176dSJack Zhang */ 1192edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1193edc2176dSJack Zhang return 0; 1194edc2176dSJack Zhang 119551bd3638SHawking Zhang if (!psp->adev->psp.ta_dtm_ucode_size || 119651bd3638SHawking Zhang !psp->adev->psp.ta_dtm_start_addr) { 1197a45a9e5eSAlex Deucher dev_info(psp->adev->dev, "DTM: optional dtm ta ucode is not available\n"); 119851bd3638SHawking Zhang return 0; 119951bd3638SHawking Zhang } 120051bd3638SHawking Zhang 1201143f2305SBhawanpreet Lakha if (!psp->dtm_context.dtm_initialized) { 1202143f2305SBhawanpreet Lakha ret = psp_dtm_init_shared_buf(psp); 1203143f2305SBhawanpreet Lakha if (ret) 1204143f2305SBhawanpreet Lakha return ret; 1205143f2305SBhawanpreet Lakha } 1206143f2305SBhawanpreet Lakha 1207143f2305SBhawanpreet Lakha ret = psp_dtm_load(psp); 1208143f2305SBhawanpreet Lakha if (ret) 1209143f2305SBhawanpreet Lakha return ret; 1210143f2305SBhawanpreet Lakha 1211143f2305SBhawanpreet Lakha return 0; 1212143f2305SBhawanpreet Lakha } 1213143f2305SBhawanpreet Lakha 1214c786530bSBhawanpreet Lakha static int psp_dtm_unload(struct psp_context *psp) 1215c786530bSBhawanpreet Lakha { 1216c786530bSBhawanpreet Lakha int ret; 1217c786530bSBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1218c786530bSBhawanpreet Lakha 1219c786530bSBhawanpreet Lakha /* 1220c786530bSBhawanpreet Lakha * TODO: bypass the unloading in sriov for now 1221c786530bSBhawanpreet Lakha */ 1222c786530bSBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1223c786530bSBhawanpreet Lakha return 0; 1224c786530bSBhawanpreet Lakha 1225c786530bSBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1226c786530bSBhawanpreet Lakha if (!cmd) 1227c786530bSBhawanpreet Lakha return -ENOMEM; 1228c786530bSBhawanpreet Lakha 1229c786530bSBhawanpreet Lakha psp_prep_ta_unload_cmd_buf(cmd, psp->dtm_context.session_id); 1230c786530bSBhawanpreet Lakha 1231c786530bSBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1232c786530bSBhawanpreet Lakha 1233c786530bSBhawanpreet Lakha kfree(cmd); 1234c786530bSBhawanpreet Lakha 1235c786530bSBhawanpreet Lakha return ret; 1236c786530bSBhawanpreet Lakha } 1237c786530bSBhawanpreet Lakha 1238143f2305SBhawanpreet Lakha int psp_dtm_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 1239143f2305SBhawanpreet Lakha { 1240143f2305SBhawanpreet Lakha /* 1241143f2305SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1242143f2305SBhawanpreet Lakha */ 1243143f2305SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1244143f2305SBhawanpreet Lakha return 0; 1245143f2305SBhawanpreet Lakha 124634e48caeSJohn Clements return psp_ta_invoke(psp, ta_cmd_id, psp->dtm_context.session_id); 1247143f2305SBhawanpreet Lakha } 1248143f2305SBhawanpreet Lakha 1249143f2305SBhawanpreet Lakha static int psp_dtm_terminate(struct psp_context *psp) 1250143f2305SBhawanpreet Lakha { 1251143f2305SBhawanpreet Lakha int ret; 1252143f2305SBhawanpreet Lakha 1253edc2176dSJack Zhang /* 1254edc2176dSJack Zhang * TODO: bypass the terminate in sriov for now 1255edc2176dSJack Zhang */ 1256edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1257edc2176dSJack Zhang return 0; 1258edc2176dSJack Zhang 1259143f2305SBhawanpreet Lakha if (!psp->dtm_context.dtm_initialized) 1260143f2305SBhawanpreet Lakha return 0; 1261143f2305SBhawanpreet Lakha 1262c786530bSBhawanpreet Lakha ret = psp_dtm_unload(psp); 1263143f2305SBhawanpreet Lakha if (ret) 1264143f2305SBhawanpreet Lakha return ret; 1265143f2305SBhawanpreet Lakha 1266e95cd6b2Szhengbin psp->dtm_context.dtm_initialized = false; 1267143f2305SBhawanpreet Lakha 1268143f2305SBhawanpreet Lakha /* free hdcp shared memory */ 1269143f2305SBhawanpreet Lakha amdgpu_bo_free_kernel(&psp->dtm_context.dtm_shared_bo, 1270143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_mc_addr, 1271143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_buf); 1272143f2305SBhawanpreet Lakha 1273143f2305SBhawanpreet Lakha return 0; 1274143f2305SBhawanpreet Lakha } 1275143f2305SBhawanpreet Lakha // DTM end 1276143f2305SBhawanpreet Lakha 1277be70bbdaSHuang Rui static int psp_hw_start(struct psp_context *psp) 1278be70bbdaSHuang Rui { 127955981bd2SMonk Liu struct amdgpu_device *adev = psp->adev; 1280be70bbdaSHuang Rui int ret; 1281be70bbdaSHuang Rui 128282c4ebfaSMonk Liu if (!amdgpu_sriov_vf(adev)) { 1283f2169946SHawking Zhang if (psp->kdb_bin_size && 128442989359SHawking Zhang (psp->funcs->bootloader_load_kdb != NULL)) { 128542989359SHawking Zhang ret = psp_bootloader_load_kdb(psp); 128642989359SHawking Zhang if (ret) { 128742989359SHawking Zhang DRM_ERROR("PSP load kdb failed!\n"); 128842989359SHawking Zhang return ret; 128942989359SHawking Zhang } 129042989359SHawking Zhang } 129142989359SHawking Zhang 12920e5ca0d1SHuang Rui ret = psp_bootloader_load_sysdrv(psp); 12937a3d7bf6SEvan Quan if (ret) { 12947a3d7bf6SEvan Quan DRM_ERROR("PSP load sysdrv failed!\n"); 1295be70bbdaSHuang Rui return ret; 129655981bd2SMonk Liu } 12970e5ca0d1SHuang Rui 12987a3d7bf6SEvan Quan ret = psp_bootloader_load_sos(psp); 12997a3d7bf6SEvan Quan if (ret) { 13007a3d7bf6SEvan Quan DRM_ERROR("PSP load sos failed!\n"); 1301be70bbdaSHuang Rui return ret; 13027a3d7bf6SEvan Quan } 13037a3d7bf6SEvan Quan } 13047a3d7bf6SEvan Quan 13057a3d7bf6SEvan Quan ret = psp_ring_create(psp, PSP_RING_TYPE__KM); 13067a3d7bf6SEvan Quan if (ret) { 13077a3d7bf6SEvan Quan DRM_ERROR("PSP create ring failed!\n"); 13087a3d7bf6SEvan Quan return ret; 13097a3d7bf6SEvan Quan } 13100e5ca0d1SHuang Rui 1311fba08a77SHawking Zhang ret = psp_tmr_init(psp); 1312fba08a77SHawking Zhang if (ret) { 1313fba08a77SHawking Zhang DRM_ERROR("PSP tmr init failed!\n"); 1314fba08a77SHawking Zhang return ret; 1315fba08a77SHawking Zhang } 1316fba08a77SHawking Zhang 1317995da6ccSEvan Quan /* 131840e611bdSJohn Clements * For ASICs with DF Cstate management centralized 1319995da6ccSEvan Quan * to PMFW, TMR setup should be performed after PMFW 1320995da6ccSEvan Quan * loaded and before other non-psp firmware loaded. 1321995da6ccSEvan Quan */ 132240e611bdSJohn Clements if (psp->pmfw_centralized_cstate_management) { 132340e611bdSJohn Clements ret = psp_load_smu_fw(psp); 132440e611bdSJohn Clements if (ret) 132540e611bdSJohn Clements return ret; 132640e611bdSJohn Clements } 132740e611bdSJohn Clements 1328be70bbdaSHuang Rui ret = psp_tmr_load(psp); 13297a3d7bf6SEvan Quan if (ret) { 13307a3d7bf6SEvan Quan DRM_ERROR("PSP load tmr failed!\n"); 1331be70bbdaSHuang Rui return ret; 13327a3d7bf6SEvan Quan } 13330e5ca0d1SHuang Rui 1334be70bbdaSHuang Rui return 0; 1335be70bbdaSHuang Rui } 1336be70bbdaSHuang Rui 1337be4630d9SHawking Zhang static int psp_get_fw_type(struct amdgpu_firmware_info *ucode, 1338be4630d9SHawking Zhang enum psp_gfx_fw_type *type) 1339be4630d9SHawking Zhang { 1340be4630d9SHawking Zhang switch (ucode->ucode_id) { 1341be4630d9SHawking Zhang case AMDGPU_UCODE_ID_SDMA0: 1342be4630d9SHawking Zhang *type = GFX_FW_TYPE_SDMA0; 1343be4630d9SHawking Zhang break; 1344be4630d9SHawking Zhang case AMDGPU_UCODE_ID_SDMA1: 1345be4630d9SHawking Zhang *type = GFX_FW_TYPE_SDMA1; 1346be4630d9SHawking Zhang break; 1347b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA2: 1348b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA2; 1349b86f8d8bSJohn Clements break; 1350b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA3: 1351b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA3; 1352b86f8d8bSJohn Clements break; 1353b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA4: 1354b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA4; 1355b86f8d8bSJohn Clements break; 1356b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA5: 1357b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA5; 1358b86f8d8bSJohn Clements break; 1359b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA6: 1360b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA6; 1361b86f8d8bSJohn Clements break; 1362b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA7: 1363b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA7; 1364b86f8d8bSJohn Clements break; 1365be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_CE: 1366be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_CE; 1367be4630d9SHawking Zhang break; 1368be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_PFP: 1369be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_PFP; 1370be4630d9SHawking Zhang break; 1371be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_ME: 1372be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_ME; 1373be4630d9SHawking Zhang break; 1374be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC1: 1375be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC; 1376be4630d9SHawking Zhang break; 1377be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC1_JT: 1378be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC_ME1; 1379be4630d9SHawking Zhang break; 1380be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC2: 1381be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC; 1382be4630d9SHawking Zhang break; 1383be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC2_JT: 1384be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC_ME2; 1385be4630d9SHawking Zhang break; 1386be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_G: 1387be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_G; 1388be4630d9SHawking Zhang break; 1389be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL: 1390be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_CNTL; 1391be4630d9SHawking Zhang break; 1392be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM: 1393be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_RESTORE_LIST_GPM_MEM; 1394be4630d9SHawking Zhang break; 1395be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM: 1396be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM; 1397be4630d9SHawking Zhang break; 1398be4630d9SHawking Zhang case AMDGPU_UCODE_ID_SMC: 1399be4630d9SHawking Zhang *type = GFX_FW_TYPE_SMU; 1400be4630d9SHawking Zhang break; 1401be4630d9SHawking Zhang case AMDGPU_UCODE_ID_UVD: 1402be4630d9SHawking Zhang *type = GFX_FW_TYPE_UVD; 1403be4630d9SHawking Zhang break; 1404be4630d9SHawking Zhang case AMDGPU_UCODE_ID_UVD1: 1405be4630d9SHawking Zhang *type = GFX_FW_TYPE_UVD1; 1406be4630d9SHawking Zhang break; 1407be4630d9SHawking Zhang case AMDGPU_UCODE_ID_VCE: 1408be4630d9SHawking Zhang *type = GFX_FW_TYPE_VCE; 1409be4630d9SHawking Zhang break; 1410be4630d9SHawking Zhang case AMDGPU_UCODE_ID_VCN: 1411be4630d9SHawking Zhang *type = GFX_FW_TYPE_VCN; 1412be4630d9SHawking Zhang break; 1413d83c7a07SJane Jian case AMDGPU_UCODE_ID_VCN1: 1414d83c7a07SJane Jian *type = GFX_FW_TYPE_VCN1; 1415d83c7a07SJane Jian break; 1416be4630d9SHawking Zhang case AMDGPU_UCODE_ID_DMCU_ERAM: 1417be4630d9SHawking Zhang *type = GFX_FW_TYPE_DMCU_ERAM; 1418be4630d9SHawking Zhang break; 1419be4630d9SHawking Zhang case AMDGPU_UCODE_ID_DMCU_INTV: 1420be4630d9SHawking Zhang *type = GFX_FW_TYPE_DMCU_ISR; 1421be4630d9SHawking Zhang break; 1422c76ff09bSJack Xiao case AMDGPU_UCODE_ID_VCN0_RAM: 1423c76ff09bSJack Xiao *type = GFX_FW_TYPE_VCN0_RAM; 1424c76ff09bSJack Xiao break; 1425c76ff09bSJack Xiao case AMDGPU_UCODE_ID_VCN1_RAM: 1426c76ff09bSJack Xiao *type = GFX_FW_TYPE_VCN1_RAM; 1427c76ff09bSJack Xiao break; 14282bd2a27fSNicholas Kazlauskas case AMDGPU_UCODE_ID_DMCUB: 14292bd2a27fSNicholas Kazlauskas *type = GFX_FW_TYPE_DMUB; 14302bd2a27fSNicholas Kazlauskas break; 1431be4630d9SHawking Zhang case AMDGPU_UCODE_ID_MAXIMUM: 1432be4630d9SHawking Zhang default: 1433be4630d9SHawking Zhang return -EINVAL; 1434be4630d9SHawking Zhang } 1435be4630d9SHawking Zhang 1436be4630d9SHawking Zhang return 0; 1437be4630d9SHawking Zhang } 1438be4630d9SHawking Zhang 1439c5fb9126SXiaojie Yuan static void psp_print_fw_hdr(struct psp_context *psp, 1440c5fb9126SXiaojie Yuan struct amdgpu_firmware_info *ucode) 1441c5fb9126SXiaojie Yuan { 1442c5fb9126SXiaojie Yuan struct amdgpu_device *adev = psp->adev; 1443bfa603aaSXiaojie Yuan struct common_firmware_header *hdr; 1444c5fb9126SXiaojie Yuan 1445c5fb9126SXiaojie Yuan switch (ucode->ucode_id) { 1446c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA0: 1447c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA1: 1448c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA2: 1449c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA3: 1450c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA4: 1451c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA5: 1452c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA6: 1453c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA7: 1454bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *) 1455bfa603aaSXiaojie Yuan adev->sdma.instance[ucode->ucode_id - AMDGPU_UCODE_ID_SDMA0].fw->data; 1456bfa603aaSXiaojie Yuan amdgpu_ucode_print_sdma_hdr(hdr); 1457c5fb9126SXiaojie Yuan break; 1458c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_CE: 1459bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.ce_fw->data; 1460bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 1461c5fb9126SXiaojie Yuan break; 1462c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_PFP: 1463bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.pfp_fw->data; 1464bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 1465c5fb9126SXiaojie Yuan break; 1466c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_ME: 1467bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.me_fw->data; 1468bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 1469c5fb9126SXiaojie Yuan break; 1470c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_MEC1: 1471bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.mec_fw->data; 1472bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 1473c5fb9126SXiaojie Yuan break; 1474c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_RLC_G: 1475bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.rlc_fw->data; 1476bfa603aaSXiaojie Yuan amdgpu_ucode_print_rlc_hdr(hdr); 1477c5fb9126SXiaojie Yuan break; 1478c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SMC: 1479bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->pm.fw->data; 1480bfa603aaSXiaojie Yuan amdgpu_ucode_print_smc_hdr(hdr); 1481c5fb9126SXiaojie Yuan break; 1482c5fb9126SXiaojie Yuan default: 1483c5fb9126SXiaojie Yuan break; 1484c5fb9126SXiaojie Yuan } 1485c5fb9126SXiaojie Yuan } 1486c5fb9126SXiaojie Yuan 1487be4630d9SHawking Zhang static int psp_prep_load_ip_fw_cmd_buf(struct amdgpu_firmware_info *ucode, 1488be4630d9SHawking Zhang struct psp_gfx_cmd_resp *cmd) 1489be4630d9SHawking Zhang { 1490be4630d9SHawking Zhang int ret; 1491be4630d9SHawking Zhang uint64_t fw_mem_mc_addr = ucode->mc_addr; 1492be4630d9SHawking Zhang 1493be4630d9SHawking Zhang memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); 1494be4630d9SHawking Zhang 1495be4630d9SHawking Zhang cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW; 1496be4630d9SHawking Zhang cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr); 1497be4630d9SHawking Zhang cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr); 1498be4630d9SHawking Zhang cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size; 1499be4630d9SHawking Zhang 1500be4630d9SHawking Zhang ret = psp_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type); 1501be4630d9SHawking Zhang if (ret) 1502be4630d9SHawking Zhang DRM_ERROR("Unknown firmware type\n"); 1503be4630d9SHawking Zhang 1504be4630d9SHawking Zhang return ret; 1505be4630d9SHawking Zhang } 1506be4630d9SHawking Zhang 150713169562SHuang Rui static int psp_execute_np_fw_load(struct psp_context *psp, 150813169562SHuang Rui struct amdgpu_firmware_info *ucode) 150913169562SHuang Rui { 151013169562SHuang Rui int ret = 0; 151113169562SHuang Rui 151213169562SHuang Rui ret = psp_prep_load_ip_fw_cmd_buf(ucode, psp->cmd); 151313169562SHuang Rui if (ret) 151413169562SHuang Rui return ret; 151513169562SHuang Rui 151613169562SHuang Rui ret = psp_cmd_submit_buf(psp, ucode, psp->cmd, 151713169562SHuang Rui psp->fence_buf_mc_addr); 151813169562SHuang Rui 151913169562SHuang Rui return ret; 152013169562SHuang Rui } 152113169562SHuang Rui 152240e611bdSJohn Clements static int psp_load_smu_fw(struct psp_context *psp) 1523be70bbdaSHuang Rui { 152440e611bdSJohn Clements int ret; 15257f70443fSJohn Clements struct amdgpu_device* adev = psp->adev; 152640e611bdSJohn Clements struct amdgpu_firmware_info *ucode = 15277f70443fSJohn Clements &adev->firmware.ucode[AMDGPU_UCODE_ID_SMC]; 15280e5ca0d1SHuang Rui 152940e611bdSJohn Clements if (!ucode->fw || amdgpu_sriov_vf(psp->adev)) 153040e611bdSJohn Clements return 0; 153113169562SHuang Rui 15327f70443fSJohn Clements 15337f70443fSJohn Clements if (adev->in_gpu_reset) { 15347f70443fSJohn Clements ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD); 15357f70443fSJohn Clements if (ret) { 15367f70443fSJohn Clements DRM_WARN("Failed to set MP1 state prepare for reload\n"); 15377f70443fSJohn Clements } 15387f70443fSJohn Clements } 15397f70443fSJohn Clements 154013169562SHuang Rui ret = psp_execute_np_fw_load(psp, ucode); 154140e611bdSJohn Clements 154213169562SHuang Rui if (ret) 154340e611bdSJohn Clements DRM_ERROR("PSP load smu failed!\n"); 154440e611bdSJohn Clements 154513169562SHuang Rui return ret; 154613169562SHuang Rui } 154713169562SHuang Rui 154840e611bdSJohn Clements static bool fw_load_skip_check(struct psp_context *psp, 154940e611bdSJohn Clements struct amdgpu_firmware_info *ucode) 155040e611bdSJohn Clements { 15510e5ca0d1SHuang Rui if (!ucode->fw) 155240e611bdSJohn Clements return true; 15530e5ca0d1SHuang Rui 15540e5ca0d1SHuang Rui if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC && 1555995da6ccSEvan Quan (psp_smu_reload_quirk(psp) || 1556995da6ccSEvan Quan psp->autoload_supported || 1557995da6ccSEvan Quan psp->pmfw_centralized_cstate_management)) 155840e611bdSJohn Clements return true; 1559b86f8d8bSJohn Clements 156040e611bdSJohn Clements if (amdgpu_sriov_vf(psp->adev) && 1561e993ca4fSDaniel Wang (ucode->ucode_id == AMDGPU_UCODE_ID_SDMA0 1562e993ca4fSDaniel Wang || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 1563b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 1564b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3 1565b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA4 1566b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA5 1567b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA6 1568b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA7 1569c348ad46SJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_G 1570c348ad46SJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL 1571c348ad46SJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM 1572c2a801afSJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM 1573c2a801afSJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_SMC)) 1574e993ca4fSDaniel Wang /*skip ucode loading in SRIOV VF */ 157540e611bdSJohn Clements return true; 1576b86f8d8bSJohn Clements 1577119eb6dbSHawking Zhang if (psp->autoload_supported && 1578119eb6dbSHawking Zhang (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1_JT || 1579119eb6dbSHawking Zhang ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT)) 1580119eb6dbSHawking Zhang /* skip mec JT when autoload is enabled */ 158140e611bdSJohn Clements return true; 158240e611bdSJohn Clements 158340e611bdSJohn Clements return false; 158440e611bdSJohn Clements } 158540e611bdSJohn Clements 158640e611bdSJohn Clements static int psp_np_fw_load(struct psp_context *psp) 158740e611bdSJohn Clements { 158840e611bdSJohn Clements int i, ret; 158940e611bdSJohn Clements struct amdgpu_firmware_info *ucode; 159040e611bdSJohn Clements struct amdgpu_device* adev = psp->adev; 159140e611bdSJohn Clements 159240e611bdSJohn Clements if (psp->autoload_supported && 159340e611bdSJohn Clements !psp->pmfw_centralized_cstate_management) { 159440e611bdSJohn Clements ret = psp_load_smu_fw(psp); 159540e611bdSJohn Clements if (ret) 159640e611bdSJohn Clements return ret; 159740e611bdSJohn Clements } 159840e611bdSJohn Clements 159940e611bdSJohn Clements for (i = 0; i < adev->firmware.max_ucodes; i++) { 160040e611bdSJohn Clements ucode = &adev->firmware.ucode[i]; 160140e611bdSJohn Clements 160240e611bdSJohn Clements if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC && 160340e611bdSJohn Clements !fw_load_skip_check(psp, ucode)) { 160440e611bdSJohn Clements ret = psp_load_smu_fw(psp); 160540e611bdSJohn Clements if (ret) 160640e611bdSJohn Clements return ret; 160740e611bdSJohn Clements continue; 160840e611bdSJohn Clements } 160940e611bdSJohn Clements 161040e611bdSJohn Clements if (fw_load_skip_check(psp, ucode)) 1611119eb6dbSHawking Zhang continue; 16120e5ca0d1SHuang Rui 1613c5fb9126SXiaojie Yuan psp_print_fw_hdr(psp, ucode); 1614c5fb9126SXiaojie Yuan 161513169562SHuang Rui ret = psp_execute_np_fw_load(psp, ucode); 16160e5ca0d1SHuang Rui if (ret) 1617be70bbdaSHuang Rui return ret; 16180e5ca0d1SHuang Rui 16191a5b4ccaSHawking Zhang /* Start rlc autoload after psp recieved all the gfx firmware */ 16206de40f02SMonk Liu if (psp->autoload_supported && ucode->ucode_id == (amdgpu_sriov_vf(adev) ? 16210753e56eSEvan Quan AMDGPU_UCODE_ID_CP_MEC2 : AMDGPU_UCODE_ID_RLC_G)) { 16221a5b4ccaSHawking Zhang ret = psp_rlc_autoload(psp); 16231a5b4ccaSHawking Zhang if (ret) { 16241a5b4ccaSHawking Zhang DRM_ERROR("Failed to start rlc autoload\n"); 16251a5b4ccaSHawking Zhang return ret; 16261a5b4ccaSHawking Zhang } 16271a5b4ccaSHawking Zhang } 16280e5ca0d1SHuang Rui } 16290e5ca0d1SHuang Rui 1630be70bbdaSHuang Rui return 0; 1631be70bbdaSHuang Rui } 1632be70bbdaSHuang Rui 16330e5ca0d1SHuang Rui static int psp_load_fw(struct amdgpu_device *adev) 16340e5ca0d1SHuang Rui { 16350e5ca0d1SHuang Rui int ret; 16360e5ca0d1SHuang Rui struct psp_context *psp = &adev->psp; 16370e5ca0d1SHuang Rui 163853450efdSXiangliang Yu if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset) { 163914d20ec7Swentalou psp_ring_stop(psp, PSP_RING_TYPE__KM); /* should not destroy ring, only stop */ 164077a3c96bSMonk Liu goto skip_memalloc; 164153450efdSXiangliang Yu } 164277a3c96bSMonk Liu 164367bef0f7SHuang Rui psp->cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 164467bef0f7SHuang Rui if (!psp->cmd) 16450e5ca0d1SHuang Rui return -ENOMEM; 16460e5ca0d1SHuang Rui 164753a5cf57SHuang Rui ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, 164853a5cf57SHuang Rui AMDGPU_GEM_DOMAIN_GTT, 164953a5cf57SHuang Rui &psp->fw_pri_bo, 165053a5cf57SHuang Rui &psp->fw_pri_mc_addr, 165153a5cf57SHuang Rui &psp->fw_pri_buf); 16520e5ca0d1SHuang Rui if (ret) 16530e5ca0d1SHuang Rui goto failed; 16540e5ca0d1SHuang Rui 16550e5ca0d1SHuang Rui ret = amdgpu_bo_create_kernel(adev, PSP_FENCE_BUFFER_SIZE, PAGE_SIZE, 16560e5ca0d1SHuang Rui AMDGPU_GEM_DOMAIN_VRAM, 16570e5ca0d1SHuang Rui &psp->fence_buf_bo, 16580e5ca0d1SHuang Rui &psp->fence_buf_mc_addr, 16590e5ca0d1SHuang Rui &psp->fence_buf); 16600e5ca0d1SHuang Rui if (ret) 166137945a3aSEvan Quan goto failed; 1662a1952da7SHuang Rui 1663a1952da7SHuang Rui ret = amdgpu_bo_create_kernel(adev, PSP_CMD_BUFFER_SIZE, PAGE_SIZE, 1664a1952da7SHuang Rui AMDGPU_GEM_DOMAIN_VRAM, 1665a1952da7SHuang Rui &psp->cmd_buf_bo, &psp->cmd_buf_mc_addr, 1666a1952da7SHuang Rui (void **)&psp->cmd_buf_mem); 1667a1952da7SHuang Rui if (ret) 166837945a3aSEvan Quan goto failed; 16690e5ca0d1SHuang Rui 16700e5ca0d1SHuang Rui memset(psp->fence_buf, 0, PSP_FENCE_BUFFER_SIZE); 16710e5ca0d1SHuang Rui 1672be70bbdaSHuang Rui ret = psp_ring_init(psp, PSP_RING_TYPE__KM); 16737a3d7bf6SEvan Quan if (ret) { 16747a3d7bf6SEvan Quan DRM_ERROR("PSP ring init failed!\n"); 167537945a3aSEvan Quan goto failed; 16767a3d7bf6SEvan Quan } 16770e5ca0d1SHuang Rui 167877a3c96bSMonk Liu skip_memalloc: 1679be70bbdaSHuang Rui ret = psp_hw_start(psp); 16800e5ca0d1SHuang Rui if (ret) 168137945a3aSEvan Quan goto failed; 16820e5ca0d1SHuang Rui 1683be70bbdaSHuang Rui ret = psp_np_fw_load(psp); 16840e5ca0d1SHuang Rui if (ret) 168537945a3aSEvan Quan goto failed; 16860e5ca0d1SHuang Rui 16877091b60cSHawking Zhang ret = psp_asd_load(psp); 16887091b60cSHawking Zhang if (ret) { 16897091b60cSHawking Zhang DRM_ERROR("PSP load asd failed!\n"); 16907091b60cSHawking Zhang return ret; 16917091b60cSHawking Zhang } 16927091b60cSHawking Zhang 16937091b60cSHawking Zhang if (psp->adev->psp.ta_fw) { 16947091b60cSHawking Zhang ret = psp_ras_initialize(psp); 16957091b60cSHawking Zhang if (ret) 16967091b60cSHawking Zhang dev_err(psp->adev->dev, 16977091b60cSHawking Zhang "RAS: Failed to initialize RAS\n"); 16987091b60cSHawking Zhang 16997091b60cSHawking Zhang ret = psp_hdcp_initialize(psp); 17007091b60cSHawking Zhang if (ret) 17017091b60cSHawking Zhang dev_err(psp->adev->dev, 17027091b60cSHawking Zhang "HDCP: Failed to initialize HDCP\n"); 17037091b60cSHawking Zhang 17047091b60cSHawking Zhang ret = psp_dtm_initialize(psp); 17057091b60cSHawking Zhang if (ret) 17067091b60cSHawking Zhang dev_err(psp->adev->dev, 17077091b60cSHawking Zhang "DTM: Failed to initialize DTM\n"); 17087091b60cSHawking Zhang } 17097091b60cSHawking Zhang 17100e5ca0d1SHuang Rui return 0; 17110e5ca0d1SHuang Rui 17120e5ca0d1SHuang Rui failed: 171337945a3aSEvan Quan /* 171437945a3aSEvan Quan * all cleanup jobs (xgmi terminate, ras terminate, 171537945a3aSEvan Quan * ring destroy, cmd/fence/fw buffers destory, 171637945a3aSEvan Quan * psp->cmd destory) are delayed to psp_hw_fini 171737945a3aSEvan Quan */ 17180e5ca0d1SHuang Rui return ret; 17190e5ca0d1SHuang Rui } 17200e5ca0d1SHuang Rui 17210e5ca0d1SHuang Rui static int psp_hw_init(void *handle) 17220e5ca0d1SHuang Rui { 17230e5ca0d1SHuang Rui int ret; 17240e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 17250e5ca0d1SHuang Rui 17260e5ca0d1SHuang Rui mutex_lock(&adev->firmware.mutex); 17276e13bdf6SRex Zhu /* 17286e13bdf6SRex Zhu * This sequence is just used on hw_init only once, no need on 17296e13bdf6SRex Zhu * resume. 17306e13bdf6SRex Zhu */ 17316e13bdf6SRex Zhu ret = amdgpu_ucode_init_bo(adev); 17326e13bdf6SRex Zhu if (ret) 17336e13bdf6SRex Zhu goto failed; 17340e5ca0d1SHuang Rui 17350e5ca0d1SHuang Rui ret = psp_load_fw(adev); 17360e5ca0d1SHuang Rui if (ret) { 17370e5ca0d1SHuang Rui DRM_ERROR("PSP firmware loading failed\n"); 17380e5ca0d1SHuang Rui goto failed; 17390e5ca0d1SHuang Rui } 17400e5ca0d1SHuang Rui 17410e5ca0d1SHuang Rui mutex_unlock(&adev->firmware.mutex); 17420e5ca0d1SHuang Rui return 0; 17430e5ca0d1SHuang Rui 17440e5ca0d1SHuang Rui failed: 17450e5ca0d1SHuang Rui adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT; 17460e5ca0d1SHuang Rui mutex_unlock(&adev->firmware.mutex); 17470e5ca0d1SHuang Rui return -EINVAL; 17480e5ca0d1SHuang Rui } 17490e5ca0d1SHuang Rui 17500e5ca0d1SHuang Rui static int psp_hw_fini(void *handle) 17510e5ca0d1SHuang Rui { 17520e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 17530e5ca0d1SHuang Rui struct psp_context *psp = &adev->psp; 175412842d02STianci.Yin void *tmr_buf; 175512842d02STianci.Yin void **pptr; 17560e5ca0d1SHuang Rui 1757ed19a9a2SBhawanpreet Lakha if (psp->adev->psp.ta_fw) { 17585e5d3154Sxinhui pan psp_ras_terminate(psp); 1759143f2305SBhawanpreet Lakha psp_dtm_terminate(psp); 1760ed19a9a2SBhawanpreet Lakha psp_hdcp_terminate(psp); 1761ed19a9a2SBhawanpreet Lakha } 17625e5d3154Sxinhui pan 176371e5f0cbSHawking Zhang psp_asd_unload(psp); 176471e5f0cbSHawking Zhang 1765e3c5e982STrigger Huang psp_ring_destroy(psp, PSP_RING_TYPE__KM); 1766e3c5e982STrigger Huang 176712842d02STianci.Yin pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; 176812842d02STianci.Yin amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, pptr); 176953a5cf57SHuang Rui amdgpu_bo_free_kernel(&psp->fw_pri_bo, 177053a5cf57SHuang Rui &psp->fw_pri_mc_addr, &psp->fw_pri_buf); 1771b4de2c5aSHuang Rui amdgpu_bo_free_kernel(&psp->fence_buf_bo, 1772b4de2c5aSHuang Rui &psp->fence_buf_mc_addr, &psp->fence_buf); 1773a1952da7SHuang Rui amdgpu_bo_free_kernel(&psp->cmd_buf_bo, &psp->cmd_buf_mc_addr, 1774a1952da7SHuang Rui (void **)&psp->cmd_buf_mem); 1775b4de2c5aSHuang Rui 177667bef0f7SHuang Rui kfree(psp->cmd); 177767bef0f7SHuang Rui psp->cmd = NULL; 177867bef0f7SHuang Rui 17790e5ca0d1SHuang Rui return 0; 17800e5ca0d1SHuang Rui } 17810e5ca0d1SHuang Rui 17820e5ca0d1SHuang Rui static int psp_suspend(void *handle) 17830e5ca0d1SHuang Rui { 1784bcd6eab8SEvan Quan int ret; 1785bcd6eab8SEvan Quan struct amdgpu_device *adev = (struct amdgpu_device *)handle; 1786bcd6eab8SEvan Quan struct psp_context *psp = &adev->psp; 1787bcd6eab8SEvan Quan 17883e2e2ab5SHawking Zhang if (adev->gmc.xgmi.num_physical_nodes > 1 && 17893e2e2ab5SHawking Zhang psp->xgmi_context.initialized == 1) { 17903e2e2ab5SHawking Zhang ret = psp_xgmi_terminate(psp); 17913e2e2ab5SHawking Zhang if (ret) { 17923e2e2ab5SHawking Zhang DRM_ERROR("Failed to terminate xgmi ta\n"); 17933e2e2ab5SHawking Zhang return ret; 17943e2e2ab5SHawking Zhang } 17953e2e2ab5SHawking Zhang } 17963e2e2ab5SHawking Zhang 179754eb4ed6Sxinhui pan if (psp->adev->psp.ta_fw) { 17985e5d3154Sxinhui pan ret = psp_ras_terminate(psp); 17995e5d3154Sxinhui pan if (ret) { 18005e5d3154Sxinhui pan DRM_ERROR("Failed to terminate ras ta\n"); 18015e5d3154Sxinhui pan return ret; 18025e5d3154Sxinhui pan } 1803ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_terminate(psp); 1804ed19a9a2SBhawanpreet Lakha if (ret) { 1805ed19a9a2SBhawanpreet Lakha DRM_ERROR("Failed to terminate hdcp ta\n"); 1806ed19a9a2SBhawanpreet Lakha return ret; 1807ed19a9a2SBhawanpreet Lakha } 1808143f2305SBhawanpreet Lakha ret = psp_dtm_terminate(psp); 1809143f2305SBhawanpreet Lakha if (ret) { 1810143f2305SBhawanpreet Lakha DRM_ERROR("Failed to terminate dtm ta\n"); 1811143f2305SBhawanpreet Lakha return ret; 1812143f2305SBhawanpreet Lakha } 181354eb4ed6Sxinhui pan } 18145e5d3154Sxinhui pan 1815bcd6eab8SEvan Quan ret = psp_ring_stop(psp, PSP_RING_TYPE__KM); 1816bcd6eab8SEvan Quan if (ret) { 1817bcd6eab8SEvan Quan DRM_ERROR("PSP ring stop failed\n"); 1818bcd6eab8SEvan Quan return ret; 1819bcd6eab8SEvan Quan } 1820bcd6eab8SEvan Quan 18210e5ca0d1SHuang Rui return 0; 18220e5ca0d1SHuang Rui } 18230e5ca0d1SHuang Rui 18240e5ca0d1SHuang Rui static int psp_resume(void *handle) 18250e5ca0d1SHuang Rui { 18260e5ca0d1SHuang Rui int ret; 18270e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 182893ea9b9fSHuang Rui struct psp_context *psp = &adev->psp; 18290e5ca0d1SHuang Rui 183093ea9b9fSHuang Rui DRM_INFO("PSP is resuming...\n"); 183193ea9b9fSHuang Rui 18320586a059STianci.Yin ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME); 18330586a059STianci.Yin if (ret) { 18340586a059STianci.Yin DRM_ERROR("Failed to process memory training!\n"); 18350586a059STianci.Yin return ret; 18360586a059STianci.Yin } 18370586a059STianci.Yin 18380e5ca0d1SHuang Rui mutex_lock(&adev->firmware.mutex); 18390e5ca0d1SHuang Rui 184093ea9b9fSHuang Rui ret = psp_hw_start(psp); 18410e5ca0d1SHuang Rui if (ret) 184293ea9b9fSHuang Rui goto failed; 184393ea9b9fSHuang Rui 184493ea9b9fSHuang Rui ret = psp_np_fw_load(psp); 184593ea9b9fSHuang Rui if (ret) 184693ea9b9fSHuang Rui goto failed; 18470e5ca0d1SHuang Rui 18480d6f39bbSHawking Zhang ret = psp_asd_load(psp); 18490d6f39bbSHawking Zhang if (ret) { 18500d6f39bbSHawking Zhang DRM_ERROR("PSP load asd failed!\n"); 18510d6f39bbSHawking Zhang goto failed; 18520d6f39bbSHawking Zhang } 18530d6f39bbSHawking Zhang 18540d6f39bbSHawking Zhang if (adev->gmc.xgmi.num_physical_nodes > 1) { 18550d6f39bbSHawking Zhang ret = psp_xgmi_initialize(psp); 18560d6f39bbSHawking Zhang /* Warning the XGMI seesion initialize failure 18570d6f39bbSHawking Zhang * Instead of stop driver initialization 18580d6f39bbSHawking Zhang */ 18590d6f39bbSHawking Zhang if (ret) 18600d6f39bbSHawking Zhang dev_err(psp->adev->dev, 18610d6f39bbSHawking Zhang "XGMI: Failed to initialize XGMI session\n"); 18620d6f39bbSHawking Zhang } 18630d6f39bbSHawking Zhang 18640d6f39bbSHawking Zhang if (psp->adev->psp.ta_fw) { 18650d6f39bbSHawking Zhang ret = psp_ras_initialize(psp); 18660d6f39bbSHawking Zhang if (ret) 18670d6f39bbSHawking Zhang dev_err(psp->adev->dev, 18680d6f39bbSHawking Zhang "RAS: Failed to initialize RAS\n"); 18690d6f39bbSHawking Zhang 18700d6f39bbSHawking Zhang ret = psp_hdcp_initialize(psp); 18710d6f39bbSHawking Zhang if (ret) 18720d6f39bbSHawking Zhang dev_err(psp->adev->dev, 18730d6f39bbSHawking Zhang "HDCP: Failed to initialize HDCP\n"); 18740d6f39bbSHawking Zhang 18750d6f39bbSHawking Zhang ret = psp_dtm_initialize(psp); 18760d6f39bbSHawking Zhang if (ret) 18770d6f39bbSHawking Zhang dev_err(psp->adev->dev, 18780d6f39bbSHawking Zhang "DTM: Failed to initialize DTM\n"); 18790d6f39bbSHawking Zhang } 18800d6f39bbSHawking Zhang 18810e5ca0d1SHuang Rui mutex_unlock(&adev->firmware.mutex); 18820e5ca0d1SHuang Rui 188393ea9b9fSHuang Rui return 0; 188493ea9b9fSHuang Rui 188593ea9b9fSHuang Rui failed: 188693ea9b9fSHuang Rui DRM_ERROR("PSP resume failed\n"); 188793ea9b9fSHuang Rui mutex_unlock(&adev->firmware.mutex); 18880e5ca0d1SHuang Rui return ret; 18890e5ca0d1SHuang Rui } 18900e5ca0d1SHuang Rui 1891f75a9a5dSAlex Deucher int psp_gpu_reset(struct amdgpu_device *adev) 189298512bb8SKen Wang { 189332eaeae0SAlex Deucher int ret; 189432eaeae0SAlex Deucher 18952d4f9020SHuang Rui if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 18962d4f9020SHuang Rui return 0; 18972d4f9020SHuang Rui 189832eaeae0SAlex Deucher mutex_lock(&adev->psp.mutex); 189932eaeae0SAlex Deucher ret = psp_mode1_reset(&adev->psp); 190032eaeae0SAlex Deucher mutex_unlock(&adev->psp.mutex); 190132eaeae0SAlex Deucher 190232eaeae0SAlex Deucher return ret; 190398512bb8SKen Wang } 190498512bb8SKen Wang 19051a5b4ccaSHawking Zhang int psp_rlc_autoload_start(struct psp_context *psp) 19061a5b4ccaSHawking Zhang { 19071a5b4ccaSHawking Zhang int ret; 19081a5b4ccaSHawking Zhang struct psp_gfx_cmd_resp *cmd; 19091a5b4ccaSHawking Zhang 19101a5b4ccaSHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 19111a5b4ccaSHawking Zhang if (!cmd) 19121a5b4ccaSHawking Zhang return -ENOMEM; 19131a5b4ccaSHawking Zhang 19141a5b4ccaSHawking Zhang cmd->cmd_id = GFX_CMD_ID_AUTOLOAD_RLC; 19151a5b4ccaSHawking Zhang 19161a5b4ccaSHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 19171a5b4ccaSHawking Zhang psp->fence_buf_mc_addr); 19181a5b4ccaSHawking Zhang kfree(cmd); 19191a5b4ccaSHawking Zhang return ret; 19201a5b4ccaSHawking Zhang } 19211a5b4ccaSHawking Zhang 192286ddf352SJack Xiao int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx, 192386ddf352SJack Xiao uint64_t cmd_gpu_addr, int cmd_size) 192486ddf352SJack Xiao { 192586ddf352SJack Xiao struct amdgpu_firmware_info ucode = {0}; 192686ddf352SJack Xiao 192786ddf352SJack Xiao ucode.ucode_id = inst_idx ? AMDGPU_UCODE_ID_VCN1_RAM : 192886ddf352SJack Xiao AMDGPU_UCODE_ID_VCN0_RAM; 192986ddf352SJack Xiao ucode.mc_addr = cmd_gpu_addr; 193086ddf352SJack Xiao ucode.ucode_size = cmd_size; 193186ddf352SJack Xiao 193286ddf352SJack Xiao return psp_execute_np_fw_load(&adev->psp, &ucode); 193386ddf352SJack Xiao } 193486ddf352SJack Xiao 1935cc65176eSHawking Zhang int psp_ring_cmd_submit(struct psp_context *psp, 1936cc65176eSHawking Zhang uint64_t cmd_buf_mc_addr, 1937cc65176eSHawking Zhang uint64_t fence_mc_addr, 1938cc65176eSHawking Zhang int index) 1939cc65176eSHawking Zhang { 1940cc65176eSHawking Zhang unsigned int psp_write_ptr_reg = 0; 19412e77541bSColin Ian King struct psp_gfx_rb_frame *write_frame; 1942cc65176eSHawking Zhang struct psp_ring *ring = &psp->km_ring; 1943cc65176eSHawking Zhang struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; 1944cc65176eSHawking Zhang struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + 1945cc65176eSHawking Zhang ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; 1946cc65176eSHawking Zhang struct amdgpu_device *adev = psp->adev; 1947cc65176eSHawking Zhang uint32_t ring_size_dw = ring->ring_size / 4; 1948cc65176eSHawking Zhang uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; 1949cc65176eSHawking Zhang 1950cc65176eSHawking Zhang /* KM (GPCOM) prepare write pointer */ 1951cc65176eSHawking Zhang psp_write_ptr_reg = psp_ring_get_wptr(psp); 1952cc65176eSHawking Zhang 1953cc65176eSHawking Zhang /* Update KM RB frame pointer to new frame */ 1954cc65176eSHawking Zhang /* write_frame ptr increments by size of rb_frame in bytes */ 1955cc65176eSHawking Zhang /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ 1956cc65176eSHawking Zhang if ((psp_write_ptr_reg % ring_size_dw) == 0) 1957cc65176eSHawking Zhang write_frame = ring_buffer_start; 1958cc65176eSHawking Zhang else 1959cc65176eSHawking Zhang write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); 1960cc65176eSHawking Zhang /* Check invalid write_frame ptr address */ 1961cc65176eSHawking Zhang if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { 1962cc65176eSHawking Zhang DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", 1963cc65176eSHawking Zhang ring_buffer_start, ring_buffer_end, write_frame); 1964cc65176eSHawking Zhang DRM_ERROR("write_frame is pointing to address out of bounds\n"); 1965cc65176eSHawking Zhang return -EINVAL; 1966cc65176eSHawking Zhang } 1967cc65176eSHawking Zhang 1968cc65176eSHawking Zhang /* Initialize KM RB frame */ 1969cc65176eSHawking Zhang memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); 1970cc65176eSHawking Zhang 1971cc65176eSHawking Zhang /* Update KM RB frame */ 1972cc65176eSHawking Zhang write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); 1973cc65176eSHawking Zhang write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); 1974cc65176eSHawking Zhang write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); 1975cc65176eSHawking Zhang write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); 1976cc65176eSHawking Zhang write_frame->fence_value = index; 1977cc65176eSHawking Zhang amdgpu_asic_flush_hdp(adev, NULL); 1978cc65176eSHawking Zhang 1979cc65176eSHawking Zhang /* Update the write Pointer in DWORDs */ 1980cc65176eSHawking Zhang psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; 1981cc65176eSHawking Zhang psp_ring_set_wptr(psp, psp_write_ptr_reg); 1982cc65176eSHawking Zhang return 0; 1983cc65176eSHawking Zhang } 1984cc65176eSHawking Zhang 1985dc7195f6SHawking Zhang int psp_init_asd_microcode(struct psp_context *psp, 1986dc7195f6SHawking Zhang const char *chip_name) 1987dc7195f6SHawking Zhang { 1988dc7195f6SHawking Zhang struct amdgpu_device *adev = psp->adev; 1989dc7195f6SHawking Zhang char fw_name[30]; 1990dc7195f6SHawking Zhang const struct psp_firmware_header_v1_0 *asd_hdr; 1991dc7195f6SHawking Zhang int err = 0; 1992dc7195f6SHawking Zhang 1993dc7195f6SHawking Zhang if (!chip_name) { 1994dc7195f6SHawking Zhang dev_err(adev->dev, "invalid chip name for asd microcode\n"); 1995dc7195f6SHawking Zhang return -EINVAL; 1996dc7195f6SHawking Zhang } 1997dc7195f6SHawking Zhang 1998dc7195f6SHawking Zhang snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name); 1999dc7195f6SHawking Zhang err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev); 2000dc7195f6SHawking Zhang if (err) 2001dc7195f6SHawking Zhang goto out; 2002dc7195f6SHawking Zhang 2003dc7195f6SHawking Zhang err = amdgpu_ucode_validate(adev->psp.asd_fw); 2004dc7195f6SHawking Zhang if (err) 2005dc7195f6SHawking Zhang goto out; 2006dc7195f6SHawking Zhang 2007dc7195f6SHawking Zhang asd_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data; 2008dc7195f6SHawking Zhang adev->psp.asd_fw_version = le32_to_cpu(asd_hdr->header.ucode_version); 2009dc7195f6SHawking Zhang adev->psp.asd_feature_version = le32_to_cpu(asd_hdr->ucode_feature_version); 2010dc7195f6SHawking Zhang adev->psp.asd_ucode_size = le32_to_cpu(asd_hdr->header.ucode_size_bytes); 2011dc7195f6SHawking Zhang adev->psp.asd_start_addr = (uint8_t *)asd_hdr + 2012dc7195f6SHawking Zhang le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes); 2013dc7195f6SHawking Zhang return 0; 2014dc7195f6SHawking Zhang out: 2015dc7195f6SHawking Zhang dev_err(adev->dev, "fail to initialize asd microcode\n"); 2016dc7195f6SHawking Zhang release_firmware(adev->psp.asd_fw); 2017dc7195f6SHawking Zhang adev->psp.asd_fw = NULL; 2018dc7195f6SHawking Zhang return err; 2019dc7195f6SHawking Zhang } 2020dc7195f6SHawking Zhang 20211c301f44SHawking Zhang int psp_init_sos_microcode(struct psp_context *psp, 20221c301f44SHawking Zhang const char *chip_name) 20231c301f44SHawking Zhang { 20241c301f44SHawking Zhang struct amdgpu_device *adev = psp->adev; 20251c301f44SHawking Zhang char fw_name[30]; 20261c301f44SHawking Zhang const struct psp_firmware_header_v1_0 *sos_hdr; 20271c301f44SHawking Zhang const struct psp_firmware_header_v1_1 *sos_hdr_v1_1; 20281c301f44SHawking Zhang const struct psp_firmware_header_v1_2 *sos_hdr_v1_2; 20291c301f44SHawking Zhang int err = 0; 20301c301f44SHawking Zhang 20311c301f44SHawking Zhang if (!chip_name) { 20321c301f44SHawking Zhang dev_err(adev->dev, "invalid chip name for sos microcode\n"); 20331c301f44SHawking Zhang return -EINVAL; 20341c301f44SHawking Zhang } 20351c301f44SHawking Zhang 20361c301f44SHawking Zhang snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sos.bin", chip_name); 20371c301f44SHawking Zhang err = request_firmware(&adev->psp.sos_fw, fw_name, adev->dev); 20381c301f44SHawking Zhang if (err) 20391c301f44SHawking Zhang goto out; 20401c301f44SHawking Zhang 20411c301f44SHawking Zhang err = amdgpu_ucode_validate(adev->psp.sos_fw); 20421c301f44SHawking Zhang if (err) 20431c301f44SHawking Zhang goto out; 20441c301f44SHawking Zhang 20451c301f44SHawking Zhang sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; 20461c301f44SHawking Zhang amdgpu_ucode_print_psp_hdr(&sos_hdr->header); 20471c301f44SHawking Zhang 20481c301f44SHawking Zhang switch (sos_hdr->header.header_version_major) { 20491c301f44SHawking Zhang case 1: 20501c301f44SHawking Zhang adev->psp.sos_fw_version = le32_to_cpu(sos_hdr->header.ucode_version); 20511c301f44SHawking Zhang adev->psp.sos_feature_version = le32_to_cpu(sos_hdr->ucode_feature_version); 20521c301f44SHawking Zhang adev->psp.sos_bin_size = le32_to_cpu(sos_hdr->sos_size_bytes); 20531c301f44SHawking Zhang adev->psp.sys_bin_size = le32_to_cpu(sos_hdr->sos_offset_bytes); 20541c301f44SHawking Zhang adev->psp.sys_start_addr = (uint8_t *)sos_hdr + 20551c301f44SHawking Zhang le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes); 20561c301f44SHawking Zhang adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr + 20571c301f44SHawking Zhang le32_to_cpu(sos_hdr->sos_offset_bytes); 20581c301f44SHawking Zhang if (sos_hdr->header.header_version_minor == 1) { 20591c301f44SHawking Zhang sos_hdr_v1_1 = (const struct psp_firmware_header_v1_1 *)adev->psp.sos_fw->data; 20601c301f44SHawking Zhang adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_1->toc_size_bytes); 20611c301f44SHawking Zhang adev->psp.toc_start_addr = (uint8_t *)adev->psp.sys_start_addr + 20621c301f44SHawking Zhang le32_to_cpu(sos_hdr_v1_1->toc_offset_bytes); 20631c301f44SHawking Zhang adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_1->kdb_size_bytes); 20641c301f44SHawking Zhang adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + 20651c301f44SHawking Zhang le32_to_cpu(sos_hdr_v1_1->kdb_offset_bytes); 20661c301f44SHawking Zhang } 20671c301f44SHawking Zhang if (sos_hdr->header.header_version_minor == 2) { 20681c301f44SHawking Zhang sos_hdr_v1_2 = (const struct psp_firmware_header_v1_2 *)adev->psp.sos_fw->data; 20691c301f44SHawking Zhang adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_2->kdb_size_bytes); 20701c301f44SHawking Zhang adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + 20711c301f44SHawking Zhang le32_to_cpu(sos_hdr_v1_2->kdb_offset_bytes); 20721c301f44SHawking Zhang } 20731c301f44SHawking Zhang break; 20741c301f44SHawking Zhang default: 20751c301f44SHawking Zhang dev_err(adev->dev, 20761c301f44SHawking Zhang "unsupported psp sos firmware\n"); 20771c301f44SHawking Zhang err = -EINVAL; 20781c301f44SHawking Zhang goto out; 20791c301f44SHawking Zhang } 20801c301f44SHawking Zhang 20811c301f44SHawking Zhang return 0; 20821c301f44SHawking Zhang out: 20831c301f44SHawking Zhang dev_err(adev->dev, 20841c301f44SHawking Zhang "failed to init sos firmware\n"); 20851c301f44SHawking Zhang release_firmware(adev->psp.sos_fw); 20861c301f44SHawking Zhang adev->psp.sos_fw = NULL; 20871c301f44SHawking Zhang 20881c301f44SHawking Zhang return err; 20891c301f44SHawking Zhang } 20901c301f44SHawking Zhang 20910e5ca0d1SHuang Rui static int psp_set_clockgating_state(void *handle, 20920e5ca0d1SHuang Rui enum amd_clockgating_state state) 20930e5ca0d1SHuang Rui { 20940e5ca0d1SHuang Rui return 0; 20950e5ca0d1SHuang Rui } 20960e5ca0d1SHuang Rui 20970e5ca0d1SHuang Rui static int psp_set_powergating_state(void *handle, 20980e5ca0d1SHuang Rui enum amd_powergating_state state) 20990e5ca0d1SHuang Rui { 21000e5ca0d1SHuang Rui return 0; 21010e5ca0d1SHuang Rui } 21020e5ca0d1SHuang Rui 210357430471SAndrey Grodzovsky static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev, 210457430471SAndrey Grodzovsky struct device_attribute *attr, 210557430471SAndrey Grodzovsky char *buf) 210657430471SAndrey Grodzovsky { 210757430471SAndrey Grodzovsky struct drm_device *ddev = dev_get_drvdata(dev); 210857430471SAndrey Grodzovsky struct amdgpu_device *adev = ddev->dev_private; 210957430471SAndrey Grodzovsky uint32_t fw_ver; 211057430471SAndrey Grodzovsky int ret; 211157430471SAndrey Grodzovsky 211290f88cddSAndrey Grodzovsky if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) { 211390f88cddSAndrey Grodzovsky DRM_INFO("PSP block is not ready yet."); 211490f88cddSAndrey Grodzovsky return -EBUSY; 211590f88cddSAndrey Grodzovsky } 211690f88cddSAndrey Grodzovsky 211757430471SAndrey Grodzovsky mutex_lock(&adev->psp.mutex); 211857430471SAndrey Grodzovsky ret = psp_read_usbc_pd_fw(&adev->psp, &fw_ver); 211957430471SAndrey Grodzovsky mutex_unlock(&adev->psp.mutex); 212057430471SAndrey Grodzovsky 212157430471SAndrey Grodzovsky if (ret) { 212257430471SAndrey Grodzovsky DRM_ERROR("Failed to read USBC PD FW, err = %d", ret); 212357430471SAndrey Grodzovsky return ret; 212457430471SAndrey Grodzovsky } 212557430471SAndrey Grodzovsky 212657430471SAndrey Grodzovsky return snprintf(buf, PAGE_SIZE, "%x\n", fw_ver); 212757430471SAndrey Grodzovsky } 212857430471SAndrey Grodzovsky 212957430471SAndrey Grodzovsky static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, 213057430471SAndrey Grodzovsky struct device_attribute *attr, 213157430471SAndrey Grodzovsky const char *buf, 213257430471SAndrey Grodzovsky size_t count) 213357430471SAndrey Grodzovsky { 213457430471SAndrey Grodzovsky struct drm_device *ddev = dev_get_drvdata(dev); 213557430471SAndrey Grodzovsky struct amdgpu_device *adev = ddev->dev_private; 213657430471SAndrey Grodzovsky void *cpu_addr; 213757430471SAndrey Grodzovsky dma_addr_t dma_addr; 213857430471SAndrey Grodzovsky int ret; 213957430471SAndrey Grodzovsky char fw_name[100]; 214057430471SAndrey Grodzovsky const struct firmware *usbc_pd_fw; 214157430471SAndrey Grodzovsky 214290f88cddSAndrey Grodzovsky if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) { 214390f88cddSAndrey Grodzovsky DRM_INFO("PSP block is not ready yet."); 214490f88cddSAndrey Grodzovsky return -EBUSY; 214590f88cddSAndrey Grodzovsky } 214657430471SAndrey Grodzovsky 214757430471SAndrey Grodzovsky snprintf(fw_name, sizeof(fw_name), "amdgpu/%s", buf); 214857430471SAndrey Grodzovsky ret = request_firmware(&usbc_pd_fw, fw_name, adev->dev); 214957430471SAndrey Grodzovsky if (ret) 215057430471SAndrey Grodzovsky goto fail; 215157430471SAndrey Grodzovsky 215257430471SAndrey Grodzovsky /* We need contiguous physical mem to place the FW for psp to access */ 215357430471SAndrey Grodzovsky cpu_addr = dma_alloc_coherent(adev->dev, usbc_pd_fw->size, &dma_addr, GFP_KERNEL); 215457430471SAndrey Grodzovsky 215557430471SAndrey Grodzovsky ret = dma_mapping_error(adev->dev, dma_addr); 215657430471SAndrey Grodzovsky if (ret) 215757430471SAndrey Grodzovsky goto rel_buf; 215857430471SAndrey Grodzovsky 215957430471SAndrey Grodzovsky memcpy_toio(cpu_addr, usbc_pd_fw->data, usbc_pd_fw->size); 216057430471SAndrey Grodzovsky 21616863d607SAndrey Grodzovsky /* 21626863d607SAndrey Grodzovsky * x86 specific workaround. 21636863d607SAndrey Grodzovsky * Without it the buffer is invisible in PSP. 21646863d607SAndrey Grodzovsky * 21656863d607SAndrey Grodzovsky * TODO Remove once PSP starts snooping CPU cache 21666863d607SAndrey Grodzovsky */ 21676863d607SAndrey Grodzovsky #ifdef CONFIG_X86 216857430471SAndrey Grodzovsky clflush_cache_range(cpu_addr, (usbc_pd_fw->size & ~(L1_CACHE_BYTES - 1))); 21696863d607SAndrey Grodzovsky #endif 217057430471SAndrey Grodzovsky 217157430471SAndrey Grodzovsky mutex_lock(&adev->psp.mutex); 217257430471SAndrey Grodzovsky ret = psp_load_usbc_pd_fw(&adev->psp, dma_addr); 217357430471SAndrey Grodzovsky mutex_unlock(&adev->psp.mutex); 217457430471SAndrey Grodzovsky 217557430471SAndrey Grodzovsky rel_buf: 217657430471SAndrey Grodzovsky dma_free_coherent(adev->dev, usbc_pd_fw->size, cpu_addr, dma_addr); 217757430471SAndrey Grodzovsky release_firmware(usbc_pd_fw); 217857430471SAndrey Grodzovsky 217957430471SAndrey Grodzovsky fail: 218057430471SAndrey Grodzovsky if (ret) { 218157430471SAndrey Grodzovsky DRM_ERROR("Failed to load USBC PD FW, err = %d", ret); 218257430471SAndrey Grodzovsky return ret; 218357430471SAndrey Grodzovsky } 218457430471SAndrey Grodzovsky 218557430471SAndrey Grodzovsky return count; 218657430471SAndrey Grodzovsky } 218757430471SAndrey Grodzovsky 218857430471SAndrey Grodzovsky static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR, 218957430471SAndrey Grodzovsky psp_usbc_pd_fw_sysfs_read, 219057430471SAndrey Grodzovsky psp_usbc_pd_fw_sysfs_write); 219157430471SAndrey Grodzovsky 219257430471SAndrey Grodzovsky 219357430471SAndrey Grodzovsky 21940e5ca0d1SHuang Rui const struct amd_ip_funcs psp_ip_funcs = { 21950e5ca0d1SHuang Rui .name = "psp", 21960e5ca0d1SHuang Rui .early_init = psp_early_init, 219790f88cddSAndrey Grodzovsky .late_init = NULL, 21980e5ca0d1SHuang Rui .sw_init = psp_sw_init, 21990e5ca0d1SHuang Rui .sw_fini = psp_sw_fini, 22000e5ca0d1SHuang Rui .hw_init = psp_hw_init, 22010e5ca0d1SHuang Rui .hw_fini = psp_hw_fini, 22020e5ca0d1SHuang Rui .suspend = psp_suspend, 22030e5ca0d1SHuang Rui .resume = psp_resume, 22040e5ca0d1SHuang Rui .is_idle = NULL, 2205f75a9a5dSAlex Deucher .check_soft_reset = NULL, 22060e5ca0d1SHuang Rui .wait_for_idle = NULL, 2207f75a9a5dSAlex Deucher .soft_reset = NULL, 22080e5ca0d1SHuang Rui .set_clockgating_state = psp_set_clockgating_state, 22090e5ca0d1SHuang Rui .set_powergating_state = psp_set_powergating_state, 22100e5ca0d1SHuang Rui }; 22110e5ca0d1SHuang Rui 221257430471SAndrey Grodzovsky static int psp_sysfs_init(struct amdgpu_device *adev) 221357430471SAndrey Grodzovsky { 221457430471SAndrey Grodzovsky int ret = device_create_file(adev->dev, &dev_attr_usbc_pd_fw); 221557430471SAndrey Grodzovsky 221657430471SAndrey Grodzovsky if (ret) 221757430471SAndrey Grodzovsky DRM_ERROR("Failed to create USBC PD FW control file!"); 221857430471SAndrey Grodzovsky 221957430471SAndrey Grodzovsky return ret; 222057430471SAndrey Grodzovsky } 222157430471SAndrey Grodzovsky 222257430471SAndrey Grodzovsky static void psp_sysfs_fini(struct amdgpu_device *adev) 222357430471SAndrey Grodzovsky { 222457430471SAndrey Grodzovsky device_remove_file(adev->dev, &dev_attr_usbc_pd_fw); 222557430471SAndrey Grodzovsky } 222657430471SAndrey Grodzovsky 22270e5ca0d1SHuang Rui const struct amdgpu_ip_block_version psp_v3_1_ip_block = 22280e5ca0d1SHuang Rui { 22290e5ca0d1SHuang Rui .type = AMD_IP_BLOCK_TYPE_PSP, 22300e5ca0d1SHuang Rui .major = 3, 22310e5ca0d1SHuang Rui .minor = 1, 22320e5ca0d1SHuang Rui .rev = 0, 22330e5ca0d1SHuang Rui .funcs = &psp_ip_funcs, 22340e5ca0d1SHuang Rui }; 2235dfbd6438SHuang Rui 2236dfbd6438SHuang Rui const struct amdgpu_ip_block_version psp_v10_0_ip_block = 2237dfbd6438SHuang Rui { 2238dfbd6438SHuang Rui .type = AMD_IP_BLOCK_TYPE_PSP, 2239dfbd6438SHuang Rui .major = 10, 2240dfbd6438SHuang Rui .minor = 0, 2241dfbd6438SHuang Rui .rev = 0, 2242dfbd6438SHuang Rui .funcs = &psp_ip_funcs, 2243dfbd6438SHuang Rui }; 2244654f761cSFeifei Xu 2245654f761cSFeifei Xu const struct amdgpu_ip_block_version psp_v11_0_ip_block = 2246654f761cSFeifei Xu { 2247654f761cSFeifei Xu .type = AMD_IP_BLOCK_TYPE_PSP, 2248654f761cSFeifei Xu .major = 11, 2249654f761cSFeifei Xu .minor = 0, 2250654f761cSFeifei Xu .rev = 0, 2251654f761cSFeifei Xu .funcs = &psp_ip_funcs, 2252654f761cSFeifei Xu }; 22536a7a0bdbSAaron Liu 22546a7a0bdbSAaron Liu const struct amdgpu_ip_block_version psp_v12_0_ip_block = 22556a7a0bdbSAaron Liu { 22566a7a0bdbSAaron Liu .type = AMD_IP_BLOCK_TYPE_PSP, 22576a7a0bdbSAaron Liu .major = 12, 22586a7a0bdbSAaron Liu .minor = 0, 22596a7a0bdbSAaron Liu .rev = 0, 22606a7a0bdbSAaron Liu .funcs = &psp_ip_funcs, 22616a7a0bdbSAaron Liu }; 2262