2017-05-04 15:28:30 -04: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-06-10 00:07:51 +02:00
# include <linux/module.h>
# include <linux/pci.h>
2017-05-04 15:28:30 -04:00
# include "amdgpu.h"
# include "amdgpu_psp.h"
# include "amdgpu_ucode.h"
# include "soc15_common.h"
# include "psp_v10_0.h"
2017-11-27 17:20:55 +08:00
# include "mp/mp_10_0_offset.h"
2017-11-27 17:00:12 +08:00
# include "gc/gc_9_1_offset.h"
2017-11-27 18:40:15 +08:00
# include "sdma0/sdma0_4_1_offset.h"
2017-05-04 15:28:30 -04:00
2017-09-15 17:36:19 -04:00
MODULE_FIRMWARE ( " amdgpu/raven_asd.bin " ) ;
2018-07-10 20:12:38 +08:00
MODULE_FIRMWARE ( " amdgpu/picasso_asd.bin " ) ;
2018-06-05 14:05:45 +08:00
MODULE_FIRMWARE ( " amdgpu/raven2_asd.bin " ) ;
2019-10-14 18:27:11 +08:00
MODULE_FIRMWARE ( " amdgpu/picasso_ta.bin " ) ;
MODULE_FIRMWARE ( " amdgpu/raven2_ta.bin " ) ;
MODULE_FIRMWARE ( " amdgpu/raven_ta.bin " ) ;
2017-09-15 17:36:19 -04:00
2018-01-23 16:17:24 -05:00
static int psp_v10_0_init_microcode ( struct psp_context * psp )
2017-07-14 18:31:18 +08:00
{
struct amdgpu_device * adev = psp - > adev ;
const char * chip_name ;
char fw_name [ 30 ] ;
int err = 0 ;
const struct psp_firmware_header_v1_0 * hdr ;
2019-06-19 14:37:29 -04:00
const struct ta_firmware_header_v1_0 * ta_hdr ;
2017-07-14 18:31:18 +08:00
DRM_DEBUG ( " \n " ) ;
switch ( adev - > asic_type ) {
case CHIP_RAVEN :
2018-06-05 14:05:45 +08:00
if ( adev - > rev_id > = 0x8 )
chip_name = " raven2 " ;
2018-09-13 15:41:57 -05:00
else if ( adev - > pdev - > device = = 0x15d8 )
chip_name = " picasso " ;
2018-06-05 14:05:45 +08:00
else
chip_name = " raven " ;
2017-07-14 18:31:18 +08:00
break ;
default : BUG ( ) ;
}
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 ;
hdr = ( const struct psp_firmware_header_v1_0 * ) adev - > psp . asd_fw - > data ;
adev - > psp . asd_fw_version = le32_to_cpu ( hdr - > header . ucode_version ) ;
adev - > psp . asd_feature_version = le32_to_cpu ( hdr - > ucode_feature_version ) ;
adev - > psp . asd_ucode_size = le32_to_cpu ( hdr - > header . ucode_size_bytes ) ;
adev - > psp . asd_start_addr = ( uint8_t * ) hdr +
le32_to_cpu ( hdr - > header . ucode_array_offset_bytes ) ;
2019-06-19 14:37:29 -04:00
snprintf ( fw_name , sizeof ( fw_name ) , " amdgpu/%s_ta.bin " , chip_name ) ;
err = request_firmware ( & adev - > psp . ta_fw , fw_name , adev - > dev ) ;
if ( err ) {
release_firmware ( adev - > psp . ta_fw ) ;
adev - > psp . ta_fw = NULL ;
dev_info ( adev - > dev ,
" psp v10.0: Failed to load firmware \" %s \" \n " ,
fw_name ) ;
} else {
err = amdgpu_ucode_validate ( adev - > psp . ta_fw ) ;
if ( err )
goto out2 ;
ta_hdr = ( const struct ta_firmware_header_v1_0 * )
adev - > psp . ta_fw - > data ;
adev - > psp . ta_hdcp_ucode_version =
le32_to_cpu ( ta_hdr - > ta_hdcp_ucode_version ) ;
adev - > psp . ta_hdcp_ucode_size =
le32_to_cpu ( ta_hdr - > ta_hdcp_size_bytes ) ;
adev - > psp . ta_hdcp_start_addr =
( uint8_t * ) ta_hdr +
le32_to_cpu ( ta_hdr - > header . ucode_array_offset_bytes ) ;
2019-06-19 14:40:58 -04:00
adev - > psp . ta_fw_version = le32_to_cpu ( ta_hdr - > header . ucode_version ) ;
adev - > psp . ta_dtm_ucode_version =
le32_to_cpu ( ta_hdr - > ta_dtm_ucode_version ) ;
adev - > psp . ta_dtm_ucode_size =
le32_to_cpu ( ta_hdr - > ta_dtm_size_bytes ) ;
adev - > psp . ta_dtm_start_addr =
( uint8_t * ) adev - > psp . ta_hdcp_start_addr +
le32_to_cpu ( ta_hdr - > ta_dtm_offset_bytes ) ;
2019-06-19 14:37:29 -04:00
}
2017-07-14 18:31:18 +08:00
return 0 ;
2019-06-19 14:37:29 -04:00
out2 :
release_firmware ( adev - > psp . ta_fw ) ;
adev - > psp . ta_fw = NULL ;
2017-07-14 18:31:18 +08:00
out :
if ( err ) {
dev_err ( adev - > dev ,
" psp v10.0: Failed to load firmware \" %s \" \n " ,
fw_name ) ;
release_firmware ( adev - > psp . asd_fw ) ;
adev - > psp . asd_fw = NULL ;
}
return err ;
}
2018-01-23 16:17:24 -05:00
static int psp_v10_0_ring_init ( struct psp_context * psp ,
enum psp_ring_type ring_type )
2017-05-04 15:28:30 -04:00
{
int ret = 0 ;
struct psp_ring * ring ;
struct amdgpu_device * adev = psp - > adev ;
ring = & psp - > km_ring ;
ring - > ring_type = ring_type ;
/* allocate 4k Page of Local Frame Buffer memory for ring */
ring - > ring_size = 0x1000 ;
ret = amdgpu_bo_create_kernel ( adev , ring - > ring_size , PAGE_SIZE ,
AMDGPU_GEM_DOMAIN_VRAM ,
& adev - > firmware . rbuf ,
& ring - > ring_mem_mc_addr ,
( void * * ) & ring - > ring_mem ) ;
if ( ret ) {
ring - > ring_size = 0 ;
return ret ;
}
return 0 ;
}
2018-01-23 16:17:24 -05:00
static int psp_v10_0_ring_create ( struct psp_context * psp ,
enum psp_ring_type ring_type )
2017-07-14 18:34:48 +08:00
{
int ret = 0 ;
unsigned int psp_ring_reg = 0 ;
struct psp_ring * ring = & psp - > km_ring ;
struct amdgpu_device * adev = psp - > adev ;
/* Write low address of the ring to C2PMSG_69 */
psp_ring_reg = lower_32_bits ( ring - > ring_mem_mc_addr ) ;
WREG32_SOC15 ( MP0 , 0 , mmMP0_SMN_C2PMSG_69 , psp_ring_reg ) ;
/* Write high address of the ring to C2PMSG_70 */
psp_ring_reg = upper_32_bits ( ring - > ring_mem_mc_addr ) ;
WREG32_SOC15 ( MP0 , 0 , mmMP0_SMN_C2PMSG_70 , psp_ring_reg ) ;
/* Write size of ring to C2PMSG_71 */
psp_ring_reg = ring - > ring_size ;
WREG32_SOC15 ( MP0 , 0 , mmMP0_SMN_C2PMSG_71 , psp_ring_reg ) ;
/* Write the ring initialization command to C2PMSG_64 */
psp_ring_reg = ring_type ;
psp_ring_reg = psp_ring_reg < < 16 ;
WREG32_SOC15 ( MP0 , 0 , mmMP0_SMN_C2PMSG_64 , psp_ring_reg ) ;
/* There might be handshake issue with hardware which needs delay */
mdelay ( 20 ) ;
/* Wait for response flag (bit 31) in C2PMSG_64 */
ret = psp_wait_for ( psp , SOC15_REG_OFFSET ( MP0 , 0 , mmMP0_SMN_C2PMSG_64 ) ,
0x80000000 , 0x8000FFFF , false ) ;
return ret ;
}
2018-01-23 16:17:24 -05:00
static int psp_v10_0_ring_stop ( struct psp_context * psp ,
enum psp_ring_type ring_type )
2017-07-14 18:37:44 +08:00
{
int ret = 0 ;
unsigned int psp_ring_reg = 0 ;
struct amdgpu_device * adev = psp - > adev ;
/* Write the ring destroy command to C2PMSG_64 */
psp_ring_reg = 3 < < 16 ;
WREG32_SOC15 ( MP0 , 0 , mmMP0_SMN_C2PMSG_64 , psp_ring_reg ) ;
/* There might be handshake issue with hardware which needs delay */
mdelay ( 20 ) ;
/* Wait for response flag (bit 31) in C2PMSG_64 */
ret = psp_wait_for ( psp , SOC15_REG_OFFSET ( MP0 , 0 , mmMP0_SMN_C2PMSG_64 ) ,
0x80000000 , 0x80000000 , false ) ;
2017-09-08 13:04:52 +08:00
return ret ;
}
2018-01-23 16:17:24 -05:00
static int psp_v10_0_ring_destroy ( struct psp_context * psp ,
enum psp_ring_type ring_type )
2017-09-08 13:04:52 +08:00
{
int ret = 0 ;
struct psp_ring * ring = & psp - > km_ring ;
struct amdgpu_device * adev = psp - > adev ;
ret = psp_v10_0_ring_stop ( psp , ring_type ) ;
if ( ret )
DRM_ERROR ( " Fail to stop psp ring \n " ) ;
2017-07-14 18:37:44 +08:00
amdgpu_bo_free_kernel ( & adev - > firmware . rbuf ,
& ring - > ring_mem_mc_addr ,
( void * * ) & ring - > ring_mem ) ;
return ret ;
}
2017-05-04 15:28:30 -04:00
static int
2017-11-29 13:51:32 -05:00
psp_v10_0_sram_map ( struct amdgpu_device * adev ,
2018-01-23 16:17:24 -05:00
unsigned int * sram_offset , unsigned int * sram_addr_reg_offset ,
unsigned int * sram_data_reg_offset ,
enum AMDGPU_UCODE_ID ucode_id )
2017-05-04 15:28:30 -04:00
{
int ret = 0 ;
switch ( ucode_id ) {
/* TODO: needs to confirm */
#if 0
case AMDGPU_UCODE_ID_SMC :
* sram_offset = 0 ;
* sram_addr_reg_offset = 0 ;
* sram_data_reg_offset = 0 ;
break ;
# endif
case AMDGPU_UCODE_ID_CP_CE :
* sram_offset = 0x0 ;
* sram_addr_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_CE_UCODE_ADDR ) ;
* sram_data_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_CE_UCODE_DATA ) ;
break ;
case AMDGPU_UCODE_ID_CP_PFP :
* sram_offset = 0x0 ;
* sram_addr_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_PFP_UCODE_ADDR ) ;
* sram_data_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_PFP_UCODE_DATA ) ;
break ;
case AMDGPU_UCODE_ID_CP_ME :
* sram_offset = 0x0 ;
* sram_addr_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_HYP_ME_UCODE_ADDR ) ;
* sram_data_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_HYP_ME_UCODE_DATA ) ;
break ;
case AMDGPU_UCODE_ID_CP_MEC1 :
* sram_offset = 0x10000 ;
* sram_addr_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_MEC_ME1_UCODE_ADDR ) ;
* sram_data_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_MEC_ME1_UCODE_DATA ) ;
break ;
case AMDGPU_UCODE_ID_CP_MEC2 :
* sram_offset = 0x10000 ;
* sram_addr_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_HYP_MEC2_UCODE_ADDR ) ;
* sram_data_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmCP_HYP_MEC2_UCODE_DATA ) ;
break ;
case AMDGPU_UCODE_ID_RLC_G :
* sram_offset = 0x2000 ;
* sram_addr_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmRLC_GPM_UCODE_ADDR ) ;
* sram_data_reg_offset = SOC15_REG_OFFSET ( GC , 0 , mmRLC_GPM_UCODE_DATA ) ;
break ;
case AMDGPU_UCODE_ID_SDMA0 :
* sram_offset = 0x0 ;
* sram_addr_reg_offset = SOC15_REG_OFFSET ( SDMA0 , 0 , mmSDMA0_UCODE_ADDR ) ;
* sram_data_reg_offset = SOC15_REG_OFFSET ( SDMA0 , 0 , mmSDMA0_UCODE_DATA ) ;
break ;
/* TODO: needs to confirm */
#if 0
case AMDGPU_UCODE_ID_SDMA1 :
* sram_offset = ;
* sram_addr_reg_offset = ;
break ;
case AMDGPU_UCODE_ID_UVD :
* sram_offset = ;
* sram_addr_reg_offset = ;
break ;
case AMDGPU_UCODE_ID_VCE :
* sram_offset = ;
* sram_addr_reg_offset = ;
break ;
# endif
case AMDGPU_UCODE_ID_MAXIMUM :
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
2018-01-23 16:17:24 -05:00
static bool psp_v10_0_compare_sram_data ( struct psp_context * psp ,
struct amdgpu_firmware_info * ucode ,
enum AMDGPU_UCODE_ID ucode_type )
2017-05-04 15:28:30 -04:00
{
int err = 0 ;
unsigned int fw_sram_reg_val = 0 ;
unsigned int fw_sram_addr_reg_offset = 0 ;
unsigned int fw_sram_data_reg_offset = 0 ;
unsigned int ucode_size ;
uint32_t * ucode_mem = NULL ;
struct amdgpu_device * adev = psp - > adev ;
2017-11-29 13:51:32 -05:00
err = psp_v10_0_sram_map ( adev , & fw_sram_reg_val , & fw_sram_addr_reg_offset ,
2017-05-04 15:28:30 -04:00
& fw_sram_data_reg_offset , ucode_type ) ;
if ( err )
return false ;
WREG32 ( fw_sram_addr_reg_offset , fw_sram_reg_val ) ;
ucode_size = ucode - > ucode_size ;
ucode_mem = ( uint32_t * ) ucode - > kaddr ;
while ( ! ucode_size ) {
fw_sram_reg_val = RREG32 ( fw_sram_data_reg_offset ) ;
if ( * ucode_mem ! = fw_sram_reg_val )
return false ;
ucode_mem + + ;
/* 4 bytes */
ucode_size - = 4 ;
}
return true ;
}
2017-09-14 16:25:19 +08:00
2018-01-23 16:17:24 -05:00
static int psp_v10_0_mode1_reset ( struct psp_context * psp )
2017-09-14 16:25:19 +08:00
{
DRM_INFO ( " psp mode 1 reset not supported now! \n " ) ;
return - EINVAL ;
}
2018-01-23 16:17:24 -05:00
2019-11-18 17:13:56 +08:00
static uint32_t psp_v10_0_ring_get_wptr ( struct psp_context * psp )
{
struct amdgpu_device * adev = psp - > adev ;
return RREG32_SOC15 ( MP0 , 0 , mmMP0_SMN_C2PMSG_67 ) ;
}
static void psp_v10_0_ring_set_wptr ( struct psp_context * psp , uint32_t value )
{
struct amdgpu_device * adev = psp - > adev ;
WREG32_SOC15 ( MP0 , 0 , mmMP0_SMN_C2PMSG_67 , value ) ;
}
2018-01-23 16:17:24 -05:00
static const struct psp_funcs psp_v10_0_funcs = {
. init_microcode = psp_v10_0_init_microcode ,
. ring_init = psp_v10_0_ring_init ,
. ring_create = psp_v10_0_ring_create ,
. ring_stop = psp_v10_0_ring_stop ,
. ring_destroy = psp_v10_0_ring_destroy ,
. compare_sram_data = psp_v10_0_compare_sram_data ,
. mode1_reset = psp_v10_0_mode1_reset ,
2019-11-18 17:13:56 +08:00
. ring_get_wptr = psp_v10_0_ring_get_wptr ,
. ring_set_wptr = psp_v10_0_ring_set_wptr ,
2018-01-23 16:17:24 -05:00
} ;
void psp_v10_0_set_psp_funcs ( struct psp_context * psp )
{
psp - > funcs = & psp_v10_0_funcs ;
}