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> 28f89f8c6bSAndrey Grodzovsky #include <drm/drm_drv.h> 29fdf2f6c5SSam Ravnborg 300e5ca0d1SHuang Rui #include "amdgpu.h" 310e5ca0d1SHuang Rui #include "amdgpu_psp.h" 320e5ca0d1SHuang Rui #include "amdgpu_ucode.h" 330e5ca0d1SHuang Rui #include "soc15_common.h" 340e5ca0d1SHuang Rui #include "psp_v3_1.h" 35c1798b54SHuang Rui #include "psp_v10_0.h" 36654f761cSFeifei Xu #include "psp_v11_0.h" 376a7a0bdbSAaron Liu #include "psp_v12_0.h" 38ee821083SHawking Zhang #include "psp_v13_0.h" 390e5ca0d1SHuang Rui 40bff77e86SLe Ma #include "amdgpu_ras.h" 41ecaafb7bSJinzhou Su #include "amdgpu_securedisplay.h" 42c6a11133SHawking Zhang #include "amdgpu_atomfirmware.h" 43bff77e86SLe Ma 44f89f8c6bSAndrey Grodzovsky #include <drm/drm_drv.h> 45f89f8c6bSAndrey Grodzovsky 4657430471SAndrey Grodzovsky static int psp_sysfs_init(struct amdgpu_device *adev); 4757430471SAndrey Grodzovsky static void psp_sysfs_fini(struct amdgpu_device *adev); 4857430471SAndrey Grodzovsky 4940e611bdSJohn Clements static int psp_load_smu_fw(struct psp_context *psp); 5040e611bdSJohn Clements 51995da6ccSEvan Quan /* 52995da6ccSEvan Quan * Due to DF Cstate management centralized to PMFW, the firmware 53995da6ccSEvan Quan * loading sequence will be updated as below: 54995da6ccSEvan Quan * - Load KDB 55995da6ccSEvan Quan * - Load SYS_DRV 56995da6ccSEvan Quan * - Load tOS 57995da6ccSEvan Quan * - Load PMFW 58995da6ccSEvan Quan * - Setup TMR 59995da6ccSEvan Quan * - Load other non-psp fw 60995da6ccSEvan Quan * - Load ASD 61995da6ccSEvan Quan * - Load XGMI/RAS/HDCP/DTM TA if any 62995da6ccSEvan Quan * 63995da6ccSEvan Quan * This new sequence is required for 64b335f289SHawking Zhang * - Arcturus and onwards 65995da6ccSEvan Quan * - Navi12 and onwards 66995da6ccSEvan Quan */ 67995da6ccSEvan Quan static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp) 68995da6ccSEvan Quan { 69995da6ccSEvan Quan struct amdgpu_device *adev = psp->adev; 70995da6ccSEvan Quan 71995da6ccSEvan Quan psp->pmfw_centralized_cstate_management = false; 72995da6ccSEvan Quan 73995da6ccSEvan Quan if (amdgpu_sriov_vf(adev)) 74995da6ccSEvan Quan return; 75995da6ccSEvan Quan 76995da6ccSEvan Quan if (adev->flags & AMD_IS_APU) 77995da6ccSEvan Quan return; 78995da6ccSEvan Quan 79b335f289SHawking Zhang if ((adev->asic_type >= CHIP_ARCTURUS) || 80995da6ccSEvan Quan (adev->asic_type >= CHIP_NAVI12)) 81995da6ccSEvan Quan psp->pmfw_centralized_cstate_management = true; 82995da6ccSEvan Quan } 83995da6ccSEvan Quan 840e5ca0d1SHuang Rui static int psp_early_init(void *handle) 850e5ca0d1SHuang Rui { 860e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 879d6fea57SAlex Deucher struct psp_context *psp = &adev->psp; 880e5ca0d1SHuang Rui 890e5ca0d1SHuang Rui switch (adev->asic_type) { 900e5ca0d1SHuang Rui case CHIP_VEGA10: 91ff13dc67SAlex Deucher case CHIP_VEGA12: 92e7f9ccb4SAlex Deucher psp_v3_1_set_psp_funcs(psp); 931d1f41cfSHawking Zhang psp->autoload_supported = false; 940e5ca0d1SHuang Rui break; 95c1798b54SHuang Rui case CHIP_RAVEN: 96e7f9ccb4SAlex Deucher psp_v10_0_set_psp_funcs(psp); 971d1f41cfSHawking Zhang psp->autoload_supported = false; 98c1798b54SHuang Rui break; 99654f761cSFeifei Xu case CHIP_VEGA20: 100f36d9ab9SJohn Clements case CHIP_ARCTURUS: 1011d1f41cfSHawking Zhang psp_v11_0_set_psp_funcs(psp); 1021d1f41cfSHawking Zhang psp->autoload_supported = false; 1031d1f41cfSHawking Zhang break; 104bc290fe5STao Zhou case CHIP_NAVI10: 10582522b2dSXiaojie Yuan case CHIP_NAVI14: 106739cdbd6SXiaojie Yuan case CHIP_NAVI12: 107344fed0bSLikun Gao case CHIP_SIENNA_CICHLID: 108c82b38ecSJiansong Chen case CHIP_NAVY_FLOUNDER: 109ed3b7353SHuang Rui case CHIP_VANGOGH: 110462c272bSTao Zhou case CHIP_DIMGREY_CAVEFISH: 111c0729819SChengming Gui case CHIP_BEIGE_GOBY: 112654f761cSFeifei Xu psp_v11_0_set_psp_funcs(psp); 1131d1f41cfSHawking Zhang psp->autoload_supported = true; 114654f761cSFeifei Xu break; 1156a7a0bdbSAaron Liu case CHIP_RENOIR: 1166a7a0bdbSAaron Liu psp_v12_0_set_psp_funcs(psp); 1176a7a0bdbSAaron Liu break; 118ee821083SHawking Zhang case CHIP_ALDEBARAN: 119ee821083SHawking Zhang psp_v13_0_set_psp_funcs(psp); 120ee821083SHawking Zhang break; 121903bb18bSAaron Liu case CHIP_YELLOW_CARP: 122903bb18bSAaron Liu psp_v13_0_set_psp_funcs(psp); 123903bb18bSAaron Liu psp->autoload_supported = true; 124903bb18bSAaron Liu break; 1250e5ca0d1SHuang Rui default: 1260e5ca0d1SHuang Rui return -EINVAL; 1270e5ca0d1SHuang Rui } 1280e5ca0d1SHuang Rui 1290e5ca0d1SHuang Rui psp->adev = adev; 1300e5ca0d1SHuang Rui 131995da6ccSEvan Quan psp_check_pmfw_centralized_cstate_management(psp); 132995da6ccSEvan Quan 1339d6fea57SAlex Deucher return 0; 1349d6fea57SAlex Deucher } 1359d6fea57SAlex Deucher 136963cee55SLikun Gao static void psp_memory_training_fini(struct psp_context *psp) 137963cee55SLikun Gao { 138963cee55SLikun Gao struct psp_memory_training_context *ctx = &psp->mem_train_ctx; 139963cee55SLikun Gao 140963cee55SLikun Gao ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT; 141963cee55SLikun Gao kfree(ctx->sys_cache); 142963cee55SLikun Gao ctx->sys_cache = NULL; 143963cee55SLikun Gao } 144963cee55SLikun Gao 145963cee55SLikun Gao static int psp_memory_training_init(struct psp_context *psp) 146963cee55SLikun Gao { 147963cee55SLikun Gao int ret; 148963cee55SLikun Gao struct psp_memory_training_context *ctx = &psp->mem_train_ctx; 149963cee55SLikun Gao 150963cee55SLikun Gao if (ctx->init != PSP_MEM_TRAIN_RESERVE_SUCCESS) { 151963cee55SLikun Gao DRM_DEBUG("memory training is not supported!\n"); 152963cee55SLikun Gao return 0; 153963cee55SLikun Gao } 154963cee55SLikun Gao 155963cee55SLikun Gao ctx->sys_cache = kzalloc(ctx->train_data_size, GFP_KERNEL); 156963cee55SLikun Gao if (ctx->sys_cache == NULL) { 157963cee55SLikun Gao DRM_ERROR("alloc mem_train_ctx.sys_cache failed!\n"); 158963cee55SLikun Gao ret = -ENOMEM; 159963cee55SLikun Gao goto Err_out; 160963cee55SLikun Gao } 161963cee55SLikun Gao 162963cee55SLikun Gao DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n", 163963cee55SLikun Gao ctx->train_data_size, 164963cee55SLikun Gao ctx->p2c_train_data_offset, 165963cee55SLikun Gao ctx->c2p_train_data_offset); 166963cee55SLikun Gao ctx->init = PSP_MEM_TRAIN_INIT_SUCCESS; 167963cee55SLikun Gao return 0; 168963cee55SLikun Gao 169963cee55SLikun Gao Err_out: 170963cee55SLikun Gao psp_memory_training_fini(psp); 171963cee55SLikun Gao return ret; 172963cee55SLikun Gao } 173963cee55SLikun Gao 174*3d689ae4SHawking Zhang /* 175*3d689ae4SHawking Zhang * Helper funciton to query psp runtime database entry 176*3d689ae4SHawking Zhang * 177*3d689ae4SHawking Zhang * @adev: amdgpu_device pointer 178*3d689ae4SHawking Zhang * @entry_type: the type of psp runtime database entry 179*3d689ae4SHawking Zhang * @db_entry: runtime database entry pointer 180*3d689ae4SHawking Zhang * 181*3d689ae4SHawking Zhang * Return false if runtime database doesn't exit or entry is invalid 182*3d689ae4SHawking Zhang * or true if the specific database entry is found, and copy to @db_entry 183*3d689ae4SHawking Zhang */ 184*3d689ae4SHawking Zhang static bool psp_get_runtime_db_entry(struct amdgpu_device *adev, 185*3d689ae4SHawking Zhang enum psp_runtime_entry_type entry_type, 186*3d689ae4SHawking Zhang void *db_entry) 187*3d689ae4SHawking Zhang { 188*3d689ae4SHawking Zhang uint64_t db_header_pos, db_dir_pos; 189*3d689ae4SHawking Zhang struct psp_runtime_data_header db_header = {0}; 190*3d689ae4SHawking Zhang struct psp_runtime_data_directory db_dir = {0}; 191*3d689ae4SHawking Zhang bool ret = false; 192*3d689ae4SHawking Zhang int i; 193*3d689ae4SHawking Zhang 194*3d689ae4SHawking Zhang db_header_pos = adev->gmc.mc_vram_size - PSP_RUNTIME_DB_OFFSET; 195*3d689ae4SHawking Zhang db_dir_pos = db_header_pos + sizeof(struct psp_runtime_data_header); 196*3d689ae4SHawking Zhang 197*3d689ae4SHawking Zhang /* read runtime db header from vram */ 198*3d689ae4SHawking Zhang amdgpu_device_vram_access(adev, db_header_pos, (uint32_t *)&db_header, 199*3d689ae4SHawking Zhang sizeof(struct psp_runtime_data_header), false); 200*3d689ae4SHawking Zhang 201*3d689ae4SHawking Zhang if (db_header.cookie != PSP_RUNTIME_DB_COOKIE_ID) { 202*3d689ae4SHawking Zhang /* runtime db doesn't exist, exit */ 203*3d689ae4SHawking Zhang dev_warn(adev->dev, "PSP runtime database doesn't exist\n"); 204*3d689ae4SHawking Zhang return false; 205*3d689ae4SHawking Zhang } 206*3d689ae4SHawking Zhang 207*3d689ae4SHawking Zhang /* read runtime database entry from vram */ 208*3d689ae4SHawking Zhang amdgpu_device_vram_access(adev, db_dir_pos, (uint32_t *)&db_dir, 209*3d689ae4SHawking Zhang sizeof(struct psp_runtime_data_directory), false); 210*3d689ae4SHawking Zhang 211*3d689ae4SHawking Zhang if (db_dir.entry_count >= PSP_RUNTIME_DB_DIAG_ENTRY_MAX_COUNT) { 212*3d689ae4SHawking Zhang /* invalid db entry count, exit */ 213*3d689ae4SHawking Zhang dev_warn(adev->dev, "Invalid PSP runtime database entry count\n"); 214*3d689ae4SHawking Zhang return false; 215*3d689ae4SHawking Zhang } 216*3d689ae4SHawking Zhang 217*3d689ae4SHawking Zhang /* look up for requested entry type */ 218*3d689ae4SHawking Zhang for (i = 0; i < db_dir.entry_count && !ret; i++) { 219*3d689ae4SHawking Zhang if (db_dir.entry_list[i].entry_type == entry_type) { 220*3d689ae4SHawking Zhang switch (entry_type) { 221*3d689ae4SHawking Zhang case PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG: 222*3d689ae4SHawking Zhang if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_boot_cfg_entry)) { 223*3d689ae4SHawking Zhang /* invalid db entry size */ 224*3d689ae4SHawking Zhang dev_warn(adev->dev, "Invalid PSP runtime database entry size\n"); 225*3d689ae4SHawking Zhang return false; 226*3d689ae4SHawking Zhang } 227*3d689ae4SHawking Zhang /* read runtime database entry */ 228*3d689ae4SHawking Zhang amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset, 229*3d689ae4SHawking Zhang (uint32_t *)db_entry, sizeof(struct psp_runtime_boot_cfg_entry), false); 230*3d689ae4SHawking Zhang ret = true; 231*3d689ae4SHawking Zhang break; 232*3d689ae4SHawking Zhang default: 233*3d689ae4SHawking Zhang ret = false; 234*3d689ae4SHawking Zhang break; 235*3d689ae4SHawking Zhang } 236*3d689ae4SHawking Zhang } 237*3d689ae4SHawking Zhang } 238*3d689ae4SHawking Zhang 239*3d689ae4SHawking Zhang return ret; 240*3d689ae4SHawking Zhang } 241*3d689ae4SHawking Zhang 2429d6fea57SAlex Deucher static int psp_sw_init(void *handle) 2439d6fea57SAlex Deucher { 2449d6fea57SAlex Deucher struct amdgpu_device *adev = (struct amdgpu_device *)handle; 2459d6fea57SAlex Deucher struct psp_context *psp = &adev->psp; 2469d6fea57SAlex Deucher int ret; 2479d6fea57SAlex Deucher 248162b786fSJingwen Chen if (!amdgpu_sriov_vf(adev)) { 2490e5ca0d1SHuang Rui ret = psp_init_microcode(psp); 2500e5ca0d1SHuang Rui if (ret) { 2510e5ca0d1SHuang Rui DRM_ERROR("Failed to load psp firmware!\n"); 2520e5ca0d1SHuang Rui return ret; 2530e5ca0d1SHuang Rui } 25493cdc175SZhigang Luo } else if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_ALDEBARAN) { 25593cdc175SZhigang Luo ret = psp_init_ta_microcode(psp, "aldebaran"); 25693cdc175SZhigang Luo if (ret) { 25793cdc175SZhigang Luo DRM_ERROR("Failed to initialize ta microcode!\n"); 25893cdc175SZhigang Luo return ret; 25993cdc175SZhigang Luo } 260162b786fSJingwen Chen } 2610e5ca0d1SHuang Rui 262963cee55SLikun Gao ret = psp_memory_training_init(psp); 2630586a059STianci.Yin if (ret) { 264d5e5c1bcSColin Ian King DRM_ERROR("Failed to initialize memory training!\n"); 2650586a059STianci.Yin return ret; 2660586a059STianci.Yin } 2670586a059STianci.Yin ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT); 2680586a059STianci.Yin if (ret) { 2690586a059STianci.Yin DRM_ERROR("Failed to process memory training!\n"); 2700586a059STianci.Yin return ret; 2710586a059STianci.Yin } 2720586a059STianci.Yin 273ce87c98dSAndrey Grodzovsky if (adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_SIENNA_CICHLID) { 27490f88cddSAndrey Grodzovsky ret= psp_sysfs_init(adev); 27590f88cddSAndrey Grodzovsky if (ret) { 27690f88cddSAndrey Grodzovsky return ret; 27790f88cddSAndrey Grodzovsky } 27890f88cddSAndrey Grodzovsky } 27990f88cddSAndrey Grodzovsky 2800e5ca0d1SHuang Rui return 0; 2810e5ca0d1SHuang Rui } 2820e5ca0d1SHuang Rui 2830e5ca0d1SHuang Rui static int psp_sw_fini(void *handle) 2840e5ca0d1SHuang Rui { 285c833d8aaSMonk Liu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 286c833d8aaSMonk Liu 287963cee55SLikun Gao psp_memory_training_fini(&adev->psp); 288f61772cdSLiu ChengZhe if (adev->psp.sos_fw) { 289c833d8aaSMonk Liu release_firmware(adev->psp.sos_fw); 290c833d8aaSMonk Liu adev->psp.sos_fw = NULL; 291f61772cdSLiu ChengZhe } 292f61772cdSLiu ChengZhe if (adev->psp.asd_fw) { 293c833d8aaSMonk Liu release_firmware(adev->psp.asd_fw); 294c833d8aaSMonk Liu adev->psp.asd_fw = NULL; 295f61772cdSLiu ChengZhe } 296f61772cdSLiu ChengZhe if (adev->psp.ta_fw) { 29751e7177fSHawking Zhang release_firmware(adev->psp.ta_fw); 29851e7177fSHawking Zhang adev->psp.ta_fw = NULL; 299f61772cdSLiu ChengZhe } 30057430471SAndrey Grodzovsky 30123d9bd60SAndrey Grodzovsky if (adev->asic_type == CHIP_NAVI10 || 30223d9bd60SAndrey Grodzovsky adev->asic_type == CHIP_SIENNA_CICHLID) 30357430471SAndrey Grodzovsky psp_sysfs_fini(adev); 30457430471SAndrey Grodzovsky 3050e5ca0d1SHuang Rui return 0; 3060e5ca0d1SHuang Rui } 3070e5ca0d1SHuang Rui 3080e5ca0d1SHuang Rui int psp_wait_for(struct psp_context *psp, uint32_t reg_index, 3090e5ca0d1SHuang Rui uint32_t reg_val, uint32_t mask, bool check_changed) 3100e5ca0d1SHuang Rui { 3110e5ca0d1SHuang Rui uint32_t val; 3120e5ca0d1SHuang Rui int i; 3130e5ca0d1SHuang Rui struct amdgpu_device *adev = psp->adev; 3140e5ca0d1SHuang Rui 3157afefb81SAndrey Grodzovsky if (psp->adev->no_hw_access) 316bf36b52eSAndrey Grodzovsky return 0; 317bf36b52eSAndrey Grodzovsky 3180e5ca0d1SHuang Rui for (i = 0; i < adev->usec_timeout; i++) { 3192890decfSZhang, Jerry val = RREG32(reg_index); 3200e5ca0d1SHuang Rui if (check_changed) { 3210e5ca0d1SHuang Rui if (val != reg_val) 3220e5ca0d1SHuang Rui return 0; 3230e5ca0d1SHuang Rui } else { 3240e5ca0d1SHuang Rui if ((val & mask) == reg_val) 3250e5ca0d1SHuang Rui return 0; 3260e5ca0d1SHuang Rui } 3270e5ca0d1SHuang Rui udelay(1); 3280e5ca0d1SHuang Rui } 3290e5ca0d1SHuang Rui 3300e5ca0d1SHuang Rui return -ETIME; 3310e5ca0d1SHuang Rui } 3320e5ca0d1SHuang Rui 3330e5ca0d1SHuang Rui static int 3340e5ca0d1SHuang Rui psp_cmd_submit_buf(struct psp_context *psp, 3350e5ca0d1SHuang Rui struct amdgpu_firmware_info *ucode, 3360b25cbf9SHawking Zhang struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr) 3370e5ca0d1SHuang Rui { 3380e5ca0d1SHuang Rui int ret; 339f89f8c6bSAndrey Grodzovsky int index, idx; 34057995aa8Spengzhou int timeout = 20000; 341c2c6f816SJohn Clements bool ras_intr = false; 342d73cd701SEmily Deng bool skip_unsupport = false; 3430e5ca0d1SHuang Rui 3447afefb81SAndrey Grodzovsky if (psp->adev->no_hw_access) 345bf36b52eSAndrey Grodzovsky return 0; 346bf36b52eSAndrey Grodzovsky 347f89f8c6bSAndrey Grodzovsky if (!drm_dev_enter(&psp->adev->ddev, &idx)) 348f89f8c6bSAndrey Grodzovsky return 0; 349f89f8c6bSAndrey Grodzovsky 35032eaeae0SAlex Deucher mutex_lock(&psp->mutex); 35132eaeae0SAlex Deucher 352a1952da7SHuang Rui memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE); 3530e5ca0d1SHuang Rui 354a1952da7SHuang Rui memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp)); 3550e5ca0d1SHuang Rui 3560b25cbf9SHawking Zhang index = atomic_inc_return(&psp->fence_value); 3575bdd0b72SHawking Zhang ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index); 3580b25cbf9SHawking Zhang if (ret) { 3590b25cbf9SHawking Zhang atomic_dec(&psp->fence_value); 360f89f8c6bSAndrey Grodzovsky goto exit; 361ca7f65c7Skbuild test robot } 3620e5ca0d1SHuang Rui 363810085ddSEric Huang amdgpu_device_invalidate_hdp(psp->adev, NULL); 364ea114213Sxinhui pan while (*((unsigned int *)psp->fence_buf) != index) { 365ea114213Sxinhui pan if (--timeout == 0) 3667a3d7bf6SEvan Quan break; 367bff77e86SLe Ma /* 368bff77e86SLe Ma * Shouldn't wait for timeout when err_event_athub occurs, 369bff77e86SLe Ma * because gpu reset thread triggered and lock resource should 370bff77e86SLe Ma * be released for psp resume sequence. 371bff77e86SLe Ma */ 372c2c6f816SJohn Clements ras_intr = amdgpu_ras_intr_triggered(); 373c2c6f816SJohn Clements if (ras_intr) 374bff77e86SLe Ma break; 37557995aa8Spengzhou usleep_range(10, 100); 376810085ddSEric Huang amdgpu_device_invalidate_hdp(psp->adev, NULL); 377ea114213Sxinhui pan } 3780b25cbf9SHawking Zhang 3793bda8acdSEmily Deng /* We allow TEE_ERROR_NOT_SUPPORTED for VMR command and PSP_ERR_UNKNOWN_COMMAND in SRIOV */ 3803bda8acdSEmily Deng skip_unsupport = (psp->cmd_buf_mem->resp.status == TEE_ERROR_NOT_SUPPORTED || 3813bda8acdSEmily Deng psp->cmd_buf_mem->resp.status == PSP_ERR_UNKNOWN_COMMAND) && amdgpu_sriov_vf(psp->adev); 382d73cd701SEmily Deng 38319ae3330SJohn Clements memcpy((void*)&cmd->resp, (void*)&psp->cmd_buf_mem->resp, sizeof(struct psp_gfx_resp)); 38419ae3330SJohn Clements 385466bcb75SAaron Liu /* In some cases, psp response status is not 0 even there is no 386466bcb75SAaron Liu * problem while the command is submitted. Some version of PSP FW 387466bcb75SAaron Liu * doesn't write 0 to that field. 388466bcb75SAaron Liu * So here we would like to only print a warning instead of an error 389466bcb75SAaron Liu * during psp initialization to avoid breaking hw_init and it doesn't 390466bcb75SAaron Liu * return -EINVAL. 391466bcb75SAaron Liu */ 392d73cd701SEmily Deng if (!skip_unsupport && (psp->cmd_buf_mem->resp.status || !timeout) && !ras_intr) { 39376223c54SXiangliang Yu if (ucode) 394466bcb75SAaron Liu DRM_WARN("failed to load ucode id (%d) ", 39576223c54SXiangliang Yu ucode->ucode_id); 396e6e193c0SJohn Clements DRM_WARN("psp command (0x%X) failed and response status is (0x%X)\n", 3971f01cd99SHawking Zhang psp->cmd_buf_mem->cmd_id, 398e6e193c0SJohn Clements psp->cmd_buf_mem->resp.status); 399728b3d05SZhigang Luo if (!timeout) { 400f89f8c6bSAndrey Grodzovsky ret = -EINVAL; 401f89f8c6bSAndrey Grodzovsky goto exit; 40228a16027SHuang Rui } 40332eaeae0SAlex Deucher } 40428a16027SHuang Rui 405435198f3SJames Zhu if (ucode) { 406435198f3SJames Zhu ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo; 407435198f3SJames Zhu ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi; 408435198f3SJames Zhu } 409435198f3SJames Zhu 410f89f8c6bSAndrey Grodzovsky exit: 411f89f8c6bSAndrey Grodzovsky mutex_unlock(&psp->mutex); 412f89f8c6bSAndrey Grodzovsky drm_dev_exit(idx); 4130e5ca0d1SHuang Rui return ret; 4140e5ca0d1SHuang Rui } 4150e5ca0d1SHuang Rui 4165ec996dfSXiangliang Yu static void psp_prep_tmr_cmd_buf(struct psp_context *psp, 4175ec996dfSXiangliang Yu struct psp_gfx_cmd_resp *cmd, 41836c08237SOak Zeng uint64_t tmr_mc, struct amdgpu_bo *tmr_bo) 4190e5ca0d1SHuang Rui { 42036c08237SOak Zeng struct amdgpu_device *adev = psp->adev; 42136c08237SOak Zeng uint32_t size = amdgpu_bo_size(tmr_bo); 42236c08237SOak Zeng uint64_t tmr_pa = amdgpu_gmc_vram_pa(adev, tmr_bo); 42336c08237SOak Zeng 424a2676149SHawking Zhang if (amdgpu_sriov_vf(psp->adev)) 4255ec996dfSXiangliang Yu cmd->cmd_id = GFX_CMD_ID_SETUP_VMR; 4265ec996dfSXiangliang Yu else 4270e5ca0d1SHuang Rui cmd->cmd_id = GFX_CMD_ID_SETUP_TMR; 428f03defe0SAlex Deucher cmd->cmd.cmd_setup_tmr.buf_phy_addr_lo = lower_32_bits(tmr_mc); 429f03defe0SAlex Deucher cmd->cmd.cmd_setup_tmr.buf_phy_addr_hi = upper_32_bits(tmr_mc); 4300e5ca0d1SHuang Rui cmd->cmd.cmd_setup_tmr.buf_size = size; 43136c08237SOak Zeng cmd->cmd.cmd_setup_tmr.bitfield.virt_phy_addr = 1; 43236c08237SOak Zeng cmd->cmd.cmd_setup_tmr.system_phy_addr_lo = lower_32_bits(tmr_pa); 43336c08237SOak Zeng cmd->cmd.cmd_setup_tmr.system_phy_addr_hi = upper_32_bits(tmr_pa); 4340e5ca0d1SHuang Rui } 4350e5ca0d1SHuang Rui 4367ea49e76SHawking Zhang static void psp_prep_load_toc_cmd_buf(struct psp_gfx_cmd_resp *cmd, 4377ea49e76SHawking Zhang uint64_t pri_buf_mc, uint32_t size) 4387ea49e76SHawking Zhang { 4397ea49e76SHawking Zhang cmd->cmd_id = GFX_CMD_ID_LOAD_TOC; 4407ea49e76SHawking Zhang cmd->cmd.cmd_load_toc.toc_phy_addr_lo = lower_32_bits(pri_buf_mc); 4417ea49e76SHawking Zhang cmd->cmd.cmd_load_toc.toc_phy_addr_hi = upper_32_bits(pri_buf_mc); 4427ea49e76SHawking Zhang cmd->cmd.cmd_load_toc.toc_size = size; 4437ea49e76SHawking Zhang } 4447ea49e76SHawking Zhang 4457ea49e76SHawking Zhang /* Issue LOAD TOC cmd to PSP to part toc and calculate tmr size needed */ 4467ea49e76SHawking Zhang static int psp_load_toc(struct psp_context *psp, 4477ea49e76SHawking Zhang uint32_t *tmr_size) 4487ea49e76SHawking Zhang { 4497ea49e76SHawking Zhang int ret; 4507ea49e76SHawking Zhang struct psp_gfx_cmd_resp *cmd; 4517ea49e76SHawking Zhang 4527ea49e76SHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 4537ea49e76SHawking Zhang if (!cmd) 4547ea49e76SHawking Zhang return -ENOMEM; 4557ea49e76SHawking Zhang /* Copy toc to psp firmware private buffer */ 456f89f8c6bSAndrey Grodzovsky psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size); 4577ea49e76SHawking Zhang 4587ea49e76SHawking Zhang psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size); 4597ea49e76SHawking Zhang 4607ea49e76SHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 4617ea49e76SHawking Zhang psp->fence_buf_mc_addr); 4627ea49e76SHawking Zhang if (!ret) 4637ea49e76SHawking Zhang *tmr_size = psp->cmd_buf_mem->resp.tmr_size; 4647ea49e76SHawking Zhang kfree(cmd); 4657ea49e76SHawking Zhang return ret; 4667ea49e76SHawking Zhang } 4677ea49e76SHawking Zhang 4680e5ca0d1SHuang Rui /* Set up Trusted Memory Region */ 4690e5ca0d1SHuang Rui static int psp_tmr_init(struct psp_context *psp) 4700e5ca0d1SHuang Rui { 4710e5ca0d1SHuang Rui int ret; 4727ea49e76SHawking Zhang int tmr_size; 47312842d02STianci.Yin void *tmr_buf; 47412842d02STianci.Yin void **pptr; 4750e5ca0d1SHuang Rui 4760e5ca0d1SHuang Rui /* 477795c1b8dSshaoyunl * According to HW engineer, they prefer the TMR address be "naturally 478795c1b8dSshaoyunl * aligned" , e.g. the start address be an integer divide of TMR size. 4790e5ca0d1SHuang Rui * 4800e5ca0d1SHuang Rui * Note: this memory need be reserved till the driver 4810e5ca0d1SHuang Rui * uninitializes. 4820e5ca0d1SHuang Rui */ 48347bfa5f6SOak Zeng tmr_size = PSP_TMR_SIZE(psp->adev); 4847ea49e76SHawking Zhang 4857ea49e76SHawking Zhang /* For ASICs support RLC autoload, psp will parse the toc 4867ea49e76SHawking Zhang * and calculate the total size of TMR needed */ 4871b657824SJiange Zhao if (!amdgpu_sriov_vf(psp->adev) && 4881b657824SJiange Zhao psp->toc_start_addr && 4897ea49e76SHawking Zhang psp->toc_bin_size && 4907ea49e76SHawking Zhang psp->fw_pri_buf) { 4917ea49e76SHawking Zhang ret = psp_load_toc(psp, &tmr_size); 4927ea49e76SHawking Zhang if (ret) { 4937ea49e76SHawking Zhang DRM_ERROR("Failed to load toc\n"); 4947ea49e76SHawking Zhang return ret; 4957ea49e76SHawking Zhang } 4967ea49e76SHawking Zhang } 4977ea49e76SHawking Zhang 49812842d02STianci.Yin pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; 49947bfa5f6SOak Zeng ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_SIZE(psp->adev), 5000e5ca0d1SHuang Rui AMDGPU_GEM_DOMAIN_VRAM, 50112842d02STianci.Yin &psp->tmr_bo, &psp->tmr_mc_addr, pptr); 5026f2b1fccSHuang Rui 5036f2b1fccSHuang Rui return ret; 5046f2b1fccSHuang Rui } 5056f2b1fccSHuang Rui 506f61772cdSLiu ChengZhe static bool psp_skip_tmr(struct psp_context *psp) 507f61772cdSLiu ChengZhe { 508f61772cdSLiu ChengZhe switch (psp->adev->asic_type) { 509f61772cdSLiu ChengZhe case CHIP_NAVI12: 510f61772cdSLiu ChengZhe case CHIP_SIENNA_CICHLID: 511e7de0d84SZhigang Luo case CHIP_ALDEBARAN: 512f61772cdSLiu ChengZhe return true; 513f61772cdSLiu ChengZhe default: 514f61772cdSLiu ChengZhe return false; 515f61772cdSLiu ChengZhe } 516f61772cdSLiu ChengZhe } 517f61772cdSLiu ChengZhe 5186f2b1fccSHuang Rui static int psp_tmr_load(struct psp_context *psp) 5196f2b1fccSHuang Rui { 5206f2b1fccSHuang Rui int ret; 5216f2b1fccSHuang Rui struct psp_gfx_cmd_resp *cmd; 5226f2b1fccSHuang Rui 523f61772cdSLiu ChengZhe /* For Navi12 and CHIP_SIENNA_CICHLID SRIOV, do not set up TMR. 524f61772cdSLiu ChengZhe * Already set up by host driver. 525f61772cdSLiu ChengZhe */ 526f61772cdSLiu ChengZhe if (amdgpu_sriov_vf(psp->adev) && psp_skip_tmr(psp)) 527f61772cdSLiu ChengZhe return 0; 528f61772cdSLiu ChengZhe 5296f2b1fccSHuang Rui cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 5306f2b1fccSHuang Rui if (!cmd) 5316f2b1fccSHuang Rui return -ENOMEM; 5320e5ca0d1SHuang Rui 53336c08237SOak Zeng psp_prep_tmr_cmd_buf(psp, cmd, psp->tmr_mc_addr, psp->tmr_bo); 5347ea49e76SHawking Zhang DRM_INFO("reserve 0x%lx from 0x%llx for PSP TMR\n", 5357ea49e76SHawking Zhang amdgpu_bo_size(psp->tmr_bo), psp->tmr_mc_addr); 5360e5ca0d1SHuang Rui 5370e5ca0d1SHuang Rui ret = psp_cmd_submit_buf(psp, NULL, cmd, 5380b25cbf9SHawking Zhang psp->fence_buf_mc_addr); 5390e5ca0d1SHuang Rui 5400e5ca0d1SHuang Rui kfree(cmd); 5410e5ca0d1SHuang Rui 5420e5ca0d1SHuang Rui return ret; 5430e5ca0d1SHuang Rui } 5440e5ca0d1SHuang Rui 54590937420SHuang Rui static void psp_prep_tmr_unload_cmd_buf(struct psp_context *psp, 54690937420SHuang Rui struct psp_gfx_cmd_resp *cmd) 54790937420SHuang Rui { 54890937420SHuang Rui if (amdgpu_sriov_vf(psp->adev)) 54990937420SHuang Rui cmd->cmd_id = GFX_CMD_ID_DESTROY_VMR; 55090937420SHuang Rui else 55190937420SHuang Rui cmd->cmd_id = GFX_CMD_ID_DESTROY_TMR; 55290937420SHuang Rui } 55390937420SHuang Rui 55490937420SHuang Rui static int psp_tmr_unload(struct psp_context *psp) 55590937420SHuang Rui { 55690937420SHuang Rui int ret; 55790937420SHuang Rui struct psp_gfx_cmd_resp *cmd; 55890937420SHuang Rui 55990937420SHuang Rui cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 56090937420SHuang Rui if (!cmd) 56190937420SHuang Rui return -ENOMEM; 56290937420SHuang Rui 56390937420SHuang Rui psp_prep_tmr_unload_cmd_buf(psp, cmd); 56490937420SHuang Rui DRM_INFO("free PSP TMR buffer\n"); 56590937420SHuang Rui 56690937420SHuang Rui ret = psp_cmd_submit_buf(psp, NULL, cmd, 56790937420SHuang Rui psp->fence_buf_mc_addr); 56890937420SHuang Rui 56990937420SHuang Rui kfree(cmd); 57090937420SHuang Rui 57190937420SHuang Rui return ret; 57290937420SHuang Rui } 57390937420SHuang Rui 57490937420SHuang Rui static int psp_tmr_terminate(struct psp_context *psp) 57590937420SHuang Rui { 57690937420SHuang Rui int ret; 57790937420SHuang Rui void *tmr_buf; 57890937420SHuang Rui void **pptr; 57990937420SHuang Rui 58090937420SHuang Rui ret = psp_tmr_unload(psp); 58190937420SHuang Rui if (ret) 58290937420SHuang Rui return ret; 58390937420SHuang Rui 58490937420SHuang Rui /* free TMR memory buffer */ 58590937420SHuang Rui pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; 58690937420SHuang Rui amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, pptr); 58790937420SHuang Rui 58890937420SHuang Rui return 0; 58990937420SHuang Rui } 59090937420SHuang Rui 59119ae3330SJohn Clements int psp_get_fw_attestation_records_addr(struct psp_context *psp, 59219ae3330SJohn Clements uint64_t *output_ptr) 59319ae3330SJohn Clements { 59419ae3330SJohn Clements int ret; 59519ae3330SJohn Clements struct psp_gfx_cmd_resp *cmd; 59619ae3330SJohn Clements 59719ae3330SJohn Clements if (!output_ptr) 59819ae3330SJohn Clements return -EINVAL; 59919ae3330SJohn Clements 60019ae3330SJohn Clements if (amdgpu_sriov_vf(psp->adev)) 60119ae3330SJohn Clements return 0; 60219ae3330SJohn Clements 60319ae3330SJohn Clements cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 60419ae3330SJohn Clements if (!cmd) 60519ae3330SJohn Clements return -ENOMEM; 60619ae3330SJohn Clements 60719ae3330SJohn Clements cmd->cmd_id = GFX_CMD_ID_GET_FW_ATTESTATION; 60819ae3330SJohn Clements 60919ae3330SJohn Clements ret = psp_cmd_submit_buf(psp, NULL, cmd, 61019ae3330SJohn Clements psp->fence_buf_mc_addr); 61119ae3330SJohn Clements 61219ae3330SJohn Clements if (!ret) { 61319ae3330SJohn Clements *output_ptr = ((uint64_t)cmd->resp.uresp.fwar_db_info.fwar_db_addr_lo) + 61419ae3330SJohn Clements ((uint64_t)cmd->resp.uresp.fwar_db_info.fwar_db_addr_hi << 32); 61519ae3330SJohn Clements } 61619ae3330SJohn Clements 61719ae3330SJohn Clements kfree(cmd); 61819ae3330SJohn Clements 61919ae3330SJohn Clements return ret; 62019ae3330SJohn Clements } 62119ae3330SJohn Clements 622c6642234SHawking Zhang static int psp_boot_config_get(struct amdgpu_device *adev, uint32_t *boot_cfg) 623c6642234SHawking Zhang { 624c6642234SHawking Zhang struct psp_context *psp = &adev->psp; 625c6642234SHawking Zhang struct psp_gfx_cmd_resp *cmd = psp->cmd; 626c6642234SHawking Zhang int ret; 627c6642234SHawking Zhang 628c6642234SHawking Zhang if (amdgpu_sriov_vf(adev)) 629c6642234SHawking Zhang return 0; 630c6642234SHawking Zhang 631c6642234SHawking Zhang memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); 632c6642234SHawking Zhang 633c6642234SHawking Zhang cmd->cmd_id = GFX_CMD_ID_BOOT_CFG; 634c6642234SHawking Zhang cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_GET; 635c6642234SHawking Zhang 636c6642234SHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 637c6642234SHawking Zhang if (!ret) { 638c6642234SHawking Zhang *boot_cfg = 639c6642234SHawking Zhang (cmd->resp.uresp.boot_cfg.boot_cfg & BOOT_CONFIG_GECC) ? 1 : 0; 640c6642234SHawking Zhang } 641c6642234SHawking Zhang 642c6642234SHawking Zhang return ret; 643c6642234SHawking Zhang } 644c6642234SHawking Zhang 64555188d64SHawking Zhang static int psp_boot_config_set(struct amdgpu_device *adev, uint32_t boot_cfg) 646cad7b751SJohn Clements { 647cad7b751SJohn Clements struct psp_context *psp = &adev->psp; 648cad7b751SJohn Clements struct psp_gfx_cmd_resp *cmd = psp->cmd; 649cad7b751SJohn Clements 650c6a11133SHawking Zhang if (amdgpu_sriov_vf(adev)) 651cad7b751SJohn Clements return 0; 652cad7b751SJohn Clements 653cad7b751SJohn Clements memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); 654cad7b751SJohn Clements 655cad7b751SJohn Clements cmd->cmd_id = GFX_CMD_ID_BOOT_CFG; 656cad7b751SJohn Clements cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_SET; 65755188d64SHawking Zhang cmd->cmd.boot_cfg.boot_config = boot_cfg; 65855188d64SHawking Zhang cmd->cmd.boot_cfg.boot_config_valid = boot_cfg; 659cad7b751SJohn Clements 660cad7b751SJohn Clements return psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 661cad7b751SJohn Clements } 662cad7b751SJohn Clements 6630d2c1855SJohn Clements static int psp_rl_load(struct amdgpu_device *adev) 6640d2c1855SJohn Clements { 6650d2c1855SJohn Clements struct psp_context *psp = &adev->psp; 6660d2c1855SJohn Clements struct psp_gfx_cmd_resp *cmd = psp->cmd; 6670d2c1855SJohn Clements 6680d2c1855SJohn Clements if (psp->rl_bin_size == 0) 6690d2c1855SJohn Clements return 0; 6700d2c1855SJohn Clements 6710d2c1855SJohn Clements memset(psp->fw_pri_buf, 0, PSP_1_MEG); 6720d2c1855SJohn Clements memcpy(psp->fw_pri_buf, psp->rl_start_addr, psp->rl_bin_size); 6730d2c1855SJohn Clements 6740d2c1855SJohn Clements memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); 6750d2c1855SJohn Clements 6760d2c1855SJohn Clements cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW; 6770d2c1855SJohn Clements cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(psp->fw_pri_mc_addr); 6780d2c1855SJohn Clements cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(psp->fw_pri_mc_addr); 6790d2c1855SJohn Clements cmd->cmd.cmd_load_ip_fw.fw_size = psp->rl_bin_size; 6800d2c1855SJohn Clements cmd->cmd.cmd_load_ip_fw.fw_type = GFX_FW_TYPE_REG_LIST; 6810d2c1855SJohn Clements 6820d2c1855SJohn Clements return psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 6830d2c1855SJohn Clements } 6840d2c1855SJohn Clements 685c64ab828SHawking Zhang static void psp_prep_asd_load_cmd_buf(struct psp_gfx_cmd_resp *cmd, 686c64ab828SHawking Zhang uint64_t asd_mc, uint32_t size) 6870e5ca0d1SHuang Rui { 6880e5ca0d1SHuang Rui cmd->cmd_id = GFX_CMD_ID_LOAD_ASD; 6890e5ca0d1SHuang Rui cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(asd_mc); 6900e5ca0d1SHuang Rui cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(asd_mc); 6910e5ca0d1SHuang Rui cmd->cmd.cmd_load_ta.app_len = size; 6920e5ca0d1SHuang Rui 693c64ab828SHawking Zhang cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = 0; 694c64ab828SHawking Zhang cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = 0; 695c64ab828SHawking Zhang cmd->cmd.cmd_load_ta.cmd_buf_len = 0; 6960e5ca0d1SHuang Rui } 6970e5ca0d1SHuang Rui 6980e5ca0d1SHuang Rui static int psp_asd_load(struct psp_context *psp) 6990e5ca0d1SHuang Rui { 7000e5ca0d1SHuang Rui int ret; 7010e5ca0d1SHuang Rui struct psp_gfx_cmd_resp *cmd; 7020e5ca0d1SHuang Rui 703943cafb8SXiangliang Yu /* If PSP version doesn't match ASD version, asd loading will be failed. 704943cafb8SXiangliang Yu * add workaround to bypass it for sriov now. 705943cafb8SXiangliang Yu * TODO: add version check to make it common 706943cafb8SXiangliang Yu */ 707eb5f4f46SDennis Li if (amdgpu_sriov_vf(psp->adev) || !psp->asd_ucode_size) 708943cafb8SXiangliang Yu return 0; 709943cafb8SXiangliang Yu 7100e5ca0d1SHuang Rui cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 7110e5ca0d1SHuang Rui if (!cmd) 7120e5ca0d1SHuang Rui return -ENOMEM; 7130e5ca0d1SHuang Rui 714f89f8c6bSAndrey Grodzovsky psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size); 7150e5ca0d1SHuang Rui 716c64ab828SHawking Zhang psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr, 717c64ab828SHawking Zhang psp->asd_ucode_size); 7180e5ca0d1SHuang Rui 7190e5ca0d1SHuang Rui ret = psp_cmd_submit_buf(psp, NULL, cmd, 7200b25cbf9SHawking Zhang psp->fence_buf_mc_addr); 721c64ab828SHawking Zhang if (!ret) { 722c64ab828SHawking Zhang psp->asd_context.asd_initialized = true; 723c64ab828SHawking Zhang psp->asd_context.session_id = cmd->resp.session_id; 724c64ab828SHawking Zhang } 7250e5ca0d1SHuang Rui 7260e5ca0d1SHuang Rui kfree(cmd); 7270e5ca0d1SHuang Rui 7280e5ca0d1SHuang Rui return ret; 7290e5ca0d1SHuang Rui } 7300e5ca0d1SHuang Rui 7311f455f25SJohn Clements static void psp_prep_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd, 7321f455f25SJohn Clements uint32_t session_id) 73371e5f0cbSHawking Zhang { 73471e5f0cbSHawking Zhang cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA; 7351f455f25SJohn Clements cmd->cmd.cmd_unload_ta.session_id = session_id; 73671e5f0cbSHawking Zhang } 73771e5f0cbSHawking Zhang 73871e5f0cbSHawking Zhang static int psp_asd_unload(struct psp_context *psp) 73971e5f0cbSHawking Zhang { 74071e5f0cbSHawking Zhang int ret; 74171e5f0cbSHawking Zhang struct psp_gfx_cmd_resp *cmd; 74271e5f0cbSHawking Zhang 74371e5f0cbSHawking Zhang if (amdgpu_sriov_vf(psp->adev)) 74471e5f0cbSHawking Zhang return 0; 74571e5f0cbSHawking Zhang 74671e5f0cbSHawking Zhang if (!psp->asd_context.asd_initialized) 74771e5f0cbSHawking Zhang return 0; 74871e5f0cbSHawking Zhang 74971e5f0cbSHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 75071e5f0cbSHawking Zhang if (!cmd) 75171e5f0cbSHawking Zhang return -ENOMEM; 75271e5f0cbSHawking Zhang 7531f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->asd_context.session_id); 75471e5f0cbSHawking Zhang 75571e5f0cbSHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 75671e5f0cbSHawking Zhang psp->fence_buf_mc_addr); 75771e5f0cbSHawking Zhang if (!ret) 75871e5f0cbSHawking Zhang psp->asd_context.asd_initialized = false; 75971e5f0cbSHawking Zhang 76071e5f0cbSHawking Zhang kfree(cmd); 76171e5f0cbSHawking Zhang 76271e5f0cbSHawking Zhang return ret; 76371e5f0cbSHawking Zhang } 76471e5f0cbSHawking Zhang 765c5d19419STrigger Huang static void psp_prep_reg_prog_cmd_buf(struct psp_gfx_cmd_resp *cmd, 766c5d19419STrigger Huang uint32_t id, uint32_t value) 767c5d19419STrigger Huang { 768c5d19419STrigger Huang cmd->cmd_id = GFX_CMD_ID_PROG_REG; 769c5d19419STrigger Huang cmd->cmd.cmd_setup_reg_prog.reg_value = value; 770c5d19419STrigger Huang cmd->cmd.cmd_setup_reg_prog.reg_id = id; 771c5d19419STrigger Huang } 772c5d19419STrigger Huang 773c5d19419STrigger Huang int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg, 774c5d19419STrigger Huang uint32_t value) 775c5d19419STrigger Huang { 776c5d19419STrigger Huang struct psp_gfx_cmd_resp *cmd = NULL; 777c5d19419STrigger Huang int ret = 0; 778c5d19419STrigger Huang 779c5d19419STrigger Huang if (reg >= PSP_REG_LAST) 780c5d19419STrigger Huang return -EINVAL; 781c5d19419STrigger Huang 782c5d19419STrigger Huang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 783c5d19419STrigger Huang if (!cmd) 784c5d19419STrigger Huang return -ENOMEM; 785c5d19419STrigger Huang 786c5d19419STrigger Huang psp_prep_reg_prog_cmd_buf(cmd, reg, value); 787c5d19419STrigger Huang ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 7882b9ced5aSRohit Khaire if (ret) 7892b9ced5aSRohit Khaire DRM_ERROR("PSP failed to program reg id %d", reg); 790c5d19419STrigger Huang 791c5d19419STrigger Huang kfree(cmd); 792c5d19419STrigger Huang return ret; 793c5d19419STrigger Huang } 794c5d19419STrigger Huang 7951f455f25SJohn Clements static void psp_prep_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd, 7961f455f25SJohn Clements uint64_t ta_bin_mc, 7971f455f25SJohn Clements uint32_t ta_bin_size, 7981f455f25SJohn Clements uint64_t ta_shared_mc, 7991f455f25SJohn Clements uint32_t ta_shared_size) 80097c8d171SHawking Zhang { 80197c8d171SHawking Zhang cmd->cmd_id = GFX_CMD_ID_LOAD_TA; 8021f455f25SJohn Clements cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(ta_bin_mc); 8031f455f25SJohn Clements cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(ta_bin_mc); 8041f455f25SJohn Clements cmd->cmd.cmd_load_ta.app_len = ta_bin_size; 80597c8d171SHawking Zhang 8061f455f25SJohn Clements cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(ta_shared_mc); 8071f455f25SJohn Clements cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(ta_shared_mc); 8081f455f25SJohn Clements cmd->cmd.cmd_load_ta.cmd_buf_len = ta_shared_size; 80997c8d171SHawking Zhang } 81097c8d171SHawking Zhang 81197c8d171SHawking Zhang static int psp_xgmi_init_shared_buf(struct psp_context *psp) 81297c8d171SHawking Zhang { 81397c8d171SHawking Zhang int ret; 81497c8d171SHawking Zhang 81597c8d171SHawking Zhang /* 81697c8d171SHawking Zhang * Allocate 16k memory aligned to 4k from Frame Buffer (local 81797c8d171SHawking Zhang * physical) for xgmi ta <-> Driver 81897c8d171SHawking Zhang */ 81997c8d171SHawking Zhang ret = amdgpu_bo_create_kernel(psp->adev, PSP_XGMI_SHARED_MEM_SIZE, 82097c8d171SHawking Zhang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 82197c8d171SHawking Zhang &psp->xgmi_context.xgmi_shared_bo, 82297c8d171SHawking Zhang &psp->xgmi_context.xgmi_shared_mc_addr, 82397c8d171SHawking Zhang &psp->xgmi_context.xgmi_shared_buf); 82497c8d171SHawking Zhang 82597c8d171SHawking Zhang return ret; 82697c8d171SHawking Zhang } 82797c8d171SHawking Zhang 82834e48caeSJohn Clements static void psp_prep_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd, 82934e48caeSJohn Clements uint32_t ta_cmd_id, 83034e48caeSJohn Clements uint32_t session_id) 83134e48caeSJohn Clements { 83234e48caeSJohn Clements cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD; 83334e48caeSJohn Clements cmd->cmd.cmd_invoke_cmd.session_id = session_id; 83434e48caeSJohn Clements cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id; 83534e48caeSJohn Clements } 83634e48caeSJohn Clements 837f3167919SNirmoy Das static int psp_ta_invoke(struct psp_context *psp, 83834e48caeSJohn Clements uint32_t ta_cmd_id, 83934e48caeSJohn Clements uint32_t session_id) 84034e48caeSJohn Clements { 84134e48caeSJohn Clements int ret; 84234e48caeSJohn Clements struct psp_gfx_cmd_resp *cmd; 84334e48caeSJohn Clements 84434e48caeSJohn Clements cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 84534e48caeSJohn Clements if (!cmd) 84634e48caeSJohn Clements return -ENOMEM; 84734e48caeSJohn Clements 84834e48caeSJohn Clements psp_prep_ta_invoke_cmd_buf(cmd, ta_cmd_id, session_id); 84934e48caeSJohn Clements 85034e48caeSJohn Clements ret = psp_cmd_submit_buf(psp, NULL, cmd, 85134e48caeSJohn Clements psp->fence_buf_mc_addr); 85234e48caeSJohn Clements 85334e48caeSJohn Clements kfree(cmd); 85434e48caeSJohn Clements 85534e48caeSJohn Clements return ret; 85634e48caeSJohn Clements } 85734e48caeSJohn Clements 85897c8d171SHawking Zhang static int psp_xgmi_load(struct psp_context *psp) 85997c8d171SHawking Zhang { 86097c8d171SHawking Zhang int ret; 86197c8d171SHawking Zhang struct psp_gfx_cmd_resp *cmd; 86297c8d171SHawking Zhang 86397c8d171SHawking Zhang /* 86497c8d171SHawking Zhang * TODO: bypass the loading in sriov for now 86597c8d171SHawking Zhang */ 86697c8d171SHawking Zhang 86797c8d171SHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 86897c8d171SHawking Zhang if (!cmd) 86997c8d171SHawking Zhang return -ENOMEM; 87097c8d171SHawking Zhang 871f89f8c6bSAndrey Grodzovsky psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size); 87297c8d171SHawking Zhang 8731f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 8741f455f25SJohn Clements psp->fw_pri_mc_addr, 8751f455f25SJohn Clements psp->ta_xgmi_ucode_size, 87697c8d171SHawking Zhang psp->xgmi_context.xgmi_shared_mc_addr, 8771f455f25SJohn Clements PSP_XGMI_SHARED_MEM_SIZE); 87897c8d171SHawking Zhang 87997c8d171SHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 88097c8d171SHawking Zhang psp->fence_buf_mc_addr); 88197c8d171SHawking Zhang 88297c8d171SHawking Zhang if (!ret) { 88397c8d171SHawking Zhang psp->xgmi_context.initialized = 1; 88497c8d171SHawking Zhang psp->xgmi_context.session_id = cmd->resp.session_id; 88597c8d171SHawking Zhang } 88697c8d171SHawking Zhang 88797c8d171SHawking Zhang kfree(cmd); 88897c8d171SHawking Zhang 88997c8d171SHawking Zhang return ret; 89097c8d171SHawking Zhang } 89197c8d171SHawking Zhang 89297c8d171SHawking Zhang static int psp_xgmi_unload(struct psp_context *psp) 89397c8d171SHawking Zhang { 89497c8d171SHawking Zhang int ret; 89597c8d171SHawking Zhang struct psp_gfx_cmd_resp *cmd; 8969c8c81feSJohn Clements struct amdgpu_device *adev = psp->adev; 8979c8c81feSJohn Clements 89899d1da67SFeifei Xu /* XGMI TA unload currently is not supported on Arcturus/Aldebaran A+A */ 89999d1da67SFeifei Xu if (adev->asic_type == CHIP_ARCTURUS || 90099d1da67SFeifei Xu (adev->asic_type == CHIP_ALDEBARAN && adev->gmc.xgmi.connected_to_cpu)) 9019c8c81feSJohn Clements return 0; 90297c8d171SHawking Zhang 90397c8d171SHawking Zhang /* 90497c8d171SHawking Zhang * TODO: bypass the unloading in sriov for now 90597c8d171SHawking Zhang */ 90697c8d171SHawking Zhang 90797c8d171SHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 90897c8d171SHawking Zhang if (!cmd) 90997c8d171SHawking Zhang return -ENOMEM; 91097c8d171SHawking Zhang 9111f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->xgmi_context.session_id); 91297c8d171SHawking Zhang 91397c8d171SHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 91497c8d171SHawking Zhang psp->fence_buf_mc_addr); 91597c8d171SHawking Zhang 91697c8d171SHawking Zhang kfree(cmd); 91797c8d171SHawking Zhang 91897c8d171SHawking Zhang return ret; 91997c8d171SHawking Zhang } 92097c8d171SHawking Zhang 921ca6e1e59SHawking Zhang int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 922ca6e1e59SHawking Zhang { 92334e48caeSJohn Clements return psp_ta_invoke(psp, ta_cmd_id, psp->xgmi_context.session_id); 924ca6e1e59SHawking Zhang } 925ca6e1e59SHawking Zhang 9260b9d3760SHawking Zhang int psp_xgmi_terminate(struct psp_context *psp) 9273e2e2ab5SHawking Zhang { 9283e2e2ab5SHawking Zhang int ret; 9293e2e2ab5SHawking Zhang 9303e2e2ab5SHawking Zhang if (!psp->xgmi_context.initialized) 9313e2e2ab5SHawking Zhang return 0; 9323e2e2ab5SHawking Zhang 9333e2e2ab5SHawking Zhang ret = psp_xgmi_unload(psp); 9343e2e2ab5SHawking Zhang if (ret) 9353e2e2ab5SHawking Zhang return ret; 9363e2e2ab5SHawking Zhang 9373e2e2ab5SHawking Zhang psp->xgmi_context.initialized = 0; 9383e2e2ab5SHawking Zhang 9393e2e2ab5SHawking Zhang /* free xgmi shared memory */ 9403e2e2ab5SHawking Zhang amdgpu_bo_free_kernel(&psp->xgmi_context.xgmi_shared_bo, 9413e2e2ab5SHawking Zhang &psp->xgmi_context.xgmi_shared_mc_addr, 9423e2e2ab5SHawking Zhang &psp->xgmi_context.xgmi_shared_buf); 9433e2e2ab5SHawking Zhang 9443e2e2ab5SHawking Zhang return 0; 9453e2e2ab5SHawking Zhang } 9463e2e2ab5SHawking Zhang 9470b9d3760SHawking Zhang int psp_xgmi_initialize(struct psp_context *psp) 9483e2e2ab5SHawking Zhang { 9493e2e2ab5SHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 9503e2e2ab5SHawking Zhang int ret; 9513e2e2ab5SHawking Zhang 95251bd3638SHawking Zhang if (!psp->adev->psp.ta_fw || 95351bd3638SHawking Zhang !psp->adev->psp.ta_xgmi_ucode_size || 95451bd3638SHawking Zhang !psp->adev->psp.ta_xgmi_start_addr) 9551d69511eSAlex Deucher return -ENOENT; 9561d69511eSAlex Deucher 9573e2e2ab5SHawking Zhang if (!psp->xgmi_context.initialized) { 9583e2e2ab5SHawking Zhang ret = psp_xgmi_init_shared_buf(psp); 9593e2e2ab5SHawking Zhang if (ret) 9603e2e2ab5SHawking Zhang return ret; 9613e2e2ab5SHawking Zhang } 9623e2e2ab5SHawking Zhang 9633e2e2ab5SHawking Zhang /* Load XGMI TA */ 9643e2e2ab5SHawking Zhang ret = psp_xgmi_load(psp); 9653e2e2ab5SHawking Zhang if (ret) 9663e2e2ab5SHawking Zhang return ret; 9673e2e2ab5SHawking Zhang 9683e2e2ab5SHawking Zhang /* Initialize XGMI session */ 9693e2e2ab5SHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory *)(psp->xgmi_context.xgmi_shared_buf); 9703e2e2ab5SHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 9713e2e2ab5SHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__INITIALIZE; 9723e2e2ab5SHawking Zhang 9733e2e2ab5SHawking Zhang ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id); 9743e2e2ab5SHawking Zhang 9753e2e2ab5SHawking Zhang return ret; 9763e2e2ab5SHawking Zhang } 9773e2e2ab5SHawking Zhang 97835ccba4eSHawking Zhang int psp_xgmi_get_hive_id(struct psp_context *psp, uint64_t *hive_id) 97935ccba4eSHawking Zhang { 98035ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 98135ccba4eSHawking Zhang int ret; 98235ccba4eSHawking Zhang 98335ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.xgmi_shared_buf; 98435ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 98535ccba4eSHawking Zhang 98635ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_HIVE_ID; 98735ccba4eSHawking Zhang 98835ccba4eSHawking Zhang /* Invoke xgmi ta to get hive id */ 98935ccba4eSHawking Zhang ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id); 99035ccba4eSHawking Zhang if (ret) 99135ccba4eSHawking Zhang return ret; 99235ccba4eSHawking Zhang 99335ccba4eSHawking Zhang *hive_id = xgmi_cmd->xgmi_out_message.get_hive_id.hive_id; 99435ccba4eSHawking Zhang 99535ccba4eSHawking Zhang return 0; 99635ccba4eSHawking Zhang } 99735ccba4eSHawking Zhang 99835ccba4eSHawking Zhang int psp_xgmi_get_node_id(struct psp_context *psp, uint64_t *node_id) 99935ccba4eSHawking Zhang { 100035ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 100135ccba4eSHawking Zhang int ret; 100235ccba4eSHawking Zhang 100335ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.xgmi_shared_buf; 100435ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 100535ccba4eSHawking Zhang 100635ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_NODE_ID; 100735ccba4eSHawking Zhang 100835ccba4eSHawking Zhang /* Invoke xgmi ta to get the node id */ 100935ccba4eSHawking Zhang ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id); 101035ccba4eSHawking Zhang if (ret) 101135ccba4eSHawking Zhang return ret; 101235ccba4eSHawking Zhang 101335ccba4eSHawking Zhang *node_id = xgmi_cmd->xgmi_out_message.get_node_id.node_id; 101435ccba4eSHawking Zhang 101535ccba4eSHawking Zhang return 0; 101635ccba4eSHawking Zhang } 101735ccba4eSHawking Zhang 101835ccba4eSHawking Zhang int psp_xgmi_get_topology_info(struct psp_context *psp, 101935ccba4eSHawking Zhang int number_devices, 102035ccba4eSHawking Zhang struct psp_xgmi_topology_info *topology) 102135ccba4eSHawking Zhang { 102235ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 102335ccba4eSHawking Zhang struct ta_xgmi_cmd_get_topology_info_input *topology_info_input; 102435ccba4eSHawking Zhang struct ta_xgmi_cmd_get_topology_info_output *topology_info_output; 102535ccba4eSHawking Zhang int i; 102635ccba4eSHawking Zhang int ret; 102735ccba4eSHawking Zhang 102835ccba4eSHawking Zhang if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES) 102935ccba4eSHawking Zhang return -EINVAL; 103035ccba4eSHawking Zhang 103135ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.xgmi_shared_buf; 103235ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 103335ccba4eSHawking Zhang 103435ccba4eSHawking Zhang /* Fill in the shared memory with topology information as input */ 103535ccba4eSHawking Zhang topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info; 103635ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO; 103735ccba4eSHawking Zhang topology_info_input->num_nodes = number_devices; 103835ccba4eSHawking Zhang 103935ccba4eSHawking Zhang for (i = 0; i < topology_info_input->num_nodes; i++) { 104035ccba4eSHawking Zhang topology_info_input->nodes[i].node_id = topology->nodes[i].node_id; 104135ccba4eSHawking Zhang topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops; 104235ccba4eSHawking Zhang topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled; 104335ccba4eSHawking Zhang topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine; 104435ccba4eSHawking Zhang } 104535ccba4eSHawking Zhang 104635ccba4eSHawking Zhang /* Invoke xgmi ta to get the topology information */ 104735ccba4eSHawking Zhang ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO); 104835ccba4eSHawking Zhang if (ret) 104935ccba4eSHawking Zhang return ret; 105035ccba4eSHawking Zhang 105135ccba4eSHawking Zhang /* Read the output topology information from the shared memory */ 105235ccba4eSHawking Zhang topology_info_output = &xgmi_cmd->xgmi_out_message.get_topology_info; 105335ccba4eSHawking Zhang topology->num_nodes = xgmi_cmd->xgmi_out_message.get_topology_info.num_nodes; 105435ccba4eSHawking Zhang for (i = 0; i < topology->num_nodes; i++) { 105535ccba4eSHawking Zhang topology->nodes[i].node_id = topology_info_output->nodes[i].node_id; 105635ccba4eSHawking Zhang topology->nodes[i].num_hops = topology_info_output->nodes[i].num_hops; 105735ccba4eSHawking Zhang topology->nodes[i].is_sharing_enabled = topology_info_output->nodes[i].is_sharing_enabled; 105835ccba4eSHawking Zhang topology->nodes[i].sdma_engine = topology_info_output->nodes[i].sdma_engine; 105935ccba4eSHawking Zhang } 106035ccba4eSHawking Zhang 106135ccba4eSHawking Zhang return 0; 106235ccba4eSHawking Zhang } 106335ccba4eSHawking Zhang 106435ccba4eSHawking Zhang int psp_xgmi_set_topology_info(struct psp_context *psp, 106535ccba4eSHawking Zhang int number_devices, 106635ccba4eSHawking Zhang struct psp_xgmi_topology_info *topology) 106735ccba4eSHawking Zhang { 106835ccba4eSHawking Zhang struct ta_xgmi_shared_memory *xgmi_cmd; 106935ccba4eSHawking Zhang struct ta_xgmi_cmd_get_topology_info_input *topology_info_input; 107035ccba4eSHawking Zhang int i; 107135ccba4eSHawking Zhang 107235ccba4eSHawking Zhang if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES) 107335ccba4eSHawking Zhang return -EINVAL; 107435ccba4eSHawking Zhang 107535ccba4eSHawking Zhang xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.xgmi_shared_buf; 107635ccba4eSHawking Zhang memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory)); 107735ccba4eSHawking Zhang 107835ccba4eSHawking Zhang topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info; 107935ccba4eSHawking Zhang xgmi_cmd->cmd_id = TA_COMMAND_XGMI__SET_TOPOLOGY_INFO; 108035ccba4eSHawking Zhang topology_info_input->num_nodes = number_devices; 108135ccba4eSHawking Zhang 108235ccba4eSHawking Zhang for (i = 0; i < topology_info_input->num_nodes; i++) { 108335ccba4eSHawking Zhang topology_info_input->nodes[i].node_id = topology->nodes[i].node_id; 108435ccba4eSHawking Zhang topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops; 108535ccba4eSHawking Zhang topology_info_input->nodes[i].is_sharing_enabled = 1; 108635ccba4eSHawking Zhang topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine; 108735ccba4eSHawking Zhang } 108835ccba4eSHawking Zhang 108935ccba4eSHawking Zhang /* Invoke xgmi ta to set topology information */ 109035ccba4eSHawking Zhang return psp_xgmi_invoke(psp, TA_COMMAND_XGMI__SET_TOPOLOGY_INFO); 109135ccba4eSHawking Zhang } 109235ccba4eSHawking Zhang 10935e5d3154Sxinhui pan // ras begin 10945e5d3154Sxinhui pan static int psp_ras_init_shared_buf(struct psp_context *psp) 10955e5d3154Sxinhui pan { 10965e5d3154Sxinhui pan int ret; 10975e5d3154Sxinhui pan 10985e5d3154Sxinhui pan /* 10995e5d3154Sxinhui pan * Allocate 16k memory aligned to 4k from Frame Buffer (local 11005e5d3154Sxinhui pan * physical) for ras ta <-> Driver 11015e5d3154Sxinhui pan */ 11025e5d3154Sxinhui pan ret = amdgpu_bo_create_kernel(psp->adev, PSP_RAS_SHARED_MEM_SIZE, 11035e5d3154Sxinhui pan PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 11045e5d3154Sxinhui pan &psp->ras.ras_shared_bo, 11055e5d3154Sxinhui pan &psp->ras.ras_shared_mc_addr, 11065e5d3154Sxinhui pan &psp->ras.ras_shared_buf); 11075e5d3154Sxinhui pan 11085e5d3154Sxinhui pan return ret; 11095e5d3154Sxinhui pan } 11105e5d3154Sxinhui pan 11115e5d3154Sxinhui pan static int psp_ras_load(struct psp_context *psp) 11125e5d3154Sxinhui pan { 11135e5d3154Sxinhui pan int ret; 11145e5d3154Sxinhui pan struct psp_gfx_cmd_resp *cmd; 11159c7e2cebSJohn Clements struct ta_ras_shared_memory *ras_cmd; 11165e5d3154Sxinhui pan 11175e5d3154Sxinhui pan /* 11185e5d3154Sxinhui pan * TODO: bypass the loading in sriov for now 11195e5d3154Sxinhui pan */ 11205e5d3154Sxinhui pan if (amdgpu_sriov_vf(psp->adev)) 11215e5d3154Sxinhui pan return 0; 11225e5d3154Sxinhui pan 11235e5d3154Sxinhui pan cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 11245e5d3154Sxinhui pan if (!cmd) 11255e5d3154Sxinhui pan return -ENOMEM; 11265e5d3154Sxinhui pan 1127f89f8c6bSAndrey Grodzovsky psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size); 11285e5d3154Sxinhui pan 11297e882aeeSJohn Clements ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; 11307e882aeeSJohn Clements 11317e882aeeSJohn Clements if (psp->adev->gmc.xgmi.connected_to_cpu) 11327e882aeeSJohn Clements ras_cmd->ras_in_message.init_flags.poison_mode_en = 1; 11337e882aeeSJohn Clements else 11347e882aeeSJohn Clements ras_cmd->ras_in_message.init_flags.dgpu_mode = 1; 11357e882aeeSJohn Clements 11361f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 11371f455f25SJohn Clements psp->fw_pri_mc_addr, 11381f455f25SJohn Clements psp->ta_ras_ucode_size, 11395e5d3154Sxinhui pan psp->ras.ras_shared_mc_addr, 11401f455f25SJohn Clements PSP_RAS_SHARED_MEM_SIZE); 11415e5d3154Sxinhui pan 11425e5d3154Sxinhui pan ret = psp_cmd_submit_buf(psp, NULL, cmd, 11435e5d3154Sxinhui pan psp->fence_buf_mc_addr); 11445e5d3154Sxinhui pan 11455e5d3154Sxinhui pan if (!ret) { 11465e5d3154Sxinhui pan psp->ras.session_id = cmd->resp.session_id; 11479c7e2cebSJohn Clements 11489c7e2cebSJohn Clements if (!ras_cmd->ras_status) 11499c7e2cebSJohn Clements psp->ras.ras_initialized = true; 11509c7e2cebSJohn Clements else 11519c7e2cebSJohn Clements dev_warn(psp->adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status); 11525e5d3154Sxinhui pan } 11535e5d3154Sxinhui pan 11549c7e2cebSJohn Clements if (ret || ras_cmd->ras_status) 11559c7e2cebSJohn Clements amdgpu_ras_fini(psp->adev); 11569c7e2cebSJohn Clements 11575e5d3154Sxinhui pan kfree(cmd); 11585e5d3154Sxinhui pan 11595e5d3154Sxinhui pan return ret; 11605e5d3154Sxinhui pan } 11615e5d3154Sxinhui pan 11625e5d3154Sxinhui pan static int psp_ras_unload(struct psp_context *psp) 11635e5d3154Sxinhui pan { 11645e5d3154Sxinhui pan int ret; 11655e5d3154Sxinhui pan struct psp_gfx_cmd_resp *cmd; 11665e5d3154Sxinhui pan 11675e5d3154Sxinhui pan /* 11685e5d3154Sxinhui pan * TODO: bypass the unloading in sriov for now 11695e5d3154Sxinhui pan */ 11705e5d3154Sxinhui pan if (amdgpu_sriov_vf(psp->adev)) 11715e5d3154Sxinhui pan return 0; 11725e5d3154Sxinhui pan 11735e5d3154Sxinhui pan cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 11745e5d3154Sxinhui pan if (!cmd) 11755e5d3154Sxinhui pan return -ENOMEM; 11765e5d3154Sxinhui pan 11771f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->ras.session_id); 11785e5d3154Sxinhui pan 11795e5d3154Sxinhui pan ret = psp_cmd_submit_buf(psp, NULL, cmd, 11805e5d3154Sxinhui pan psp->fence_buf_mc_addr); 11815e5d3154Sxinhui pan 11825e5d3154Sxinhui pan kfree(cmd); 11835e5d3154Sxinhui pan 11845e5d3154Sxinhui pan return ret; 11855e5d3154Sxinhui pan } 11865e5d3154Sxinhui pan 11875e5d3154Sxinhui pan int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 11885e5d3154Sxinhui pan { 118943965797SJohn Clements struct ta_ras_shared_memory *ras_cmd; 119043965797SJohn Clements int ret; 119143965797SJohn Clements 119243965797SJohn Clements ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; 119343965797SJohn Clements 11945e5d3154Sxinhui pan /* 11955e5d3154Sxinhui pan * TODO: bypass the loading in sriov for now 11965e5d3154Sxinhui pan */ 11975e5d3154Sxinhui pan if (amdgpu_sriov_vf(psp->adev)) 11985e5d3154Sxinhui pan return 0; 11995e5d3154Sxinhui pan 120043965797SJohn Clements ret = psp_ta_invoke(psp, ta_cmd_id, psp->ras.session_id); 120143965797SJohn Clements 1202624e8c87SJohn Clements if (amdgpu_ras_intr_triggered()) 1203624e8c87SJohn Clements return ret; 1204624e8c87SJohn Clements 120543965797SJohn Clements if (ras_cmd->if_version > RAS_TA_HOST_IF_VER) 120643965797SJohn Clements { 120743965797SJohn Clements DRM_WARN("RAS: Unsupported Interface"); 120843965797SJohn Clements return -EINVAL; 120943965797SJohn Clements } 121043965797SJohn Clements 121143965797SJohn Clements if (!ret) { 121243965797SJohn Clements if (ras_cmd->ras_out_message.flags.err_inject_switch_disable_flag) { 121343965797SJohn Clements dev_warn(psp->adev->dev, "ECC switch disabled\n"); 121443965797SJohn Clements 121543965797SJohn Clements ras_cmd->ras_status = TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE; 121643965797SJohn Clements } 121743965797SJohn Clements else if (ras_cmd->ras_out_message.flags.reg_access_failure_flag) 121843965797SJohn Clements dev_warn(psp->adev->dev, 121943965797SJohn Clements "RAS internal register access blocked\n"); 122043965797SJohn Clements } 122143965797SJohn Clements 122243965797SJohn Clements return ret; 12235e5d3154Sxinhui pan } 12245e5d3154Sxinhui pan 1225011907fdSDennis Li static int psp_ras_status_to_errno(struct amdgpu_device *adev, 1226011907fdSDennis Li enum ta_ras_status ras_status) 1227011907fdSDennis Li { 1228011907fdSDennis Li int ret = -EINVAL; 1229011907fdSDennis Li 1230011907fdSDennis Li switch (ras_status) { 1231011907fdSDennis Li case TA_RAS_STATUS__SUCCESS: 1232011907fdSDennis Li ret = 0; 1233011907fdSDennis Li break; 1234011907fdSDennis Li case TA_RAS_STATUS__RESET_NEEDED: 1235011907fdSDennis Li ret = -EAGAIN; 1236011907fdSDennis Li break; 1237011907fdSDennis Li case TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE: 1238011907fdSDennis Li dev_warn(adev->dev, "RAS WARN: ras function unavailable\n"); 1239011907fdSDennis Li break; 1240011907fdSDennis Li case TA_RAS_STATUS__ERROR_ASD_READ_WRITE: 1241011907fdSDennis Li dev_warn(adev->dev, "RAS WARN: asd read or write failed\n"); 1242011907fdSDennis Li break; 1243011907fdSDennis Li default: 1244011907fdSDennis Li dev_err(adev->dev, "RAS ERROR: ras function failed ret 0x%X\n", ret); 1245011907fdSDennis Li } 1246011907fdSDennis Li 1247011907fdSDennis Li return ret; 1248011907fdSDennis Li } 1249011907fdSDennis Li 12505e5d3154Sxinhui pan int psp_ras_enable_features(struct psp_context *psp, 12515e5d3154Sxinhui pan union ta_ras_cmd_input *info, bool enable) 12525e5d3154Sxinhui pan { 12535e5d3154Sxinhui pan struct ta_ras_shared_memory *ras_cmd; 12545e5d3154Sxinhui pan int ret; 12555e5d3154Sxinhui pan 12565e5d3154Sxinhui pan if (!psp->ras.ras_initialized) 12575e5d3154Sxinhui pan return -EINVAL; 12585e5d3154Sxinhui pan 12595e5d3154Sxinhui pan ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; 12605e5d3154Sxinhui pan memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory)); 12615e5d3154Sxinhui pan 12625e5d3154Sxinhui pan if (enable) 12635e5d3154Sxinhui pan ras_cmd->cmd_id = TA_RAS_COMMAND__ENABLE_FEATURES; 12645e5d3154Sxinhui pan else 12655e5d3154Sxinhui pan ras_cmd->cmd_id = TA_RAS_COMMAND__DISABLE_FEATURES; 12665e5d3154Sxinhui pan 12675e5d3154Sxinhui pan ras_cmd->ras_in_message = *info; 12685e5d3154Sxinhui pan 12695e5d3154Sxinhui pan ret = psp_ras_invoke(psp, ras_cmd->cmd_id); 12705e5d3154Sxinhui pan if (ret) 12715e5d3154Sxinhui pan return -EINVAL; 12725e5d3154Sxinhui pan 1273011907fdSDennis Li return psp_ras_status_to_errno(psp->adev, ras_cmd->ras_status); 12745e5d3154Sxinhui pan } 12755e5d3154Sxinhui pan 12765e5d3154Sxinhui pan static int psp_ras_terminate(struct psp_context *psp) 12775e5d3154Sxinhui pan { 12785e5d3154Sxinhui pan int ret; 12795e5d3154Sxinhui pan 1280edc2176dSJack Zhang /* 1281edc2176dSJack Zhang * TODO: bypass the terminate in sriov for now 1282edc2176dSJack Zhang */ 1283edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1284edc2176dSJack Zhang return 0; 1285edc2176dSJack Zhang 12865e5d3154Sxinhui pan if (!psp->ras.ras_initialized) 12875e5d3154Sxinhui pan return 0; 12885e5d3154Sxinhui pan 12895e5d3154Sxinhui pan ret = psp_ras_unload(psp); 12905e5d3154Sxinhui pan if (ret) 12915e5d3154Sxinhui pan return ret; 12925e5d3154Sxinhui pan 1293e95cd6b2Szhengbin psp->ras.ras_initialized = false; 12945e5d3154Sxinhui pan 12955e5d3154Sxinhui pan /* free ras shared memory */ 12965e5d3154Sxinhui pan amdgpu_bo_free_kernel(&psp->ras.ras_shared_bo, 12975e5d3154Sxinhui pan &psp->ras.ras_shared_mc_addr, 12985e5d3154Sxinhui pan &psp->ras.ras_shared_buf); 12995e5d3154Sxinhui pan 13005e5d3154Sxinhui pan return 0; 13015e5d3154Sxinhui pan } 13025e5d3154Sxinhui pan 13035e5d3154Sxinhui pan static int psp_ras_initialize(struct psp_context *psp) 13045e5d3154Sxinhui pan { 13055e5d3154Sxinhui pan int ret; 13066246a416SHawking Zhang uint32_t boot_cfg = 0xFF; 13076246a416SHawking Zhang struct amdgpu_device *adev = psp->adev; 13085e5d3154Sxinhui pan 1309edc2176dSJack Zhang /* 1310edc2176dSJack Zhang * TODO: bypass the initialize in sriov for now 1311edc2176dSJack Zhang */ 13126246a416SHawking Zhang if (amdgpu_sriov_vf(adev)) 1313edc2176dSJack Zhang return 0; 1314edc2176dSJack Zhang 13156246a416SHawking Zhang if (!adev->psp.ta_ras_ucode_size || 13166246a416SHawking Zhang !adev->psp.ta_ras_start_addr) { 13176246a416SHawking Zhang dev_info(adev->dev, "RAS: optional ras ta ucode is not available\n"); 131851bd3638SHawking Zhang return 0; 131951bd3638SHawking Zhang } 132051bd3638SHawking Zhang 13216246a416SHawking Zhang if (amdgpu_atomfirmware_dynamic_boot_config_supported(adev)) { 13226246a416SHawking Zhang /* query GECC enablement status from boot config 13236246a416SHawking Zhang * boot_cfg: 1: GECC is enabled or 0: GECC is disabled 13246246a416SHawking Zhang */ 13256246a416SHawking Zhang ret = psp_boot_config_get(adev, &boot_cfg); 13266246a416SHawking Zhang if (ret) 13276246a416SHawking Zhang dev_warn(adev->dev, "PSP get boot config failed\n"); 13286246a416SHawking Zhang 13296246a416SHawking Zhang if (!amdgpu_ras_is_supported(psp->adev, AMDGPU_RAS_BLOCK__UMC)) { 13306246a416SHawking Zhang if (!boot_cfg) { 13316246a416SHawking Zhang dev_info(adev->dev, "GECC is disabled\n"); 13326246a416SHawking Zhang } else { 13336246a416SHawking Zhang /* disable GECC in next boot cycle if ras is 13346246a416SHawking Zhang * disabled by module parameter amdgpu_ras_enable 13356246a416SHawking Zhang * and/or amdgpu_ras_mask, or boot_config_get call 13366246a416SHawking Zhang * is failed 13376246a416SHawking Zhang */ 13386246a416SHawking Zhang ret = psp_boot_config_set(adev, 0); 13396246a416SHawking Zhang if (ret) 13406246a416SHawking Zhang dev_warn(adev->dev, "PSP set boot config failed\n"); 13416246a416SHawking Zhang else 13426246a416SHawking Zhang dev_warn(adev->dev, "GECC will be disabled in next boot cycle " 13436246a416SHawking Zhang "if set amdgpu_ras_enable and/or amdgpu_ras_mask to 0x0\n"); 13446246a416SHawking Zhang } 13456246a416SHawking Zhang } else { 13466246a416SHawking Zhang if (1 == boot_cfg) { 13476246a416SHawking Zhang dev_info(adev->dev, "GECC is enabled\n"); 13486246a416SHawking Zhang } else { 13496246a416SHawking Zhang /* enable GECC in next boot cycle if it is disabled 13506246a416SHawking Zhang * in boot config, or force enable GECC if failed to 13516246a416SHawking Zhang * get boot configuration 13526246a416SHawking Zhang */ 13536246a416SHawking Zhang ret = psp_boot_config_set(adev, BOOT_CONFIG_GECC); 13546246a416SHawking Zhang if (ret) 13556246a416SHawking Zhang dev_warn(adev->dev, "PSP set boot config failed\n"); 13566246a416SHawking Zhang else 13576246a416SHawking Zhang dev_warn(adev->dev, "GECC will be enabled in next boot cycle\n"); 13586246a416SHawking Zhang } 13596246a416SHawking Zhang } 13606246a416SHawking Zhang } 13616246a416SHawking Zhang 13625e5d3154Sxinhui pan if (!psp->ras.ras_initialized) { 13635e5d3154Sxinhui pan ret = psp_ras_init_shared_buf(psp); 13645e5d3154Sxinhui pan if (ret) 13655e5d3154Sxinhui pan return ret; 13665e5d3154Sxinhui pan } 13675e5d3154Sxinhui pan 13685e5d3154Sxinhui pan ret = psp_ras_load(psp); 13695e5d3154Sxinhui pan if (ret) 13705e5d3154Sxinhui pan return ret; 13715e5d3154Sxinhui pan 13725e5d3154Sxinhui pan return 0; 13735e5d3154Sxinhui pan } 1374001a0a95SHawking Zhang 1375001a0a95SHawking Zhang int psp_ras_trigger_error(struct psp_context *psp, 1376001a0a95SHawking Zhang struct ta_ras_trigger_error_input *info) 1377001a0a95SHawking Zhang { 1378001a0a95SHawking Zhang struct ta_ras_shared_memory *ras_cmd; 1379001a0a95SHawking Zhang int ret; 1380001a0a95SHawking Zhang 1381001a0a95SHawking Zhang if (!psp->ras.ras_initialized) 1382001a0a95SHawking Zhang return -EINVAL; 1383001a0a95SHawking Zhang 1384001a0a95SHawking Zhang ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; 1385001a0a95SHawking Zhang memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory)); 1386001a0a95SHawking Zhang 1387001a0a95SHawking Zhang ras_cmd->cmd_id = TA_RAS_COMMAND__TRIGGER_ERROR; 1388001a0a95SHawking Zhang ras_cmd->ras_in_message.trigger_error = *info; 1389001a0a95SHawking Zhang 1390001a0a95SHawking Zhang ret = psp_ras_invoke(psp, ras_cmd->cmd_id); 1391001a0a95SHawking Zhang if (ret) 1392001a0a95SHawking Zhang return -EINVAL; 1393001a0a95SHawking Zhang 1394001a0a95SHawking Zhang /* If err_event_athub occurs error inject was successful, however 1395001a0a95SHawking Zhang return status from TA is no long reliable */ 1396001a0a95SHawking Zhang if (amdgpu_ras_intr_triggered()) 1397001a0a95SHawking Zhang return 0; 1398001a0a95SHawking Zhang 1399011907fdSDennis Li return psp_ras_status_to_errno(psp->adev, ras_cmd->ras_status); 1400001a0a95SHawking Zhang } 14015e5d3154Sxinhui pan // ras end 14025e5d3154Sxinhui pan 1403ed19a9a2SBhawanpreet Lakha // HDCP start 1404ed19a9a2SBhawanpreet Lakha static int psp_hdcp_init_shared_buf(struct psp_context *psp) 1405ed19a9a2SBhawanpreet Lakha { 1406ed19a9a2SBhawanpreet Lakha int ret; 1407ed19a9a2SBhawanpreet Lakha 1408ed19a9a2SBhawanpreet Lakha /* 1409ed19a9a2SBhawanpreet Lakha * Allocate 16k memory aligned to 4k from Frame Buffer (local 1410ed19a9a2SBhawanpreet Lakha * physical) for hdcp ta <-> Driver 1411ed19a9a2SBhawanpreet Lakha */ 1412ed19a9a2SBhawanpreet Lakha ret = amdgpu_bo_create_kernel(psp->adev, PSP_HDCP_SHARED_MEM_SIZE, 1413ed19a9a2SBhawanpreet Lakha PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 1414ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_bo, 1415ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_mc_addr, 1416ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_buf); 1417ed19a9a2SBhawanpreet Lakha 1418ed19a9a2SBhawanpreet Lakha return ret; 1419ed19a9a2SBhawanpreet Lakha } 1420ed19a9a2SBhawanpreet Lakha 1421ed19a9a2SBhawanpreet Lakha static int psp_hdcp_load(struct psp_context *psp) 1422ed19a9a2SBhawanpreet Lakha { 1423ed19a9a2SBhawanpreet Lakha int ret; 1424ed19a9a2SBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1425ed19a9a2SBhawanpreet Lakha 1426ed19a9a2SBhawanpreet Lakha /* 1427ed19a9a2SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1428ed19a9a2SBhawanpreet Lakha */ 1429ed19a9a2SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1430ed19a9a2SBhawanpreet Lakha return 0; 1431ed19a9a2SBhawanpreet Lakha 1432ed19a9a2SBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1433ed19a9a2SBhawanpreet Lakha if (!cmd) 1434ed19a9a2SBhawanpreet Lakha return -ENOMEM; 1435ed19a9a2SBhawanpreet Lakha 1436f89f8c6bSAndrey Grodzovsky psp_copy_fw(psp, psp->ta_hdcp_start_addr, 1437ed19a9a2SBhawanpreet Lakha psp->ta_hdcp_ucode_size); 1438ed19a9a2SBhawanpreet Lakha 14391f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 14401f455f25SJohn Clements psp->fw_pri_mc_addr, 1441ed19a9a2SBhawanpreet Lakha psp->ta_hdcp_ucode_size, 14421f455f25SJohn Clements psp->hdcp_context.hdcp_shared_mc_addr, 1443ed19a9a2SBhawanpreet Lakha PSP_HDCP_SHARED_MEM_SIZE); 1444ed19a9a2SBhawanpreet Lakha 1445ed19a9a2SBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1446ed19a9a2SBhawanpreet Lakha 1447ed19a9a2SBhawanpreet Lakha if (!ret) { 1448e95cd6b2Szhengbin psp->hdcp_context.hdcp_initialized = true; 1449ed19a9a2SBhawanpreet Lakha psp->hdcp_context.session_id = cmd->resp.session_id; 14508913f7ffSBhawanpreet Lakha mutex_init(&psp->hdcp_context.mutex); 1451ed19a9a2SBhawanpreet Lakha } 1452ed19a9a2SBhawanpreet Lakha 1453ed19a9a2SBhawanpreet Lakha kfree(cmd); 1454ed19a9a2SBhawanpreet Lakha 1455ed19a9a2SBhawanpreet Lakha return ret; 1456ed19a9a2SBhawanpreet Lakha } 1457ed19a9a2SBhawanpreet Lakha static int psp_hdcp_initialize(struct psp_context *psp) 1458ed19a9a2SBhawanpreet Lakha { 1459ed19a9a2SBhawanpreet Lakha int ret; 1460ed19a9a2SBhawanpreet Lakha 1461edc2176dSJack Zhang /* 1462edc2176dSJack Zhang * TODO: bypass the initialize in sriov for now 1463edc2176dSJack Zhang */ 1464edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1465edc2176dSJack Zhang return 0; 1466edc2176dSJack Zhang 146751bd3638SHawking Zhang if (!psp->adev->psp.ta_hdcp_ucode_size || 146851bd3638SHawking Zhang !psp->adev->psp.ta_hdcp_start_addr) { 1469a45a9e5eSAlex Deucher dev_info(psp->adev->dev, "HDCP: optional hdcp ta ucode is not available\n"); 147051bd3638SHawking Zhang return 0; 147151bd3638SHawking Zhang } 147251bd3638SHawking Zhang 1473ed19a9a2SBhawanpreet Lakha if (!psp->hdcp_context.hdcp_initialized) { 1474ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_init_shared_buf(psp); 1475ed19a9a2SBhawanpreet Lakha if (ret) 1476ed19a9a2SBhawanpreet Lakha return ret; 1477ed19a9a2SBhawanpreet Lakha } 1478ed19a9a2SBhawanpreet Lakha 1479ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_load(psp); 1480ed19a9a2SBhawanpreet Lakha if (ret) 1481ed19a9a2SBhawanpreet Lakha return ret; 1482ed19a9a2SBhawanpreet Lakha 1483ed19a9a2SBhawanpreet Lakha return 0; 1484ed19a9a2SBhawanpreet Lakha } 1485ed19a9a2SBhawanpreet Lakha 1486ed19a9a2SBhawanpreet Lakha static int psp_hdcp_unload(struct psp_context *psp) 1487ed19a9a2SBhawanpreet Lakha { 1488ed19a9a2SBhawanpreet Lakha int ret; 1489ed19a9a2SBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1490ed19a9a2SBhawanpreet Lakha 1491ed19a9a2SBhawanpreet Lakha /* 1492ed19a9a2SBhawanpreet Lakha * TODO: bypass the unloading in sriov for now 1493ed19a9a2SBhawanpreet Lakha */ 1494ed19a9a2SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1495ed19a9a2SBhawanpreet Lakha return 0; 1496ed19a9a2SBhawanpreet Lakha 1497ed19a9a2SBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1498ed19a9a2SBhawanpreet Lakha if (!cmd) 1499ed19a9a2SBhawanpreet Lakha return -ENOMEM; 1500ed19a9a2SBhawanpreet Lakha 15011f455f25SJohn Clements psp_prep_ta_unload_cmd_buf(cmd, psp->hdcp_context.session_id); 1502ed19a9a2SBhawanpreet Lakha 1503ed19a9a2SBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1504ed19a9a2SBhawanpreet Lakha 1505ed19a9a2SBhawanpreet Lakha kfree(cmd); 1506ed19a9a2SBhawanpreet Lakha 1507ed19a9a2SBhawanpreet Lakha return ret; 1508ed19a9a2SBhawanpreet Lakha } 1509ed19a9a2SBhawanpreet Lakha 1510ed19a9a2SBhawanpreet Lakha int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 1511ed19a9a2SBhawanpreet Lakha { 1512ed19a9a2SBhawanpreet Lakha /* 1513ed19a9a2SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1514ed19a9a2SBhawanpreet Lakha */ 1515ed19a9a2SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1516ed19a9a2SBhawanpreet Lakha return 0; 1517ed19a9a2SBhawanpreet Lakha 151834e48caeSJohn Clements return psp_ta_invoke(psp, ta_cmd_id, psp->hdcp_context.session_id); 1519ed19a9a2SBhawanpreet Lakha } 1520ed19a9a2SBhawanpreet Lakha 1521ed19a9a2SBhawanpreet Lakha static int psp_hdcp_terminate(struct psp_context *psp) 1522ed19a9a2SBhawanpreet Lakha { 1523ed19a9a2SBhawanpreet Lakha int ret; 1524ed19a9a2SBhawanpreet Lakha 1525edc2176dSJack Zhang /* 1526edc2176dSJack Zhang * TODO: bypass the terminate in sriov for now 1527edc2176dSJack Zhang */ 1528edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1529edc2176dSJack Zhang return 0; 1530edc2176dSJack Zhang 15310d232dadSJiawei Gu if (!psp->hdcp_context.hdcp_initialized) { 15320d232dadSJiawei Gu if (psp->hdcp_context.hdcp_shared_buf) 15330d232dadSJiawei Gu goto out; 15340d232dadSJiawei Gu else 1535ed19a9a2SBhawanpreet Lakha return 0; 15360d232dadSJiawei Gu } 1537ed19a9a2SBhawanpreet Lakha 1538ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_unload(psp); 1539ed19a9a2SBhawanpreet Lakha if (ret) 1540ed19a9a2SBhawanpreet Lakha return ret; 1541ed19a9a2SBhawanpreet Lakha 1542e95cd6b2Szhengbin psp->hdcp_context.hdcp_initialized = false; 1543ed19a9a2SBhawanpreet Lakha 15440d232dadSJiawei Gu out: 1545ed19a9a2SBhawanpreet Lakha /* free hdcp shared memory */ 1546ed19a9a2SBhawanpreet Lakha amdgpu_bo_free_kernel(&psp->hdcp_context.hdcp_shared_bo, 1547ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_mc_addr, 1548ed19a9a2SBhawanpreet Lakha &psp->hdcp_context.hdcp_shared_buf); 1549ed19a9a2SBhawanpreet Lakha 1550ed19a9a2SBhawanpreet Lakha return 0; 1551ed19a9a2SBhawanpreet Lakha } 1552ed19a9a2SBhawanpreet Lakha // HDCP end 1553ed19a9a2SBhawanpreet Lakha 1554143f2305SBhawanpreet Lakha // DTM start 1555143f2305SBhawanpreet Lakha static int psp_dtm_init_shared_buf(struct psp_context *psp) 1556143f2305SBhawanpreet Lakha { 1557143f2305SBhawanpreet Lakha int ret; 1558143f2305SBhawanpreet Lakha 1559143f2305SBhawanpreet Lakha /* 1560143f2305SBhawanpreet Lakha * Allocate 16k memory aligned to 4k from Frame Buffer (local 1561143f2305SBhawanpreet Lakha * physical) for dtm ta <-> Driver 1562143f2305SBhawanpreet Lakha */ 1563143f2305SBhawanpreet Lakha ret = amdgpu_bo_create_kernel(psp->adev, PSP_DTM_SHARED_MEM_SIZE, 1564143f2305SBhawanpreet Lakha PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 1565143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_bo, 1566143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_mc_addr, 1567143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_buf); 1568143f2305SBhawanpreet Lakha 1569143f2305SBhawanpreet Lakha return ret; 1570143f2305SBhawanpreet Lakha } 1571143f2305SBhawanpreet Lakha 1572143f2305SBhawanpreet Lakha static int psp_dtm_load(struct psp_context *psp) 1573143f2305SBhawanpreet Lakha { 1574143f2305SBhawanpreet Lakha int ret; 1575143f2305SBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1576143f2305SBhawanpreet Lakha 1577143f2305SBhawanpreet Lakha /* 1578143f2305SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1579143f2305SBhawanpreet Lakha */ 1580143f2305SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1581143f2305SBhawanpreet Lakha return 0; 1582143f2305SBhawanpreet Lakha 1583143f2305SBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1584143f2305SBhawanpreet Lakha if (!cmd) 1585143f2305SBhawanpreet Lakha return -ENOMEM; 1586143f2305SBhawanpreet Lakha 1587f89f8c6bSAndrey Grodzovsky psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size); 1588143f2305SBhawanpreet Lakha 15891f455f25SJohn Clements psp_prep_ta_load_cmd_buf(cmd, 15901f455f25SJohn Clements psp->fw_pri_mc_addr, 1591143f2305SBhawanpreet Lakha psp->ta_dtm_ucode_size, 15921f455f25SJohn Clements psp->dtm_context.dtm_shared_mc_addr, 1593143f2305SBhawanpreet Lakha PSP_DTM_SHARED_MEM_SIZE); 1594143f2305SBhawanpreet Lakha 1595143f2305SBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1596143f2305SBhawanpreet Lakha 1597143f2305SBhawanpreet Lakha if (!ret) { 1598e95cd6b2Szhengbin psp->dtm_context.dtm_initialized = true; 1599143f2305SBhawanpreet Lakha psp->dtm_context.session_id = cmd->resp.session_id; 16008913f7ffSBhawanpreet Lakha mutex_init(&psp->dtm_context.mutex); 1601143f2305SBhawanpreet Lakha } 1602143f2305SBhawanpreet Lakha 1603143f2305SBhawanpreet Lakha kfree(cmd); 1604143f2305SBhawanpreet Lakha 1605143f2305SBhawanpreet Lakha return ret; 1606143f2305SBhawanpreet Lakha } 1607143f2305SBhawanpreet Lakha 1608143f2305SBhawanpreet Lakha static int psp_dtm_initialize(struct psp_context *psp) 1609143f2305SBhawanpreet Lakha { 1610143f2305SBhawanpreet Lakha int ret; 1611143f2305SBhawanpreet Lakha 1612edc2176dSJack Zhang /* 1613edc2176dSJack Zhang * TODO: bypass the initialize in sriov for now 1614edc2176dSJack Zhang */ 1615edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1616edc2176dSJack Zhang return 0; 1617edc2176dSJack Zhang 161851bd3638SHawking Zhang if (!psp->adev->psp.ta_dtm_ucode_size || 161951bd3638SHawking Zhang !psp->adev->psp.ta_dtm_start_addr) { 1620a45a9e5eSAlex Deucher dev_info(psp->adev->dev, "DTM: optional dtm ta ucode is not available\n"); 162151bd3638SHawking Zhang return 0; 162251bd3638SHawking Zhang } 162351bd3638SHawking Zhang 1624143f2305SBhawanpreet Lakha if (!psp->dtm_context.dtm_initialized) { 1625143f2305SBhawanpreet Lakha ret = psp_dtm_init_shared_buf(psp); 1626143f2305SBhawanpreet Lakha if (ret) 1627143f2305SBhawanpreet Lakha return ret; 1628143f2305SBhawanpreet Lakha } 1629143f2305SBhawanpreet Lakha 1630143f2305SBhawanpreet Lakha ret = psp_dtm_load(psp); 1631143f2305SBhawanpreet Lakha if (ret) 1632143f2305SBhawanpreet Lakha return ret; 1633143f2305SBhawanpreet Lakha 1634143f2305SBhawanpreet Lakha return 0; 1635143f2305SBhawanpreet Lakha } 1636143f2305SBhawanpreet Lakha 1637c786530bSBhawanpreet Lakha static int psp_dtm_unload(struct psp_context *psp) 1638c786530bSBhawanpreet Lakha { 1639c786530bSBhawanpreet Lakha int ret; 1640c786530bSBhawanpreet Lakha struct psp_gfx_cmd_resp *cmd; 1641c786530bSBhawanpreet Lakha 1642c786530bSBhawanpreet Lakha /* 1643c786530bSBhawanpreet Lakha * TODO: bypass the unloading in sriov for now 1644c786530bSBhawanpreet Lakha */ 1645c786530bSBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1646c786530bSBhawanpreet Lakha return 0; 1647c786530bSBhawanpreet Lakha 1648c786530bSBhawanpreet Lakha cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1649c786530bSBhawanpreet Lakha if (!cmd) 1650c786530bSBhawanpreet Lakha return -ENOMEM; 1651c786530bSBhawanpreet Lakha 1652c786530bSBhawanpreet Lakha psp_prep_ta_unload_cmd_buf(cmd, psp->dtm_context.session_id); 1653c786530bSBhawanpreet Lakha 1654c786530bSBhawanpreet Lakha ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1655c786530bSBhawanpreet Lakha 1656c786530bSBhawanpreet Lakha kfree(cmd); 1657c786530bSBhawanpreet Lakha 1658c786530bSBhawanpreet Lakha return ret; 1659c786530bSBhawanpreet Lakha } 1660c786530bSBhawanpreet Lakha 1661143f2305SBhawanpreet Lakha int psp_dtm_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 1662143f2305SBhawanpreet Lakha { 1663143f2305SBhawanpreet Lakha /* 1664143f2305SBhawanpreet Lakha * TODO: bypass the loading in sriov for now 1665143f2305SBhawanpreet Lakha */ 1666143f2305SBhawanpreet Lakha if (amdgpu_sriov_vf(psp->adev)) 1667143f2305SBhawanpreet Lakha return 0; 1668143f2305SBhawanpreet Lakha 166934e48caeSJohn Clements return psp_ta_invoke(psp, ta_cmd_id, psp->dtm_context.session_id); 1670143f2305SBhawanpreet Lakha } 1671143f2305SBhawanpreet Lakha 1672143f2305SBhawanpreet Lakha static int psp_dtm_terminate(struct psp_context *psp) 1673143f2305SBhawanpreet Lakha { 1674143f2305SBhawanpreet Lakha int ret; 1675143f2305SBhawanpreet Lakha 1676edc2176dSJack Zhang /* 1677edc2176dSJack Zhang * TODO: bypass the terminate in sriov for now 1678edc2176dSJack Zhang */ 1679edc2176dSJack Zhang if (amdgpu_sriov_vf(psp->adev)) 1680edc2176dSJack Zhang return 0; 1681edc2176dSJack Zhang 16820d232dadSJiawei Gu if (!psp->dtm_context.dtm_initialized) { 16830d232dadSJiawei Gu if (psp->dtm_context.dtm_shared_buf) 16840d232dadSJiawei Gu goto out; 16850d232dadSJiawei Gu else 1686143f2305SBhawanpreet Lakha return 0; 16870d232dadSJiawei Gu } 1688143f2305SBhawanpreet Lakha 1689c786530bSBhawanpreet Lakha ret = psp_dtm_unload(psp); 1690143f2305SBhawanpreet Lakha if (ret) 1691143f2305SBhawanpreet Lakha return ret; 1692143f2305SBhawanpreet Lakha 1693e95cd6b2Szhengbin psp->dtm_context.dtm_initialized = false; 1694143f2305SBhawanpreet Lakha 16950d232dadSJiawei Gu out: 1696143f2305SBhawanpreet Lakha /* free hdcp shared memory */ 1697143f2305SBhawanpreet Lakha amdgpu_bo_free_kernel(&psp->dtm_context.dtm_shared_bo, 1698143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_mc_addr, 1699143f2305SBhawanpreet Lakha &psp->dtm_context.dtm_shared_buf); 1700143f2305SBhawanpreet Lakha 1701143f2305SBhawanpreet Lakha return 0; 1702143f2305SBhawanpreet Lakha } 1703143f2305SBhawanpreet Lakha // DTM end 1704143f2305SBhawanpreet Lakha 17058602692bSWenhui Sheng // RAP start 17068602692bSWenhui Sheng static int psp_rap_init_shared_buf(struct psp_context *psp) 17078602692bSWenhui Sheng { 17088602692bSWenhui Sheng int ret; 17098602692bSWenhui Sheng 17108602692bSWenhui Sheng /* 17118602692bSWenhui Sheng * Allocate 16k memory aligned to 4k from Frame Buffer (local 17128602692bSWenhui Sheng * physical) for rap ta <-> Driver 17138602692bSWenhui Sheng */ 17148602692bSWenhui Sheng ret = amdgpu_bo_create_kernel(psp->adev, PSP_RAP_SHARED_MEM_SIZE, 17158602692bSWenhui Sheng PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 17168602692bSWenhui Sheng &psp->rap_context.rap_shared_bo, 17178602692bSWenhui Sheng &psp->rap_context.rap_shared_mc_addr, 17188602692bSWenhui Sheng &psp->rap_context.rap_shared_buf); 17198602692bSWenhui Sheng 17208602692bSWenhui Sheng return ret; 17218602692bSWenhui Sheng } 17228602692bSWenhui Sheng 17238602692bSWenhui Sheng static int psp_rap_load(struct psp_context *psp) 17248602692bSWenhui Sheng { 17258602692bSWenhui Sheng int ret; 17268602692bSWenhui Sheng struct psp_gfx_cmd_resp *cmd; 17278602692bSWenhui Sheng 17288602692bSWenhui Sheng cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 17298602692bSWenhui Sheng if (!cmd) 17308602692bSWenhui Sheng return -ENOMEM; 17318602692bSWenhui Sheng 1732f89f8c6bSAndrey Grodzovsky psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size); 17338602692bSWenhui Sheng 17348602692bSWenhui Sheng psp_prep_ta_load_cmd_buf(cmd, 17358602692bSWenhui Sheng psp->fw_pri_mc_addr, 17368602692bSWenhui Sheng psp->ta_rap_ucode_size, 17378602692bSWenhui Sheng psp->rap_context.rap_shared_mc_addr, 17388602692bSWenhui Sheng PSP_RAP_SHARED_MEM_SIZE); 17398602692bSWenhui Sheng 17408602692bSWenhui Sheng ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 17418602692bSWenhui Sheng 17428602692bSWenhui Sheng if (!ret) { 17438602692bSWenhui Sheng psp->rap_context.rap_initialized = true; 17448602692bSWenhui Sheng psp->rap_context.session_id = cmd->resp.session_id; 17458602692bSWenhui Sheng mutex_init(&psp->rap_context.mutex); 17468602692bSWenhui Sheng } 17478602692bSWenhui Sheng 17488602692bSWenhui Sheng kfree(cmd); 17498602692bSWenhui Sheng 17508602692bSWenhui Sheng return ret; 17518602692bSWenhui Sheng } 17528602692bSWenhui Sheng 17538602692bSWenhui Sheng static int psp_rap_unload(struct psp_context *psp) 17548602692bSWenhui Sheng { 17558602692bSWenhui Sheng int ret; 17568602692bSWenhui Sheng struct psp_gfx_cmd_resp *cmd; 17578602692bSWenhui Sheng 17588602692bSWenhui Sheng cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 17598602692bSWenhui Sheng if (!cmd) 17608602692bSWenhui Sheng return -ENOMEM; 17618602692bSWenhui Sheng 17628602692bSWenhui Sheng psp_prep_ta_unload_cmd_buf(cmd, psp->rap_context.session_id); 17638602692bSWenhui Sheng 17648602692bSWenhui Sheng ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 17658602692bSWenhui Sheng 17668602692bSWenhui Sheng kfree(cmd); 17678602692bSWenhui Sheng 17688602692bSWenhui Sheng return ret; 17698602692bSWenhui Sheng } 17708602692bSWenhui Sheng 17718602692bSWenhui Sheng static int psp_rap_initialize(struct psp_context *psp) 17728602692bSWenhui Sheng { 17738602692bSWenhui Sheng int ret; 17742fb3c5d0SKevin Wang enum ta_rap_status status = TA_RAP_STATUS__SUCCESS; 17758602692bSWenhui Sheng 17768602692bSWenhui Sheng /* 17778602692bSWenhui Sheng * TODO: bypass the initialize in sriov for now 17788602692bSWenhui Sheng */ 17798602692bSWenhui Sheng if (amdgpu_sriov_vf(psp->adev)) 17808602692bSWenhui Sheng return 0; 17818602692bSWenhui Sheng 17828602692bSWenhui Sheng if (!psp->adev->psp.ta_rap_ucode_size || 17838602692bSWenhui Sheng !psp->adev->psp.ta_rap_start_addr) { 17848602692bSWenhui Sheng dev_info(psp->adev->dev, "RAP: optional rap ta ucode is not available\n"); 17858602692bSWenhui Sheng return 0; 17868602692bSWenhui Sheng } 17878602692bSWenhui Sheng 17888602692bSWenhui Sheng if (!psp->rap_context.rap_initialized) { 17898602692bSWenhui Sheng ret = psp_rap_init_shared_buf(psp); 17908602692bSWenhui Sheng if (ret) 17918602692bSWenhui Sheng return ret; 17928602692bSWenhui Sheng } 17938602692bSWenhui Sheng 17948602692bSWenhui Sheng ret = psp_rap_load(psp); 17958602692bSWenhui Sheng if (ret) 17968602692bSWenhui Sheng return ret; 17978602692bSWenhui Sheng 17982fb3c5d0SKevin Wang ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE, &status); 17992fb3c5d0SKevin Wang if (ret || status != TA_RAP_STATUS__SUCCESS) { 18008602692bSWenhui Sheng psp_rap_unload(psp); 18018602692bSWenhui Sheng 18028602692bSWenhui Sheng amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo, 18038602692bSWenhui Sheng &psp->rap_context.rap_shared_mc_addr, 18048602692bSWenhui Sheng &psp->rap_context.rap_shared_buf); 18058602692bSWenhui Sheng 18068602692bSWenhui Sheng psp->rap_context.rap_initialized = false; 18078602692bSWenhui Sheng 18082fb3c5d0SKevin Wang dev_warn(psp->adev->dev, "RAP TA initialize fail (%d) status %d.\n", 18092fb3c5d0SKevin Wang ret, status); 18102fb3c5d0SKevin Wang 18112fb3c5d0SKevin Wang return ret; 18128602692bSWenhui Sheng } 18138602692bSWenhui Sheng 18148602692bSWenhui Sheng return 0; 18158602692bSWenhui Sheng } 18168602692bSWenhui Sheng 18178602692bSWenhui Sheng static int psp_rap_terminate(struct psp_context *psp) 18188602692bSWenhui Sheng { 18198602692bSWenhui Sheng int ret; 18208602692bSWenhui Sheng 18218602692bSWenhui Sheng if (!psp->rap_context.rap_initialized) 18228602692bSWenhui Sheng return 0; 18238602692bSWenhui Sheng 18248602692bSWenhui Sheng ret = psp_rap_unload(psp); 18258602692bSWenhui Sheng 18268602692bSWenhui Sheng psp->rap_context.rap_initialized = false; 18278602692bSWenhui Sheng 18288602692bSWenhui Sheng /* free rap shared memory */ 18298602692bSWenhui Sheng amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo, 18308602692bSWenhui Sheng &psp->rap_context.rap_shared_mc_addr, 18318602692bSWenhui Sheng &psp->rap_context.rap_shared_buf); 18328602692bSWenhui Sheng 18338602692bSWenhui Sheng return ret; 18348602692bSWenhui Sheng } 18358602692bSWenhui Sheng 18362fb3c5d0SKevin Wang int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id, enum ta_rap_status *status) 18378602692bSWenhui Sheng { 18388602692bSWenhui Sheng struct ta_rap_shared_memory *rap_cmd; 18392fb3c5d0SKevin Wang int ret = 0; 18408602692bSWenhui Sheng 18418602692bSWenhui Sheng if (!psp->rap_context.rap_initialized) 18422fb3c5d0SKevin Wang return 0; 18438602692bSWenhui Sheng 18448602692bSWenhui Sheng if (ta_cmd_id != TA_CMD_RAP__INITIALIZE && 18458602692bSWenhui Sheng ta_cmd_id != TA_CMD_RAP__VALIDATE_L0) 18468602692bSWenhui Sheng return -EINVAL; 18478602692bSWenhui Sheng 18488602692bSWenhui Sheng mutex_lock(&psp->rap_context.mutex); 18498602692bSWenhui Sheng 18508602692bSWenhui Sheng rap_cmd = (struct ta_rap_shared_memory *) 18518602692bSWenhui Sheng psp->rap_context.rap_shared_buf; 18528602692bSWenhui Sheng memset(rap_cmd, 0, sizeof(struct ta_rap_shared_memory)); 18538602692bSWenhui Sheng 18548602692bSWenhui Sheng rap_cmd->cmd_id = ta_cmd_id; 18558602692bSWenhui Sheng rap_cmd->validation_method_id = METHOD_A; 18568602692bSWenhui Sheng 18578602692bSWenhui Sheng ret = psp_ta_invoke(psp, rap_cmd->cmd_id, psp->rap_context.session_id); 18582fb3c5d0SKevin Wang if (ret) 18592fb3c5d0SKevin Wang goto out_unlock; 18602fb3c5d0SKevin Wang 18612fb3c5d0SKevin Wang if (status) 18622fb3c5d0SKevin Wang *status = rap_cmd->rap_status; 18632fb3c5d0SKevin Wang 18642fb3c5d0SKevin Wang out_unlock: 18658602692bSWenhui Sheng mutex_unlock(&psp->rap_context.mutex); 18662fb3c5d0SKevin Wang 18678602692bSWenhui Sheng return ret; 18688602692bSWenhui Sheng } 18698602692bSWenhui Sheng // RAP end 18708602692bSWenhui Sheng 1871ecaafb7bSJinzhou Su /* securedisplay start */ 1872ecaafb7bSJinzhou Su static int psp_securedisplay_init_shared_buf(struct psp_context *psp) 1873ecaafb7bSJinzhou Su { 1874ecaafb7bSJinzhou Su int ret; 1875ecaafb7bSJinzhou Su 1876ecaafb7bSJinzhou Su /* 1877ecaafb7bSJinzhou Su * Allocate 16k memory aligned to 4k from Frame Buffer (local 1878ecaafb7bSJinzhou Su * physical) for sa ta <-> Driver 1879ecaafb7bSJinzhou Su */ 1880ecaafb7bSJinzhou Su ret = amdgpu_bo_create_kernel(psp->adev, PSP_SECUREDISPLAY_SHARED_MEM_SIZE, 1881ecaafb7bSJinzhou Su PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 1882ecaafb7bSJinzhou Su &psp->securedisplay_context.securedisplay_shared_bo, 1883ecaafb7bSJinzhou Su &psp->securedisplay_context.securedisplay_shared_mc_addr, 1884ecaafb7bSJinzhou Su &psp->securedisplay_context.securedisplay_shared_buf); 1885ecaafb7bSJinzhou Su 1886ecaafb7bSJinzhou Su return ret; 1887ecaafb7bSJinzhou Su } 1888ecaafb7bSJinzhou Su 1889ecaafb7bSJinzhou Su static int psp_securedisplay_load(struct psp_context *psp) 1890ecaafb7bSJinzhou Su { 1891ecaafb7bSJinzhou Su int ret; 1892ecaafb7bSJinzhou Su struct psp_gfx_cmd_resp *cmd; 1893ecaafb7bSJinzhou Su 1894ecaafb7bSJinzhou Su cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1895ecaafb7bSJinzhou Su if (!cmd) 1896ecaafb7bSJinzhou Su return -ENOMEM; 1897ecaafb7bSJinzhou Su 1898ecaafb7bSJinzhou Su memset(psp->fw_pri_buf, 0, PSP_1_MEG); 1899ecaafb7bSJinzhou Su memcpy(psp->fw_pri_buf, psp->ta_securedisplay_start_addr, psp->ta_securedisplay_ucode_size); 1900ecaafb7bSJinzhou Su 1901ecaafb7bSJinzhou Su psp_prep_ta_load_cmd_buf(cmd, 1902ecaafb7bSJinzhou Su psp->fw_pri_mc_addr, 1903ecaafb7bSJinzhou Su psp->ta_securedisplay_ucode_size, 1904ecaafb7bSJinzhou Su psp->securedisplay_context.securedisplay_shared_mc_addr, 1905ecaafb7bSJinzhou Su PSP_SECUREDISPLAY_SHARED_MEM_SIZE); 1906ecaafb7bSJinzhou Su 1907ecaafb7bSJinzhou Su ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1908ecaafb7bSJinzhou Su 1909ecaafb7bSJinzhou Su if (ret) 1910ecaafb7bSJinzhou Su goto failed; 1911ecaafb7bSJinzhou Su 1912ecaafb7bSJinzhou Su psp->securedisplay_context.securedisplay_initialized = true; 1913ecaafb7bSJinzhou Su psp->securedisplay_context.session_id = cmd->resp.session_id; 1914ecaafb7bSJinzhou Su mutex_init(&psp->securedisplay_context.mutex); 1915ecaafb7bSJinzhou Su 1916ecaafb7bSJinzhou Su failed: 1917ecaafb7bSJinzhou Su kfree(cmd); 1918ecaafb7bSJinzhou Su return ret; 1919ecaafb7bSJinzhou Su } 1920ecaafb7bSJinzhou Su 1921ecaafb7bSJinzhou Su static int psp_securedisplay_unload(struct psp_context *psp) 1922ecaafb7bSJinzhou Su { 1923ecaafb7bSJinzhou Su int ret; 1924ecaafb7bSJinzhou Su struct psp_gfx_cmd_resp *cmd; 1925ecaafb7bSJinzhou Su 1926ecaafb7bSJinzhou Su cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 1927ecaafb7bSJinzhou Su if (!cmd) 1928ecaafb7bSJinzhou Su return -ENOMEM; 1929ecaafb7bSJinzhou Su 1930ecaafb7bSJinzhou Su psp_prep_ta_unload_cmd_buf(cmd, psp->securedisplay_context.session_id); 1931ecaafb7bSJinzhou Su 1932ecaafb7bSJinzhou Su ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); 1933ecaafb7bSJinzhou Su 1934ecaafb7bSJinzhou Su kfree(cmd); 1935ecaafb7bSJinzhou Su 1936ecaafb7bSJinzhou Su return ret; 1937ecaafb7bSJinzhou Su } 1938ecaafb7bSJinzhou Su 1939ecaafb7bSJinzhou Su static int psp_securedisplay_initialize(struct psp_context *psp) 1940ecaafb7bSJinzhou Su { 1941ecaafb7bSJinzhou Su int ret; 1942ecaafb7bSJinzhou Su struct securedisplay_cmd *securedisplay_cmd; 1943ecaafb7bSJinzhou Su 1944ecaafb7bSJinzhou Su /* 1945ecaafb7bSJinzhou Su * TODO: bypass the initialize in sriov for now 1946ecaafb7bSJinzhou Su */ 1947ecaafb7bSJinzhou Su if (amdgpu_sriov_vf(psp->adev)) 1948ecaafb7bSJinzhou Su return 0; 1949ecaafb7bSJinzhou Su 1950ecaafb7bSJinzhou Su if (!psp->adev->psp.ta_securedisplay_ucode_size || 1951ecaafb7bSJinzhou Su !psp->adev->psp.ta_securedisplay_start_addr) { 1952ecaafb7bSJinzhou Su dev_info(psp->adev->dev, "SECUREDISPLAY: securedisplay ta ucode is not available\n"); 1953ecaafb7bSJinzhou Su return 0; 1954ecaafb7bSJinzhou Su } 1955ecaafb7bSJinzhou Su 1956ecaafb7bSJinzhou Su if (!psp->securedisplay_context.securedisplay_initialized) { 1957ecaafb7bSJinzhou Su ret = psp_securedisplay_init_shared_buf(psp); 1958ecaafb7bSJinzhou Su if (ret) 1959ecaafb7bSJinzhou Su return ret; 1960ecaafb7bSJinzhou Su } 1961ecaafb7bSJinzhou Su 1962ecaafb7bSJinzhou Su ret = psp_securedisplay_load(psp); 1963ecaafb7bSJinzhou Su if (ret) 1964ecaafb7bSJinzhou Su return ret; 1965ecaafb7bSJinzhou Su 1966ecaafb7bSJinzhou Su psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd, 1967ecaafb7bSJinzhou Su TA_SECUREDISPLAY_COMMAND__QUERY_TA); 1968ecaafb7bSJinzhou Su 1969ecaafb7bSJinzhou Su ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA); 1970ecaafb7bSJinzhou Su if (ret) { 1971ecaafb7bSJinzhou Su psp_securedisplay_unload(psp); 1972ecaafb7bSJinzhou Su 1973ecaafb7bSJinzhou Su amdgpu_bo_free_kernel(&psp->securedisplay_context.securedisplay_shared_bo, 1974ecaafb7bSJinzhou Su &psp->securedisplay_context.securedisplay_shared_mc_addr, 1975ecaafb7bSJinzhou Su &psp->securedisplay_context.securedisplay_shared_buf); 1976ecaafb7bSJinzhou Su 1977ecaafb7bSJinzhou Su psp->securedisplay_context.securedisplay_initialized = false; 1978ecaafb7bSJinzhou Su 1979ecaafb7bSJinzhou Su dev_err(psp->adev->dev, "SECUREDISPLAY TA initialize fail.\n"); 1980ecaafb7bSJinzhou Su return -EINVAL; 1981ecaafb7bSJinzhou Su } 1982ecaafb7bSJinzhou Su 1983ecaafb7bSJinzhou Su if (securedisplay_cmd->status != TA_SECUREDISPLAY_STATUS__SUCCESS) { 1984ecaafb7bSJinzhou Su psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status); 1985ecaafb7bSJinzhou Su dev_err(psp->adev->dev, "SECUREDISPLAY: query securedisplay TA failed. ret 0x%x\n", 1986ecaafb7bSJinzhou Su securedisplay_cmd->securedisplay_out_message.query_ta.query_cmd_ret); 1987ecaafb7bSJinzhou Su } 1988ecaafb7bSJinzhou Su 1989ecaafb7bSJinzhou Su return 0; 1990ecaafb7bSJinzhou Su } 1991ecaafb7bSJinzhou Su 1992ecaafb7bSJinzhou Su static int psp_securedisplay_terminate(struct psp_context *psp) 1993ecaafb7bSJinzhou Su { 1994ecaafb7bSJinzhou Su int ret; 1995ecaafb7bSJinzhou Su 1996ecaafb7bSJinzhou Su /* 1997ecaafb7bSJinzhou Su * TODO:bypass the terminate in sriov for now 1998ecaafb7bSJinzhou Su */ 1999ecaafb7bSJinzhou Su if (amdgpu_sriov_vf(psp->adev)) 2000ecaafb7bSJinzhou Su return 0; 2001ecaafb7bSJinzhou Su 2002ecaafb7bSJinzhou Su if (!psp->securedisplay_context.securedisplay_initialized) 2003ecaafb7bSJinzhou Su return 0; 2004ecaafb7bSJinzhou Su 2005ecaafb7bSJinzhou Su ret = psp_securedisplay_unload(psp); 2006ecaafb7bSJinzhou Su if (ret) 2007ecaafb7bSJinzhou Su return ret; 2008ecaafb7bSJinzhou Su 2009ecaafb7bSJinzhou Su psp->securedisplay_context.securedisplay_initialized = false; 2010ecaafb7bSJinzhou Su 2011ecaafb7bSJinzhou Su /* free securedisplay shared memory */ 2012ecaafb7bSJinzhou Su amdgpu_bo_free_kernel(&psp->securedisplay_context.securedisplay_shared_bo, 2013ecaafb7bSJinzhou Su &psp->securedisplay_context.securedisplay_shared_mc_addr, 2014ecaafb7bSJinzhou Su &psp->securedisplay_context.securedisplay_shared_buf); 2015ecaafb7bSJinzhou Su 2016ecaafb7bSJinzhou Su return ret; 2017ecaafb7bSJinzhou Su } 2018ecaafb7bSJinzhou Su 2019ecaafb7bSJinzhou Su int psp_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id) 2020ecaafb7bSJinzhou Su { 2021ecaafb7bSJinzhou Su int ret; 2022ecaafb7bSJinzhou Su 2023ecaafb7bSJinzhou Su if (!psp->securedisplay_context.securedisplay_initialized) 2024ecaafb7bSJinzhou Su return -EINVAL; 2025ecaafb7bSJinzhou Su 2026ecaafb7bSJinzhou Su if (ta_cmd_id != TA_SECUREDISPLAY_COMMAND__QUERY_TA && 2027ecaafb7bSJinzhou Su ta_cmd_id != TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC) 2028ecaafb7bSJinzhou Su return -EINVAL; 2029ecaafb7bSJinzhou Su 2030ecaafb7bSJinzhou Su mutex_lock(&psp->securedisplay_context.mutex); 2031ecaafb7bSJinzhou Su 2032ecaafb7bSJinzhou Su ret = psp_ta_invoke(psp, ta_cmd_id, psp->securedisplay_context.session_id); 2033ecaafb7bSJinzhou Su 2034ecaafb7bSJinzhou Su mutex_unlock(&psp->securedisplay_context.mutex); 2035ecaafb7bSJinzhou Su 2036ecaafb7bSJinzhou Su return ret; 2037ecaafb7bSJinzhou Su } 2038ecaafb7bSJinzhou Su /* SECUREDISPLAY end */ 2039ecaafb7bSJinzhou Su 2040be70bbdaSHuang Rui static int psp_hw_start(struct psp_context *psp) 2041be70bbdaSHuang Rui { 204255981bd2SMonk Liu struct amdgpu_device *adev = psp->adev; 2043be70bbdaSHuang Rui int ret; 2044be70bbdaSHuang Rui 204582c4ebfaSMonk Liu if (!amdgpu_sriov_vf(adev)) { 2046f2169946SHawking Zhang if (psp->kdb_bin_size && 204742989359SHawking Zhang (psp->funcs->bootloader_load_kdb != NULL)) { 204842989359SHawking Zhang ret = psp_bootloader_load_kdb(psp); 204942989359SHawking Zhang if (ret) { 205042989359SHawking Zhang DRM_ERROR("PSP load kdb failed!\n"); 205142989359SHawking Zhang return ret; 205242989359SHawking Zhang } 205342989359SHawking Zhang } 205442989359SHawking Zhang 205570509057SLikun Gao if (psp->spl_bin_size) { 205670509057SLikun Gao ret = psp_bootloader_load_spl(psp); 205770509057SLikun Gao if (ret) { 205870509057SLikun Gao DRM_ERROR("PSP load spl failed!\n"); 205970509057SLikun Gao return ret; 206070509057SLikun Gao } 206170509057SLikun Gao } 206270509057SLikun Gao 20630e5ca0d1SHuang Rui ret = psp_bootloader_load_sysdrv(psp); 20647a3d7bf6SEvan Quan if (ret) { 20657a3d7bf6SEvan Quan DRM_ERROR("PSP load sysdrv failed!\n"); 2066be70bbdaSHuang Rui return ret; 206755981bd2SMonk Liu } 20680e5ca0d1SHuang Rui 20697a3d7bf6SEvan Quan ret = psp_bootloader_load_sos(psp); 20707a3d7bf6SEvan Quan if (ret) { 20717a3d7bf6SEvan Quan DRM_ERROR("PSP load sos failed!\n"); 2072be70bbdaSHuang Rui return ret; 20737a3d7bf6SEvan Quan } 20747a3d7bf6SEvan Quan } 20757a3d7bf6SEvan Quan 20767a3d7bf6SEvan Quan ret = psp_ring_create(psp, PSP_RING_TYPE__KM); 20777a3d7bf6SEvan Quan if (ret) { 20787a3d7bf6SEvan Quan DRM_ERROR("PSP create ring failed!\n"); 20797a3d7bf6SEvan Quan return ret; 20807a3d7bf6SEvan Quan } 20810e5ca0d1SHuang Rui 2082fba08a77SHawking Zhang ret = psp_tmr_init(psp); 2083fba08a77SHawking Zhang if (ret) { 2084fba08a77SHawking Zhang DRM_ERROR("PSP tmr init failed!\n"); 2085fba08a77SHawking Zhang return ret; 2086fba08a77SHawking Zhang } 2087fba08a77SHawking Zhang 2088995da6ccSEvan Quan /* 208940e611bdSJohn Clements * For ASICs with DF Cstate management centralized 2090995da6ccSEvan Quan * to PMFW, TMR setup should be performed after PMFW 2091995da6ccSEvan Quan * loaded and before other non-psp firmware loaded. 2092995da6ccSEvan Quan */ 209340e611bdSJohn Clements if (psp->pmfw_centralized_cstate_management) { 209440e611bdSJohn Clements ret = psp_load_smu_fw(psp); 209540e611bdSJohn Clements if (ret) 209640e611bdSJohn Clements return ret; 209740e611bdSJohn Clements } 209840e611bdSJohn Clements 2099be70bbdaSHuang Rui ret = psp_tmr_load(psp); 21007a3d7bf6SEvan Quan if (ret) { 21017a3d7bf6SEvan Quan DRM_ERROR("PSP load tmr failed!\n"); 2102be70bbdaSHuang Rui return ret; 21037a3d7bf6SEvan Quan } 21040e5ca0d1SHuang Rui 2105be70bbdaSHuang Rui return 0; 2106be70bbdaSHuang Rui } 2107be70bbdaSHuang Rui 2108be4630d9SHawking Zhang static int psp_get_fw_type(struct amdgpu_firmware_info *ucode, 2109be4630d9SHawking Zhang enum psp_gfx_fw_type *type) 2110be4630d9SHawking Zhang { 2111be4630d9SHawking Zhang switch (ucode->ucode_id) { 2112be4630d9SHawking Zhang case AMDGPU_UCODE_ID_SDMA0: 2113be4630d9SHawking Zhang *type = GFX_FW_TYPE_SDMA0; 2114be4630d9SHawking Zhang break; 2115be4630d9SHawking Zhang case AMDGPU_UCODE_ID_SDMA1: 2116be4630d9SHawking Zhang *type = GFX_FW_TYPE_SDMA1; 2117be4630d9SHawking Zhang break; 2118b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA2: 2119b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA2; 2120b86f8d8bSJohn Clements break; 2121b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA3: 2122b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA3; 2123b86f8d8bSJohn Clements break; 2124b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA4: 2125b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA4; 2126b86f8d8bSJohn Clements break; 2127b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA5: 2128b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA5; 2129b86f8d8bSJohn Clements break; 2130b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA6: 2131b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA6; 2132b86f8d8bSJohn Clements break; 2133b86f8d8bSJohn Clements case AMDGPU_UCODE_ID_SDMA7: 2134b86f8d8bSJohn Clements *type = GFX_FW_TYPE_SDMA7; 2135b86f8d8bSJohn Clements break; 213693fd978bSJack Xiao case AMDGPU_UCODE_ID_CP_MES: 213793fd978bSJack Xiao *type = GFX_FW_TYPE_CP_MES; 213893fd978bSJack Xiao break; 213993fd978bSJack Xiao case AMDGPU_UCODE_ID_CP_MES_DATA: 214093fd978bSJack Xiao *type = GFX_FW_TYPE_MES_STACK; 214193fd978bSJack Xiao break; 2142be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_CE: 2143be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_CE; 2144be4630d9SHawking Zhang break; 2145be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_PFP: 2146be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_PFP; 2147be4630d9SHawking Zhang break; 2148be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_ME: 2149be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_ME; 2150be4630d9SHawking Zhang break; 2151be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC1: 2152be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC; 2153be4630d9SHawking Zhang break; 2154be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC1_JT: 2155be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC_ME1; 2156be4630d9SHawking Zhang break; 2157be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC2: 2158be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC; 2159be4630d9SHawking Zhang break; 2160be4630d9SHawking Zhang case AMDGPU_UCODE_ID_CP_MEC2_JT: 2161be4630d9SHawking Zhang *type = GFX_FW_TYPE_CP_MEC_ME2; 2162be4630d9SHawking Zhang break; 2163be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_G: 2164be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_G; 2165be4630d9SHawking Zhang break; 2166be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL: 2167be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_CNTL; 2168be4630d9SHawking Zhang break; 2169be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM: 2170be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_RESTORE_LIST_GPM_MEM; 2171be4630d9SHawking Zhang break; 2172be4630d9SHawking Zhang case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM: 2173be4630d9SHawking Zhang *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM; 2174be4630d9SHawking Zhang break; 21755bab858eSLikun Gao case AMDGPU_UCODE_ID_RLC_IRAM: 21765bab858eSLikun Gao *type = GFX_FW_TYPE_RLC_IRAM; 21775bab858eSLikun Gao break; 21785bab858eSLikun Gao case AMDGPU_UCODE_ID_RLC_DRAM: 21795bab858eSLikun Gao *type = GFX_FW_TYPE_RLC_DRAM_BOOT; 21805bab858eSLikun Gao break; 2181be4630d9SHawking Zhang case AMDGPU_UCODE_ID_SMC: 2182be4630d9SHawking Zhang *type = GFX_FW_TYPE_SMU; 2183be4630d9SHawking Zhang break; 2184be4630d9SHawking Zhang case AMDGPU_UCODE_ID_UVD: 2185be4630d9SHawking Zhang *type = GFX_FW_TYPE_UVD; 2186be4630d9SHawking Zhang break; 2187be4630d9SHawking Zhang case AMDGPU_UCODE_ID_UVD1: 2188be4630d9SHawking Zhang *type = GFX_FW_TYPE_UVD1; 2189be4630d9SHawking Zhang break; 2190be4630d9SHawking Zhang case AMDGPU_UCODE_ID_VCE: 2191be4630d9SHawking Zhang *type = GFX_FW_TYPE_VCE; 2192be4630d9SHawking Zhang break; 2193be4630d9SHawking Zhang case AMDGPU_UCODE_ID_VCN: 2194be4630d9SHawking Zhang *type = GFX_FW_TYPE_VCN; 2195be4630d9SHawking Zhang break; 2196d83c7a07SJane Jian case AMDGPU_UCODE_ID_VCN1: 2197d83c7a07SJane Jian *type = GFX_FW_TYPE_VCN1; 2198d83c7a07SJane Jian break; 2199be4630d9SHawking Zhang case AMDGPU_UCODE_ID_DMCU_ERAM: 2200be4630d9SHawking Zhang *type = GFX_FW_TYPE_DMCU_ERAM; 2201be4630d9SHawking Zhang break; 2202be4630d9SHawking Zhang case AMDGPU_UCODE_ID_DMCU_INTV: 2203be4630d9SHawking Zhang *type = GFX_FW_TYPE_DMCU_ISR; 2204be4630d9SHawking Zhang break; 2205c76ff09bSJack Xiao case AMDGPU_UCODE_ID_VCN0_RAM: 2206c76ff09bSJack Xiao *type = GFX_FW_TYPE_VCN0_RAM; 2207c76ff09bSJack Xiao break; 2208c76ff09bSJack Xiao case AMDGPU_UCODE_ID_VCN1_RAM: 2209c76ff09bSJack Xiao *type = GFX_FW_TYPE_VCN1_RAM; 2210c76ff09bSJack Xiao break; 22112bd2a27fSNicholas Kazlauskas case AMDGPU_UCODE_ID_DMCUB: 22122bd2a27fSNicholas Kazlauskas *type = GFX_FW_TYPE_DMUB; 22132bd2a27fSNicholas Kazlauskas break; 2214be4630d9SHawking Zhang case AMDGPU_UCODE_ID_MAXIMUM: 2215be4630d9SHawking Zhang default: 2216be4630d9SHawking Zhang return -EINVAL; 2217be4630d9SHawking Zhang } 2218be4630d9SHawking Zhang 2219be4630d9SHawking Zhang return 0; 2220be4630d9SHawking Zhang } 2221be4630d9SHawking Zhang 2222c5fb9126SXiaojie Yuan static void psp_print_fw_hdr(struct psp_context *psp, 2223c5fb9126SXiaojie Yuan struct amdgpu_firmware_info *ucode) 2224c5fb9126SXiaojie Yuan { 2225c5fb9126SXiaojie Yuan struct amdgpu_device *adev = psp->adev; 2226bfa603aaSXiaojie Yuan struct common_firmware_header *hdr; 2227c5fb9126SXiaojie Yuan 2228c5fb9126SXiaojie Yuan switch (ucode->ucode_id) { 2229c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA0: 2230c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA1: 2231c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA2: 2232c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA3: 2233c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA4: 2234c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA5: 2235c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA6: 2236c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SDMA7: 2237bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *) 2238bfa603aaSXiaojie Yuan adev->sdma.instance[ucode->ucode_id - AMDGPU_UCODE_ID_SDMA0].fw->data; 2239bfa603aaSXiaojie Yuan amdgpu_ucode_print_sdma_hdr(hdr); 2240c5fb9126SXiaojie Yuan break; 2241c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_CE: 2242bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.ce_fw->data; 2243bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 2244c5fb9126SXiaojie Yuan break; 2245c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_PFP: 2246bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.pfp_fw->data; 2247bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 2248c5fb9126SXiaojie Yuan break; 2249c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_ME: 2250bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.me_fw->data; 2251bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 2252c5fb9126SXiaojie Yuan break; 2253c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_CP_MEC1: 2254bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.mec_fw->data; 2255bfa603aaSXiaojie Yuan amdgpu_ucode_print_gfx_hdr(hdr); 2256c5fb9126SXiaojie Yuan break; 2257c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_RLC_G: 2258bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->gfx.rlc_fw->data; 2259bfa603aaSXiaojie Yuan amdgpu_ucode_print_rlc_hdr(hdr); 2260c5fb9126SXiaojie Yuan break; 2261c5fb9126SXiaojie Yuan case AMDGPU_UCODE_ID_SMC: 2262bfa603aaSXiaojie Yuan hdr = (struct common_firmware_header *)adev->pm.fw->data; 2263bfa603aaSXiaojie Yuan amdgpu_ucode_print_smc_hdr(hdr); 2264c5fb9126SXiaojie Yuan break; 2265c5fb9126SXiaojie Yuan default: 2266c5fb9126SXiaojie Yuan break; 2267c5fb9126SXiaojie Yuan } 2268c5fb9126SXiaojie Yuan } 2269c5fb9126SXiaojie Yuan 2270be4630d9SHawking Zhang static int psp_prep_load_ip_fw_cmd_buf(struct amdgpu_firmware_info *ucode, 2271be4630d9SHawking Zhang struct psp_gfx_cmd_resp *cmd) 2272be4630d9SHawking Zhang { 2273be4630d9SHawking Zhang int ret; 2274be4630d9SHawking Zhang uint64_t fw_mem_mc_addr = ucode->mc_addr; 2275be4630d9SHawking Zhang 2276be4630d9SHawking Zhang memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); 2277be4630d9SHawking Zhang 2278be4630d9SHawking Zhang cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW; 2279be4630d9SHawking Zhang cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr); 2280be4630d9SHawking Zhang cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr); 2281be4630d9SHawking Zhang cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size; 2282be4630d9SHawking Zhang 2283be4630d9SHawking Zhang ret = psp_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type); 2284be4630d9SHawking Zhang if (ret) 2285be4630d9SHawking Zhang DRM_ERROR("Unknown firmware type\n"); 2286be4630d9SHawking Zhang 2287be4630d9SHawking Zhang return ret; 2288be4630d9SHawking Zhang } 2289be4630d9SHawking Zhang 229013169562SHuang Rui static int psp_execute_np_fw_load(struct psp_context *psp, 229113169562SHuang Rui struct amdgpu_firmware_info *ucode) 229213169562SHuang Rui { 229313169562SHuang Rui int ret = 0; 229413169562SHuang Rui 229513169562SHuang Rui ret = psp_prep_load_ip_fw_cmd_buf(ucode, psp->cmd); 229613169562SHuang Rui if (ret) 229713169562SHuang Rui return ret; 229813169562SHuang Rui 229913169562SHuang Rui ret = psp_cmd_submit_buf(psp, ucode, psp->cmd, 230013169562SHuang Rui psp->fence_buf_mc_addr); 230113169562SHuang Rui 230213169562SHuang Rui return ret; 230313169562SHuang Rui } 230413169562SHuang Rui 230540e611bdSJohn Clements static int psp_load_smu_fw(struct psp_context *psp) 2306be70bbdaSHuang Rui { 230740e611bdSJohn Clements int ret; 23087f70443fSJohn Clements struct amdgpu_device *adev = psp->adev; 230940e611bdSJohn Clements struct amdgpu_firmware_info *ucode = 23107f70443fSJohn Clements &adev->firmware.ucode[AMDGPU_UCODE_ID_SMC]; 23110bcfa78cSLikun Gao struct amdgpu_ras *ras = psp->ras.ras; 23120e5ca0d1SHuang Rui 231340e611bdSJohn Clements if (!ucode->fw || amdgpu_sriov_vf(psp->adev)) 231440e611bdSJohn Clements return 0; 231513169562SHuang Rui 23161689fca0SEvan Quan if ((amdgpu_in_reset(adev) && 23178ab0d6f0SLuben Tuikov ras && adev->ras_enabled && 23184a7ffbdbSChengming Gui (adev->asic_type == CHIP_ARCTURUS || 23195f0f1727SEvan Quan adev->asic_type == CHIP_VEGA20))) { 23207f70443fSJohn Clements ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD); 23217f70443fSJohn Clements if (ret) { 23227f70443fSJohn Clements DRM_WARN("Failed to set MP1 state prepare for reload\n"); 23237f70443fSJohn Clements } 23247f70443fSJohn Clements } 23257f70443fSJohn Clements 232613169562SHuang Rui ret = psp_execute_np_fw_load(psp, ucode); 232740e611bdSJohn Clements 232813169562SHuang Rui if (ret) 232940e611bdSJohn Clements DRM_ERROR("PSP load smu failed!\n"); 233040e611bdSJohn Clements 233113169562SHuang Rui return ret; 233213169562SHuang Rui } 233313169562SHuang Rui 233440e611bdSJohn Clements static bool fw_load_skip_check(struct psp_context *psp, 233540e611bdSJohn Clements struct amdgpu_firmware_info *ucode) 233640e611bdSJohn Clements { 23370e5ca0d1SHuang Rui if (!ucode->fw) 233840e611bdSJohn Clements return true; 23390e5ca0d1SHuang Rui 23400e5ca0d1SHuang Rui if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC && 2341995da6ccSEvan Quan (psp_smu_reload_quirk(psp) || 2342995da6ccSEvan Quan psp->autoload_supported || 2343995da6ccSEvan Quan psp->pmfw_centralized_cstate_management)) 234440e611bdSJohn Clements return true; 2345b86f8d8bSJohn Clements 234640e611bdSJohn Clements if (amdgpu_sriov_vf(psp->adev) && 2347e993ca4fSDaniel Wang (ucode->ucode_id == AMDGPU_UCODE_ID_SDMA0 2348e993ca4fSDaniel Wang || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 2349b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 2350b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3 2351b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA4 2352b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA5 2353b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA6 2354b86f8d8bSJohn Clements || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA7 2355c348ad46SJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_G 2356c348ad46SJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL 2357c348ad46SJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM 2358c2a801afSJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM 2359c2a801afSJack Zhang || ucode->ucode_id == AMDGPU_UCODE_ID_SMC)) 2360e993ca4fSDaniel Wang /*skip ucode loading in SRIOV VF */ 236140e611bdSJohn Clements return true; 2362b86f8d8bSJohn Clements 2363119eb6dbSHawking Zhang if (psp->autoload_supported && 2364119eb6dbSHawking Zhang (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1_JT || 2365119eb6dbSHawking Zhang ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT)) 2366119eb6dbSHawking Zhang /* skip mec JT when autoload is enabled */ 236740e611bdSJohn Clements return true; 236840e611bdSJohn Clements 236940e611bdSJohn Clements return false; 237040e611bdSJohn Clements } 237140e611bdSJohn Clements 2372a2052839SLijo Lazar int psp_load_fw_list(struct psp_context *psp, 2373a2052839SLijo Lazar struct amdgpu_firmware_info **ucode_list, int ucode_count) 2374a2052839SLijo Lazar { 2375a2052839SLijo Lazar int ret = 0, i; 2376a2052839SLijo Lazar struct amdgpu_firmware_info *ucode; 2377a2052839SLijo Lazar 2378a2052839SLijo Lazar for (i = 0; i < ucode_count; ++i) { 2379a2052839SLijo Lazar ucode = ucode_list[i]; 2380a2052839SLijo Lazar psp_print_fw_hdr(psp, ucode); 2381a2052839SLijo Lazar ret = psp_execute_np_fw_load(psp, ucode); 2382a2052839SLijo Lazar if (ret) 2383a2052839SLijo Lazar return ret; 2384a2052839SLijo Lazar } 2385a2052839SLijo Lazar return ret; 2386a2052839SLijo Lazar } 2387a2052839SLijo Lazar 238840e611bdSJohn Clements static int psp_np_fw_load(struct psp_context *psp) 238940e611bdSJohn Clements { 239040e611bdSJohn Clements int i, ret; 239140e611bdSJohn Clements struct amdgpu_firmware_info *ucode; 239240e611bdSJohn Clements struct amdgpu_device *adev = psp->adev; 239340e611bdSJohn Clements 239440e611bdSJohn Clements if (psp->autoload_supported && 239540e611bdSJohn Clements !psp->pmfw_centralized_cstate_management) { 239640e611bdSJohn Clements ret = psp_load_smu_fw(psp); 239740e611bdSJohn Clements if (ret) 239840e611bdSJohn Clements return ret; 239940e611bdSJohn Clements } 240040e611bdSJohn Clements 240140e611bdSJohn Clements for (i = 0; i < adev->firmware.max_ucodes; i++) { 240240e611bdSJohn Clements ucode = &adev->firmware.ucode[i]; 240340e611bdSJohn Clements 240440e611bdSJohn Clements if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC && 240540e611bdSJohn Clements !fw_load_skip_check(psp, ucode)) { 240640e611bdSJohn Clements ret = psp_load_smu_fw(psp); 240740e611bdSJohn Clements if (ret) 240840e611bdSJohn Clements return ret; 240940e611bdSJohn Clements continue; 241040e611bdSJohn Clements } 241140e611bdSJohn Clements 241240e611bdSJohn Clements if (fw_load_skip_check(psp, ucode)) 2413119eb6dbSHawking Zhang continue; 24140e5ca0d1SHuang Rui 2415738c822cSLikun Gao if (psp->autoload_supported && 2416462c272bSTao Zhou (adev->asic_type >= CHIP_SIENNA_CICHLID && 2417462c272bSTao Zhou adev->asic_type <= CHIP_DIMGREY_CAVEFISH) && 2418738c822cSLikun Gao (ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 || 2419738c822cSLikun Gao ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 || 2420738c822cSLikun Gao ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3)) 2421738c822cSLikun Gao /* PSP only receive one SDMA fw for sienna_cichlid, 2422738c822cSLikun Gao * as all four sdma fw are same */ 2423738c822cSLikun Gao continue; 2424738c822cSLikun Gao 2425c5fb9126SXiaojie Yuan psp_print_fw_hdr(psp, ucode); 2426c5fb9126SXiaojie Yuan 242713169562SHuang Rui ret = psp_execute_np_fw_load(psp, ucode); 24280e5ca0d1SHuang Rui if (ret) 2429be70bbdaSHuang Rui return ret; 24300e5ca0d1SHuang Rui 24311a5b4ccaSHawking Zhang /* Start rlc autoload after psp recieved all the gfx firmware */ 24326de40f02SMonk Liu if (psp->autoload_supported && ucode->ucode_id == (amdgpu_sriov_vf(adev) ? 24330753e56eSEvan Quan AMDGPU_UCODE_ID_CP_MEC2 : AMDGPU_UCODE_ID_RLC_G)) { 2434999a69e2SHawking Zhang ret = psp_rlc_autoload_start(psp); 24351a5b4ccaSHawking Zhang if (ret) { 24361a5b4ccaSHawking Zhang DRM_ERROR("Failed to start rlc autoload\n"); 24371a5b4ccaSHawking Zhang return ret; 24381a5b4ccaSHawking Zhang } 24391a5b4ccaSHawking Zhang } 24400e5ca0d1SHuang Rui } 24410e5ca0d1SHuang Rui 2442be70bbdaSHuang Rui return 0; 2443be70bbdaSHuang Rui } 2444be70bbdaSHuang Rui 24450e5ca0d1SHuang Rui static int psp_load_fw(struct amdgpu_device *adev) 24460e5ca0d1SHuang Rui { 24470e5ca0d1SHuang Rui int ret; 24480e5ca0d1SHuang Rui struct psp_context *psp = &adev->psp; 24490e5ca0d1SHuang Rui 245053b3f8f4SDennis Li if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) { 245114d20ec7Swentalou psp_ring_stop(psp, PSP_RING_TYPE__KM); /* should not destroy ring, only stop */ 245277a3c96bSMonk Liu goto skip_memalloc; 245353450efdSXiangliang Yu } 245477a3c96bSMonk Liu 245567bef0f7SHuang Rui psp->cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 245667bef0f7SHuang Rui if (!psp->cmd) 24570e5ca0d1SHuang Rui return -ENOMEM; 24580e5ca0d1SHuang Rui 2459e1944debSZhigang Luo if (amdgpu_sriov_vf(adev)) { 2460e1944debSZhigang Luo ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, 2461e1944debSZhigang Luo AMDGPU_GEM_DOMAIN_VRAM, 2462e1944debSZhigang Luo &psp->fw_pri_bo, 2463e1944debSZhigang Luo &psp->fw_pri_mc_addr, 2464e1944debSZhigang Luo &psp->fw_pri_buf); 2465e1944debSZhigang Luo } else { 246653a5cf57SHuang Rui ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, 246753a5cf57SHuang Rui AMDGPU_GEM_DOMAIN_GTT, 246853a5cf57SHuang Rui &psp->fw_pri_bo, 246953a5cf57SHuang Rui &psp->fw_pri_mc_addr, 247053a5cf57SHuang Rui &psp->fw_pri_buf); 2471e1944debSZhigang Luo } 2472e1944debSZhigang Luo 24730e5ca0d1SHuang Rui if (ret) 24740e5ca0d1SHuang Rui goto failed; 24750e5ca0d1SHuang Rui 24760e5ca0d1SHuang Rui ret = amdgpu_bo_create_kernel(adev, PSP_FENCE_BUFFER_SIZE, PAGE_SIZE, 24770e5ca0d1SHuang Rui AMDGPU_GEM_DOMAIN_VRAM, 24780e5ca0d1SHuang Rui &psp->fence_buf_bo, 24790e5ca0d1SHuang Rui &psp->fence_buf_mc_addr, 24800e5ca0d1SHuang Rui &psp->fence_buf); 24810e5ca0d1SHuang Rui if (ret) 248237945a3aSEvan Quan goto failed; 2483a1952da7SHuang Rui 2484a1952da7SHuang Rui ret = amdgpu_bo_create_kernel(adev, PSP_CMD_BUFFER_SIZE, PAGE_SIZE, 2485a1952da7SHuang Rui AMDGPU_GEM_DOMAIN_VRAM, 2486a1952da7SHuang Rui &psp->cmd_buf_bo, &psp->cmd_buf_mc_addr, 2487a1952da7SHuang Rui (void **)&psp->cmd_buf_mem); 2488a1952da7SHuang Rui if (ret) 248937945a3aSEvan Quan goto failed; 24900e5ca0d1SHuang Rui 24910e5ca0d1SHuang Rui memset(psp->fence_buf, 0, PSP_FENCE_BUFFER_SIZE); 24920e5ca0d1SHuang Rui 2493be70bbdaSHuang Rui ret = psp_ring_init(psp, PSP_RING_TYPE__KM); 24947a3d7bf6SEvan Quan if (ret) { 24957a3d7bf6SEvan Quan DRM_ERROR("PSP ring init failed!\n"); 249637945a3aSEvan Quan goto failed; 24977a3d7bf6SEvan Quan } 24980e5ca0d1SHuang Rui 249977a3c96bSMonk Liu skip_memalloc: 2500be70bbdaSHuang Rui ret = psp_hw_start(psp); 25010e5ca0d1SHuang Rui if (ret) 250237945a3aSEvan Quan goto failed; 25030e5ca0d1SHuang Rui 2504be70bbdaSHuang Rui ret = psp_np_fw_load(psp); 25050e5ca0d1SHuang Rui if (ret) 250637945a3aSEvan Quan goto failed; 25070e5ca0d1SHuang Rui 25087091b60cSHawking Zhang ret = psp_asd_load(psp); 25097091b60cSHawking Zhang if (ret) { 25107091b60cSHawking Zhang DRM_ERROR("PSP load asd failed!\n"); 25117091b60cSHawking Zhang return ret; 25127091b60cSHawking Zhang } 25137091b60cSHawking Zhang 25140d2c1855SJohn Clements ret = psp_rl_load(adev); 25150d2c1855SJohn Clements if (ret) { 25160d2c1855SJohn Clements DRM_ERROR("PSP load RL failed!\n"); 25170d2c1855SJohn Clements return ret; 25180d2c1855SJohn Clements } 25190d2c1855SJohn Clements 25207091b60cSHawking Zhang if (psp->adev->psp.ta_fw) { 25217091b60cSHawking Zhang ret = psp_ras_initialize(psp); 25227091b60cSHawking Zhang if (ret) 25237091b60cSHawking Zhang dev_err(psp->adev->dev, 25247091b60cSHawking Zhang "RAS: Failed to initialize RAS\n"); 25257091b60cSHawking Zhang 25267091b60cSHawking Zhang ret = psp_hdcp_initialize(psp); 25277091b60cSHawking Zhang if (ret) 25287091b60cSHawking Zhang dev_err(psp->adev->dev, 25297091b60cSHawking Zhang "HDCP: Failed to initialize HDCP\n"); 25307091b60cSHawking Zhang 25317091b60cSHawking Zhang ret = psp_dtm_initialize(psp); 25327091b60cSHawking Zhang if (ret) 25337091b60cSHawking Zhang dev_err(psp->adev->dev, 25347091b60cSHawking Zhang "DTM: Failed to initialize DTM\n"); 25358602692bSWenhui Sheng 25368602692bSWenhui Sheng ret = psp_rap_initialize(psp); 25378602692bSWenhui Sheng if (ret) 25388602692bSWenhui Sheng dev_err(psp->adev->dev, 25398602692bSWenhui Sheng "RAP: Failed to initialize RAP\n"); 2540ecaafb7bSJinzhou Su 2541ecaafb7bSJinzhou Su ret = psp_securedisplay_initialize(psp); 2542ecaafb7bSJinzhou Su if (ret) 2543ecaafb7bSJinzhou Su dev_err(psp->adev->dev, 2544ecaafb7bSJinzhou Su "SECUREDISPLAY: Failed to initialize SECUREDISPLAY\n"); 25457091b60cSHawking Zhang } 25467091b60cSHawking Zhang 25470e5ca0d1SHuang Rui return 0; 25480e5ca0d1SHuang Rui 25490e5ca0d1SHuang Rui failed: 255037945a3aSEvan Quan /* 255137945a3aSEvan Quan * all cleanup jobs (xgmi terminate, ras terminate, 255237945a3aSEvan Quan * ring destroy, cmd/fence/fw buffers destory, 255337945a3aSEvan Quan * psp->cmd destory) are delayed to psp_hw_fini 255437945a3aSEvan Quan */ 25550e5ca0d1SHuang Rui return ret; 25560e5ca0d1SHuang Rui } 25570e5ca0d1SHuang Rui 25580e5ca0d1SHuang Rui static int psp_hw_init(void *handle) 25590e5ca0d1SHuang Rui { 25600e5ca0d1SHuang Rui int ret; 25610e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 25620e5ca0d1SHuang Rui 25630e5ca0d1SHuang Rui mutex_lock(&adev->firmware.mutex); 25646e13bdf6SRex Zhu /* 25656e13bdf6SRex Zhu * This sequence is just used on hw_init only once, no need on 25666e13bdf6SRex Zhu * resume. 25676e13bdf6SRex Zhu */ 25686e13bdf6SRex Zhu ret = amdgpu_ucode_init_bo(adev); 25696e13bdf6SRex Zhu if (ret) 25706e13bdf6SRex Zhu goto failed; 25710e5ca0d1SHuang Rui 25720e5ca0d1SHuang Rui ret = psp_load_fw(adev); 25730e5ca0d1SHuang Rui if (ret) { 25740e5ca0d1SHuang Rui DRM_ERROR("PSP firmware loading failed\n"); 25750e5ca0d1SHuang Rui goto failed; 25760e5ca0d1SHuang Rui } 25770e5ca0d1SHuang Rui 25780e5ca0d1SHuang Rui mutex_unlock(&adev->firmware.mutex); 257903597b47SKevin Wang return 0; 25800e5ca0d1SHuang Rui 25810e5ca0d1SHuang Rui failed: 25820e5ca0d1SHuang Rui adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT; 25830e5ca0d1SHuang Rui mutex_unlock(&adev->firmware.mutex); 25840e5ca0d1SHuang Rui return -EINVAL; 25850e5ca0d1SHuang Rui } 25860e5ca0d1SHuang Rui 25870e5ca0d1SHuang Rui static int psp_hw_fini(void *handle) 25880e5ca0d1SHuang Rui { 25890e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 25900e5ca0d1SHuang Rui struct psp_context *psp = &adev->psp; 25910e5ca0d1SHuang Rui 2592ed19a9a2SBhawanpreet Lakha if (psp->adev->psp.ta_fw) { 25935e5d3154Sxinhui pan psp_ras_terminate(psp); 2594ecaafb7bSJinzhou Su psp_securedisplay_terminate(psp); 25958602692bSWenhui Sheng psp_rap_terminate(psp); 2596143f2305SBhawanpreet Lakha psp_dtm_terminate(psp); 2597ed19a9a2SBhawanpreet Lakha psp_hdcp_terminate(psp); 2598ed19a9a2SBhawanpreet Lakha } 25995e5d3154Sxinhui pan 260071e5f0cbSHawking Zhang psp_asd_unload(psp); 260171e5f0cbSHawking Zhang 260290937420SHuang Rui psp_tmr_terminate(psp); 2603e3c5e982STrigger Huang psp_ring_destroy(psp, PSP_RING_TYPE__KM); 2604e3c5e982STrigger Huang 260553a5cf57SHuang Rui amdgpu_bo_free_kernel(&psp->fw_pri_bo, 260653a5cf57SHuang Rui &psp->fw_pri_mc_addr, &psp->fw_pri_buf); 2607b4de2c5aSHuang Rui amdgpu_bo_free_kernel(&psp->fence_buf_bo, 2608b4de2c5aSHuang Rui &psp->fence_buf_mc_addr, &psp->fence_buf); 2609a1952da7SHuang Rui amdgpu_bo_free_kernel(&psp->cmd_buf_bo, &psp->cmd_buf_mc_addr, 2610a1952da7SHuang Rui (void **)&psp->cmd_buf_mem); 2611b4de2c5aSHuang Rui 261267bef0f7SHuang Rui kfree(psp->cmd); 261367bef0f7SHuang Rui psp->cmd = NULL; 261467bef0f7SHuang Rui 26150e5ca0d1SHuang Rui return 0; 26160e5ca0d1SHuang Rui } 26170e5ca0d1SHuang Rui 26180e5ca0d1SHuang Rui static int psp_suspend(void *handle) 26190e5ca0d1SHuang Rui { 2620bcd6eab8SEvan Quan int ret; 2621bcd6eab8SEvan Quan struct amdgpu_device *adev = (struct amdgpu_device *)handle; 2622bcd6eab8SEvan Quan struct psp_context *psp = &adev->psp; 2623bcd6eab8SEvan Quan 26243e2e2ab5SHawking Zhang if (adev->gmc.xgmi.num_physical_nodes > 1 && 26253e2e2ab5SHawking Zhang psp->xgmi_context.initialized == 1) { 26263e2e2ab5SHawking Zhang ret = psp_xgmi_terminate(psp); 26273e2e2ab5SHawking Zhang if (ret) { 26283e2e2ab5SHawking Zhang DRM_ERROR("Failed to terminate xgmi ta\n"); 26293e2e2ab5SHawking Zhang return ret; 26303e2e2ab5SHawking Zhang } 26313e2e2ab5SHawking Zhang } 26323e2e2ab5SHawking Zhang 263354eb4ed6Sxinhui pan if (psp->adev->psp.ta_fw) { 26345e5d3154Sxinhui pan ret = psp_ras_terminate(psp); 26355e5d3154Sxinhui pan if (ret) { 26365e5d3154Sxinhui pan DRM_ERROR("Failed to terminate ras ta\n"); 26375e5d3154Sxinhui pan return ret; 26385e5d3154Sxinhui pan } 2639ed19a9a2SBhawanpreet Lakha ret = psp_hdcp_terminate(psp); 2640ed19a9a2SBhawanpreet Lakha if (ret) { 2641ed19a9a2SBhawanpreet Lakha DRM_ERROR("Failed to terminate hdcp ta\n"); 2642ed19a9a2SBhawanpreet Lakha return ret; 2643ed19a9a2SBhawanpreet Lakha } 2644143f2305SBhawanpreet Lakha ret = psp_dtm_terminate(psp); 2645143f2305SBhawanpreet Lakha if (ret) { 2646143f2305SBhawanpreet Lakha DRM_ERROR("Failed to terminate dtm ta\n"); 2647143f2305SBhawanpreet Lakha return ret; 2648143f2305SBhawanpreet Lakha } 26498602692bSWenhui Sheng ret = psp_rap_terminate(psp); 26508602692bSWenhui Sheng if (ret) { 26518602692bSWenhui Sheng DRM_ERROR("Failed to terminate rap ta\n"); 26528602692bSWenhui Sheng return ret; 26538602692bSWenhui Sheng } 2654ecaafb7bSJinzhou Su ret = psp_securedisplay_terminate(psp); 2655ecaafb7bSJinzhou Su if (ret) { 2656ecaafb7bSJinzhou Su DRM_ERROR("Failed to terminate securedisplay ta\n"); 2657ecaafb7bSJinzhou Su return ret; 2658ecaafb7bSJinzhou Su } 265954eb4ed6Sxinhui pan } 26605e5d3154Sxinhui pan 2661429f3d24SHuang Rui ret = psp_asd_unload(psp); 2662429f3d24SHuang Rui if (ret) { 2663429f3d24SHuang Rui DRM_ERROR("Failed to unload asd\n"); 2664429f3d24SHuang Rui return ret; 2665429f3d24SHuang Rui } 2666429f3d24SHuang Rui 266790937420SHuang Rui ret = psp_tmr_terminate(psp); 266890937420SHuang Rui if (ret) { 26694afaa61dSColin Ian King DRM_ERROR("Failed to terminate tmr\n"); 267090937420SHuang Rui return ret; 267190937420SHuang Rui } 267290937420SHuang Rui 2673bcd6eab8SEvan Quan ret = psp_ring_stop(psp, PSP_RING_TYPE__KM); 2674bcd6eab8SEvan Quan if (ret) { 2675bcd6eab8SEvan Quan DRM_ERROR("PSP ring stop failed\n"); 2676bcd6eab8SEvan Quan return ret; 2677bcd6eab8SEvan Quan } 2678bcd6eab8SEvan Quan 26790e5ca0d1SHuang Rui return 0; 26800e5ca0d1SHuang Rui } 26810e5ca0d1SHuang Rui 26820e5ca0d1SHuang Rui static int psp_resume(void *handle) 26830e5ca0d1SHuang Rui { 26840e5ca0d1SHuang Rui int ret; 26850e5ca0d1SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 268693ea9b9fSHuang Rui struct psp_context *psp = &adev->psp; 26870e5ca0d1SHuang Rui 268893ea9b9fSHuang Rui DRM_INFO("PSP is resuming...\n"); 268993ea9b9fSHuang Rui 26900586a059STianci.Yin ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME); 26910586a059STianci.Yin if (ret) { 26920586a059STianci.Yin DRM_ERROR("Failed to process memory training!\n"); 26930586a059STianci.Yin return ret; 26940586a059STianci.Yin } 26950586a059STianci.Yin 26960e5ca0d1SHuang Rui mutex_lock(&adev->firmware.mutex); 26970e5ca0d1SHuang Rui 269893ea9b9fSHuang Rui ret = psp_hw_start(psp); 26990e5ca0d1SHuang Rui if (ret) 270093ea9b9fSHuang Rui goto failed; 270193ea9b9fSHuang Rui 270293ea9b9fSHuang Rui ret = psp_np_fw_load(psp); 270393ea9b9fSHuang Rui if (ret) 270493ea9b9fSHuang Rui goto failed; 27050e5ca0d1SHuang Rui 27060d6f39bbSHawking Zhang ret = psp_asd_load(psp); 27070d6f39bbSHawking Zhang if (ret) { 27080d6f39bbSHawking Zhang DRM_ERROR("PSP load asd failed!\n"); 27090d6f39bbSHawking Zhang goto failed; 27100d6f39bbSHawking Zhang } 27110d6f39bbSHawking Zhang 27120d6f39bbSHawking Zhang if (adev->gmc.xgmi.num_physical_nodes > 1) { 27130d6f39bbSHawking Zhang ret = psp_xgmi_initialize(psp); 27140d6f39bbSHawking Zhang /* Warning the XGMI seesion initialize failure 27150d6f39bbSHawking Zhang * Instead of stop driver initialization 27160d6f39bbSHawking Zhang */ 27170d6f39bbSHawking Zhang if (ret) 27180d6f39bbSHawking Zhang dev_err(psp->adev->dev, 27190d6f39bbSHawking Zhang "XGMI: Failed to initialize XGMI session\n"); 27200d6f39bbSHawking Zhang } 27210d6f39bbSHawking Zhang 27220d6f39bbSHawking Zhang if (psp->adev->psp.ta_fw) { 27230d6f39bbSHawking Zhang ret = psp_ras_initialize(psp); 27240d6f39bbSHawking Zhang if (ret) 27250d6f39bbSHawking Zhang dev_err(psp->adev->dev, 27260d6f39bbSHawking Zhang "RAS: Failed to initialize RAS\n"); 27270d6f39bbSHawking Zhang 27280d6f39bbSHawking Zhang ret = psp_hdcp_initialize(psp); 27290d6f39bbSHawking Zhang if (ret) 27300d6f39bbSHawking Zhang dev_err(psp->adev->dev, 27310d6f39bbSHawking Zhang "HDCP: Failed to initialize HDCP\n"); 27320d6f39bbSHawking Zhang 27330d6f39bbSHawking Zhang ret = psp_dtm_initialize(psp); 27340d6f39bbSHawking Zhang if (ret) 27350d6f39bbSHawking Zhang dev_err(psp->adev->dev, 27360d6f39bbSHawking Zhang "DTM: Failed to initialize DTM\n"); 27378602692bSWenhui Sheng 27388602692bSWenhui Sheng ret = psp_rap_initialize(psp); 27398602692bSWenhui Sheng if (ret) 27408602692bSWenhui Sheng dev_err(psp->adev->dev, 27418602692bSWenhui Sheng "RAP: Failed to initialize RAP\n"); 2742ecaafb7bSJinzhou Su 2743ecaafb7bSJinzhou Su ret = psp_securedisplay_initialize(psp); 2744ecaafb7bSJinzhou Su if (ret) 2745ecaafb7bSJinzhou Su dev_err(psp->adev->dev, 2746ecaafb7bSJinzhou Su "SECUREDISPLAY: Failed to initialize SECUREDISPLAY\n"); 27470d6f39bbSHawking Zhang } 27480d6f39bbSHawking Zhang 27490e5ca0d1SHuang Rui mutex_unlock(&adev->firmware.mutex); 27500e5ca0d1SHuang Rui 275193ea9b9fSHuang Rui return 0; 275293ea9b9fSHuang Rui 275393ea9b9fSHuang Rui failed: 275493ea9b9fSHuang Rui DRM_ERROR("PSP resume failed\n"); 275593ea9b9fSHuang Rui mutex_unlock(&adev->firmware.mutex); 27560e5ca0d1SHuang Rui return ret; 27570e5ca0d1SHuang Rui } 27580e5ca0d1SHuang Rui 2759f75a9a5dSAlex Deucher int psp_gpu_reset(struct amdgpu_device *adev) 276098512bb8SKen Wang { 276132eaeae0SAlex Deucher int ret; 276232eaeae0SAlex Deucher 27632d4f9020SHuang Rui if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 27642d4f9020SHuang Rui return 0; 27652d4f9020SHuang Rui 276632eaeae0SAlex Deucher mutex_lock(&adev->psp.mutex); 276732eaeae0SAlex Deucher ret = psp_mode1_reset(&adev->psp); 276832eaeae0SAlex Deucher mutex_unlock(&adev->psp.mutex); 276932eaeae0SAlex Deucher 277032eaeae0SAlex Deucher return ret; 277198512bb8SKen Wang } 277298512bb8SKen Wang 27731a5b4ccaSHawking Zhang int psp_rlc_autoload_start(struct psp_context *psp) 27741a5b4ccaSHawking Zhang { 27751a5b4ccaSHawking Zhang int ret; 27761a5b4ccaSHawking Zhang struct psp_gfx_cmd_resp *cmd; 27771a5b4ccaSHawking Zhang 27781a5b4ccaSHawking Zhang cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 27791a5b4ccaSHawking Zhang if (!cmd) 27801a5b4ccaSHawking Zhang return -ENOMEM; 27811a5b4ccaSHawking Zhang 27821a5b4ccaSHawking Zhang cmd->cmd_id = GFX_CMD_ID_AUTOLOAD_RLC; 27831a5b4ccaSHawking Zhang 27841a5b4ccaSHawking Zhang ret = psp_cmd_submit_buf(psp, NULL, cmd, 27851a5b4ccaSHawking Zhang psp->fence_buf_mc_addr); 27861a5b4ccaSHawking Zhang kfree(cmd); 27871a5b4ccaSHawking Zhang return ret; 27881a5b4ccaSHawking Zhang } 27891a5b4ccaSHawking Zhang 279086ddf352SJack Xiao int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx, 279186ddf352SJack Xiao uint64_t cmd_gpu_addr, int cmd_size) 279286ddf352SJack Xiao { 279386ddf352SJack Xiao struct amdgpu_firmware_info ucode = {0}; 279486ddf352SJack Xiao 279586ddf352SJack Xiao ucode.ucode_id = inst_idx ? AMDGPU_UCODE_ID_VCN1_RAM : 279686ddf352SJack Xiao AMDGPU_UCODE_ID_VCN0_RAM; 279786ddf352SJack Xiao ucode.mc_addr = cmd_gpu_addr; 279886ddf352SJack Xiao ucode.ucode_size = cmd_size; 279986ddf352SJack Xiao 280086ddf352SJack Xiao return psp_execute_np_fw_load(&adev->psp, &ucode); 280186ddf352SJack Xiao } 280286ddf352SJack Xiao 2803cc65176eSHawking Zhang int psp_ring_cmd_submit(struct psp_context *psp, 2804cc65176eSHawking Zhang uint64_t cmd_buf_mc_addr, 2805cc65176eSHawking Zhang uint64_t fence_mc_addr, 2806cc65176eSHawking Zhang int index) 2807cc65176eSHawking Zhang { 2808cc65176eSHawking Zhang unsigned int psp_write_ptr_reg = 0; 28092e77541bSColin Ian King struct psp_gfx_rb_frame *write_frame; 2810cc65176eSHawking Zhang struct psp_ring *ring = &psp->km_ring; 2811cc65176eSHawking Zhang struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; 2812cc65176eSHawking Zhang struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + 2813cc65176eSHawking Zhang ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; 2814cc65176eSHawking Zhang struct amdgpu_device *adev = psp->adev; 2815cc65176eSHawking Zhang uint32_t ring_size_dw = ring->ring_size / 4; 2816cc65176eSHawking Zhang uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; 2817cc65176eSHawking Zhang 2818cc65176eSHawking Zhang /* KM (GPCOM) prepare write pointer */ 2819cc65176eSHawking Zhang psp_write_ptr_reg = psp_ring_get_wptr(psp); 2820cc65176eSHawking Zhang 2821cc65176eSHawking Zhang /* Update KM RB frame pointer to new frame */ 2822cc65176eSHawking Zhang /* write_frame ptr increments by size of rb_frame in bytes */ 2823cc65176eSHawking Zhang /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ 2824cc65176eSHawking Zhang if ((psp_write_ptr_reg % ring_size_dw) == 0) 2825cc65176eSHawking Zhang write_frame = ring_buffer_start; 2826cc65176eSHawking Zhang else 2827cc65176eSHawking Zhang write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); 2828cc65176eSHawking Zhang /* Check invalid write_frame ptr address */ 2829cc65176eSHawking Zhang if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { 2830cc65176eSHawking Zhang DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", 2831cc65176eSHawking Zhang ring_buffer_start, ring_buffer_end, write_frame); 2832cc65176eSHawking Zhang DRM_ERROR("write_frame is pointing to address out of bounds\n"); 2833cc65176eSHawking Zhang return -EINVAL; 2834cc65176eSHawking Zhang } 2835cc65176eSHawking Zhang 2836cc65176eSHawking Zhang /* Initialize KM RB frame */ 2837cc65176eSHawking Zhang memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); 2838cc65176eSHawking Zhang 2839cc65176eSHawking Zhang /* Update KM RB frame */ 2840cc65176eSHawking Zhang write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); 2841cc65176eSHawking Zhang write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); 2842cc65176eSHawking Zhang write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); 2843cc65176eSHawking Zhang write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); 2844cc65176eSHawking Zhang write_frame->fence_value = index; 2845810085ddSEric Huang amdgpu_device_flush_hdp(adev, NULL); 2846cc65176eSHawking Zhang 2847cc65176eSHawking Zhang /* Update the write Pointer in DWORDs */ 2848cc65176eSHawking Zhang psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; 2849cc65176eSHawking Zhang psp_ring_set_wptr(psp, psp_write_ptr_reg); 2850cc65176eSHawking Zhang return 0; 2851cc65176eSHawking Zhang } 2852cc65176eSHawking Zhang 2853dc7195f6SHawking Zhang int psp_init_asd_microcode(struct psp_context *psp, 2854dc7195f6SHawking Zhang const char *chip_name) 2855dc7195f6SHawking Zhang { 2856dc7195f6SHawking Zhang struct amdgpu_device *adev = psp->adev; 28570a305e34STao Zhou char fw_name[PSP_FW_NAME_LEN]; 2858dc7195f6SHawking Zhang const struct psp_firmware_header_v1_0 *asd_hdr; 2859dc7195f6SHawking Zhang int err = 0; 2860dc7195f6SHawking Zhang 2861dc7195f6SHawking Zhang if (!chip_name) { 2862dc7195f6SHawking Zhang dev_err(adev->dev, "invalid chip name for asd microcode\n"); 2863dc7195f6SHawking Zhang return -EINVAL; 2864dc7195f6SHawking Zhang } 2865dc7195f6SHawking Zhang 2866dc7195f6SHawking Zhang snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name); 2867dc7195f6SHawking Zhang err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev); 2868dc7195f6SHawking Zhang if (err) 2869dc7195f6SHawking Zhang goto out; 2870dc7195f6SHawking Zhang 2871dc7195f6SHawking Zhang err = amdgpu_ucode_validate(adev->psp.asd_fw); 2872dc7195f6SHawking Zhang if (err) 2873dc7195f6SHawking Zhang goto out; 2874dc7195f6SHawking Zhang 2875dc7195f6SHawking Zhang asd_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data; 2876dc7195f6SHawking Zhang adev->psp.asd_fw_version = le32_to_cpu(asd_hdr->header.ucode_version); 287779a0f441SJohn Clements adev->psp.asd_feature_version = le32_to_cpu(asd_hdr->sos.fw_version); 2878dc7195f6SHawking Zhang adev->psp.asd_ucode_size = le32_to_cpu(asd_hdr->header.ucode_size_bytes); 2879dc7195f6SHawking Zhang adev->psp.asd_start_addr = (uint8_t *)asd_hdr + 2880dc7195f6SHawking Zhang le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes); 2881dc7195f6SHawking Zhang return 0; 2882dc7195f6SHawking Zhang out: 2883dc7195f6SHawking Zhang dev_err(adev->dev, "fail to initialize asd microcode\n"); 2884dc7195f6SHawking Zhang release_firmware(adev->psp.asd_fw); 2885dc7195f6SHawking Zhang adev->psp.asd_fw = NULL; 2886dc7195f6SHawking Zhang return err; 2887dc7195f6SHawking Zhang } 2888dc7195f6SHawking Zhang 28895120cb54SHuang Rui int psp_init_toc_microcode(struct psp_context *psp, 28905120cb54SHuang Rui const char *chip_name) 28915120cb54SHuang Rui { 28925120cb54SHuang Rui struct amdgpu_device *adev = psp->adev; 28935120cb54SHuang Rui char fw_name[30]; 28945120cb54SHuang Rui const struct psp_firmware_header_v1_0 *toc_hdr; 28955120cb54SHuang Rui int err = 0; 28965120cb54SHuang Rui 28975120cb54SHuang Rui if (!chip_name) { 28985120cb54SHuang Rui dev_err(adev->dev, "invalid chip name for toc microcode\n"); 28995120cb54SHuang Rui return -EINVAL; 29005120cb54SHuang Rui } 29015120cb54SHuang Rui 29025120cb54SHuang Rui snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", chip_name); 29035120cb54SHuang Rui err = request_firmware(&adev->psp.toc_fw, fw_name, adev->dev); 29045120cb54SHuang Rui if (err) 29055120cb54SHuang Rui goto out; 29065120cb54SHuang Rui 29075120cb54SHuang Rui err = amdgpu_ucode_validate(adev->psp.toc_fw); 29085120cb54SHuang Rui if (err) 29095120cb54SHuang Rui goto out; 29105120cb54SHuang Rui 29115120cb54SHuang Rui toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data; 29125120cb54SHuang Rui adev->psp.toc_fw_version = le32_to_cpu(toc_hdr->header.ucode_version); 291379a0f441SJohn Clements adev->psp.toc_feature_version = le32_to_cpu(toc_hdr->sos.fw_version); 29145120cb54SHuang Rui adev->psp.toc_bin_size = le32_to_cpu(toc_hdr->header.ucode_size_bytes); 29155120cb54SHuang Rui adev->psp.toc_start_addr = (uint8_t *)toc_hdr + 29165120cb54SHuang Rui le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes); 29175120cb54SHuang Rui return 0; 29185120cb54SHuang Rui out: 29195120cb54SHuang Rui dev_err(adev->dev, "fail to request/validate toc microcode\n"); 29205120cb54SHuang Rui release_firmware(adev->psp.toc_fw); 29215120cb54SHuang Rui adev->psp.toc_fw = NULL; 29225120cb54SHuang Rui return err; 29235120cb54SHuang Rui } 29245120cb54SHuang Rui 29252a9a151fSJohn Clements static int psp_init_sos_base_fw(struct amdgpu_device *adev) 29262a9a151fSJohn Clements { 29272a9a151fSJohn Clements const struct psp_firmware_header_v1_0 *sos_hdr; 29282a9a151fSJohn Clements const struct psp_firmware_header_v1_3 *sos_hdr_v1_3; 29292a9a151fSJohn Clements 29302a9a151fSJohn Clements sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; 29312a9a151fSJohn Clements 29322a9a151fSJohn Clements if (adev->gmc.xgmi.connected_to_cpu || (adev->asic_type != CHIP_ALDEBARAN)) { 29332a9a151fSJohn Clements adev->psp.sos_fw_version = le32_to_cpu(sos_hdr->header.ucode_version); 29342a9a151fSJohn Clements adev->psp.sos_feature_version = le32_to_cpu(sos_hdr->sos.fw_version); 29352a9a151fSJohn Clements 29362a9a151fSJohn Clements adev->psp.sys_bin_size = le32_to_cpu(sos_hdr->sos.offset_bytes); 29372a9a151fSJohn Clements adev->psp.sys_start_addr = (uint8_t *)sos_hdr + 29382a9a151fSJohn Clements le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes); 29392a9a151fSJohn Clements 29402a9a151fSJohn Clements adev->psp.sos_bin_size = le32_to_cpu(sos_hdr->sos.size_bytes); 29412a9a151fSJohn Clements adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr + 29422a9a151fSJohn Clements le32_to_cpu(sos_hdr->sos.offset_bytes); 29432a9a151fSJohn Clements } else { 29442a9a151fSJohn Clements /* Load alternate PSP SOS FW */ 29452a9a151fSJohn Clements sos_hdr_v1_3 = (const struct psp_firmware_header_v1_3 *)adev->psp.sos_fw->data; 29462a9a151fSJohn Clements 29472a9a151fSJohn Clements adev->psp.sos_fw_version = le32_to_cpu(sos_hdr_v1_3->sos_aux.fw_version); 29482a9a151fSJohn Clements adev->psp.sos_feature_version = le32_to_cpu(sos_hdr_v1_3->sos_aux.fw_version); 29492a9a151fSJohn Clements 29502a9a151fSJohn Clements adev->psp.sys_bin_size = le32_to_cpu(sos_hdr_v1_3->sys_drv_aux.size_bytes); 29512a9a151fSJohn Clements adev->psp.sys_start_addr = (uint8_t *)adev->psp.sys_start_addr + 29522a9a151fSJohn Clements le32_to_cpu(sos_hdr_v1_3->sys_drv_aux.offset_bytes); 29532a9a151fSJohn Clements 29542a9a151fSJohn Clements adev->psp.sos_bin_size = le32_to_cpu(sos_hdr_v1_3->sos_aux.size_bytes); 29552a9a151fSJohn Clements adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr + 29562a9a151fSJohn Clements le32_to_cpu(sos_hdr_v1_3->sos_aux.offset_bytes); 29572a9a151fSJohn Clements } 29582a9a151fSJohn Clements 29592a9a151fSJohn Clements if ((adev->psp.sys_bin_size == 0) || (adev->psp.sos_bin_size == 0)) { 29602a9a151fSJohn Clements dev_warn(adev->dev, "PSP SOS FW not available"); 29612a9a151fSJohn Clements return -EINVAL; 29622a9a151fSJohn Clements } 29632a9a151fSJohn Clements 29642a9a151fSJohn Clements return 0; 29652a9a151fSJohn Clements } 29662a9a151fSJohn Clements 29671c301f44SHawking Zhang int psp_init_sos_microcode(struct psp_context *psp, 29681c301f44SHawking Zhang const char *chip_name) 29691c301f44SHawking Zhang { 29701c301f44SHawking Zhang struct amdgpu_device *adev = psp->adev; 29710a305e34STao Zhou char fw_name[PSP_FW_NAME_LEN]; 29721c301f44SHawking Zhang const struct psp_firmware_header_v1_0 *sos_hdr; 29731c301f44SHawking Zhang const struct psp_firmware_header_v1_1 *sos_hdr_v1_1; 29741c301f44SHawking Zhang const struct psp_firmware_header_v1_2 *sos_hdr_v1_2; 297543a188e0SLikun Gao const struct psp_firmware_header_v1_3 *sos_hdr_v1_3; 29761c301f44SHawking Zhang int err = 0; 29771c301f44SHawking Zhang 29781c301f44SHawking Zhang if (!chip_name) { 29791c301f44SHawking Zhang dev_err(adev->dev, "invalid chip name for sos microcode\n"); 29801c301f44SHawking Zhang return -EINVAL; 29811c301f44SHawking Zhang } 29821c301f44SHawking Zhang 29831c301f44SHawking Zhang snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sos.bin", chip_name); 29841c301f44SHawking Zhang err = request_firmware(&adev->psp.sos_fw, fw_name, adev->dev); 29851c301f44SHawking Zhang if (err) 29861c301f44SHawking Zhang goto out; 29871c301f44SHawking Zhang 29881c301f44SHawking Zhang err = amdgpu_ucode_validate(adev->psp.sos_fw); 29891c301f44SHawking Zhang if (err) 29901c301f44SHawking Zhang goto out; 29911c301f44SHawking Zhang 29921c301f44SHawking Zhang sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; 29931c301f44SHawking Zhang amdgpu_ucode_print_psp_hdr(&sos_hdr->header); 29941c301f44SHawking Zhang 29951c301f44SHawking Zhang switch (sos_hdr->header.header_version_major) { 29961c301f44SHawking Zhang case 1: 29972a9a151fSJohn Clements err = psp_init_sos_base_fw(adev); 29982a9a151fSJohn Clements if (err) 29992a9a151fSJohn Clements goto out; 30002a9a151fSJohn Clements 30011c301f44SHawking Zhang if (sos_hdr->header.header_version_minor == 1) { 30021c301f44SHawking Zhang sos_hdr_v1_1 = (const struct psp_firmware_header_v1_1 *)adev->psp.sos_fw->data; 300379a0f441SJohn Clements adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_1->toc.size_bytes); 30041c301f44SHawking Zhang adev->psp.toc_start_addr = (uint8_t *)adev->psp.sys_start_addr + 300579a0f441SJohn Clements le32_to_cpu(sos_hdr_v1_1->toc.offset_bytes); 300679a0f441SJohn Clements adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_1->kdb.size_bytes); 30071c301f44SHawking Zhang adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + 300879a0f441SJohn Clements le32_to_cpu(sos_hdr_v1_1->kdb.offset_bytes); 30091c301f44SHawking Zhang } 30101c301f44SHawking Zhang if (sos_hdr->header.header_version_minor == 2) { 30111c301f44SHawking Zhang sos_hdr_v1_2 = (const struct psp_firmware_header_v1_2 *)adev->psp.sos_fw->data; 301279a0f441SJohn Clements adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_2->kdb.size_bytes); 30131c301f44SHawking Zhang adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + 301479a0f441SJohn Clements le32_to_cpu(sos_hdr_v1_2->kdb.offset_bytes); 30151c301f44SHawking Zhang } 301643a188e0SLikun Gao if (sos_hdr->header.header_version_minor == 3) { 301743a188e0SLikun Gao sos_hdr_v1_3 = (const struct psp_firmware_header_v1_3 *)adev->psp.sos_fw->data; 301879a0f441SJohn Clements adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_3->v1_1.toc.size_bytes); 301943a188e0SLikun Gao adev->psp.toc_start_addr = (uint8_t *)adev->psp.sys_start_addr + 302079a0f441SJohn Clements le32_to_cpu(sos_hdr_v1_3->v1_1.toc.offset_bytes); 302179a0f441SJohn Clements adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_3->v1_1.kdb.size_bytes); 302243a188e0SLikun Gao adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + 302379a0f441SJohn Clements le32_to_cpu(sos_hdr_v1_3->v1_1.kdb.offset_bytes); 302479a0f441SJohn Clements adev->psp.spl_bin_size = le32_to_cpu(sos_hdr_v1_3->spl.size_bytes); 302543a188e0SLikun Gao adev->psp.spl_start_addr = (uint8_t *)adev->psp.sys_start_addr + 302679a0f441SJohn Clements le32_to_cpu(sos_hdr_v1_3->spl.offset_bytes); 302779a0f441SJohn Clements adev->psp.rl_bin_size = le32_to_cpu(sos_hdr_v1_3->rl.size_bytes); 3028b2aa382aSJohn Clements adev->psp.rl_start_addr = (uint8_t *)adev->psp.sys_start_addr + 302979a0f441SJohn Clements le32_to_cpu(sos_hdr_v1_3->rl.offset_bytes); 303043a188e0SLikun Gao } 30311c301f44SHawking Zhang break; 30321c301f44SHawking Zhang default: 30331c301f44SHawking Zhang dev_err(adev->dev, 30341c301f44SHawking Zhang "unsupported psp sos firmware\n"); 30351c301f44SHawking Zhang err = -EINVAL; 30361c301f44SHawking Zhang goto out; 30371c301f44SHawking Zhang } 30381c301f44SHawking Zhang 30391c301f44SHawking Zhang return 0; 30401c301f44SHawking Zhang out: 30411c301f44SHawking Zhang dev_err(adev->dev, 30421c301f44SHawking Zhang "failed to init sos firmware\n"); 30431c301f44SHawking Zhang release_firmware(adev->psp.sos_fw); 30441c301f44SHawking Zhang adev->psp.sos_fw = NULL; 30451c301f44SHawking Zhang 30461c301f44SHawking Zhang return err; 30471c301f44SHawking Zhang } 30481c301f44SHawking Zhang 3049c18dd61aSLee Jones static int parse_ta_bin_descriptor(struct psp_context *psp, 3050dcf9864dSJohn Clements const struct ta_fw_bin_desc *desc, 3051dcf9864dSJohn Clements const struct ta_firmware_header_v2_0 *ta_hdr) 3052dcf9864dSJohn Clements { 3053dcf9864dSJohn Clements uint8_t *ucode_start_addr = NULL; 3054dcf9864dSJohn Clements 3055dcf9864dSJohn Clements if (!psp || !desc || !ta_hdr) 3056dcf9864dSJohn Clements return -EINVAL; 3057dcf9864dSJohn Clements 3058a3302729SJohn Clements ucode_start_addr = (uint8_t *)ta_hdr + 3059a3302729SJohn Clements le32_to_cpu(desc->offset_bytes) + 3060a3302729SJohn Clements le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); 3061dcf9864dSJohn Clements 3062dcf9864dSJohn Clements switch (desc->fw_type) { 3063dcf9864dSJohn Clements case TA_FW_TYPE_PSP_ASD: 3064dcf9864dSJohn Clements psp->asd_fw_version = le32_to_cpu(desc->fw_version); 3065dcf9864dSJohn Clements psp->asd_feature_version = le32_to_cpu(desc->fw_version); 3066dcf9864dSJohn Clements psp->asd_ucode_size = le32_to_cpu(desc->size_bytes); 3067dcf9864dSJohn Clements psp->asd_start_addr = ucode_start_addr; 3068dcf9864dSJohn Clements break; 3069dcf9864dSJohn Clements case TA_FW_TYPE_PSP_XGMI: 3070dcf9864dSJohn Clements psp->ta_xgmi_ucode_version = le32_to_cpu(desc->fw_version); 3071dcf9864dSJohn Clements psp->ta_xgmi_ucode_size = le32_to_cpu(desc->size_bytes); 3072dcf9864dSJohn Clements psp->ta_xgmi_start_addr = ucode_start_addr; 3073dcf9864dSJohn Clements break; 3074dcf9864dSJohn Clements case TA_FW_TYPE_PSP_RAS: 3075dcf9864dSJohn Clements psp->ta_ras_ucode_version = le32_to_cpu(desc->fw_version); 3076dcf9864dSJohn Clements psp->ta_ras_ucode_size = le32_to_cpu(desc->size_bytes); 3077dcf9864dSJohn Clements psp->ta_ras_start_addr = ucode_start_addr; 3078dcf9864dSJohn Clements break; 3079dcf9864dSJohn Clements case TA_FW_TYPE_PSP_HDCP: 3080dcf9864dSJohn Clements psp->ta_hdcp_ucode_version = le32_to_cpu(desc->fw_version); 3081dcf9864dSJohn Clements psp->ta_hdcp_ucode_size = le32_to_cpu(desc->size_bytes); 3082dcf9864dSJohn Clements psp->ta_hdcp_start_addr = ucode_start_addr; 3083dcf9864dSJohn Clements break; 3084dcf9864dSJohn Clements case TA_FW_TYPE_PSP_DTM: 3085dcf9864dSJohn Clements psp->ta_dtm_ucode_version = le32_to_cpu(desc->fw_version); 3086dcf9864dSJohn Clements psp->ta_dtm_ucode_size = le32_to_cpu(desc->size_bytes); 3087dcf9864dSJohn Clements psp->ta_dtm_start_addr = ucode_start_addr; 3088dcf9864dSJohn Clements break; 30898602692bSWenhui Sheng case TA_FW_TYPE_PSP_RAP: 30908602692bSWenhui Sheng psp->ta_rap_ucode_version = le32_to_cpu(desc->fw_version); 30918602692bSWenhui Sheng psp->ta_rap_ucode_size = le32_to_cpu(desc->size_bytes); 30928602692bSWenhui Sheng psp->ta_rap_start_addr = ucode_start_addr; 30938602692bSWenhui Sheng break; 3094ecaafb7bSJinzhou Su case TA_FW_TYPE_PSP_SECUREDISPLAY: 3095ecaafb7bSJinzhou Su psp->ta_securedisplay_ucode_version = le32_to_cpu(desc->fw_version); 3096ecaafb7bSJinzhou Su psp->ta_securedisplay_ucode_size = le32_to_cpu(desc->size_bytes); 3097ecaafb7bSJinzhou Su psp->ta_securedisplay_start_addr = ucode_start_addr; 3098ecaafb7bSJinzhou Su break; 3099dcf9864dSJohn Clements default: 3100dcf9864dSJohn Clements dev_warn(psp->adev->dev, "Unsupported TA type: %d\n", desc->fw_type); 3101dcf9864dSJohn Clements break; 3102dcf9864dSJohn Clements } 3103dcf9864dSJohn Clements 3104dcf9864dSJohn Clements return 0; 3105dcf9864dSJohn Clements } 3106dcf9864dSJohn Clements 3107dcf9864dSJohn Clements int psp_init_ta_microcode(struct psp_context *psp, 3108dcf9864dSJohn Clements const char *chip_name) 3109dcf9864dSJohn Clements { 3110dcf9864dSJohn Clements struct amdgpu_device *adev = psp->adev; 31116cb445e8SBhawanpreet Lakha char fw_name[PSP_FW_NAME_LEN]; 3112dcf9864dSJohn Clements const struct ta_firmware_header_v2_0 *ta_hdr; 3113dcf9864dSJohn Clements int err = 0; 3114dcf9864dSJohn Clements int ta_index = 0; 3115dcf9864dSJohn Clements 3116dcf9864dSJohn Clements if (!chip_name) { 3117dcf9864dSJohn Clements dev_err(adev->dev, "invalid chip name for ta microcode\n"); 3118dcf9864dSJohn Clements return -EINVAL; 3119dcf9864dSJohn Clements } 3120dcf9864dSJohn Clements 3121dcf9864dSJohn Clements snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); 3122dcf9864dSJohn Clements err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); 3123dcf9864dSJohn Clements if (err) 3124dcf9864dSJohn Clements goto out; 3125dcf9864dSJohn Clements 3126dcf9864dSJohn Clements err = amdgpu_ucode_validate(adev->psp.ta_fw); 3127dcf9864dSJohn Clements if (err) 3128dcf9864dSJohn Clements goto out; 3129dcf9864dSJohn Clements 3130dcf9864dSJohn Clements ta_hdr = (const struct ta_firmware_header_v2_0 *)adev->psp.ta_fw->data; 3131dcf9864dSJohn Clements 3132dcf9864dSJohn Clements if (le16_to_cpu(ta_hdr->header.header_version_major) != 2) { 3133dcf9864dSJohn Clements dev_err(adev->dev, "unsupported TA header version\n"); 3134dcf9864dSJohn Clements err = -EINVAL; 3135dcf9864dSJohn Clements goto out; 3136dcf9864dSJohn Clements } 3137dcf9864dSJohn Clements 3138dcf9864dSJohn Clements if (le32_to_cpu(ta_hdr->ta_fw_bin_count) >= UCODE_MAX_TA_PACKAGING) { 3139dcf9864dSJohn Clements dev_err(adev->dev, "packed TA count exceeds maximum limit\n"); 3140dcf9864dSJohn Clements err = -EINVAL; 3141dcf9864dSJohn Clements goto out; 3142dcf9864dSJohn Clements } 3143dcf9864dSJohn Clements 3144dcf9864dSJohn Clements for (ta_index = 0; ta_index < le32_to_cpu(ta_hdr->ta_fw_bin_count); ta_index++) { 3145dcf9864dSJohn Clements err = parse_ta_bin_descriptor(psp, 3146dcf9864dSJohn Clements &ta_hdr->ta_fw_bin[ta_index], 3147dcf9864dSJohn Clements ta_hdr); 3148dcf9864dSJohn Clements if (err) 3149dcf9864dSJohn Clements goto out; 3150dcf9864dSJohn Clements } 3151dcf9864dSJohn Clements 3152dcf9864dSJohn Clements return 0; 3153dcf9864dSJohn Clements out: 3154dcf9864dSJohn Clements dev_err(adev->dev, "fail to initialize ta microcode\n"); 3155dcf9864dSJohn Clements release_firmware(adev->psp.ta_fw); 3156dcf9864dSJohn Clements adev->psp.ta_fw = NULL; 3157dcf9864dSJohn Clements return err; 3158dcf9864dSJohn Clements } 3159dcf9864dSJohn Clements 31600e5ca0d1SHuang Rui static int psp_set_clockgating_state(void *handle, 31610e5ca0d1SHuang Rui enum amd_clockgating_state state) 31620e5ca0d1SHuang Rui { 31630e5ca0d1SHuang Rui return 0; 31640e5ca0d1SHuang Rui } 31650e5ca0d1SHuang Rui 31660e5ca0d1SHuang Rui static int psp_set_powergating_state(void *handle, 31670e5ca0d1SHuang Rui enum amd_powergating_state state) 31680e5ca0d1SHuang Rui { 31690e5ca0d1SHuang Rui return 0; 31700e5ca0d1SHuang Rui } 31710e5ca0d1SHuang Rui 317257430471SAndrey Grodzovsky static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev, 317357430471SAndrey Grodzovsky struct device_attribute *attr, 317457430471SAndrey Grodzovsky char *buf) 317557430471SAndrey Grodzovsky { 317657430471SAndrey Grodzovsky struct drm_device *ddev = dev_get_drvdata(dev); 31771348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev); 317857430471SAndrey Grodzovsky uint32_t fw_ver; 317957430471SAndrey Grodzovsky int ret; 318057430471SAndrey Grodzovsky 318190f88cddSAndrey Grodzovsky if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) { 318290f88cddSAndrey Grodzovsky DRM_INFO("PSP block is not ready yet."); 318390f88cddSAndrey Grodzovsky return -EBUSY; 318490f88cddSAndrey Grodzovsky } 318590f88cddSAndrey Grodzovsky 318657430471SAndrey Grodzovsky mutex_lock(&adev->psp.mutex); 318757430471SAndrey Grodzovsky ret = psp_read_usbc_pd_fw(&adev->psp, &fw_ver); 318857430471SAndrey Grodzovsky mutex_unlock(&adev->psp.mutex); 318957430471SAndrey Grodzovsky 319057430471SAndrey Grodzovsky if (ret) { 319157430471SAndrey Grodzovsky DRM_ERROR("Failed to read USBC PD FW, err = %d", ret); 319257430471SAndrey Grodzovsky return ret; 319357430471SAndrey Grodzovsky } 319457430471SAndrey Grodzovsky 319536000c7aSTian Tao return sysfs_emit(buf, "%x\n", fw_ver); 319657430471SAndrey Grodzovsky } 319757430471SAndrey Grodzovsky 319857430471SAndrey Grodzovsky static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, 319957430471SAndrey Grodzovsky struct device_attribute *attr, 320057430471SAndrey Grodzovsky const char *buf, 320157430471SAndrey Grodzovsky size_t count) 320257430471SAndrey Grodzovsky { 320357430471SAndrey Grodzovsky struct drm_device *ddev = dev_get_drvdata(dev); 32041348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev); 320557430471SAndrey Grodzovsky void *cpu_addr; 320657430471SAndrey Grodzovsky dma_addr_t dma_addr; 3207f89f8c6bSAndrey Grodzovsky int ret, idx; 320857430471SAndrey Grodzovsky char fw_name[100]; 320957430471SAndrey Grodzovsky const struct firmware *usbc_pd_fw; 321057430471SAndrey Grodzovsky 321190f88cddSAndrey Grodzovsky if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) { 321290f88cddSAndrey Grodzovsky DRM_INFO("PSP block is not ready yet."); 321390f88cddSAndrey Grodzovsky return -EBUSY; 321490f88cddSAndrey Grodzovsky } 321557430471SAndrey Grodzovsky 3216f89f8c6bSAndrey Grodzovsky if (!drm_dev_enter(ddev, &idx)) 3217f89f8c6bSAndrey Grodzovsky return -ENODEV; 3218f89f8c6bSAndrey Grodzovsky 321957430471SAndrey Grodzovsky snprintf(fw_name, sizeof(fw_name), "amdgpu/%s", buf); 322057430471SAndrey Grodzovsky ret = request_firmware(&usbc_pd_fw, fw_name, adev->dev); 322157430471SAndrey Grodzovsky if (ret) 322257430471SAndrey Grodzovsky goto fail; 322357430471SAndrey Grodzovsky 322457430471SAndrey Grodzovsky /* We need contiguous physical mem to place the FW for psp to access */ 322557430471SAndrey Grodzovsky cpu_addr = dma_alloc_coherent(adev->dev, usbc_pd_fw->size, &dma_addr, GFP_KERNEL); 322657430471SAndrey Grodzovsky 322757430471SAndrey Grodzovsky ret = dma_mapping_error(adev->dev, dma_addr); 322857430471SAndrey Grodzovsky if (ret) 322957430471SAndrey Grodzovsky goto rel_buf; 323057430471SAndrey Grodzovsky 323157430471SAndrey Grodzovsky memcpy_toio(cpu_addr, usbc_pd_fw->data, usbc_pd_fw->size); 323257430471SAndrey Grodzovsky 32336863d607SAndrey Grodzovsky /* 32346863d607SAndrey Grodzovsky * x86 specific workaround. 32356863d607SAndrey Grodzovsky * Without it the buffer is invisible in PSP. 32366863d607SAndrey Grodzovsky * 32376863d607SAndrey Grodzovsky * TODO Remove once PSP starts snooping CPU cache 32386863d607SAndrey Grodzovsky */ 32396863d607SAndrey Grodzovsky #ifdef CONFIG_X86 324057430471SAndrey Grodzovsky clflush_cache_range(cpu_addr, (usbc_pd_fw->size & ~(L1_CACHE_BYTES - 1))); 32416863d607SAndrey Grodzovsky #endif 324257430471SAndrey Grodzovsky 324357430471SAndrey Grodzovsky mutex_lock(&adev->psp.mutex); 324457430471SAndrey Grodzovsky ret = psp_load_usbc_pd_fw(&adev->psp, dma_addr); 324557430471SAndrey Grodzovsky mutex_unlock(&adev->psp.mutex); 324657430471SAndrey Grodzovsky 324757430471SAndrey Grodzovsky rel_buf: 324857430471SAndrey Grodzovsky dma_free_coherent(adev->dev, usbc_pd_fw->size, cpu_addr, dma_addr); 324957430471SAndrey Grodzovsky release_firmware(usbc_pd_fw); 325057430471SAndrey Grodzovsky fail: 325157430471SAndrey Grodzovsky if (ret) { 325257430471SAndrey Grodzovsky DRM_ERROR("Failed to load USBC PD FW, err = %d", ret); 3253f89f8c6bSAndrey Grodzovsky count = ret; 325457430471SAndrey Grodzovsky } 325557430471SAndrey Grodzovsky 3256f89f8c6bSAndrey Grodzovsky drm_dev_exit(idx); 325757430471SAndrey Grodzovsky return count; 325857430471SAndrey Grodzovsky } 325957430471SAndrey Grodzovsky 3260f89f8c6bSAndrey Grodzovsky void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size) 3261f89f8c6bSAndrey Grodzovsky { 3262f89f8c6bSAndrey Grodzovsky int idx; 3263f89f8c6bSAndrey Grodzovsky 3264f89f8c6bSAndrey Grodzovsky if (!drm_dev_enter(&psp->adev->ddev, &idx)) 3265f89f8c6bSAndrey Grodzovsky return; 3266f89f8c6bSAndrey Grodzovsky 3267f89f8c6bSAndrey Grodzovsky memset(psp->fw_pri_buf, 0, PSP_1_MEG); 3268f89f8c6bSAndrey Grodzovsky memcpy(psp->fw_pri_buf, start_addr, bin_size); 3269f89f8c6bSAndrey Grodzovsky 3270f89f8c6bSAndrey Grodzovsky drm_dev_exit(idx); 3271f89f8c6bSAndrey Grodzovsky } 3272f89f8c6bSAndrey Grodzovsky 327357430471SAndrey Grodzovsky static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR, 327457430471SAndrey Grodzovsky psp_usbc_pd_fw_sysfs_read, 327557430471SAndrey Grodzovsky psp_usbc_pd_fw_sysfs_write); 327657430471SAndrey Grodzovsky 327757430471SAndrey Grodzovsky 327857430471SAndrey Grodzovsky 32790e5ca0d1SHuang Rui const struct amd_ip_funcs psp_ip_funcs = { 32800e5ca0d1SHuang Rui .name = "psp", 32810e5ca0d1SHuang Rui .early_init = psp_early_init, 328290f88cddSAndrey Grodzovsky .late_init = NULL, 32830e5ca0d1SHuang Rui .sw_init = psp_sw_init, 32840e5ca0d1SHuang Rui .sw_fini = psp_sw_fini, 32850e5ca0d1SHuang Rui .hw_init = psp_hw_init, 32860e5ca0d1SHuang Rui .hw_fini = psp_hw_fini, 32870e5ca0d1SHuang Rui .suspend = psp_suspend, 32880e5ca0d1SHuang Rui .resume = psp_resume, 32890e5ca0d1SHuang Rui .is_idle = NULL, 3290f75a9a5dSAlex Deucher .check_soft_reset = NULL, 32910e5ca0d1SHuang Rui .wait_for_idle = NULL, 3292f75a9a5dSAlex Deucher .soft_reset = NULL, 32930e5ca0d1SHuang Rui .set_clockgating_state = psp_set_clockgating_state, 32940e5ca0d1SHuang Rui .set_powergating_state = psp_set_powergating_state, 32950e5ca0d1SHuang Rui }; 32960e5ca0d1SHuang Rui 329757430471SAndrey Grodzovsky static int psp_sysfs_init(struct amdgpu_device *adev) 329857430471SAndrey Grodzovsky { 329957430471SAndrey Grodzovsky int ret = device_create_file(adev->dev, &dev_attr_usbc_pd_fw); 330057430471SAndrey Grodzovsky 330157430471SAndrey Grodzovsky if (ret) 330257430471SAndrey Grodzovsky DRM_ERROR("Failed to create USBC PD FW control file!"); 330357430471SAndrey Grodzovsky 330457430471SAndrey Grodzovsky return ret; 330557430471SAndrey Grodzovsky } 330657430471SAndrey Grodzovsky 330757430471SAndrey Grodzovsky static void psp_sysfs_fini(struct amdgpu_device *adev) 330857430471SAndrey Grodzovsky { 330957430471SAndrey Grodzovsky device_remove_file(adev->dev, &dev_attr_usbc_pd_fw); 331057430471SAndrey Grodzovsky } 331157430471SAndrey Grodzovsky 33120e5ca0d1SHuang Rui const struct amdgpu_ip_block_version psp_v3_1_ip_block = 33130e5ca0d1SHuang Rui { 33140e5ca0d1SHuang Rui .type = AMD_IP_BLOCK_TYPE_PSP, 33150e5ca0d1SHuang Rui .major = 3, 33160e5ca0d1SHuang Rui .minor = 1, 33170e5ca0d1SHuang Rui .rev = 0, 33180e5ca0d1SHuang Rui .funcs = &psp_ip_funcs, 33190e5ca0d1SHuang Rui }; 3320dfbd6438SHuang Rui 3321dfbd6438SHuang Rui const struct amdgpu_ip_block_version psp_v10_0_ip_block = 3322dfbd6438SHuang Rui { 3323dfbd6438SHuang Rui .type = AMD_IP_BLOCK_TYPE_PSP, 3324dfbd6438SHuang Rui .major = 10, 3325dfbd6438SHuang Rui .minor = 0, 3326dfbd6438SHuang Rui .rev = 0, 3327dfbd6438SHuang Rui .funcs = &psp_ip_funcs, 3328dfbd6438SHuang Rui }; 3329654f761cSFeifei Xu 3330654f761cSFeifei Xu const struct amdgpu_ip_block_version psp_v11_0_ip_block = 3331654f761cSFeifei Xu { 3332654f761cSFeifei Xu .type = AMD_IP_BLOCK_TYPE_PSP, 3333654f761cSFeifei Xu .major = 11, 3334654f761cSFeifei Xu .minor = 0, 3335654f761cSFeifei Xu .rev = 0, 3336654f761cSFeifei Xu .funcs = &psp_ip_funcs, 3337654f761cSFeifei Xu }; 33386a7a0bdbSAaron Liu 33396a7a0bdbSAaron Liu const struct amdgpu_ip_block_version psp_v12_0_ip_block = 33406a7a0bdbSAaron Liu { 33416a7a0bdbSAaron Liu .type = AMD_IP_BLOCK_TYPE_PSP, 33426a7a0bdbSAaron Liu .major = 12, 33436a7a0bdbSAaron Liu .minor = 0, 33446a7a0bdbSAaron Liu .rev = 0, 33456a7a0bdbSAaron Liu .funcs = &psp_ip_funcs, 33466a7a0bdbSAaron Liu }; 33479fbd96a1SHawking Zhang 33489fbd96a1SHawking Zhang const struct amdgpu_ip_block_version psp_v13_0_ip_block = { 33499fbd96a1SHawking Zhang .type = AMD_IP_BLOCK_TYPE_PSP, 33509fbd96a1SHawking Zhang .major = 13, 33519fbd96a1SHawking Zhang .minor = 0, 33529fbd96a1SHawking Zhang .rev = 0, 33539fbd96a1SHawking Zhang .funcs = &psp_ip_funcs, 33549fbd96a1SHawking Zhang }; 3355