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>
2019-12-19 14:58:18 -05:00
# include <linux/dma-mapping.h>
2019-06-10 00:07:56 +02:00
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"
2019-08-09 10:32:15 -05:00
# include "psp_v12_0.h"
2017-03-03 18:37:23 -05:00
2019-10-25 17:48:52 +08:00
# include "amdgpu_ras.h"
2019-12-19 14:58:18 -05:00
static int psp_sysfs_init ( struct amdgpu_device * adev ) ;
static void psp_sysfs_fini ( struct amdgpu_device * adev ) ;
2020-04-14 15:21:35 +08:00
static int psp_load_smu_fw ( struct psp_context * psp ) ;
2020-02-24 17:06:41 +08:00
/*
* Due to DF Cstate management centralized to PMFW , the firmware
* loading sequence will be updated as below :
* - Load KDB
* - Load SYS_DRV
* - Load tOS
* - Load PMFW
* - Setup TMR
* - Load other non - psp fw
* - Load ASD
* - Load XGMI / RAS / HDCP / DTM TA if any
*
* This new sequence is required for
* - Arcturus
* - Navi12 and onwards
*/
static void psp_check_pmfw_centralized_cstate_management ( struct psp_context * psp )
{
struct amdgpu_device * adev = psp - > adev ;
psp - > pmfw_centralized_cstate_management = false ;
if ( amdgpu_sriov_vf ( adev ) )
return ;
if ( adev - > flags & AMD_IS_APU )
return ;
if ( ( adev - > asic_type = = CHIP_ARCTURUS ) | |
( adev - > asic_type > = CHIP_NAVI12 ) )
psp - > pmfw_centralized_cstate_management = true ;
}
2017-03-03 18:37:23 -05:00
static int psp_early_init ( void * handle )
{
struct amdgpu_device * adev = ( struct amdgpu_device * ) handle ;
2019-05-08 21:45:06 -05:00
struct psp_context * psp = & adev - > psp ;
2017-03-03 18:37:23 -05:00
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 ) ;
2018-12-13 01:23:56 +08:00
psp - > autoload_supported = false ;
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 ) ;
2018-12-13 01:23:56 +08:00
psp - > autoload_supported = false ;
2016-12-16 10:08:48 +08:00
break ;
2018-05-11 14:54:50 +08:00
case CHIP_VEGA20 :
2019-08-01 18:05:50 +08:00
case CHIP_ARCTURUS :
2018-12-13 01:23:56 +08:00
psp_v11_0_set_psp_funcs ( psp ) ;
psp - > autoload_supported = false ;
break ;
2018-05-21 16:32:05 +08:00
case CHIP_NAVI10 :
2019-07-08 14:03:15 -05:00
case CHIP_NAVI14 :
2019-08-02 08:59:36 -05:00
case CHIP_NAVI12 :
2018-05-11 14:54:50 +08:00
psp_v11_0_set_psp_funcs ( psp ) ;
2018-12-13 01:23:56 +08:00
psp - > autoload_supported = true ;
2018-05-11 14:54:50 +08:00
break ;
2019-08-09 10:32:15 -05:00
case CHIP_RENOIR :
psp_v12_0_set_psp_funcs ( psp ) ;
break ;
2017-03-03 18:37:23 -05:00
default :
return - EINVAL ;
}
psp - > adev = adev ;
2020-02-24 17:06:41 +08:00
psp_check_pmfw_centralized_cstate_management ( psp ) ;
2019-05-08 21:45:06 -05:00
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 ;
2017-03-03 18:37:23 -05:00
ret = psp_init_microcode ( psp ) ;
if ( ret ) {
DRM_ERROR ( " Failed to load psp firmware! \n " ) ;
return ret ;
}
2019-09-30 14:07:00 +08:00
ret = psp_mem_training_init ( psp ) ;
if ( ret ) {
2019-10-18 09:15:08 +01:00
DRM_ERROR ( " Failed to initialize memory training! \n " ) ;
2019-09-30 14:07:00 +08:00
return ret ;
}
ret = psp_mem_training ( psp , PSP_MEM_TRAIN_COLD_BOOT ) ;
if ( ret ) {
DRM_ERROR ( " Failed to process memory training! \n " ) ;
return ret ;
}
2020-03-04 16:36:42 -05:00
if ( adev - > asic_type = = CHIP_NAVI10 ) {
ret = psp_sysfs_init ( adev ) ;
if ( ret ) {
return ret ;
}
}
2017-03-03 18:37:23 -05:00
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 ;
2019-09-30 14:07:00 +08:00
psp_mem_training_fini ( & adev - > psp ) ;
2017-09-19 16:09:53 +08:00
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 ;
}
2019-12-19 14:58:18 -05:00
if ( adev - > asic_type = = CHIP_NAVI10 )
psp_sysfs_fini ( adev ) ;
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 ;
2019-01-23 11:35:31 +08:00
int timeout = 2000 ;
2020-03-11 11:51:02 +08:00
bool ras_intr = false ;
2020-03-25 18:58:02 +08:00
bool skip_unsupport = false ;
2017-03-03 18:37:23 -05:00
2019-07-08 13:33:22 -05:00
mutex_lock ( & psp - > mutex ) ;
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 ) ;
2019-11-18 17:39:55 +08:00
ret = psp_ring_cmd_submit ( psp , psp - > cmd_buf_mc_addr , fence_mc_addr , index ) ;
2018-09-28 14:23:11 +08:00
if ( ret ) {
atomic_dec ( & psp - > fence_value ) ;
2019-07-08 13:33:22 -05:00
mutex_unlock ( & psp - > mutex ) ;
2018-09-28 14:23:11 +08:00
return ret ;
}
2017-03-03 18:37:23 -05:00
2019-09-17 15:17:41 -05:00
amdgpu_asic_invalidate_hdp ( psp - > adev , NULL ) ;
2019-01-23 11:35:31 +08:00
while ( * ( ( unsigned int * ) psp - > fence_buf ) ! = index ) {
if ( - - timeout = = 0 )
2019-03-15 10:26:49 +08:00
break ;
2019-10-25 17:48:52 +08:00
/*
* Shouldn ' t wait for timeout when err_event_athub occurs ,
* because gpu reset thread triggered and lock resource should
* be released for psp resume sequence .
*/
2020-03-11 11:51:02 +08:00
ras_intr = amdgpu_ras_intr_triggered ( ) ;
if ( ras_intr )
2019-10-25 17:48:52 +08:00
break ;
2017-03-03 18:37:23 -05:00
msleep ( 1 ) ;
2019-09-17 15:17:41 -05:00
amdgpu_asic_invalidate_hdp ( psp - > adev , NULL ) ;
2019-01-23 11:35:31 +08:00
}
2017-03-03 18:37:23 -05:00
2020-03-25 18:58:02 +08:00
/* We allow TEE_ERROR_NOT_SUPPORTED for VMR command in SRIOV */
skip_unsupport = ( psp - > cmd_buf_mem - > resp . status = = 0xffff000a ) & & amdgpu_sriov_vf ( psp - > adev ) ;
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 .
*/
2020-03-25 18:58:02 +08:00
if ( ! skip_unsupport & & ( psp - > cmd_buf_mem - > resp . status | | ! timeout ) & & ! ras_intr ) {
2018-12-13 15:34:12 +08:00
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-12-26 11:13:53 +08:00
DRM_WARN ( " psp command (0x%X) failed and response status is (0x%X) \n " ,
2019-09-23 20:41:04 +08:00
psp - > cmd_buf_mem - > cmd_id ,
2019-12-26 11:13:53 +08:00
psp - > cmd_buf_mem - > resp . status ) ;
2020-03-25 15:34:21 -04:00
if ( ! timeout ) {
2019-07-08 13:33:22 -05:00
mutex_unlock ( & psp - > mutex ) ;
2019-03-15 10:26:49 +08:00
return - EINVAL ;
2019-07-08 13:33:22 -05:00
}
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 ;
}
2019-07-08 13:33:22 -05:00
mutex_unlock ( & psp - > mutex ) ;
2018-08-10 00:31:39 +08:00
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 )
{
2020-04-20 16:01:11 +08:00
if ( amdgpu_sriov_vf ( psp - > adev ) )
2018-12-05 11:23:43 +08:00
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 ;
}
2018-10-24 15:25:38 +08:00
static void psp_prep_load_toc_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint64_t pri_buf_mc , uint32_t size )
{
cmd - > cmd_id = GFX_CMD_ID_LOAD_TOC ;
cmd - > cmd . cmd_load_toc . toc_phy_addr_lo = lower_32_bits ( pri_buf_mc ) ;
cmd - > cmd . cmd_load_toc . toc_phy_addr_hi = upper_32_bits ( pri_buf_mc ) ;
cmd - > cmd . cmd_load_toc . toc_size = size ;
}
/* Issue LOAD TOC cmd to PSP to part toc and calculate tmr size needed */
static int psp_load_toc ( struct psp_context * psp ,
uint32_t * tmr_size )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
/* Copy toc to psp firmware private buffer */
memset ( psp - > fw_pri_buf , 0 , PSP_1_MEG ) ;
memcpy ( psp - > fw_pri_buf , psp - > toc_start_addr , psp - > toc_bin_size ) ;
psp_prep_load_toc_cmd_buf ( cmd , psp - > fw_pri_mc_addr , psp - > toc_bin_size ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
if ( ! ret )
* tmr_size = psp - > cmd_buf_mem - > resp . tmr_size ;
kfree ( cmd ) ;
return ret ;
}
2017-03-03 18:37:23 -05:00
/* Set up Trusted Memory Region */
static int psp_tmr_init ( struct psp_context * psp )
{
int ret ;
2018-10-24 15:25:38 +08:00
int tmr_size ;
2019-08-28 10:03:40 +08:00
void * tmr_buf ;
void * * pptr ;
2017-03-03 18:37:23 -05:00
/*
2019-03-25 16:07:23 -04:00
* According to HW engineer , they prefer the TMR address be " naturally
* aligned " , e.g. the start address be an integer divide of TMR size.
2017-03-03 18:37:23 -05:00
*
* Note : this memory need be reserved till the driver
* uninitializes .
*/
2018-10-24 15:25:38 +08:00
tmr_size = PSP_TMR_SIZE ;
/* For ASICs support RLC autoload, psp will parse the toc
* and calculate the total size of TMR needed */
2019-09-12 13:18:41 +08:00
if ( ! amdgpu_sriov_vf ( psp - > adev ) & &
psp - > toc_start_addr & &
2018-10-24 15:25:38 +08:00
psp - > toc_bin_size & &
psp - > fw_pri_buf ) {
ret = psp_load_toc ( psp , & tmr_size ) ;
if ( ret ) {
DRM_ERROR ( " Failed to load toc \n " ) ;
return ret ;
}
}
2019-08-28 10:03:40 +08:00
pptr = amdgpu_sriov_vf ( psp - > adev ) ? & tmr_buf : NULL ;
2018-10-24 15:25:38 +08:00
ret = amdgpu_bo_create_kernel ( psp - > adev , tmr_size , PSP_TMR_SIZE ,
2017-03-03 18:37:23 -05:00
AMDGPU_GEM_DOMAIN_VRAM ,
2019-08-28 10:03:40 +08:00
& psp - > tmr_bo , & psp - > tmr_mc_addr , pptr ) ;
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-10-24 15:25:38 +08:00
psp_prep_tmr_cmd_buf ( psp , cmd , psp - > tmr_mc_addr ,
amdgpu_bo_size ( psp - > tmr_bo ) ) ;
DRM_INFO ( " reserve 0x%lx from 0x%llx for PSP TMR \n " ,
amdgpu_bo_size ( psp - > tmr_bo ) , 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
kfree ( cmd ) ;
return ret ;
}
2019-12-02 13:16:09 +08:00
static void psp_prep_asd_load_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint64_t asd_mc , uint32_t size )
2017-03-03 18:37:23 -05:00
{
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 ;
2019-12-02 13:16:09 +08:00
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_lo = 0 ;
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_hi = 0 ;
cmd - > cmd . cmd_load_ta . cmd_buf_len = 0 ;
2017-03-21 18:02:04 +08:00
}
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
2019-12-02 13:16:09 +08:00
psp_prep_asd_load_cmd_buf ( cmd , psp - > fw_pri_mc_addr ,
psp - > asd_ucode_size ) ;
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 ) ;
2019-12-02 13:16:09 +08:00
if ( ! ret ) {
psp - > asd_context . asd_initialized = true ;
psp - > asd_context . session_id = cmd - > resp . session_id ;
}
2017-03-03 18:37:23 -05:00
kfree ( cmd ) ;
return ret ;
}
2019-12-26 11:19:36 +08:00
static void psp_prep_ta_unload_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint32_t session_id )
2019-12-02 13:37:42 +08:00
{
cmd - > cmd_id = GFX_CMD_ID_UNLOAD_TA ;
2019-12-26 11:19:36 +08:00
cmd - > cmd . cmd_unload_ta . session_id = session_id ;
2019-12-02 13:37:42 +08:00
}
static int psp_asd_unload ( struct psp_context * psp )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
if ( ! psp - > asd_context . asd_initialized )
return 0 ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_unload_cmd_buf ( cmd , psp - > asd_context . session_id ) ;
2019-12-02 13:37:42 +08:00
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
if ( ! ret )
psp - > asd_context . asd_initialized = false ;
kfree ( cmd ) ;
return ret ;
}
2019-05-06 15:27:23 +08:00
static void psp_prep_reg_prog_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint32_t id , uint32_t value )
{
cmd - > cmd_id = GFX_CMD_ID_PROG_REG ;
cmd - > cmd . cmd_setup_reg_prog . reg_value = value ;
cmd - > cmd . cmd_setup_reg_prog . reg_id = id ;
}
int psp_reg_program ( struct psp_context * psp , enum psp_reg_prog_id reg ,
uint32_t value )
{
struct psp_gfx_cmd_resp * cmd = NULL ;
int ret = 0 ;
if ( reg > = PSP_REG_LAST )
return - EINVAL ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
psp_prep_reg_prog_cmd_buf ( cmd , reg , value ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd , psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
2019-12-26 11:19:36 +08:00
static void psp_prep_ta_load_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint64_t ta_bin_mc ,
uint32_t ta_bin_size ,
uint64_t ta_shared_mc ,
uint32_t ta_shared_size )
2018-10-12 09:43:23 +08:00
{
2019-12-26 11:19:36 +08:00
cmd - > cmd_id = GFX_CMD_ID_LOAD_TA ;
cmd - > cmd . cmd_load_ta . app_phy_addr_lo = lower_32_bits ( ta_bin_mc ) ;
cmd - > cmd . cmd_load_ta . app_phy_addr_hi = upper_32_bits ( ta_bin_mc ) ;
cmd - > cmd . cmd_load_ta . app_len = ta_bin_size ;
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_lo = lower_32_bits ( ta_shared_mc ) ;
cmd - > cmd . cmd_load_ta . cmd_buf_phy_addr_hi = upper_32_bits ( ta_shared_mc ) ;
cmd - > cmd . cmd_load_ta . cmd_buf_len = ta_shared_size ;
2018-10-12 09:43:23 +08:00
}
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 ;
}
2019-12-26 11:27:46 +08:00
static void psp_prep_ta_invoke_cmd_buf ( struct psp_gfx_cmd_resp * cmd ,
uint32_t ta_cmd_id ,
uint32_t session_id )
{
cmd - > cmd_id = GFX_CMD_ID_INVOKE_CMD ;
cmd - > cmd . cmd_invoke_cmd . session_id = session_id ;
cmd - > cmd . cmd_invoke_cmd . ta_cmd_id = ta_cmd_id ;
}
int psp_ta_invoke ( struct psp_context * psp ,
uint32_t ta_cmd_id ,
uint32_t session_id )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
psp_prep_ta_invoke_cmd_buf ( cmd , ta_cmd_id , session_id ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
2018-10-12 09:43:23 +08:00
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
*/
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 ) ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_load_cmd_buf ( cmd ,
psp - > fw_pri_mc_addr ,
psp - > ta_xgmi_ucode_size ,
psp - > xgmi_context . xgmi_shared_mc_addr ,
PSP_XGMI_SHARED_MEM_SIZE ) ;
2018-10-12 09:43:23 +08:00
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 int psp_xgmi_unload ( struct psp_context * psp )
{
int ret ;
struct psp_gfx_cmd_resp * cmd ;
2020-01-08 16:36:14 +08:00
struct amdgpu_device * adev = psp - > adev ;
/* XGMI TA unload currently is not supported on Arcturus */
if ( adev - > asic_type = = CHIP_ARCTURUS )
return 0 ;
2018-10-12 09:43:23 +08:00
/*
* TODO : bypass the unloading in sriov for now
*/
cmd = kzalloc ( sizeof ( struct psp_gfx_cmd_resp ) , GFP_KERNEL ) ;
if ( ! cmd )
return - ENOMEM ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_unload_cmd_buf ( cmd , psp - > xgmi_context . session_id ) ;
2018-10-12 09:43:23 +08:00
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
int psp_xgmi_invoke ( struct psp_context * psp , uint32_t ta_cmd_id )
{
2019-12-26 11:27:46 +08:00
return psp_ta_invoke ( psp , ta_cmd_id , psp - > xgmi_context . session_id ) ;
2018-09-28 15:01:57 +08:00
}
2019-12-23 16:51:42 +08:00
int psp_xgmi_terminate ( struct psp_context * psp )
2018-09-28 21:28:10 +08:00
{
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 ;
}
2019-12-23 16:51:42 +08:00
int psp_xgmi_initialize ( struct psp_context * psp )
2018-09-28 21:28:10 +08:00
{
struct ta_xgmi_shared_memory * xgmi_cmd ;
int ret ;
2019-11-11 12:26:36 +08:00
if ( ! psp - > adev - > psp . ta_fw | |
! psp - > adev - > psp . ta_xgmi_ucode_size | |
! psp - > adev - > psp . ta_xgmi_start_addr )
2019-02-12 09:54:31 -05:00
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 ;
}
2018-11-21 11:17:49 +08:00
// ras begin
static int psp_ras_init_shared_buf ( struct psp_context * psp )
{
int ret ;
/*
* Allocate 16 k memory aligned to 4 k from Frame Buffer ( local
* physical ) for ras ta < - > Driver
*/
ret = amdgpu_bo_create_kernel ( psp - > adev , PSP_RAS_SHARED_MEM_SIZE ,
PAGE_SIZE , AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > ras . ras_shared_bo ,
& psp - > ras . ras_shared_mc_addr ,
& psp - > ras . ras_shared_buf ) ;
return ret ;
}
static int psp_ras_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_ras_start_addr , psp - > ta_ras_ucode_size ) ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_load_cmd_buf ( cmd ,
psp - > fw_pri_mc_addr ,
psp - > ta_ras_ucode_size ,
psp - > ras . ras_shared_mc_addr ,
PSP_RAS_SHARED_MEM_SIZE ) ;
2018-11-21 11:17:49 +08:00
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
if ( ! ret ) {
2019-12-23 21:46:21 +08:00
psp - > ras . ras_initialized = true ;
2018-11-21 11:17:49 +08:00
psp - > ras . session_id = cmd - > resp . session_id ;
}
kfree ( cmd ) ;
return ret ;
}
static int psp_ras_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 ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_unload_cmd_buf ( cmd , psp - > ras . session_id ) ;
2018-11-21 11:17:49 +08:00
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
int psp_ras_invoke ( struct psp_context * psp , uint32_t ta_cmd_id )
{
2020-04-30 17:12:26 +08:00
struct ta_ras_shared_memory * ras_cmd ;
int ret ;
ras_cmd = ( struct ta_ras_shared_memory * ) psp - > ras . ras_shared_buf ;
2018-11-21 11:17:49 +08:00
/*
* TODO : bypass the loading in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2020-04-30 17:12:26 +08:00
ret = psp_ta_invoke ( psp , ta_cmd_id , psp - > ras . session_id ) ;
if ( ras_cmd - > if_version > RAS_TA_HOST_IF_VER )
{
DRM_WARN ( " RAS: Unsupported Interface " ) ;
return - EINVAL ;
}
if ( amdgpu_ras_intr_triggered ( ) )
return ret ;
if ( ! ret ) {
if ( ras_cmd - > ras_out_message . flags . err_inject_switch_disable_flag ) {
dev_warn ( psp - > adev - > dev , " ECC switch disabled \n " ) ;
ras_cmd - > ras_status = TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE ;
}
else if ( ras_cmd - > ras_out_message . flags . reg_access_failure_flag )
dev_warn ( psp - > adev - > dev ,
" RAS internal register access blocked \n " ) ;
}
return ret ;
2018-11-21 11:17:49 +08:00
}
int psp_ras_enable_features ( struct psp_context * psp ,
union ta_ras_cmd_input * info , bool enable )
{
struct ta_ras_shared_memory * ras_cmd ;
int ret ;
if ( ! psp - > ras . ras_initialized )
return - EINVAL ;
ras_cmd = ( struct ta_ras_shared_memory * ) psp - > ras . ras_shared_buf ;
memset ( ras_cmd , 0 , sizeof ( struct ta_ras_shared_memory ) ) ;
if ( enable )
ras_cmd - > cmd_id = TA_RAS_COMMAND__ENABLE_FEATURES ;
else
ras_cmd - > cmd_id = TA_RAS_COMMAND__DISABLE_FEATURES ;
ras_cmd - > ras_in_message = * info ;
ret = psp_ras_invoke ( psp , ras_cmd - > cmd_id ) ;
if ( ret )
return - EINVAL ;
return ras_cmd - > ras_status ;
}
static int psp_ras_terminate ( struct psp_context * psp )
{
int ret ;
2019-11-21 13:59:28 +08:00
/*
* TODO : bypass the terminate in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2018-11-21 11:17:49 +08:00
if ( ! psp - > ras . ras_initialized )
return 0 ;
ret = psp_ras_unload ( psp ) ;
if ( ret )
return ret ;
2019-12-23 21:46:21 +08:00
psp - > ras . ras_initialized = false ;
2018-11-21 11:17:49 +08:00
/* free ras shared memory */
amdgpu_bo_free_kernel ( & psp - > ras . ras_shared_bo ,
& psp - > ras . ras_shared_mc_addr ,
& psp - > ras . ras_shared_buf ) ;
return 0 ;
}
static int psp_ras_initialize ( struct psp_context * psp )
{
int ret ;
2019-11-21 13:59:28 +08:00
/*
* TODO : bypass the initialize in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2019-11-11 12:26:36 +08:00
if ( ! psp - > adev - > psp . ta_ras_ucode_size | |
! psp - > adev - > psp . ta_ras_start_addr ) {
2020-04-03 12:25:48 -04:00
dev_info ( psp - > adev - > dev , " RAS: optional ras ta ucode is not available \n " ) ;
2019-11-11 12:26:36 +08:00
return 0 ;
}
2018-11-21 11:17:49 +08:00
if ( ! psp - > ras . ras_initialized ) {
ret = psp_ras_init_shared_buf ( psp ) ;
if ( ret )
return ret ;
}
ret = psp_ras_load ( psp ) ;
if ( ret )
return ret ;
return 0 ;
}
// ras end
2019-06-19 14:37:29 -04:00
// HDCP start
static int psp_hdcp_init_shared_buf ( struct psp_context * psp )
{
int ret ;
/*
* Allocate 16 k memory aligned to 4 k from Frame Buffer ( local
* physical ) for hdcp ta < - > Driver
*/
ret = amdgpu_bo_create_kernel ( psp - > adev , PSP_HDCP_SHARED_MEM_SIZE ,
PAGE_SIZE , AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > hdcp_context . hdcp_shared_bo ,
& psp - > hdcp_context . hdcp_shared_mc_addr ,
& psp - > hdcp_context . hdcp_shared_buf ) ;
return ret ;
}
static int psp_hdcp_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_hdcp_start_addr ,
psp - > ta_hdcp_ucode_size ) ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_load_cmd_buf ( cmd ,
psp - > fw_pri_mc_addr ,
psp - > ta_hdcp_ucode_size ,
psp - > hdcp_context . hdcp_shared_mc_addr ,
PSP_HDCP_SHARED_MEM_SIZE ) ;
2019-06-19 14:37:29 -04:00
ret = psp_cmd_submit_buf ( psp , NULL , cmd , psp - > fence_buf_mc_addr ) ;
if ( ! ret ) {
2019-12-23 21:46:21 +08:00
psp - > hdcp_context . hdcp_initialized = true ;
2019-06-19 14:37:29 -04:00
psp - > hdcp_context . session_id = cmd - > resp . session_id ;
2020-03-30 17:44:00 -04:00
mutex_init ( & psp - > hdcp_context . mutex ) ;
2019-06-19 14:37:29 -04:00
}
kfree ( cmd ) ;
return ret ;
}
static int psp_hdcp_initialize ( struct psp_context * psp )
{
int ret ;
2019-11-21 13:59:28 +08:00
/*
* TODO : bypass the initialize in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2019-11-11 12:26:36 +08:00
if ( ! psp - > adev - > psp . ta_hdcp_ucode_size | |
! psp - > adev - > psp . ta_hdcp_start_addr ) {
2020-04-03 12:25:48 -04:00
dev_info ( psp - > adev - > dev , " HDCP: optional hdcp ta ucode is not available \n " ) ;
2019-11-11 12:26:36 +08:00
return 0 ;
}
2019-06-19 14:37:29 -04:00
if ( ! psp - > hdcp_context . hdcp_initialized ) {
ret = psp_hdcp_init_shared_buf ( psp ) ;
if ( ret )
return ret ;
}
ret = psp_hdcp_load ( psp ) ;
if ( ret )
return ret ;
return 0 ;
}
static int psp_hdcp_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 ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_unload_cmd_buf ( cmd , psp - > hdcp_context . session_id ) ;
2019-06-19 14:37:29 -04:00
ret = psp_cmd_submit_buf ( psp , NULL , cmd , psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
int psp_hdcp_invoke ( struct psp_context * psp , uint32_t ta_cmd_id )
{
/*
* TODO : bypass the loading in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2019-12-26 11:27:46 +08:00
return psp_ta_invoke ( psp , ta_cmd_id , psp - > hdcp_context . session_id ) ;
2019-06-19 14:37:29 -04:00
}
static int psp_hdcp_terminate ( struct psp_context * psp )
{
int ret ;
2019-11-21 13:59:28 +08:00
/*
* TODO : bypass the terminate in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2019-06-19 14:37:29 -04:00
if ( ! psp - > hdcp_context . hdcp_initialized )
return 0 ;
ret = psp_hdcp_unload ( psp ) ;
if ( ret )
return ret ;
2019-12-23 21:46:21 +08:00
psp - > hdcp_context . hdcp_initialized = false ;
2019-06-19 14:37:29 -04:00
/* free hdcp shared memory */
amdgpu_bo_free_kernel ( & psp - > hdcp_context . hdcp_shared_bo ,
& psp - > hdcp_context . hdcp_shared_mc_addr ,
& psp - > hdcp_context . hdcp_shared_buf ) ;
return 0 ;
}
// HDCP end
2019-06-19 14:40:58 -04:00
// DTM start
static int psp_dtm_init_shared_buf ( struct psp_context * psp )
{
int ret ;
/*
* Allocate 16 k memory aligned to 4 k from Frame Buffer ( local
* physical ) for dtm ta < - > Driver
*/
ret = amdgpu_bo_create_kernel ( psp - > adev , PSP_DTM_SHARED_MEM_SIZE ,
PAGE_SIZE , AMDGPU_GEM_DOMAIN_VRAM ,
& psp - > dtm_context . dtm_shared_bo ,
& psp - > dtm_context . dtm_shared_mc_addr ,
& psp - > dtm_context . dtm_shared_buf ) ;
return ret ;
}
static int psp_dtm_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_dtm_start_addr , psp - > ta_dtm_ucode_size ) ;
2019-12-26 11:19:36 +08:00
psp_prep_ta_load_cmd_buf ( cmd ,
psp - > fw_pri_mc_addr ,
psp - > ta_dtm_ucode_size ,
psp - > dtm_context . dtm_shared_mc_addr ,
PSP_DTM_SHARED_MEM_SIZE ) ;
2019-06-19 14:40:58 -04:00
ret = psp_cmd_submit_buf ( psp , NULL , cmd , psp - > fence_buf_mc_addr ) ;
if ( ! ret ) {
2019-12-23 21:46:21 +08:00
psp - > dtm_context . dtm_initialized = true ;
2019-06-19 14:40:58 -04:00
psp - > dtm_context . session_id = cmd - > resp . session_id ;
2020-03-30 17:44:00 -04:00
mutex_init ( & psp - > dtm_context . mutex ) ;
2019-06-19 14:40:58 -04:00
}
kfree ( cmd ) ;
return ret ;
}
static int psp_dtm_initialize ( struct psp_context * psp )
{
int ret ;
2019-11-21 13:59:28 +08:00
/*
* TODO : bypass the initialize in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2019-11-11 12:26:36 +08:00
if ( ! psp - > adev - > psp . ta_dtm_ucode_size | |
! psp - > adev - > psp . ta_dtm_start_addr ) {
2020-04-03 12:25:48 -04:00
dev_info ( psp - > adev - > dev , " DTM: optional dtm ta ucode is not available \n " ) ;
2019-11-11 12:26:36 +08:00
return 0 ;
}
2019-06-19 14:40:58 -04:00
if ( ! psp - > dtm_context . dtm_initialized ) {
ret = psp_dtm_init_shared_buf ( psp ) ;
if ( ret )
return ret ;
}
ret = psp_dtm_load ( psp ) ;
if ( ret )
return ret ;
return 0 ;
}
2020-02-07 10:41:20 -05:00
static int psp_dtm_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_ta_unload_cmd_buf ( cmd , psp - > dtm_context . session_id ) ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd , psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
2019-06-19 14:40:58 -04:00
int psp_dtm_invoke ( struct psp_context * psp , uint32_t ta_cmd_id )
{
/*
* TODO : bypass the loading in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2019-12-26 11:27:46 +08:00
return psp_ta_invoke ( psp , ta_cmd_id , psp - > dtm_context . session_id ) ;
2019-06-19 14:40:58 -04:00
}
static int psp_dtm_terminate ( struct psp_context * psp )
{
int ret ;
2019-11-21 13:59:28 +08:00
/*
* TODO : bypass the terminate in sriov for now
*/
if ( amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2019-06-19 14:40:58 -04:00
if ( ! psp - > dtm_context . dtm_initialized )
return 0 ;
2020-02-07 10:41:20 -05:00
ret = psp_dtm_unload ( psp ) ;
2019-06-19 14:40:58 -04:00
if ( ret )
return ret ;
2019-12-23 21:46:21 +08:00
psp - > dtm_context . dtm_initialized = false ;
2019-06-19 14:40:58 -04:00
/* free hdcp shared memory */
amdgpu_bo_free_kernel ( & psp - > dtm_context . dtm_shared_bo ,
& psp - > dtm_context . dtm_shared_mc_addr ,
& psp - > dtm_context . dtm_shared_buf ) ;
return 0 ;
}
// DTM end
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 ;
2020-02-21 14:54:29 +08:00
if ( ! amdgpu_sriov_vf ( adev ) ) {
2019-07-16 13:48:19 +08:00
if ( psp - > kdb_bin_size & &
2019-07-11 00:13:54 +08:00
( psp - > funcs - > bootloader_load_kdb ! = NULL ) ) {
ret = psp_bootloader_load_kdb ( psp ) ;
if ( ret ) {
DRM_ERROR ( " PSP load kdb failed! \n " ) ;
return ret ;
}
}
2017-09-15 18:42:12 +08:00
ret = psp_bootloader_load_sysdrv ( psp ) ;
2019-03-15 10:26:49 +08:00
if ( ret ) {
DRM_ERROR ( " PSP load sysdrv failed! \n " ) ;
2017-09-15 18:42:12 +08:00
return ret ;
2019-03-15 10:26:49 +08:00
}
2017-03-03 18:37:23 -05:00
2017-09-15 18:42:12 +08:00
ret = psp_bootloader_load_sos ( psp ) ;
2019-03-15 10:26:49 +08:00
if ( ret ) {
DRM_ERROR ( " PSP load sos failed! \n " ) ;
2017-09-15 18:42:12 +08:00
return ret ;
2019-03-15 10:26:49 +08:00
}
2017-09-15 18:42:12 +08:00
}
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 ) ;
2019-03-15 10:26:49 +08:00
if ( ret ) {
DRM_ERROR ( " PSP create ring failed! \n " ) ;
2017-03-21 18:36:57 +08:00
return ret ;
2019-03-15 10:26:49 +08:00
}
2017-03-03 18:37:23 -05:00
2018-11-12 16:33:08 +08:00
ret = psp_tmr_init ( psp ) ;
if ( ret ) {
DRM_ERROR ( " PSP tmr init failed! \n " ) ;
return ret ;
}
2020-02-24 17:06:41 +08:00
/*
2020-04-14 15:21:35 +08:00
* For ASICs with DF Cstate management centralized
2020-02-24 17:06:41 +08:00
* to PMFW , TMR setup should be performed after PMFW
* loaded and before other non - psp firmware loaded .
*/
2020-04-14 15:21:35 +08:00
if ( psp - > pmfw_centralized_cstate_management ) {
ret = psp_load_smu_fw ( psp ) ;
if ( ret )
2020-02-24 17:06:41 +08:00
return ret ;
2020-04-14 15:21:35 +08:00
}
ret = psp_tmr_load ( psp ) ;
if ( ret ) {
DRM_ERROR ( " PSP load tmr failed! \n " ) ;
return ret ;
2019-03-15 10:26:49 +08:00
}
2017-03-03 18:37:23 -05:00
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 ;
2019-08-01 17:59:55 +08:00
case AMDGPU_UCODE_ID_SDMA2 :
* type = GFX_FW_TYPE_SDMA2 ;
break ;
case AMDGPU_UCODE_ID_SDMA3 :
* type = GFX_FW_TYPE_SDMA3 ;
break ;
case AMDGPU_UCODE_ID_SDMA4 :
* type = GFX_FW_TYPE_SDMA4 ;
break ;
case AMDGPU_UCODE_ID_SDMA5 :
* type = GFX_FW_TYPE_SDMA5 ;
break ;
case AMDGPU_UCODE_ID_SDMA6 :
* type = GFX_FW_TYPE_SDMA6 ;
break ;
case AMDGPU_UCODE_ID_SDMA7 :
* type = GFX_FW_TYPE_SDMA7 ;
break ;
2019-01-03 21:38:41 +08:00
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 ;
2019-12-16 14:56:35 +08:00
case AMDGPU_UCODE_ID_VCN1 :
* type = GFX_FW_TYPE_VCN1 ;
break ;
2019-01-03 21:38:41 +08:00
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 ;
2019-05-14 11:53:57 +08:00
case AMDGPU_UCODE_ID_VCN0_RAM :
* type = GFX_FW_TYPE_VCN0_RAM ;
break ;
case AMDGPU_UCODE_ID_VCN1_RAM :
* type = GFX_FW_TYPE_VCN1_RAM ;
break ;
2019-10-22 13:24:00 -04:00
case AMDGPU_UCODE_ID_DMCUB :
* type = GFX_FW_TYPE_DMUB ;
break ;
2019-01-03 21:38:41 +08:00
case AMDGPU_UCODE_ID_MAXIMUM :
default :
return - EINVAL ;
}
return 0 ;
}
2019-08-15 17:44:22 +08:00
static void psp_print_fw_hdr ( struct psp_context * psp ,
struct amdgpu_firmware_info * ucode )
{
struct amdgpu_device * adev = psp - > adev ;
2019-09-05 16:50:22 +08:00
struct common_firmware_header * hdr ;
2019-08-15 17:44:22 +08:00
switch ( ucode - > ucode_id ) {
case AMDGPU_UCODE_ID_SDMA0 :
case AMDGPU_UCODE_ID_SDMA1 :
case AMDGPU_UCODE_ID_SDMA2 :
case AMDGPU_UCODE_ID_SDMA3 :
case AMDGPU_UCODE_ID_SDMA4 :
case AMDGPU_UCODE_ID_SDMA5 :
case AMDGPU_UCODE_ID_SDMA6 :
case AMDGPU_UCODE_ID_SDMA7 :
2019-09-05 16:50:22 +08:00
hdr = ( struct common_firmware_header * )
adev - > sdma . instance [ ucode - > ucode_id - AMDGPU_UCODE_ID_SDMA0 ] . fw - > data ;
amdgpu_ucode_print_sdma_hdr ( hdr ) ;
2019-08-15 17:44:22 +08:00
break ;
case AMDGPU_UCODE_ID_CP_CE :
2019-09-05 16:50:22 +08:00
hdr = ( struct common_firmware_header * ) adev - > gfx . ce_fw - > data ;
amdgpu_ucode_print_gfx_hdr ( hdr ) ;
2019-08-15 17:44:22 +08:00
break ;
case AMDGPU_UCODE_ID_CP_PFP :
2019-09-05 16:50:22 +08:00
hdr = ( struct common_firmware_header * ) adev - > gfx . pfp_fw - > data ;
amdgpu_ucode_print_gfx_hdr ( hdr ) ;
2019-08-15 17:44:22 +08:00
break ;
case AMDGPU_UCODE_ID_CP_ME :
2019-09-05 16:50:22 +08:00
hdr = ( struct common_firmware_header * ) adev - > gfx . me_fw - > data ;
amdgpu_ucode_print_gfx_hdr ( hdr ) ;
2019-08-15 17:44:22 +08:00
break ;
case AMDGPU_UCODE_ID_CP_MEC1 :
2019-09-05 16:50:22 +08:00
hdr = ( struct common_firmware_header * ) adev - > gfx . mec_fw - > data ;
amdgpu_ucode_print_gfx_hdr ( hdr ) ;
2019-08-15 17:44:22 +08:00
break ;
case AMDGPU_UCODE_ID_RLC_G :
2019-09-05 16:50:22 +08:00
hdr = ( struct common_firmware_header * ) adev - > gfx . rlc_fw - > data ;
amdgpu_ucode_print_rlc_hdr ( hdr ) ;
2019-08-15 17:44:22 +08:00
break ;
case AMDGPU_UCODE_ID_SMC :
2019-09-05 16:50:22 +08:00
hdr = ( struct common_firmware_header * ) adev - > pm . fw - > data ;
amdgpu_ucode_print_smc_hdr ( hdr ) ;
2019-08-15 17:44:22 +08:00
break ;
default :
break ;
}
}
2019-01-03 21:38:41 +08:00
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 ;
}
2019-02-14 19:08:22 +08:00
static int psp_execute_np_fw_load ( struct psp_context * psp ,
2020-04-14 15:21:35 +08:00
struct amdgpu_firmware_info * ucode )
2019-02-14 19:08:22 +08:00
{
int ret = 0 ;
ret = psp_prep_load_ip_fw_cmd_buf ( ucode , psp - > cmd ) ;
if ( ret )
return ret ;
ret = psp_cmd_submit_buf ( psp , ucode , psp - > cmd ,
psp - > fence_buf_mc_addr ) ;
return ret ;
}
2020-04-14 15:21:35 +08:00
static int psp_load_smu_fw ( struct psp_context * psp )
{
int ret ;
2020-04-14 15:22:29 +08:00
struct amdgpu_device * adev = psp - > adev ;
2020-04-14 15:21:35 +08:00
struct amdgpu_firmware_info * ucode =
2020-04-14 15:22:29 +08:00
& adev - > firmware . ucode [ AMDGPU_UCODE_ID_SMC ] ;
2020-04-14 15:21:35 +08:00
if ( ! ucode - > fw | | amdgpu_sriov_vf ( psp - > adev ) )
return 0 ;
2020-04-14 15:22:29 +08:00
if ( adev - > in_gpu_reset ) {
ret = amdgpu_dpm_set_mp1_state ( adev , PP_MP1_STATE_UNLOAD ) ;
if ( ret ) {
DRM_WARN ( " Failed to set MP1 state prepare for reload \n " ) ;
}
}
2020-04-14 15:21:35 +08:00
ret = psp_execute_np_fw_load ( psp , ucode ) ;
if ( ret )
DRM_ERROR ( " PSP load smu failed! \n " ) ;
return ret ;
}
static bool fw_load_skip_check ( struct psp_context * psp ,
struct amdgpu_firmware_info * ucode )
{
if ( ! ucode - > fw )
return true ;
if ( ucode - > ucode_id = = AMDGPU_UCODE_ID_SMC & &
( psp_smu_reload_quirk ( psp ) | |
psp - > autoload_supported | |
psp - > pmfw_centralized_cstate_management ) )
return true ;
if ( amdgpu_sriov_vf ( psp - > adev ) & &
( ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA0
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA1
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA2
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA3
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA4
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA5
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA6
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SDMA7
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_RLC_G
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM
| | ucode - > ucode_id = = AMDGPU_UCODE_ID_SMC ) )
/*skip ucode loading in SRIOV VF */
return true ;
if ( psp - > autoload_supported & &
( ucode - > ucode_id = = AMDGPU_UCODE_ID_CP_MEC1_JT | |
ucode - > ucode_id = = AMDGPU_UCODE_ID_CP_MEC2_JT ) )
/* skip mec JT when autoload is enabled */
return true ;
return false ;
}
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
2020-04-14 15:21:35 +08:00
if ( psp - > autoload_supported & &
! psp - > pmfw_centralized_cstate_management ) {
ret = psp_load_smu_fw ( psp ) ;
2019-02-14 19:08:22 +08:00
if ( ret )
return ret ;
}
2017-03-03 18:37:23 -05:00
for ( i = 0 ; i < adev - > firmware . max_ucodes ; i + + ) {
ucode = & adev - > firmware . ucode [ i ] ;
if ( ucode - > ucode_id = = AMDGPU_UCODE_ID_SMC & &
2020-04-14 15:21:35 +08:00
! fw_load_skip_check ( psp , ucode ) ) {
ret = psp_load_smu_fw ( psp ) ;
if ( ret )
return ret ;
2017-04-20 11:45:09 +08:00
continue ;
2020-04-14 15:21:35 +08:00
}
2019-08-01 17:59:55 +08:00
2020-04-14 15:21:35 +08:00
if ( fw_load_skip_check ( psp , ucode ) )
2018-12-13 01:29:53 +08:00
continue ;
2017-03-03 18:37:23 -05:00
2019-08-15 17:44:22 +08:00
psp_print_fw_hdr ( psp , ucode ) ;
2019-02-14 19:08:22 +08:00
ret = psp_execute_np_fw_load ( psp , ucode ) ;
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
2018-10-24 19:41:13 +08:00
/* Start rlc autoload after psp recieved all the gfx firmware */
2019-11-26 19:38:22 +08:00
if ( psp - > autoload_supported & & ucode - > ucode_id = = ( amdgpu_sriov_vf ( adev ) ?
2019-12-23 16:13:48 +08:00
AMDGPU_UCODE_ID_CP_MEC2 : AMDGPU_UCODE_ID_RLC_G ) ) {
2018-10-24 19:41:13 +08:00
ret = psp_rlc_autoload ( psp ) ;
if ( ret ) {
DRM_ERROR ( " Failed to start rlc autoload \n " ) ;
return ret ;
}
}
2017-03-03 18:37:23 -05:00
}
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 ;
2019-12-18 19:01:43 +08:00
ret = amdgpu_bo_create_kernel ( adev , PSP_1_MEG , PSP_1_MEG ,
AMDGPU_GEM_DOMAIN_GTT ,
& psp - > fw_pri_bo ,
& psp - > fw_pri_mc_addr ,
& psp - > fw_pri_buf ) ;
if ( ret )
goto failed ;
2017-03-03 18:37:23 -05:00
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 )
2019-03-15 16:25:15 +08:00
goto failed ;
2017-06-11 18:57:08 +08:00
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 )
2019-03-15 16:25:15 +08:00
goto failed ;
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 ) ;
2019-03-15 10:26:49 +08:00
if ( ret ) {
DRM_ERROR ( " PSP ring init failed! \n " ) ;
2019-03-15 16:25:15 +08:00
goto failed ;
2019-03-15 10:26:49 +08:00
}
2017-03-03 18:37:23 -05:00
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 )
2019-03-15 16:25:15 +08:00
goto failed ;
2017-03-03 18:37:23 -05:00
2017-03-21 18:36:57 +08:00
ret = psp_np_fw_load ( psp ) ;
if ( ret )
2019-03-15 16:25:15 +08:00
goto failed ;
2017-03-03 18:37:23 -05:00
2019-12-02 13:44:38 +08:00
ret = psp_asd_load ( psp ) ;
if ( ret ) {
DRM_ERROR ( " PSP load asd failed! \n " ) ;
return ret ;
}
if ( psp - > adev - > psp . ta_fw ) {
ret = psp_ras_initialize ( psp ) ;
if ( ret )
dev_err ( psp - > adev - > dev ,
" RAS: Failed to initialize RAS \n " ) ;
ret = psp_hdcp_initialize ( psp ) ;
if ( ret )
dev_err ( psp - > adev - > dev ,
" HDCP: Failed to initialize HDCP \n " ) ;
ret = psp_dtm_initialize ( psp ) ;
if ( ret )
dev_err ( psp - > adev - > dev ,
" DTM: Failed to initialize DTM \n " ) ;
}
2017-03-03 18:37:23 -05:00
return 0 ;
failed :
2019-03-15 16:25:15 +08:00
/*
* all cleanup jobs ( xgmi terminate , ras terminate ,
* ring destroy , cmd / fence / fw buffers destory ,
* psp - > cmd destory ) are delayed to psp_hw_fini
*/
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 ;
2019-08-28 10:03:40 +08:00
void * tmr_buf ;
void * * pptr ;
2017-03-03 18:37:23 -05:00
2019-06-19 14:37:29 -04:00
if ( psp - > adev - > psp . ta_fw ) {
2019-03-11 12:17:14 +08:00
psp_ras_terminate ( psp ) ;
2019-06-19 14:40:58 -04:00
psp_dtm_terminate ( psp ) ;
2019-06-19 14:37:29 -04:00
psp_hdcp_terminate ( psp ) ;
}
2018-11-21 11:17:49 +08:00
2019-12-02 13:37:42 +08:00
psp_asd_unload ( 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
2019-08-28 10:03:40 +08:00
pptr = amdgpu_sriov_vf ( psp - > adev ) ? & tmr_buf : NULL ;
amdgpu_bo_free_kernel ( & psp - > tmr_bo , & psp - > tmr_mc_addr , pptr ) ;
2017-06-02 10:42:28 +08:00
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: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 ;
}
}
2019-03-11 12:17:14 +08:00
if ( psp - > adev - > psp . ta_fw ) {
ret = psp_ras_terminate ( psp ) ;
if ( ret ) {
DRM_ERROR ( " Failed to terminate ras ta \n " ) ;
return ret ;
}
2019-06-19 14:37:29 -04:00
ret = psp_hdcp_terminate ( psp ) ;
if ( ret ) {
DRM_ERROR ( " Failed to terminate hdcp ta \n " ) ;
return ret ;
}
2019-06-19 14:40:58 -04:00
ret = psp_dtm_terminate ( psp ) ;
if ( ret ) {
DRM_ERROR ( " Failed to terminate dtm ta \n " ) ;
return ret ;
}
2018-11-21 11:17:49 +08:00
}
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 " ) ;
2019-09-30 14:07:00 +08:00
ret = psp_mem_training ( psp , PSP_MEM_TRAIN_RESUME ) ;
if ( ret ) {
DRM_ERROR ( " Failed to process memory training! \n " ) ;
return ret ;
}
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
2019-12-06 18:09:19 +08:00
ret = psp_asd_load ( psp ) ;
if ( ret ) {
DRM_ERROR ( " PSP load asd failed! \n " ) ;
goto failed ;
}
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 " ) ;
}
if ( psp - > adev - > psp . ta_fw ) {
ret = psp_ras_initialize ( psp ) ;
if ( ret )
dev_err ( psp - > adev - > dev ,
" RAS: Failed to initialize RAS \n " ) ;
ret = psp_hdcp_initialize ( psp ) ;
if ( ret )
dev_err ( psp - > adev - > dev ,
" HDCP: Failed to initialize HDCP \n " ) ;
ret = psp_dtm_initialize ( psp ) ;
if ( ret )
dev_err ( psp - > adev - > dev ,
" DTM: Failed to initialize DTM \n " ) ;
}
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
{
2019-07-08 13:33:22 -05:00
int ret ;
2018-04-08 14:39:18 +08:00
if ( adev - > firmware . load_type ! = AMDGPU_FW_LOAD_PSP )
return 0 ;
2019-07-08 13:33:22 -05:00
mutex_lock ( & adev - > psp . mutex ) ;
ret = psp_mode1_reset ( & adev - > psp ) ;
mutex_unlock ( & adev - > psp . mutex ) ;
return ret ;
2017-09-14 16:25:19 +08:00
}
2018-10-24 19:41:13 +08:00
int psp_rlc_autoload_start ( 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 ;
cmd - > cmd_id = GFX_CMD_ID_AUTOLOAD_RLC ;
ret = psp_cmd_submit_buf ( psp , NULL , cmd ,
psp - > fence_buf_mc_addr ) ;
kfree ( cmd ) ;
return ret ;
}
2019-05-14 11:31:04 +08:00
int psp_update_vcn_sram ( struct amdgpu_device * adev , int inst_idx ,
uint64_t cmd_gpu_addr , int cmd_size )
{
struct amdgpu_firmware_info ucode = { 0 } ;
ucode . ucode_id = inst_idx ? AMDGPU_UCODE_ID_VCN1_RAM :
AMDGPU_UCODE_ID_VCN0_RAM ;
ucode . mc_addr = cmd_gpu_addr ;
ucode . ucode_size = cmd_size ;
return psp_execute_np_fw_load ( & adev - > psp , & ucode ) ;
}
2019-11-18 17:03:12 +08:00
int psp_ring_cmd_submit ( struct psp_context * psp ,
uint64_t cmd_buf_mc_addr ,
uint64_t fence_mc_addr ,
int index )
{
unsigned int psp_write_ptr_reg = 0 ;
2019-11-21 16:54:01 +00:00
struct psp_gfx_rb_frame * write_frame ;
2019-11-18 17:03:12 +08:00
struct psp_ring * ring = & psp - > km_ring ;
struct psp_gfx_rb_frame * ring_buffer_start = ring - > ring_mem ;
struct psp_gfx_rb_frame * ring_buffer_end = ring_buffer_start +
ring - > ring_size / sizeof ( struct psp_gfx_rb_frame ) - 1 ;
struct amdgpu_device * adev = psp - > adev ;
uint32_t ring_size_dw = ring - > ring_size / 4 ;
uint32_t rb_frame_size_dw = sizeof ( struct psp_gfx_rb_frame ) / 4 ;
/* KM (GPCOM) prepare write pointer */
psp_write_ptr_reg = psp_ring_get_wptr ( psp ) ;
/* Update KM RB frame pointer to new frame */
/* write_frame ptr increments by size of rb_frame in bytes */
/* psp_write_ptr_reg increments by size of rb_frame in DWORDs */
if ( ( psp_write_ptr_reg % ring_size_dw ) = = 0 )
write_frame = ring_buffer_start ;
else
write_frame = ring_buffer_start + ( psp_write_ptr_reg / rb_frame_size_dw ) ;
/* Check invalid write_frame ptr address */
if ( ( write_frame < ring_buffer_start ) | | ( ring_buffer_end < write_frame ) ) {
DRM_ERROR ( " ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p \n " ,
ring_buffer_start , ring_buffer_end , write_frame ) ;
DRM_ERROR ( " write_frame is pointing to address out of bounds \n " ) ;
return - EINVAL ;
}
/* Initialize KM RB frame */
memset ( write_frame , 0 , sizeof ( struct psp_gfx_rb_frame ) ) ;
/* Update KM RB frame */
write_frame - > cmd_buf_addr_hi = upper_32_bits ( cmd_buf_mc_addr ) ;
write_frame - > cmd_buf_addr_lo = lower_32_bits ( cmd_buf_mc_addr ) ;
write_frame - > fence_addr_hi = upper_32_bits ( fence_mc_addr ) ;
write_frame - > fence_addr_lo = lower_32_bits ( fence_mc_addr ) ;
write_frame - > fence_value = index ;
amdgpu_asic_flush_hdp ( adev , NULL ) ;
/* Update the write Pointer in DWORDs */
psp_write_ptr_reg = ( psp_write_ptr_reg + rb_frame_size_dw ) % ring_size_dw ;
psp_ring_set_wptr ( psp , psp_write_ptr_reg ) ;
return 0 ;
}
2020-04-20 17:15:07 +08:00
int psp_init_asd_microcode ( struct psp_context * psp ,
const char * chip_name )
{
struct amdgpu_device * adev = psp - > adev ;
char fw_name [ 30 ] ;
const struct psp_firmware_header_v1_0 * asd_hdr ;
int err = 0 ;
if ( ! chip_name ) {
dev_err ( adev - > dev , " invalid chip name for asd microcode \n " ) ;
return - EINVAL ;
}
snprintf ( fw_name , sizeof ( fw_name ) , " amdgpu/%s_asd.bin " , chip_name ) ;
err = request_firmware ( & adev - > psp . asd_fw , fw_name , adev - > dev ) ;
if ( err )
goto out ;
err = amdgpu_ucode_validate ( adev - > psp . asd_fw ) ;
if ( err )
goto out ;
asd_hdr = ( const struct psp_firmware_header_v1_0 * ) adev - > psp . asd_fw - > data ;
adev - > psp . asd_fw_version = le32_to_cpu ( asd_hdr - > header . ucode_version ) ;
adev - > psp . asd_feature_version = le32_to_cpu ( asd_hdr - > ucode_feature_version ) ;
adev - > psp . asd_ucode_size = le32_to_cpu ( asd_hdr - > header . ucode_size_bytes ) ;
adev - > psp . asd_start_addr = ( uint8_t * ) asd_hdr +
le32_to_cpu ( asd_hdr - > header . ucode_array_offset_bytes ) ;
return 0 ;
out :
dev_err ( adev - > dev , " fail to initialize asd microcode \n " ) ;
release_firmware ( adev - > psp . asd_fw ) ;
adev - > psp . asd_fw = NULL ;
return err ;
}
2020-04-20 17:47:53 +08:00
int psp_init_sos_microcode ( struct psp_context * psp ,
const char * chip_name )
{
struct amdgpu_device * adev = psp - > adev ;
char fw_name [ 30 ] ;
const struct psp_firmware_header_v1_0 * sos_hdr ;
const struct psp_firmware_header_v1_1 * sos_hdr_v1_1 ;
const struct psp_firmware_header_v1_2 * sos_hdr_v1_2 ;
int err = 0 ;
if ( ! chip_name ) {
dev_err ( adev - > dev , " invalid chip name for sos microcode \n " ) ;
return - EINVAL ;
}
snprintf ( fw_name , sizeof ( fw_name ) , " amdgpu/%s_sos.bin " , chip_name ) ;
err = request_firmware ( & adev - > psp . sos_fw , fw_name , adev - > dev ) ;
if ( err )
goto out ;
err = amdgpu_ucode_validate ( adev - > psp . sos_fw ) ;
if ( err )
goto out ;
sos_hdr = ( const struct psp_firmware_header_v1_0 * ) adev - > psp . sos_fw - > data ;
amdgpu_ucode_print_psp_hdr ( & sos_hdr - > header ) ;
switch ( sos_hdr - > header . header_version_major ) {
case 1 :
adev - > psp . sos_fw_version = le32_to_cpu ( sos_hdr - > header . ucode_version ) ;
adev - > psp . sos_feature_version = le32_to_cpu ( sos_hdr - > ucode_feature_version ) ;
adev - > psp . sos_bin_size = le32_to_cpu ( sos_hdr - > sos_size_bytes ) ;
adev - > psp . sys_bin_size = le32_to_cpu ( sos_hdr - > sos_offset_bytes ) ;
adev - > psp . sys_start_addr = ( uint8_t * ) sos_hdr +
le32_to_cpu ( sos_hdr - > header . ucode_array_offset_bytes ) ;
adev - > psp . sos_start_addr = ( uint8_t * ) adev - > psp . sys_start_addr +
le32_to_cpu ( sos_hdr - > sos_offset_bytes ) ;
if ( sos_hdr - > header . header_version_minor = = 1 ) {
sos_hdr_v1_1 = ( const struct psp_firmware_header_v1_1 * ) adev - > psp . sos_fw - > data ;
adev - > psp . toc_bin_size = le32_to_cpu ( sos_hdr_v1_1 - > toc_size_bytes ) ;
adev - > psp . toc_start_addr = ( uint8_t * ) adev - > psp . sys_start_addr +
le32_to_cpu ( sos_hdr_v1_1 - > toc_offset_bytes ) ;
adev - > psp . kdb_bin_size = le32_to_cpu ( sos_hdr_v1_1 - > kdb_size_bytes ) ;
adev - > psp . kdb_start_addr = ( uint8_t * ) adev - > psp . sys_start_addr +
le32_to_cpu ( sos_hdr_v1_1 - > kdb_offset_bytes ) ;
}
if ( sos_hdr - > header . header_version_minor = = 2 ) {
sos_hdr_v1_2 = ( const struct psp_firmware_header_v1_2 * ) adev - > psp . sos_fw - > data ;
adev - > psp . kdb_bin_size = le32_to_cpu ( sos_hdr_v1_2 - > kdb_size_bytes ) ;
adev - > psp . kdb_start_addr = ( uint8_t * ) adev - > psp . sys_start_addr +
le32_to_cpu ( sos_hdr_v1_2 - > kdb_offset_bytes ) ;
}
break ;
default :
dev_err ( adev - > dev ,
" unsupported psp sos firmware \n " ) ;
err = - EINVAL ;
goto out ;
}
return 0 ;
out :
dev_err ( adev - > dev ,
" failed to init sos firmware \n " ) ;
release_firmware ( adev - > psp . sos_fw ) ;
adev - > psp . sos_fw = NULL ;
return err ;
}
2017-03-03 18:37:23 -05:00
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 ;
}
2019-12-19 14:58:18 -05:00
static ssize_t psp_usbc_pd_fw_sysfs_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct drm_device * ddev = dev_get_drvdata ( dev ) ;
struct amdgpu_device * adev = ddev - > dev_private ;
uint32_t fw_ver ;
int ret ;
2020-03-04 16:36:42 -05:00
if ( ! adev - > ip_blocks [ AMD_IP_BLOCK_TYPE_PSP ] . status . late_initialized ) {
DRM_INFO ( " PSP block is not ready yet. " ) ;
return - EBUSY ;
}
2019-12-19 14:58:18 -05:00
mutex_lock ( & adev - > psp . mutex ) ;
ret = psp_read_usbc_pd_fw ( & adev - > psp , & fw_ver ) ;
mutex_unlock ( & adev - > psp . mutex ) ;
if ( ret ) {
DRM_ERROR ( " Failed to read USBC PD FW, err = %d " , ret ) ;
return ret ;
}
return snprintf ( buf , PAGE_SIZE , " %x \n " , fw_ver ) ;
}
static ssize_t psp_usbc_pd_fw_sysfs_write ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t count )
{
struct drm_device * ddev = dev_get_drvdata ( dev ) ;
struct amdgpu_device * adev = ddev - > dev_private ;
void * cpu_addr ;
dma_addr_t dma_addr ;
int ret ;
char fw_name [ 100 ] ;
const struct firmware * usbc_pd_fw ;
2020-03-04 16:36:42 -05:00
if ( ! adev - > ip_blocks [ AMD_IP_BLOCK_TYPE_PSP ] . status . late_initialized ) {
DRM_INFO ( " PSP block is not ready yet. " ) ;
return - EBUSY ;
}
2019-12-19 14:58:18 -05:00
snprintf ( fw_name , sizeof ( fw_name ) , " amdgpu/%s " , buf ) ;
ret = request_firmware ( & usbc_pd_fw , fw_name , adev - > dev ) ;
if ( ret )
goto fail ;
/* We need contiguous physical mem to place the FW for psp to access */
cpu_addr = dma_alloc_coherent ( adev - > dev , usbc_pd_fw - > size , & dma_addr , GFP_KERNEL ) ;
ret = dma_mapping_error ( adev - > dev , dma_addr ) ;
if ( ret )
goto rel_buf ;
memcpy_toio ( cpu_addr , usbc_pd_fw - > data , usbc_pd_fw - > size ) ;
2020-03-04 13:07:00 -05:00
/*
* x86 specific workaround .
* Without it the buffer is invisible in PSP .
*
* TODO Remove once PSP starts snooping CPU cache
*/
# ifdef CONFIG_X86
2019-12-19 14:58:18 -05:00
clflush_cache_range ( cpu_addr , ( usbc_pd_fw - > size & ~ ( L1_CACHE_BYTES - 1 ) ) ) ;
2020-03-04 13:07:00 -05:00
# endif
2019-12-19 14:58:18 -05:00
mutex_lock ( & adev - > psp . mutex ) ;
ret = psp_load_usbc_pd_fw ( & adev - > psp , dma_addr ) ;
mutex_unlock ( & adev - > psp . mutex ) ;
rel_buf :
dma_free_coherent ( adev - > dev , usbc_pd_fw - > size , cpu_addr , dma_addr ) ;
release_firmware ( usbc_pd_fw ) ;
fail :
if ( ret ) {
DRM_ERROR ( " Failed to load USBC PD FW, err = %d " , ret ) ;
return ret ;
}
return count ;
}
static DEVICE_ATTR ( usbc_pd_fw , S_IRUGO | S_IWUSR ,
psp_usbc_pd_fw_sysfs_read ,
psp_usbc_pd_fw_sysfs_write ) ;
2017-03-03 18:37:23 -05:00
const struct amd_ip_funcs psp_ip_funcs = {
. name = " psp " ,
. early_init = psp_early_init ,
2020-03-04 16:36:42 -05:00
. late_init = NULL ,
2017-03-03 18:37:23 -05:00
. 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 ,
} ;
2019-12-19 14:58:18 -05:00
static int psp_sysfs_init ( struct amdgpu_device * adev )
{
int ret = device_create_file ( adev - > dev , & dev_attr_usbc_pd_fw ) ;
if ( ret )
DRM_ERROR ( " Failed to create USBC PD FW control file! " ) ;
return ret ;
}
static void psp_sysfs_fini ( struct amdgpu_device * adev )
{
device_remove_file ( adev - > dev , & dev_attr_usbc_pd_fw ) ;
}
2017-03-03 18:37:23 -05:00
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 ,
} ;
2019-08-09 10:32:15 -05:00
const struct amdgpu_ip_block_version psp_v12_0_ip_block =
{
. type = AMD_IP_BLOCK_TYPE_PSP ,
. major = 12 ,
. minor = 0 ,
. rev = 0 ,
. funcs = & psp_ip_funcs ,
} ;