1*b843c749SSergey Zigachev /* 2*b843c749SSergey Zigachev * Copyright 2016 Advanced Micro Devices, Inc. 3*b843c749SSergey Zigachev * 4*b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a 5*b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"), 6*b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation 7*b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the 9*b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions: 10*b843c749SSergey Zigachev * 11*b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in 12*b843c749SSergey Zigachev * all copies or substantial portions of the Software. 13*b843c749SSergey Zigachev * 14*b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15*b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16*b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17*b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18*b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19*b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20*b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE. 21*b843c749SSergey Zigachev * 22*b843c749SSergey Zigachev * Author: Huang Rui 23*b843c749SSergey Zigachev * 24*b843c749SSergey Zigachev */ 25*b843c749SSergey Zigachev 26*b843c749SSergey Zigachev #include <linux/firmware.h> 27*b843c749SSergey Zigachev #include <drm/drmP.h> 28*b843c749SSergey Zigachev #include "amdgpu.h" 29*b843c749SSergey Zigachev #include "amdgpu_psp.h" 30*b843c749SSergey Zigachev #include "amdgpu_ucode.h" 31*b843c749SSergey Zigachev #include "soc15_common.h" 32*b843c749SSergey Zigachev #include "psp_v3_1.h" 33*b843c749SSergey Zigachev #include "psp_v10_0.h" 34*b843c749SSergey Zigachev 35*b843c749SSergey Zigachev static void psp_set_funcs(struct amdgpu_device *adev); 36*b843c749SSergey Zigachev 37*b843c749SSergey Zigachev static int psp_early_init(void *handle) 38*b843c749SSergey Zigachev { 39*b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle; 40*b843c749SSergey Zigachev struct psp_context *psp = &adev->psp; 41*b843c749SSergey Zigachev 42*b843c749SSergey Zigachev psp_set_funcs(adev); 43*b843c749SSergey Zigachev 44*b843c749SSergey Zigachev switch (adev->asic_type) { 45*b843c749SSergey Zigachev case CHIP_VEGA10: 46*b843c749SSergey Zigachev case CHIP_VEGA12: 47*b843c749SSergey Zigachev case CHIP_VEGA20: 48*b843c749SSergey Zigachev psp_v3_1_set_psp_funcs(psp); 49*b843c749SSergey Zigachev break; 50*b843c749SSergey Zigachev case CHIP_RAVEN: 51*b843c749SSergey Zigachev psp_v10_0_set_psp_funcs(psp); 52*b843c749SSergey Zigachev break; 53*b843c749SSergey Zigachev default: 54*b843c749SSergey Zigachev return -EINVAL; 55*b843c749SSergey Zigachev } 56*b843c749SSergey Zigachev 57*b843c749SSergey Zigachev psp->adev = adev; 58*b843c749SSergey Zigachev 59*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 60*b843c749SSergey Zigachev return 0; 61*b843c749SSergey Zigachev 62*b843c749SSergey Zigachev return 0; 63*b843c749SSergey Zigachev } 64*b843c749SSergey Zigachev 65*b843c749SSergey Zigachev static int psp_sw_init(void *handle) 66*b843c749SSergey Zigachev { 67*b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle; 68*b843c749SSergey Zigachev struct psp_context *psp = &adev->psp; 69*b843c749SSergey Zigachev int ret; 70*b843c749SSergey Zigachev 71*b843c749SSergey Zigachev ret = psp_init_microcode(psp); 72*b843c749SSergey Zigachev if (ret) { 73*b843c749SSergey Zigachev DRM_ERROR("Failed to load psp firmware!\n"); 74*b843c749SSergey Zigachev return ret; 75*b843c749SSergey Zigachev } 76*b843c749SSergey Zigachev 77*b843c749SSergey Zigachev return 0; 78*b843c749SSergey Zigachev } 79*b843c749SSergey Zigachev 80*b843c749SSergey Zigachev static int psp_sw_fini(void *handle) 81*b843c749SSergey Zigachev { 82*b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle; 83*b843c749SSergey Zigachev 84*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 85*b843c749SSergey Zigachev return 0; 86*b843c749SSergey Zigachev 87*b843c749SSergey Zigachev release_firmware(adev->psp.sos_fw); 88*b843c749SSergey Zigachev adev->psp.sos_fw = NULL; 89*b843c749SSergey Zigachev release_firmware(adev->psp.asd_fw); 90*b843c749SSergey Zigachev adev->psp.asd_fw = NULL; 91*b843c749SSergey Zigachev return 0; 92*b843c749SSergey Zigachev } 93*b843c749SSergey Zigachev 94*b843c749SSergey Zigachev int psp_wait_for(struct psp_context *psp, uint32_t reg_index, 95*b843c749SSergey Zigachev uint32_t reg_val, uint32_t mask, bool check_changed) 96*b843c749SSergey Zigachev { 97*b843c749SSergey Zigachev uint32_t val; 98*b843c749SSergey Zigachev int i; 99*b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 100*b843c749SSergey Zigachev 101*b843c749SSergey Zigachev for (i = 0; i < adev->usec_timeout; i++) { 102*b843c749SSergey Zigachev val = RREG32(reg_index); 103*b843c749SSergey Zigachev if (check_changed) { 104*b843c749SSergey Zigachev if (val != reg_val) 105*b843c749SSergey Zigachev return 0; 106*b843c749SSergey Zigachev } else { 107*b843c749SSergey Zigachev if ((val & mask) == reg_val) 108*b843c749SSergey Zigachev return 0; 109*b843c749SSergey Zigachev } 110*b843c749SSergey Zigachev udelay(1); 111*b843c749SSergey Zigachev } 112*b843c749SSergey Zigachev 113*b843c749SSergey Zigachev return -ETIME; 114*b843c749SSergey Zigachev } 115*b843c749SSergey Zigachev 116*b843c749SSergey Zigachev static int 117*b843c749SSergey Zigachev psp_cmd_submit_buf(struct psp_context *psp, 118*b843c749SSergey Zigachev struct amdgpu_firmware_info *ucode, 119*b843c749SSergey Zigachev struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr, 120*b843c749SSergey Zigachev int index) 121*b843c749SSergey Zigachev { 122*b843c749SSergey Zigachev int ret; 123*b843c749SSergey Zigachev 124*b843c749SSergey Zigachev memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE); 125*b843c749SSergey Zigachev 126*b843c749SSergey Zigachev memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp)); 127*b843c749SSergey Zigachev 128*b843c749SSergey Zigachev ret = psp_cmd_submit(psp, ucode, psp->cmd_buf_mc_addr, 129*b843c749SSergey Zigachev fence_mc_addr, index); 130*b843c749SSergey Zigachev 131*b843c749SSergey Zigachev while (*((unsigned int *)psp->fence_buf) != index) { 132*b843c749SSergey Zigachev msleep(1); 133*b843c749SSergey Zigachev } 134*b843c749SSergey Zigachev 135*b843c749SSergey Zigachev if (ucode) { 136*b843c749SSergey Zigachev ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo; 137*b843c749SSergey Zigachev ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi; 138*b843c749SSergey Zigachev } 139*b843c749SSergey Zigachev 140*b843c749SSergey Zigachev return ret; 141*b843c749SSergey Zigachev } 142*b843c749SSergey Zigachev 143*b843c749SSergey Zigachev static void psp_prep_tmr_cmd_buf(struct psp_gfx_cmd_resp *cmd, 144*b843c749SSergey Zigachev uint64_t tmr_mc, uint32_t size) 145*b843c749SSergey Zigachev { 146*b843c749SSergey Zigachev cmd->cmd_id = GFX_CMD_ID_SETUP_TMR; 147*b843c749SSergey Zigachev cmd->cmd.cmd_setup_tmr.buf_phy_addr_lo = lower_32_bits(tmr_mc); 148*b843c749SSergey Zigachev cmd->cmd.cmd_setup_tmr.buf_phy_addr_hi = upper_32_bits(tmr_mc); 149*b843c749SSergey Zigachev cmd->cmd.cmd_setup_tmr.buf_size = size; 150*b843c749SSergey Zigachev } 151*b843c749SSergey Zigachev 152*b843c749SSergey Zigachev /* Set up Trusted Memory Region */ 153*b843c749SSergey Zigachev static int psp_tmr_init(struct psp_context *psp) 154*b843c749SSergey Zigachev { 155*b843c749SSergey Zigachev int ret; 156*b843c749SSergey Zigachev 157*b843c749SSergey Zigachev /* 158*b843c749SSergey Zigachev * Allocate 3M memory aligned to 1M from Frame Buffer (local 159*b843c749SSergey Zigachev * physical). 160*b843c749SSergey Zigachev * 161*b843c749SSergey Zigachev * Note: this memory need be reserved till the driver 162*b843c749SSergey Zigachev * uninitializes. 163*b843c749SSergey Zigachev */ 164*b843c749SSergey Zigachev ret = amdgpu_bo_create_kernel(psp->adev, 0x300000, 0x100000, 165*b843c749SSergey Zigachev AMDGPU_GEM_DOMAIN_VRAM, 166*b843c749SSergey Zigachev &psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf); 167*b843c749SSergey Zigachev 168*b843c749SSergey Zigachev return ret; 169*b843c749SSergey Zigachev } 170*b843c749SSergey Zigachev 171*b843c749SSergey Zigachev static int psp_tmr_load(struct psp_context *psp) 172*b843c749SSergey Zigachev { 173*b843c749SSergey Zigachev int ret; 174*b843c749SSergey Zigachev struct psp_gfx_cmd_resp *cmd; 175*b843c749SSergey Zigachev 176*b843c749SSergey Zigachev cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 177*b843c749SSergey Zigachev if (!cmd) 178*b843c749SSergey Zigachev return -ENOMEM; 179*b843c749SSergey Zigachev 180*b843c749SSergey Zigachev psp_prep_tmr_cmd_buf(cmd, psp->tmr_mc_addr, 0x300000); 181*b843c749SSergey Zigachev 182*b843c749SSergey Zigachev ret = psp_cmd_submit_buf(psp, NULL, cmd, 183*b843c749SSergey Zigachev psp->fence_buf_mc_addr, 1); 184*b843c749SSergey Zigachev if (ret) 185*b843c749SSergey Zigachev goto failed; 186*b843c749SSergey Zigachev 187*b843c749SSergey Zigachev kfree(cmd); 188*b843c749SSergey Zigachev 189*b843c749SSergey Zigachev return 0; 190*b843c749SSergey Zigachev 191*b843c749SSergey Zigachev failed: 192*b843c749SSergey Zigachev kfree(cmd); 193*b843c749SSergey Zigachev return ret; 194*b843c749SSergey Zigachev } 195*b843c749SSergey Zigachev 196*b843c749SSergey Zigachev static void psp_prep_asd_cmd_buf(struct psp_gfx_cmd_resp *cmd, 197*b843c749SSergey Zigachev uint64_t asd_mc, uint64_t asd_mc_shared, 198*b843c749SSergey Zigachev uint32_t size, uint32_t shared_size) 199*b843c749SSergey Zigachev { 200*b843c749SSergey Zigachev cmd->cmd_id = GFX_CMD_ID_LOAD_ASD; 201*b843c749SSergey Zigachev cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(asd_mc); 202*b843c749SSergey Zigachev cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(asd_mc); 203*b843c749SSergey Zigachev cmd->cmd.cmd_load_ta.app_len = size; 204*b843c749SSergey Zigachev 205*b843c749SSergey Zigachev cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(asd_mc_shared); 206*b843c749SSergey Zigachev cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(asd_mc_shared); 207*b843c749SSergey Zigachev cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size; 208*b843c749SSergey Zigachev } 209*b843c749SSergey Zigachev 210*b843c749SSergey Zigachev static int psp_asd_init(struct psp_context *psp) 211*b843c749SSergey Zigachev { 212*b843c749SSergey Zigachev int ret; 213*b843c749SSergey Zigachev 214*b843c749SSergey Zigachev /* 215*b843c749SSergey Zigachev * Allocate 16k memory aligned to 4k from Frame Buffer (local 216*b843c749SSergey Zigachev * physical) for shared ASD <-> Driver 217*b843c749SSergey Zigachev */ 218*b843c749SSergey Zigachev ret = amdgpu_bo_create_kernel(psp->adev, PSP_ASD_SHARED_MEM_SIZE, 219*b843c749SSergey Zigachev PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 220*b843c749SSergey Zigachev &psp->asd_shared_bo, 221*b843c749SSergey Zigachev &psp->asd_shared_mc_addr, 222*b843c749SSergey Zigachev &psp->asd_shared_buf); 223*b843c749SSergey Zigachev 224*b843c749SSergey Zigachev return ret; 225*b843c749SSergey Zigachev } 226*b843c749SSergey Zigachev 227*b843c749SSergey Zigachev static int psp_asd_load(struct psp_context *psp) 228*b843c749SSergey Zigachev { 229*b843c749SSergey Zigachev int ret; 230*b843c749SSergey Zigachev struct psp_gfx_cmd_resp *cmd; 231*b843c749SSergey Zigachev 232*b843c749SSergey Zigachev /* If PSP version doesn't match ASD version, asd loading will be failed. 233*b843c749SSergey Zigachev * add workaround to bypass it for sriov now. 234*b843c749SSergey Zigachev * TODO: add version check to make it common 235*b843c749SSergey Zigachev */ 236*b843c749SSergey Zigachev if (amdgpu_sriov_vf(psp->adev)) 237*b843c749SSergey Zigachev return 0; 238*b843c749SSergey Zigachev 239*b843c749SSergey Zigachev cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 240*b843c749SSergey Zigachev if (!cmd) 241*b843c749SSergey Zigachev return -ENOMEM; 242*b843c749SSergey Zigachev 243*b843c749SSergey Zigachev memset(psp->fw_pri_buf, 0, PSP_1_MEG); 244*b843c749SSergey Zigachev memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size); 245*b843c749SSergey Zigachev 246*b843c749SSergey Zigachev psp_prep_asd_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->asd_shared_mc_addr, 247*b843c749SSergey Zigachev psp->asd_ucode_size, PSP_ASD_SHARED_MEM_SIZE); 248*b843c749SSergey Zigachev 249*b843c749SSergey Zigachev ret = psp_cmd_submit_buf(psp, NULL, cmd, 250*b843c749SSergey Zigachev psp->fence_buf_mc_addr, 2); 251*b843c749SSergey Zigachev 252*b843c749SSergey Zigachev kfree(cmd); 253*b843c749SSergey Zigachev 254*b843c749SSergey Zigachev return ret; 255*b843c749SSergey Zigachev } 256*b843c749SSergey Zigachev 257*b843c749SSergey Zigachev static int psp_hw_start(struct psp_context *psp) 258*b843c749SSergey Zigachev { 259*b843c749SSergey Zigachev struct amdgpu_device *adev = psp->adev; 260*b843c749SSergey Zigachev int ret; 261*b843c749SSergey Zigachev 262*b843c749SSergey Zigachev if (!amdgpu_sriov_vf(adev) || !adev->in_gpu_reset) { 263*b843c749SSergey Zigachev ret = psp_bootloader_load_sysdrv(psp); 264*b843c749SSergey Zigachev if (ret) 265*b843c749SSergey Zigachev return ret; 266*b843c749SSergey Zigachev 267*b843c749SSergey Zigachev ret = psp_bootloader_load_sos(psp); 268*b843c749SSergey Zigachev if (ret) 269*b843c749SSergey Zigachev return ret; 270*b843c749SSergey Zigachev } 271*b843c749SSergey Zigachev 272*b843c749SSergey Zigachev ret = psp_ring_create(psp, PSP_RING_TYPE__KM); 273*b843c749SSergey Zigachev if (ret) 274*b843c749SSergey Zigachev return ret; 275*b843c749SSergey Zigachev 276*b843c749SSergey Zigachev ret = psp_tmr_load(psp); 277*b843c749SSergey Zigachev if (ret) 278*b843c749SSergey Zigachev return ret; 279*b843c749SSergey Zigachev 280*b843c749SSergey Zigachev ret = psp_asd_load(psp); 281*b843c749SSergey Zigachev if (ret) 282*b843c749SSergey Zigachev return ret; 283*b843c749SSergey Zigachev 284*b843c749SSergey Zigachev return 0; 285*b843c749SSergey Zigachev } 286*b843c749SSergey Zigachev 287*b843c749SSergey Zigachev static int psp_np_fw_load(struct psp_context *psp) 288*b843c749SSergey Zigachev { 289*b843c749SSergey Zigachev int i, ret; 290*b843c749SSergey Zigachev struct amdgpu_firmware_info *ucode; 291*b843c749SSergey Zigachev struct amdgpu_device* adev = psp->adev; 292*b843c749SSergey Zigachev 293*b843c749SSergey Zigachev for (i = 0; i < adev->firmware.max_ucodes; i++) { 294*b843c749SSergey Zigachev ucode = &adev->firmware.ucode[i]; 295*b843c749SSergey Zigachev if (!ucode->fw) 296*b843c749SSergey Zigachev continue; 297*b843c749SSergey Zigachev 298*b843c749SSergey Zigachev if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC && 299*b843c749SSergey Zigachev psp_smu_reload_quirk(psp)) 300*b843c749SSergey Zigachev continue; 301*b843c749SSergey Zigachev if (amdgpu_sriov_vf(adev) && 302*b843c749SSergey Zigachev (ucode->ucode_id == AMDGPU_UCODE_ID_SDMA0 303*b843c749SSergey Zigachev || ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 304*b843c749SSergey Zigachev || ucode->ucode_id == AMDGPU_UCODE_ID_RLC_G)) 305*b843c749SSergey Zigachev /*skip ucode loading in SRIOV VF */ 306*b843c749SSergey Zigachev continue; 307*b843c749SSergey Zigachev 308*b843c749SSergey Zigachev ret = psp_prep_cmd_buf(ucode, psp->cmd); 309*b843c749SSergey Zigachev if (ret) 310*b843c749SSergey Zigachev return ret; 311*b843c749SSergey Zigachev 312*b843c749SSergey Zigachev ret = psp_cmd_submit_buf(psp, ucode, psp->cmd, 313*b843c749SSergey Zigachev psp->fence_buf_mc_addr, i + 3); 314*b843c749SSergey Zigachev if (ret) 315*b843c749SSergey Zigachev return ret; 316*b843c749SSergey Zigachev 317*b843c749SSergey Zigachev #if 0 318*b843c749SSergey Zigachev /* check if firmware loaded sucessfully */ 319*b843c749SSergey Zigachev if (!amdgpu_psp_check_fw_loading_status(adev, i)) 320*b843c749SSergey Zigachev return -EINVAL; 321*b843c749SSergey Zigachev #endif 322*b843c749SSergey Zigachev } 323*b843c749SSergey Zigachev 324*b843c749SSergey Zigachev return 0; 325*b843c749SSergey Zigachev } 326*b843c749SSergey Zigachev 327*b843c749SSergey Zigachev static int psp_load_fw(struct amdgpu_device *adev) 328*b843c749SSergey Zigachev { 329*b843c749SSergey Zigachev int ret; 330*b843c749SSergey Zigachev struct psp_context *psp = &adev->psp; 331*b843c749SSergey Zigachev 332*b843c749SSergey Zigachev if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset != 0) 333*b843c749SSergey Zigachev goto skip_memalloc; 334*b843c749SSergey Zigachev 335*b843c749SSergey Zigachev psp->cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); 336*b843c749SSergey Zigachev if (!psp->cmd) 337*b843c749SSergey Zigachev return -ENOMEM; 338*b843c749SSergey Zigachev 339*b843c749SSergey Zigachev ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, 340*b843c749SSergey Zigachev AMDGPU_GEM_DOMAIN_GTT, 341*b843c749SSergey Zigachev &psp->fw_pri_bo, 342*b843c749SSergey Zigachev &psp->fw_pri_mc_addr, 343*b843c749SSergey Zigachev &psp->fw_pri_buf); 344*b843c749SSergey Zigachev if (ret) 345*b843c749SSergey Zigachev goto failed; 346*b843c749SSergey Zigachev 347*b843c749SSergey Zigachev ret = amdgpu_bo_create_kernel(adev, PSP_FENCE_BUFFER_SIZE, PAGE_SIZE, 348*b843c749SSergey Zigachev AMDGPU_GEM_DOMAIN_VRAM, 349*b843c749SSergey Zigachev &psp->fence_buf_bo, 350*b843c749SSergey Zigachev &psp->fence_buf_mc_addr, 351*b843c749SSergey Zigachev &psp->fence_buf); 352*b843c749SSergey Zigachev if (ret) 353*b843c749SSergey Zigachev goto failed_mem2; 354*b843c749SSergey Zigachev 355*b843c749SSergey Zigachev ret = amdgpu_bo_create_kernel(adev, PSP_CMD_BUFFER_SIZE, PAGE_SIZE, 356*b843c749SSergey Zigachev AMDGPU_GEM_DOMAIN_VRAM, 357*b843c749SSergey Zigachev &psp->cmd_buf_bo, &psp->cmd_buf_mc_addr, 358*b843c749SSergey Zigachev (void **)&psp->cmd_buf_mem); 359*b843c749SSergey Zigachev if (ret) 360*b843c749SSergey Zigachev goto failed_mem1; 361*b843c749SSergey Zigachev 362*b843c749SSergey Zigachev memset(psp->fence_buf, 0, PSP_FENCE_BUFFER_SIZE); 363*b843c749SSergey Zigachev 364*b843c749SSergey Zigachev ret = psp_ring_init(psp, PSP_RING_TYPE__KM); 365*b843c749SSergey Zigachev if (ret) 366*b843c749SSergey Zigachev goto failed_mem; 367*b843c749SSergey Zigachev 368*b843c749SSergey Zigachev ret = psp_tmr_init(psp); 369*b843c749SSergey Zigachev if (ret) 370*b843c749SSergey Zigachev goto failed_mem; 371*b843c749SSergey Zigachev 372*b843c749SSergey Zigachev ret = psp_asd_init(psp); 373*b843c749SSergey Zigachev if (ret) 374*b843c749SSergey Zigachev goto failed_mem; 375*b843c749SSergey Zigachev 376*b843c749SSergey Zigachev skip_memalloc: 377*b843c749SSergey Zigachev ret = psp_hw_start(psp); 378*b843c749SSergey Zigachev if (ret) 379*b843c749SSergey Zigachev goto failed_mem; 380*b843c749SSergey Zigachev 381*b843c749SSergey Zigachev ret = psp_np_fw_load(psp); 382*b843c749SSergey Zigachev if (ret) 383*b843c749SSergey Zigachev goto failed_mem; 384*b843c749SSergey Zigachev 385*b843c749SSergey Zigachev return 0; 386*b843c749SSergey Zigachev 387*b843c749SSergey Zigachev failed_mem: 388*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->cmd_buf_bo, 389*b843c749SSergey Zigachev &psp->cmd_buf_mc_addr, 390*b843c749SSergey Zigachev (void **)&psp->cmd_buf_mem); 391*b843c749SSergey Zigachev failed_mem1: 392*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->fence_buf_bo, 393*b843c749SSergey Zigachev &psp->fence_buf_mc_addr, &psp->fence_buf); 394*b843c749SSergey Zigachev failed_mem2: 395*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->fw_pri_bo, 396*b843c749SSergey Zigachev &psp->fw_pri_mc_addr, &psp->fw_pri_buf); 397*b843c749SSergey Zigachev failed: 398*b843c749SSergey Zigachev kfree(psp->cmd); 399*b843c749SSergey Zigachev psp->cmd = NULL; 400*b843c749SSergey Zigachev return ret; 401*b843c749SSergey Zigachev } 402*b843c749SSergey Zigachev 403*b843c749SSergey Zigachev static int psp_hw_init(void *handle) 404*b843c749SSergey Zigachev { 405*b843c749SSergey Zigachev int ret; 406*b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle; 407*b843c749SSergey Zigachev 408*b843c749SSergey Zigachev 409*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 410*b843c749SSergey Zigachev return 0; 411*b843c749SSergey Zigachev 412*b843c749SSergey Zigachev mutex_lock(&adev->firmware.mutex); 413*b843c749SSergey Zigachev /* 414*b843c749SSergey Zigachev * This sequence is just used on hw_init only once, no need on 415*b843c749SSergey Zigachev * resume. 416*b843c749SSergey Zigachev */ 417*b843c749SSergey Zigachev ret = amdgpu_ucode_init_bo(adev); 418*b843c749SSergey Zigachev if (ret) 419*b843c749SSergey Zigachev goto failed; 420*b843c749SSergey Zigachev 421*b843c749SSergey Zigachev ret = psp_load_fw(adev); 422*b843c749SSergey Zigachev if (ret) { 423*b843c749SSergey Zigachev DRM_ERROR("PSP firmware loading failed\n"); 424*b843c749SSergey Zigachev goto failed; 425*b843c749SSergey Zigachev } 426*b843c749SSergey Zigachev 427*b843c749SSergey Zigachev mutex_unlock(&adev->firmware.mutex); 428*b843c749SSergey Zigachev return 0; 429*b843c749SSergey Zigachev 430*b843c749SSergey Zigachev failed: 431*b843c749SSergey Zigachev adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT; 432*b843c749SSergey Zigachev mutex_unlock(&adev->firmware.mutex); 433*b843c749SSergey Zigachev return -EINVAL; 434*b843c749SSergey Zigachev } 435*b843c749SSergey Zigachev 436*b843c749SSergey Zigachev static int psp_hw_fini(void *handle) 437*b843c749SSergey Zigachev { 438*b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle; 439*b843c749SSergey Zigachev struct psp_context *psp = &adev->psp; 440*b843c749SSergey Zigachev 441*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 442*b843c749SSergey Zigachev return 0; 443*b843c749SSergey Zigachev 444*b843c749SSergey Zigachev amdgpu_ucode_fini_bo(adev); 445*b843c749SSergey Zigachev 446*b843c749SSergey Zigachev psp_ring_destroy(psp, PSP_RING_TYPE__KM); 447*b843c749SSergey Zigachev 448*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf); 449*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->fw_pri_bo, 450*b843c749SSergey Zigachev &psp->fw_pri_mc_addr, &psp->fw_pri_buf); 451*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->fence_buf_bo, 452*b843c749SSergey Zigachev &psp->fence_buf_mc_addr, &psp->fence_buf); 453*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->asd_shared_bo, &psp->asd_shared_mc_addr, 454*b843c749SSergey Zigachev &psp->asd_shared_buf); 455*b843c749SSergey Zigachev amdgpu_bo_free_kernel(&psp->cmd_buf_bo, &psp->cmd_buf_mc_addr, 456*b843c749SSergey Zigachev (void **)&psp->cmd_buf_mem); 457*b843c749SSergey Zigachev 458*b843c749SSergey Zigachev kfree(psp->cmd); 459*b843c749SSergey Zigachev psp->cmd = NULL; 460*b843c749SSergey Zigachev 461*b843c749SSergey Zigachev return 0; 462*b843c749SSergey Zigachev } 463*b843c749SSergey Zigachev 464*b843c749SSergey Zigachev static int psp_suspend(void *handle) 465*b843c749SSergey Zigachev { 466*b843c749SSergey Zigachev int ret; 467*b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle; 468*b843c749SSergey Zigachev struct psp_context *psp = &adev->psp; 469*b843c749SSergey Zigachev 470*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 471*b843c749SSergey Zigachev return 0; 472*b843c749SSergey Zigachev 473*b843c749SSergey Zigachev ret = psp_ring_stop(psp, PSP_RING_TYPE__KM); 474*b843c749SSergey Zigachev if (ret) { 475*b843c749SSergey Zigachev DRM_ERROR("PSP ring stop failed\n"); 476*b843c749SSergey Zigachev return ret; 477*b843c749SSergey Zigachev } 478*b843c749SSergey Zigachev 479*b843c749SSergey Zigachev return 0; 480*b843c749SSergey Zigachev } 481*b843c749SSergey Zigachev 482*b843c749SSergey Zigachev static int psp_resume(void *handle) 483*b843c749SSergey Zigachev { 484*b843c749SSergey Zigachev int ret; 485*b843c749SSergey Zigachev struct amdgpu_device *adev = (struct amdgpu_device *)handle; 486*b843c749SSergey Zigachev struct psp_context *psp = &adev->psp; 487*b843c749SSergey Zigachev 488*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 489*b843c749SSergey Zigachev return 0; 490*b843c749SSergey Zigachev 491*b843c749SSergey Zigachev DRM_INFO("PSP is resuming...\n"); 492*b843c749SSergey Zigachev 493*b843c749SSergey Zigachev mutex_lock(&adev->firmware.mutex); 494*b843c749SSergey Zigachev 495*b843c749SSergey Zigachev ret = psp_hw_start(psp); 496*b843c749SSergey Zigachev if (ret) 497*b843c749SSergey Zigachev goto failed; 498*b843c749SSergey Zigachev 499*b843c749SSergey Zigachev ret = psp_np_fw_load(psp); 500*b843c749SSergey Zigachev if (ret) 501*b843c749SSergey Zigachev goto failed; 502*b843c749SSergey Zigachev 503*b843c749SSergey Zigachev mutex_unlock(&adev->firmware.mutex); 504*b843c749SSergey Zigachev 505*b843c749SSergey Zigachev return 0; 506*b843c749SSergey Zigachev 507*b843c749SSergey Zigachev failed: 508*b843c749SSergey Zigachev DRM_ERROR("PSP resume failed\n"); 509*b843c749SSergey Zigachev mutex_unlock(&adev->firmware.mutex); 510*b843c749SSergey Zigachev return ret; 511*b843c749SSergey Zigachev } 512*b843c749SSergey Zigachev 513*b843c749SSergey Zigachev int psp_gpu_reset(struct amdgpu_device *adev) 514*b843c749SSergey Zigachev { 515*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 516*b843c749SSergey Zigachev return 0; 517*b843c749SSergey Zigachev 518*b843c749SSergey Zigachev return psp_mode1_reset(&adev->psp); 519*b843c749SSergey Zigachev } 520*b843c749SSergey Zigachev 521*b843c749SSergey Zigachev static bool psp_check_fw_loading_status(struct amdgpu_device *adev, 522*b843c749SSergey Zigachev enum AMDGPU_UCODE_ID ucode_type) 523*b843c749SSergey Zigachev { 524*b843c749SSergey Zigachev struct amdgpu_firmware_info *ucode = NULL; 525*b843c749SSergey Zigachev 526*b843c749SSergey Zigachev if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { 527*b843c749SSergey Zigachev DRM_INFO("firmware is not loaded by PSP\n"); 528*b843c749SSergey Zigachev return true; 529*b843c749SSergey Zigachev } 530*b843c749SSergey Zigachev 531*b843c749SSergey Zigachev if (!adev->firmware.fw_size) 532*b843c749SSergey Zigachev return false; 533*b843c749SSergey Zigachev 534*b843c749SSergey Zigachev ucode = &adev->firmware.ucode[ucode_type]; 535*b843c749SSergey Zigachev if (!ucode->fw || !ucode->ucode_size) 536*b843c749SSergey Zigachev return false; 537*b843c749SSergey Zigachev 538*b843c749SSergey Zigachev return psp_compare_sram_data(&adev->psp, ucode, ucode_type); 539*b843c749SSergey Zigachev } 540*b843c749SSergey Zigachev 541*b843c749SSergey Zigachev static int psp_set_clockgating_state(void *handle, 542*b843c749SSergey Zigachev enum amd_clockgating_state state) 543*b843c749SSergey Zigachev { 544*b843c749SSergey Zigachev return 0; 545*b843c749SSergey Zigachev } 546*b843c749SSergey Zigachev 547*b843c749SSergey Zigachev static int psp_set_powergating_state(void *handle, 548*b843c749SSergey Zigachev enum amd_powergating_state state) 549*b843c749SSergey Zigachev { 550*b843c749SSergey Zigachev return 0; 551*b843c749SSergey Zigachev } 552*b843c749SSergey Zigachev 553*b843c749SSergey Zigachev const struct amd_ip_funcs psp_ip_funcs = { 554*b843c749SSergey Zigachev .name = "psp", 555*b843c749SSergey Zigachev .early_init = psp_early_init, 556*b843c749SSergey Zigachev .late_init = NULL, 557*b843c749SSergey Zigachev .sw_init = psp_sw_init, 558*b843c749SSergey Zigachev .sw_fini = psp_sw_fini, 559*b843c749SSergey Zigachev .hw_init = psp_hw_init, 560*b843c749SSergey Zigachev .hw_fini = psp_hw_fini, 561*b843c749SSergey Zigachev .suspend = psp_suspend, 562*b843c749SSergey Zigachev .resume = psp_resume, 563*b843c749SSergey Zigachev .is_idle = NULL, 564*b843c749SSergey Zigachev .check_soft_reset = NULL, 565*b843c749SSergey Zigachev .wait_for_idle = NULL, 566*b843c749SSergey Zigachev .soft_reset = NULL, 567*b843c749SSergey Zigachev .set_clockgating_state = psp_set_clockgating_state, 568*b843c749SSergey Zigachev .set_powergating_state = psp_set_powergating_state, 569*b843c749SSergey Zigachev }; 570*b843c749SSergey Zigachev 571*b843c749SSergey Zigachev static const struct amdgpu_psp_funcs psp_funcs = { 572*b843c749SSergey Zigachev .check_fw_loading_status = psp_check_fw_loading_status, 573*b843c749SSergey Zigachev }; 574*b843c749SSergey Zigachev 575*b843c749SSergey Zigachev static void psp_set_funcs(struct amdgpu_device *adev) 576*b843c749SSergey Zigachev { 577*b843c749SSergey Zigachev if (NULL == adev->firmware.funcs) 578*b843c749SSergey Zigachev adev->firmware.funcs = &psp_funcs; 579*b843c749SSergey Zigachev } 580*b843c749SSergey Zigachev 581*b843c749SSergey Zigachev const struct amdgpu_ip_block_version psp_v3_1_ip_block = 582*b843c749SSergey Zigachev { 583*b843c749SSergey Zigachev .type = AMD_IP_BLOCK_TYPE_PSP, 584*b843c749SSergey Zigachev .major = 3, 585*b843c749SSergey Zigachev .minor = 1, 586*b843c749SSergey Zigachev .rev = 0, 587*b843c749SSergey Zigachev .funcs = &psp_ip_funcs, 588*b843c749SSergey Zigachev }; 589*b843c749SSergey Zigachev 590*b843c749SSergey Zigachev const struct amdgpu_ip_block_version psp_v10_0_ip_block = 591*b843c749SSergey Zigachev { 592*b843c749SSergey Zigachev .type = AMD_IP_BLOCK_TYPE_PSP, 593*b843c749SSergey Zigachev .major = 10, 594*b843c749SSergey Zigachev .minor = 0, 595*b843c749SSergey Zigachev .rev = 0, 596*b843c749SSergey Zigachev .funcs = &psp_ip_funcs, 597*b843c749SSergey Zigachev }; 598