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