2017-03-03 18:37:23 -05:00
/*
* Copyright 2016 Advanced Micro Devices , Inc .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*
* Author : Huang Rui
*
*/
# include <linux/firmware.h>
2017-04-24 13:50:21 +09:00
# include <drm/drmP.h>
2017-03-03 18:37:23 -05:00
# include "amdgpu.h"
# include "amdgpu_psp.h"
# include "amdgpu_ucode.h"
# include "soc15_common.h"
# include "psp_v3_1.h"
2016-12-16 10:08:48 +08:00
# include "psp_v10_0.h"
2018-05-11 14:54:50 +08:00
# include "psp_v11_0.h"
2017-03-03 18:37:23 -05:00
static void psp_set_funcs ( struct amdgpu_device * adev ) ;
static int psp_early_init ( void * handle )
{
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
psp_set_funcs ( adev ) ;
return 0 ;
}
static int psp_sw_init ( void * handle )
{
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
struct psp_context * psp = & adev - > psp ;
int ret ;
switch ( adev - > asic_type ) {
case CHIP_VEGA10 :
2018-03-06 22:18:09 -05:00
case CHIP_VEGA12 :
2018-01-23 16:17:24 -05:00
psp_v3_1_set_psp_funcs ( psp ) ;
2017-03-03 18:37:23 -05:00
break ;
2016-12-16 10:08:48 +08:00
case CHIP_RAVEN :
2018-01-23 16:17:24 -05:00
psp_v10_0_set_psp_funcs ( psp ) ;
2016-12-16 10:08:48 +08:00
break ;
2018-05-11 14:54:50 +08:00
case CHIP_VEGA20 :
psp_v11_0_set_psp_funcs ( psp ) ;
break ;
2017-03-03 18:37:23 -05:00
default :
return - EINVAL ;
}
psp - > adev = adev ;
ret = psp_init_microcode ( psp ) ;
if ( ret ) {
DRM_ERROR ( " Failed to load psp firmware! \n " ) ;
return ret ;
}
return 0 ;
}
static int psp_sw_fini ( void * handle )
{
2017-09-19 16:09:53 +08:00
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
release_firmware ( adev - > psp . sos_fw ) ;
adev - > psp . sos_fw = NULL ;
release_firmware ( adev - > psp . asd_fw ) ;
adev - > psp . asd_fw = NULL ;
2019-02-12 09:54:31 -05:00
if ( adev - > psp . ta_fw ) {
release_firmware ( adev - > psp . ta_fw ) ;
adev - > psp . ta_fw = NULL ;
}
2017-03-03 18:37:23 -05:00
return 0 ;
}
int psp_wait_for ( struct psp_context * psp , uint32_t reg_index ,
uint32_t reg_val , uint32_t mask , bool check_changed )
{
uint32_t val ;
int i ;
struct amdgpu_device * adev = psp - > adev ;
for ( i = 0 ; i < adev - > usec_timeout ; i + + ) {
2017-07-14 18:20:17 +08:00
val = RREG32 ( reg_index ) ;
2017-03-03 18:37:23 -05:00
if ( check_changed ) {
if ( val ! = reg_val )
return 0 ;
} else {
if ( ( val & mask ) = = reg_val )
return 0 ;
}
udelay ( 1 ) ;
}
return - ETIME ;
}
static int
psp_cmd_submit_buf ( struct psp_context * psp ,
struct amdgpu_firmware_info * ucode ,
2018-09-28 14:23:11 +08:00
struct psp_gfx_cmd_resp * cmd , uint64_t fence_mc_addr )
2017-03-03 18:37:23 -05:00
{
int ret ;
2018-09-28 14:23:11 +08:00
int index ;
2017-03-03 18:37:23 -05:00
2017-06-11 18:57:08 +08:00
memset ( psp - > cmd_buf_mem , 0 , PSP_CMD_BUFFER_SIZE ) ;
2017-03-03 18:37:23 -05:00
2017-06-11 18:57:08 +08:00
memcpy ( psp - > cmd_buf_mem , cmd , sizeof ( struct psp_gfx_cmd_resp ) ) ;
2017-03-03 18:37:23 -05:00
2018-09-28 14:23:11 +08:00
index = atomic_inc_return ( & psp - > fence_value ) ;
2017-06-11 18:57:08 +08:00
ret = psp_cmd_submit ( psp , ucode , psp - > cmd_buf_mc_addr ,
2017-03-03 18:37:23 -05:00
fence_mc_addr , index ) ;
2018-09-28 14:23:11 +08:00
if ( ret ) {
atomic_dec ( & psp - > fence_value ) ;
return ret ;
}
2017-03-03 18:37:23 -05:00
2018-09-28 14:23:11 +08:00
while ( * ( ( unsigned int * ) psp - > fence_buf ) ! = index )
2017-03-03 18:37:23 -05:00
msleep ( 1 ) ;
2019-01-14 16:08:32 +08:00
/* In some cases, psp response status is not 0 even there is no
* problem while the command is submitted . Some version of PSP FW
* doesn ' t write 0 to that field .
* So here we would like to only print a warning instead of an error
* during psp initialization to avoid breaking hw_init and it doesn ' t
* return - EINVAL .
*/
2018-12-13 15:34:12 +08:00
if ( psp - > cmd_buf_mem - > resp . status ) {
if ( ucode )
2019-01-14 16:08:32 +08:00
DRM_WARN ( " failed to load ucode id (%d) " ,
2018-12-13 15:34:12 +08:00
ucode - > ucode_id ) ;
2019-01-14 16:08:32 +08:00
DRM_WARN ( " psp command failed and response status is (%d) \n " ,
2018-12-13 15:34:12 +08:00
psp - > cmd_buf_mem - > resp . status ) ;
2018-08-05 12:45:35 +08:00
}
2018-12-13 15:21:49 +08:00
/* get xGMI session id from response buffer */
cmd - > resp . session_id = psp - > cmd_buf_mem - > resp . session_id ;
2018-08-10 00:31:39 +08:00
if ( ucode ) {
ucode - > tmr_mc_addr_lo = psp - > cmd_buf_mem - > resp . fw_addr_lo ;
ucode - > tmr_mc_addr_hi = psp - > cmd_buf_mem - > resp . fw_addr_hi ;
}
2017-03-03 18:37:23 -05:00
return ret ;
}
2018-12-05 11:23:43 +08:00
static void psp_prep_tmr_cmd_buf ( struct psp_context * psp ,
struct psp_gfx_cmd_resp * cmd ,
2017-03-03 18:37:23 -05:00
uint64_t tmr_mc , uint32_t size )
{
2018-12-05 11:23:43 +08:00
if ( psp_support_vmr_ring ( psp ) )
cmd - > cmd_id = GFX_CMD_ID_SETUP_VMR ;
else
cmd - > cmd_id = GFX_CMD_ID_SETUP_TMR ;
2017-06-22 18:26:33 -04:00
cmd - > cmd . cmd_setup_tmr . buf_phy_addr_lo = lower_32_bits ( tmr_mc ) ;
cmd - > cmd . cmd_setup_tmr . buf_phy_addr_hi = upper_32_bits ( tmr_mc ) ;
2017-03-03 18:37:23 -05:00
cmd - > cmd . cmd_setup_tmr . buf_size = size ;
}
/* Set up Trusted Memory Region */
static int psp_tmr_init ( struct psp_context * psp )
{
int ret ;
/*
* Allocate 3 M memory aligned to 1 M from Frame Buffer ( local
* physical ) .
*
* Note : this memory need be reserved till the driver
* uninitializes .
*/
2018-08-14 10:33:25 +08:00
ret = amdgpu_bo_create_kernel ( psp - > adev , PSP_TMR_SIZE , 0x100000 ,
2017-03-03 18:37:23 -05:00
AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > tmr_bo , & psp - > tmr_mc_addr , & psp - > tmr_buf ) ;
2017-03-21 16:18:11 +08:00
return ret ;
}
static int psp_tmr_load ( struct psp_context * psp )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
2017-03-03 18:37:23 -05:00
2018-12-05 11:23:43 +08:00
psp_prep_tmr_cmd_buf ( psp , cmd , psp - > tmr_mc_addr , PSP_TMR_SIZE ) ;
2018-08-14 10:33:25 +08:00
DRM_INFO ( " reserve 0x%x from 0x%llx for PSP TMR SIZE \n " ,
PSP_TMR_SIZE , psp - > tmr_mc_addr ) ;
2017-03-03 18:37:23 -05:00
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
2018-09-28 14:23:11 +08:00
psp - > fence_buf_mc_addr ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-03-21 16:18:11 +08:00
goto failed ;
2017-03-03 18:37:23 -05:00
kfree ( cmd ) ;
return 0 ;
failed :
kfree ( cmd ) ;
return ret ;
}
static void psp_prep_asd_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint64_t asd_mc , uint64_t asd_mc_shared ,
uint32_t size , uint32_t shared_size )
{
cmd - > cmd_id = GFX_CMD_ID_LOAD_ASD ;
cmd - > cmd . cmd_load_ta . app_phy_addr_lo = lower_32_bits ( asd_mc ) ;
cmd - > cmd . cmd_load_ta . app_phy_addr_hi = upper_32_bits ( asd_mc ) ;
cmd - > cmd . cmd_load_ta . app_len = size ;
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_lo = lower_32_bits ( asd_mc_shared ) ;
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_hi = upper_32_bits ( asd_mc_shared ) ;
cmd - > cmd . cmd_load_ta . cmd_buf_len = shared_size ;
}
2017-03-21 18:02:04 +08:00
static int psp_asd_init ( struct psp_context * psp )
2017-03-03 18:37:23 -05:00
{
int ret ;
/*
* Allocate 16 k memory aligned to 4 k from Frame Buffer ( local
* physical ) for shared ASD < - > Driver
*/
2017-03-21 18:02:04 +08:00
ret = amdgpu_bo_create_kernel ( psp - > adev , PSP_ASD_SHARED_MEM_SIZE ,
PAGE_SIZE , AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > asd_shared_bo ,
& psp - > asd_shared_mc_addr ,
& psp - > asd_shared_buf ) ;
2017-03-03 18:37:23 -05:00
2017-03-21 18:02:04 +08:00
return ret ;
}
2017-03-03 18:37:23 -05:00
static int psp_asd_load ( struct psp_context * psp )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
2017-05-04 11:05:13 +08:00
/* If PSP version doesn't match ASD version, asd loading will be failed.
* add workaround to bypass it for sriov now .
* TODO : add version check to make it common
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2017-03-03 18:37:23 -05:00
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
2017-03-22 10:16:05 +08:00
memset ( psp - > fw_pri_buf , 0 , PSP_1_MEG ) ;
memcpy ( psp - > fw_pri_buf , psp - > asd_start_addr , psp - > asd_ucode_size ) ;
2017-03-03 18:37:23 -05:00
2017-03-21 18:02:04 +08:00
psp_prep_asd_cmd_buf ( cmd , psp - > fw_pri_mc_addr , psp - > asd_shared_mc_addr ,
2017-03-03 18:37:23 -05:00
psp - > asd_ucode_size , PSP_ASD_SHARED_MEM_SIZE ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
2018-09-28 14:23:11 +08:00
psp - > fence_buf_mc_addr ) ;
2017-03-03 18:37:23 -05:00
kfree ( cmd ) ;
return ret ;
}
2018-10-12 09:43:23 +08:00
static void psp_prep_xgmi_ta_load_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint64_t xgmi_ta_mc , uint64_t xgmi_mc_shared ,
uint32_t xgmi_ta_size , uint32_t shared_size )
{
cmd - > cmd_id = GFX_CMD_ID_LOAD_TA ;
cmd - > cmd . cmd_load_ta . app_phy_addr_lo = lower_32_bits ( xgmi_ta_mc ) ;
cmd - > cmd . cmd_load_ta . app_phy_addr_hi = upper_32_bits ( xgmi_ta_mc ) ;
cmd - > cmd . cmd_load_ta . app_len = xgmi_ta_size ;
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_lo = lower_32_bits ( xgmi_mc_shared ) ;
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_hi = upper_32_bits ( xgmi_mc_shared ) ;
cmd - > cmd . cmd_load_ta . cmd_buf_len = shared_size ;
}
static int psp_xgmi_init_shared_buf ( struct psp_context * psp )
{
int ret ;
/*
* Allocate 16 k memory aligned to 4 k from Frame Buffer ( local
* physical ) for xgmi ta < - > Driver
*/
ret = amdgpu_bo_create_kernel ( psp - > adev , PSP_XGMI_SHARED_MEM_SIZE ,
PAGE_SIZE , AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > xgmi_context . xgmi_shared_bo ,
& psp - > xgmi_context . xgmi_shared_mc_addr ,
& psp - > xgmi_context . xgmi_shared_buf ) ;
return ret ;
}
static int psp_xgmi_load ( struct psp_context * psp )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
/*
* TODO : bypass the loading in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
memset ( psp - > fw_pri_buf , 0 , PSP_1_MEG ) ;
memcpy ( psp - > fw_pri_buf , psp - > ta_xgmi_start_addr , psp - > ta_xgmi_ucode_size ) ;
psp_prep_xgmi_ta_load_cmd_buf ( cmd , psp - > fw_pri_mc_addr ,
psp - > xgmi_context . xgmi_shared_mc_addr ,
psp - > ta_xgmi_ucode_size , PSP_XGMI_SHARED_MEM_SIZE ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
if ( ! ret ) {
psp - > xgmi_context . initialized = 1 ;
psp - > xgmi_context . session_id = cmd - > resp . session_id ;
}
kfree ( cmd ) ;
return ret ;
}
static void psp_prep_xgmi_ta_unload_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint32_t xgmi_session_id )
{
cmd - > cmd_id = GFX_CMD_ID_UNLOAD_TA ;
cmd - > cmd . cmd_unload_ta . session_id = xgmi_session_id ;
}
static int psp_xgmi_unload ( struct psp_context * psp )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
/*
* TODO : bypass the unloading in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
psp_prep_xgmi_ta_unload_cmd_buf ( cmd , psp - > xgmi_context . session_id ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
2018-09-28 15:01:57 +08:00
static void psp_prep_xgmi_ta_invoke_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint32_t ta_cmd_id ,
uint32_t xgmi_session_id )
{
cmd - > cmd_id = GFX_CMD_ID_INVOKE_CMD ;
cmd - > cmd . cmd_invoke_cmd . session_id = xgmi_session_id ;
cmd - > cmd . cmd_invoke_cmd . ta_cmd_id = ta_cmd_id ;
/* Note: cmd_invoke_cmd.buf is not used for now */
}
int psp_xgmi_invoke ( struct psp_context * psp , uint32_t ta_cmd_id )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
/*
* TODO : bypass the loading in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
psp_prep_xgmi_ta_invoke_cmd_buf ( cmd , ta_cmd_id ,
psp - > xgmi_context . session_id ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
2018-09-28 21:28:10 +08:00
static int psp_xgmi_terminate ( struct psp_context * psp )
{
int ret ;
if ( ! psp - > xgmi_context . initialized )
return 0 ;
ret = psp_xgmi_unload ( psp ) ;
if ( ret )
return ret ;
psp - > xgmi_context . initialized = 0 ;
/* free xgmi shared memory */
amdgpu_bo_free_kernel ( & psp - > xgmi_context . xgmi_shared_bo ,
& psp - > xgmi_context . xgmi_shared_mc_addr ,
& psp - > xgmi_context . xgmi_shared_buf ) ;
return 0 ;
}
static int psp_xgmi_initialize ( struct psp_context * psp )
{
struct ta_xgmi_shared_memory * xgmi_cmd ;
int ret ;
2019-02-12 09:54:31 -05:00
if ( ! psp - > adev - > psp . ta_fw )
return - ENOENT ;
2018-09-28 21:28:10 +08:00
if ( ! psp - > xgmi_context . initialized ) {
ret = psp_xgmi_init_shared_buf ( psp ) ;
if ( ret )
return ret ;
}
/* Load XGMI TA */
ret = psp_xgmi_load ( psp ) ;
if ( ret )
return ret ;
/* Initialize XGMI session */
xgmi_cmd = ( struct ta_xgmi_shared_memory * ) ( psp - > xgmi_context . xgmi_shared_buf ) ;
memset ( xgmi_cmd , 0 , sizeof ( struct ta_xgmi_shared_memory ) ) ;
xgmi_cmd - > cmd_id = TA_COMMAND_XGMI__INITIALIZE ;
ret = psp_xgmi_invoke ( psp , xgmi_cmd - > cmd_id ) ;
return ret ;
}
2017-03-21 18:36:57 +08:00
static int psp_hw_start ( struct psp_context * psp )
2017-03-03 18:37:23 -05:00
{
2017-09-15 18:42:12 +08:00
struct amdgpu_device * adev = psp - > adev ;
2017-03-03 18:37:23 -05:00
int ret ;
2017-10-17 15:11:12 +08:00
if ( ! amdgpu_sriov_vf ( adev ) | | ! adev - > in_gpu_reset ) {
2017-09-15 18:42:12 +08:00
ret = psp_bootloader_load_sysdrv ( psp ) ;
if ( ret )
return ret ;
2017-03-03 18:37:23 -05:00
2017-09-15 18:42:12 +08:00
ret = psp_bootloader_load_sos ( psp ) ;
if ( ret )
return ret ;
}
2017-03-03 18:37:23 -05:00
2017-03-21 18:36:57 +08:00
ret = psp_ring_create ( psp , PSP_RING_TYPE__KM ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-03-21 18:36:57 +08:00
return ret ;
2017-03-03 18:37:23 -05:00
2017-03-21 18:36:57 +08:00
ret = psp_tmr_load ( psp ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-03-21 18:36:57 +08:00
return ret ;
2017-03-03 18:37:23 -05:00
ret = psp_asd_load ( psp ) ;
if ( ret )
2017-03-21 18:36:57 +08:00
return ret ;
2018-09-28 21:28:10 +08:00
if ( adev - > gmc . xgmi . num_physical_nodes > 1 ) {
ret = psp_xgmi_initialize ( psp ) ;
/* Warning the XGMI seesion initialize failure
* Instead of stop driver initialization
*/
if ( ret )
dev_err ( psp - > adev - > dev ,
" XGMI: Failed to initialize XGMI session \n " ) ;
}
2017-03-21 18:36:57 +08:00
return 0 ;
}
2019-01-03 21:38:41 +08:00
static int psp_get_fw_type ( struct amdgpu_firmware_info * ucode ,
enum psp_gfx_fw_type * type )
{
switch ( ucode - > ucode_id ) {
case AMDGPU_UCODE_ID_SDMA0 :
* type = GFX_FW_TYPE_SDMA0 ;
break ;
case AMDGPU_UCODE_ID_SDMA1 :
* type = GFX_FW_TYPE_SDMA1 ;
break ;
case AMDGPU_UCODE_ID_CP_CE :
* type = GFX_FW_TYPE_CP_CE ;
break ;
case AMDGPU_UCODE_ID_CP_PFP :
* type = GFX_FW_TYPE_CP_PFP ;
break ;
case AMDGPU_UCODE_ID_CP_ME :
* type = GFX_FW_TYPE_CP_ME ;
break ;
case AMDGPU_UCODE_ID_CP_MEC1 :
* type = GFX_FW_TYPE_CP_MEC ;
break ;
case AMDGPU_UCODE_ID_CP_MEC1_JT :
* type = GFX_FW_TYPE_CP_MEC_ME1 ;
break ;
case AMDGPU_UCODE_ID_CP_MEC2 :
* type = GFX_FW_TYPE_CP_MEC ;
break ;
case AMDGPU_UCODE_ID_CP_MEC2_JT :
* type = GFX_FW_TYPE_CP_MEC_ME2 ;
break ;
case AMDGPU_UCODE_ID_RLC_G :
* type = GFX_FW_TYPE_RLC_G ;
break ;
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL :
* type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_CNTL ;
break ;
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM :
* type = GFX_FW_TYPE_RLC_RESTORE_LIST_GPM_MEM ;
break ;
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM :
* type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM ;
break ;
case AMDGPU_UCODE_ID_SMC :
* type = GFX_FW_TYPE_SMU ;
break ;
case AMDGPU_UCODE_ID_UVD :
* type = GFX_FW_TYPE_UVD ;
break ;
case AMDGPU_UCODE_ID_UVD1 :
* type = GFX_FW_TYPE_UVD1 ;
break ;
case AMDGPU_UCODE_ID_VCE :
* type = GFX_FW_TYPE_VCE ;
break ;
case AMDGPU_UCODE_ID_VCN :
* type = GFX_FW_TYPE_VCN ;
break ;
case AMDGPU_UCODE_ID_DMCU_ERAM :
* type = GFX_FW_TYPE_DMCU_ERAM ;
break ;
case AMDGPU_UCODE_ID_DMCU_INTV :
* type = GFX_FW_TYPE_DMCU_ISR ;
break ;
case AMDGPU_UCODE_ID_MAXIMUM :
default :
return - EINVAL ;
}
return 0 ;
}
static int psp_prep_load_ip_fw_cmd_buf ( struct amdgpu_firmware_info * ucode ,
struct psp_gfx_cmd_resp * cmd )
{
int ret ;
uint64_t fw_mem_mc_addr = ucode - > mc_addr ;
memset ( cmd , 0 , sizeof ( struct psp_gfx_cmd_resp ) ) ;
cmd - > cmd_id = GFX_CMD_ID_LOAD_IP_FW ;
cmd - > cmd . cmd_load_ip_fw . fw_phy_addr_lo = lower_32_bits ( fw_mem_mc_addr ) ;
cmd - > cmd . cmd_load_ip_fw . fw_phy_addr_hi = upper_32_bits ( fw_mem_mc_addr ) ;
cmd - > cmd . cmd_load_ip_fw . fw_size = ucode - > ucode_size ;
ret = psp_get_fw_type ( ucode , & cmd - > cmd . cmd_load_ip_fw . fw_type ) ;
if ( ret )
DRM_ERROR ( " Unknown firmware type \n " ) ;
return ret ;
}
2017-03-21 18:36:57 +08:00
static int psp_np_fw_load ( struct psp_context * psp )
{
int i , ret ;
2017-03-03 18:37:23 -05:00
struct amdgpu_firmware_info * ucode ;
2017-03-21 18:36:57 +08:00
struct amdgpu_device * adev = psp - > adev ;
2017-03-03 18:37:23 -05:00
for ( i = 0 ; i < adev - > firmware . max_ucodes ; i + + ) {
ucode = & adev - > firmware . ucode [ i ] ;
if ( ! ucode - > fw )
continue ;
if ( ucode - > ucode_id = = AMDGPU_UCODE_ID_SMC & &
psp_smu_reload_quirk ( psp ) )
continue ;
2017-04-20 11:45:09 +08:00
if ( amdgpu_sriov_vf ( adev ) & &
( ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA0
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA1
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_RLC_G ) )
/*skip ucode loading in SRIOV VF */
continue ;
2017-03-03 18:37:23 -05:00
2019-01-03 21:38:41 +08:00
ret = psp_prep_load_ip_fw_cmd_buf ( ucode , psp - > cmd ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-03-21 18:36:57 +08:00
return ret ;
2017-03-03 18:37:23 -05:00
2017-03-21 18:36:57 +08:00
ret = psp_cmd_submit_buf ( psp , ucode , psp - > cmd ,
2018-09-28 14:23:11 +08:00
psp - > fence_buf_mc_addr ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-03-21 18:36:57 +08:00
return ret ;
2017-03-03 18:37:23 -05:00
#if 0
/* check if firmware loaded sucessfully */
if ( ! amdgpu_psp_check_fw_loading_status ( adev , i ) )
return - EINVAL ;
# endif
}
2017-03-21 18:36:57 +08:00
return 0 ;
}
static int psp_load_fw ( struct amdgpu_device * adev )
{
int ret ;
2017-03-03 18:37:23 -05:00
struct psp_context * psp = & adev - > psp ;
2018-12-05 14:36:33 +08:00
if ( amdgpu_sriov_vf ( adev ) & & adev - > in_gpu_reset ) {
2018-12-18 15:42:08 +08:00
psp_ring_stop ( psp , PSP_RING_TYPE__KM ) ; /* should not destroy ring, only stop */
2017-09-19 15:40:56 +08:00
goto skip_memalloc ;
2018-12-05 14:36:33 +08:00
}
2017-09-19 15:40:56 +08:00
2017-06-29 14:21:49 +08:00
psp - > cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! psp - > cmd )
2017-03-03 18:37:23 -05:00
return - ENOMEM ;
2017-03-21 16:51:00 +08:00
ret = amdgpu_bo_create_kernel ( adev , PSP_1_MEG , PSP_1_MEG ,
2017-09-19 15:40:56 +08:00
AMDGPU_GEM_DOMAIN_GTT ,
& psp - > fw_pri_bo ,
& psp - > fw_pri_mc_addr ,
& psp - > fw_pri_buf ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
goto failed ;
ret = amdgpu_bo_create_kernel ( adev , PSP_FENCE_BUFFER_SIZE , PAGE_SIZE ,
2017-09-19 15:40:56 +08:00
AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > fence_buf_bo ,
& psp - > fence_buf_mc_addr ,
& psp - > fence_buf ) ;
2017-06-11 18:57:08 +08:00
if ( ret )
goto failed_mem2 ;
ret = amdgpu_bo_create_kernel ( adev , PSP_CMD_BUFFER_SIZE , PAGE_SIZE ,
AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > cmd_buf_bo , & psp - > cmd_buf_mc_addr ,
( void * * ) & psp - > cmd_buf_mem ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-03-21 16:51:00 +08:00
goto failed_mem1 ;
2017-03-03 18:37:23 -05:00
memset ( psp - > fence_buf , 0 , PSP_FENCE_BUFFER_SIZE ) ;
2017-03-21 18:36:57 +08:00
ret = psp_ring_init ( psp , PSP_RING_TYPE__KM ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-06-11 18:57:08 +08:00
goto failed_mem ;
2017-03-03 18:37:23 -05:00
2017-03-21 18:36:57 +08:00
ret = psp_tmr_init ( psp ) ;
2017-03-21 16:18:11 +08:00
if ( ret )
goto failed_mem ;
2017-03-21 18:02:04 +08:00
ret = psp_asd_init ( psp ) ;
if ( ret )
goto failed_mem ;
2017-09-19 15:40:56 +08:00
skip_memalloc :
2017-03-21 18:36:57 +08:00
ret = psp_hw_start ( psp ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
goto failed_mem ;
2017-03-21 18:36:57 +08:00
ret = psp_np_fw_load ( psp ) ;
if ( ret )
goto failed_mem ;
2017-03-03 18:37:23 -05:00
return 0 ;
failed_mem :
2017-06-11 18:57:08 +08:00
amdgpu_bo_free_kernel ( & psp - > cmd_buf_bo ,
& psp - > cmd_buf_mc_addr ,
( void * * ) & psp - > cmd_buf_mem ) ;
failed_mem1 :
2017-03-03 18:37:23 -05:00
amdgpu_bo_free_kernel ( & psp - > fence_buf_bo ,
& psp - > fence_buf_mc_addr , & psp - > fence_buf ) ;
2017-06-11 18:57:08 +08:00
failed_mem2 :
2017-03-21 16:51:00 +08:00
amdgpu_bo_free_kernel ( & psp - > fw_pri_bo ,
& psp - > fw_pri_mc_addr , & psp - > fw_pri_buf ) ;
2017-03-03 18:37:23 -05:00
failed :
2017-06-29 14:21:49 +08:00
kfree ( psp - > cmd ) ;
psp - > cmd = NULL ;
2017-03-03 18:37:23 -05:00
return ret ;
}
static int psp_hw_init ( void * handle )
{
int ret ;
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
mutex_lock ( & adev - > firmware . mutex ) ;
2017-10-18 17:19:42 +08:00
/*
* This sequence is just used on hw_init only once , no need on
* resume .
*/
ret = amdgpu_ucode_init_bo ( adev ) ;
if ( ret )
goto failed ;
2017-03-03 18:37:23 -05:00
ret = psp_load_fw ( adev ) ;
if ( ret ) {
DRM_ERROR ( " PSP firmware loading failed \n " ) ;
goto failed ;
}
mutex_unlock ( & adev - > firmware . mutex ) ;
return 0 ;
failed :
adev - > firmware . load_type = AMDGPU_FW_LOAD_DIRECT ;
mutex_unlock ( & adev - > firmware . mutex ) ;
return - EINVAL ;
}
static int psp_hw_fini ( void * handle )
{
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
struct psp_context * psp = & adev - > psp ;
2018-09-28 21:28:10 +08:00
if ( adev - > gmc . xgmi . num_physical_nodes > 1 & &
psp - > xgmi_context . initialized = = 1 )
psp_xgmi_terminate ( psp ) ;
2017-04-17 08:50:18 -04:00
psp_ring_destroy ( psp , PSP_RING_TYPE__KM ) ;
2017-03-03 18:37:23 -05:00
2017-06-02 10:42:28 +08:00
amdgpu_bo_free_kernel ( & psp - > tmr_bo , & psp - > tmr_mc_addr , & psp - > tmr_buf ) ;
amdgpu_bo_free_kernel ( & psp - > fw_pri_bo ,
& psp - > fw_pri_mc_addr , & psp - > fw_pri_buf ) ;
amdgpu_bo_free_kernel ( & psp - > fence_buf_bo ,
& psp - > fence_buf_mc_addr , & psp - > fence_buf ) ;
2017-06-11 18:28:00 +08:00
amdgpu_bo_free_kernel ( & psp - > asd_shared_bo , & psp - > asd_shared_mc_addr ,
& psp - > asd_shared_buf ) ;
2017-06-11 18:57:08 +08:00
amdgpu_bo_free_kernel ( & psp - > cmd_buf_bo , & psp - > cmd_buf_mc_addr ,
( void * * ) & psp - > cmd_buf_mem ) ;
2017-04-10 15:29:42 +08:00
2017-06-29 14:21:49 +08:00
kfree ( psp - > cmd ) ;
psp - > cmd = NULL ;
2017-03-03 18:37:23 -05:00
return 0 ;
}
static int psp_suspend ( void * handle )
{
2017-09-08 13:09:50 +08:00
int ret ;
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
struct psp_context * psp = & adev - > psp ;
2018-09-28 21:28:10 +08:00
if ( adev - > gmc . xgmi . num_physical_nodes > 1 & &
psp - > xgmi_context . initialized = = 1 ) {
ret = psp_xgmi_terminate ( psp ) ;
if ( ret ) {
DRM_ERROR ( " Failed to terminate xgmi ta \n " ) ;
return ret ;
}
}
2017-09-08 13:09:50 +08:00
ret = psp_ring_stop ( psp , PSP_RING_TYPE__KM ) ;
if ( ret ) {
DRM_ERROR ( " PSP ring stop failed \n " ) ;
return ret ;
}
2017-03-03 18:37:23 -05:00
return 0 ;
}
static int psp_resume ( void * handle )
{
int ret ;
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
2017-03-23 11:20:25 +08:00
struct psp_context * psp = & adev - > psp ;
2017-03-03 18:37:23 -05:00
2017-03-23 11:20:25 +08:00
DRM_INFO ( " PSP is resuming... \n " ) ;
2017-03-03 18:37:23 -05:00
mutex_lock ( & adev - > firmware . mutex ) ;
2017-03-23 11:20:25 +08:00
ret = psp_hw_start ( psp ) ;
2017-03-03 18:37:23 -05:00
if ( ret )
2017-03-23 11:20:25 +08:00
goto failed ;
ret = psp_np_fw_load ( psp ) ;
if ( ret )
goto failed ;
2017-03-03 18:37:23 -05:00
mutex_unlock ( & adev - > firmware . mutex ) ;
2017-03-23 11:20:25 +08:00
return 0 ;
failed :
DRM_ERROR ( " PSP resume failed \n " ) ;
mutex_unlock ( & adev - > firmware . mutex ) ;
2017-03-03 18:37:23 -05:00
return ret ;
}
2018-01-23 16:27:31 -05:00
int psp_gpu_reset ( struct amdgpu_device * adev )
2017-09-14 16:25:19 +08:00
{
2018-04-08 14:39:18 +08:00
if ( adev - > firmware . load_type ! = AMDGPU_FW_LOAD_PSP )
return 0 ;
2017-09-14 16:25:19 +08:00
return psp_mode1_reset ( & adev - > psp ) ;
}
2017-03-03 18:37:23 -05:00
static bool psp_check_fw_loading_status ( struct amdgpu_device * adev ,
enum AMDGPU_UCODE_ID ucode_type )
{
struct amdgpu_firmware_info * ucode = NULL ;
if ( ! adev - > firmware . fw_size )
return false ;
ucode = & adev - > firmware . ucode [ ucode_type ] ;
if ( ! ucode - > fw | | ! ucode - > ucode_size )
return false ;
return psp_compare_sram_data ( & adev - > psp , ucode , ucode_type ) ;
}
static int psp_set_clockgating_state ( void * handle ,
enum amd_clockgating_state state )
{
return 0 ;
}
static int psp_set_powergating_state ( void * handle ,
enum amd_powergating_state state )
{
return 0 ;
}
const struct amd_ip_funcs psp_ip_funcs = {
. name = " psp " ,
. early_init = psp_early_init ,
. late_init = NULL ,
. sw_init = psp_sw_init ,
. sw_fini = psp_sw_fini ,
. hw_init = psp_hw_init ,
. hw_fini = psp_hw_fini ,
. suspend = psp_suspend ,
. resume = psp_resume ,
. is_idle = NULL ,
2018-01-23 16:27:31 -05:00
. check_soft_reset = NULL ,
2017-03-03 18:37:23 -05:00
. wait_for_idle = NULL ,
2018-01-23 16:27:31 -05:00
. soft_reset = NULL ,
2017-03-03 18:37:23 -05:00
. set_clockgating_state = psp_set_clockgating_state ,
. set_powergating_state = psp_set_powergating_state ,
} ;
static const struct amdgpu_psp_funcs psp_funcs = {
. check_fw_loading_status = psp_check_fw_loading_status ,
} ;
static void psp_set_funcs ( struct amdgpu_device * adev )
{
if ( NULL = = adev - > firmware . funcs )
adev - > firmware . funcs = & psp_funcs ;
}
const struct amdgpu_ip_block_version psp_v3_1_ip_block =
{
. type = AMD_IP_BLOCK_TYPE_PSP ,
. major = 3 ,
. minor = 1 ,
. rev = 0 ,
. funcs = & psp_ip_funcs ,
} ;
2016-12-16 10:01:55 +08:00
const struct amdgpu_ip_block_version psp_v10_0_ip_block =
{
. type = AMD_IP_BLOCK_TYPE_PSP ,
. major = 10 ,
. minor = 0 ,
. rev = 0 ,
. funcs = & psp_ip_funcs ,
} ;
2018-05-11 14:54:50 +08:00
const struct amdgpu_ip_block_version psp_v11_0_ip_block =
{
. type = AMD_IP_BLOCK_TYPE_PSP ,
. major = 11 ,
. minor = 0 ,
. rev = 0 ,
. funcs = & psp_ip_funcs ,
} ;