2015-04-20 17:31:14 -04:00
/*
* Copyright 2014 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 .
*
*/
# include <linux/firmware.h>
# include "drmP.h"
# include "amdgpu.h"
# include "smu8.h"
# include "smu8_fusion.h"
# include "cz_ppsmc.h"
# include "cz_smumgr.h"
# include "smu_ucode_xfer_cz.h"
# include "amdgpu_ucode.h"
# include "smu/smu_8_0_d.h"
# include "smu/smu_8_0_sh_mask.h"
# include "gca/gfx_8_0_d.h"
# include "gca/gfx_8_0_sh_mask.h"
uint32_t cz_get_argument ( struct amdgpu_device * adev )
{
return RREG32 ( mmSMU_MP1_SRBM2P_ARG_0 ) ;
}
static struct cz_smu_private_data * cz_smu_get_priv ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv =
( struct cz_smu_private_data * ) ( adev - > smu . priv ) ;
return priv ;
}
int cz_send_msg_to_smc_async ( struct amdgpu_device * adev , u16 msg )
{
int i ;
u32 content = 0 , tmp ;
for ( i = 0 ; i < adev - > usec_timeout ; i + + ) {
tmp = REG_GET_FIELD ( RREG32 ( mmSMU_MP1_SRBM2P_RESP_0 ) ,
SMU_MP1_SRBM2P_RESP_0 , CONTENT ) ;
if ( content ! = tmp )
break ;
udelay ( 1 ) ;
}
/* timeout means wrong logic*/
if ( i = = adev - > usec_timeout )
return - EINVAL ;
WREG32 ( mmSMU_MP1_SRBM2P_RESP_0 , 0 ) ;
WREG32 ( mmSMU_MP1_SRBM2P_MSG_0 , msg ) ;
return 0 ;
}
int cz_send_msg_to_smc ( struct amdgpu_device * adev , u16 msg )
{
int i ;
u32 content = 0 , tmp = 0 ;
if ( cz_send_msg_to_smc_async ( adev , msg ) )
return - EINVAL ;
for ( i = 0 ; i < adev - > usec_timeout ; i + + ) {
tmp = REG_GET_FIELD ( RREG32 ( mmSMU_MP1_SRBM2P_RESP_0 ) ,
SMU_MP1_SRBM2P_RESP_0 , CONTENT ) ;
if ( content ! = tmp )
break ;
udelay ( 1 ) ;
}
/* timeout means wrong logic*/
if ( i = = adev - > usec_timeout )
return - EINVAL ;
if ( PPSMC_Result_OK ! = tmp ) {
dev_err ( adev - > dev , " SMC Failed to send Message. \n " ) ;
return - EINVAL ;
}
return 0 ;
}
int cz_send_msg_to_smc_with_parameter_async ( struct amdgpu_device * adev ,
u16 msg , u32 parameter )
{
WREG32 ( mmSMU_MP1_SRBM2P_ARG_0 , parameter ) ;
return cz_send_msg_to_smc_async ( adev , msg ) ;
}
int cz_send_msg_to_smc_with_parameter ( struct amdgpu_device * adev ,
u16 msg , u32 parameter )
{
WREG32 ( mmSMU_MP1_SRBM2P_ARG_0 , parameter ) ;
return cz_send_msg_to_smc ( adev , msg ) ;
}
static int cz_set_smc_sram_address ( struct amdgpu_device * adev ,
u32 smc_address , u32 limit )
{
if ( smc_address & 3 )
return - EINVAL ;
if ( ( smc_address + 3 ) > limit )
return - EINVAL ;
WREG32 ( mmMP0PUB_IND_INDEX_0 , SMN_MP1_SRAM_START_ADDR + smc_address ) ;
return 0 ;
}
int cz_read_smc_sram_dword ( struct amdgpu_device * adev , u32 smc_address ,
u32 * value , u32 limit )
{
int ret ;
ret = cz_set_smc_sram_address ( adev , smc_address , limit ) ;
if ( ret )
return ret ;
* value = RREG32 ( mmMP0PUB_IND_DATA_0 ) ;
return 0 ;
}
int cz_write_smc_sram_dword ( struct amdgpu_device * adev , u32 smc_address ,
u32 value , u32 limit )
{
int ret ;
ret = cz_set_smc_sram_address ( adev , smc_address , limit ) ;
if ( ret )
return ret ;
WREG32 ( mmMP0PUB_IND_DATA_0 , value ) ;
return 0 ;
}
static int cz_smu_request_load_fw ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
uint32_t smc_addr = SMU8_FIRMWARE_HEADER_LOCATION +
offsetof ( struct SMU8_Firmware_Header , UcodeLoadStatus ) ;
cz_write_smc_sram_dword ( adev , smc_addr , 0 , smc_addr + 4 ) ;
/*prepare toc buffers*/
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_DriverDramAddrHi ,
priv - > toc_buffer . mc_addr_high ) ;
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_DriverDramAddrLo ,
priv - > toc_buffer . mc_addr_low ) ;
cz_send_msg_to_smc ( adev , PPSMC_MSG_InitJobs ) ;
/*execute jobs*/
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_ExecuteJob ,
priv - > toc_entry_aram ) ;
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_ExecuteJob ,
priv - > toc_entry_power_profiling_index ) ;
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_ExecuteJob ,
priv - > toc_entry_initialize_index ) ;
return 0 ;
}
/*
* Check if the FW has been loaded , SMU will not return if loading
* has not finished .
*/
static int cz_smu_check_fw_load_finish ( struct amdgpu_device * adev ,
uint32_t fw_mask )
{
int i ;
uint32_t index = SMN_MP1_SRAM_START_ADDR +
SMU8_FIRMWARE_HEADER_LOCATION +
offsetof ( struct SMU8_Firmware_Header , UcodeLoadStatus ) ;
WREG32 ( mmMP0PUB_IND_INDEX , index ) ;
for ( i = 0 ; i < adev - > usec_timeout ; i + + ) {
if ( fw_mask = = ( RREG32 ( mmMP0PUB_IND_DATA ) & fw_mask ) )
break ;
udelay ( 1 ) ;
}
if ( i > = adev - > usec_timeout ) {
dev_err ( adev - > dev ,
" SMU check loaded firmware failed, expecting 0x%x, getting 0x%x " ,
fw_mask , RREG32 ( mmMP0PUB_IND_DATA ) ) ;
return - EINVAL ;
}
return 0 ;
}
/*
* interfaces for different ip blocks to check firmware loading status
* 0 for success otherwise failed
*/
static int cz_smu_check_finished ( struct amdgpu_device * adev ,
enum AMDGPU_UCODE_ID id )
{
switch ( id ) {
case AMDGPU_UCODE_ID_SDMA0 :
if ( adev - > smu . fw_flags & AMDGPU_SDMA0_UCODE_LOADED )
return 0 ;
break ;
case AMDGPU_UCODE_ID_SDMA1 :
if ( adev - > smu . fw_flags & AMDGPU_SDMA1_UCODE_LOADED )
return 0 ;
break ;
case AMDGPU_UCODE_ID_CP_CE :
if ( adev - > smu . fw_flags & AMDGPU_CPCE_UCODE_LOADED )
return 0 ;
break ;
case AMDGPU_UCODE_ID_CP_PFP :
if ( adev - > smu . fw_flags & AMDGPU_CPPFP_UCODE_LOADED )
return 0 ;
case AMDGPU_UCODE_ID_CP_ME :
if ( adev - > smu . fw_flags & AMDGPU_CPME_UCODE_LOADED )
return 0 ;
break ;
case AMDGPU_UCODE_ID_CP_MEC1 :
if ( adev - > smu . fw_flags & AMDGPU_CPMEC1_UCODE_LOADED )
return 0 ;
break ;
case AMDGPU_UCODE_ID_CP_MEC2 :
if ( adev - > smu . fw_flags & AMDGPU_CPMEC2_UCODE_LOADED )
return 0 ;
break ;
case AMDGPU_UCODE_ID_RLC_G :
if ( adev - > smu . fw_flags & AMDGPU_CPRLC_UCODE_LOADED )
return 0 ;
break ;
case AMDGPU_UCODE_ID_MAXIMUM :
default :
break ;
}
return 1 ;
}
static int cz_load_mec_firmware ( struct amdgpu_device * adev )
{
struct amdgpu_firmware_info * ucode =
& adev - > firmware . ucode [ AMDGPU_UCODE_ID_CP_MEC1 ] ;
uint32_t reg_data ;
uint32_t tmp ;
if ( ucode - > fw = = NULL )
return - EINVAL ;
/* Disable MEC parsing/prefetching */
tmp = RREG32 ( mmCP_MEC_CNTL ) ;
tmp = REG_SET_FIELD ( tmp , CP_MEC_CNTL , MEC_ME1_HALT , 1 ) ;
tmp = REG_SET_FIELD ( tmp , CP_MEC_CNTL , MEC_ME2_HALT , 1 ) ;
WREG32 ( mmCP_MEC_CNTL , tmp ) ;
tmp = RREG32 ( mmCP_CPC_IC_BASE_CNTL ) ;
tmp = REG_SET_FIELD ( tmp , CP_CPC_IC_BASE_CNTL , VMID , 0 ) ;
tmp = REG_SET_FIELD ( tmp , CP_CPC_IC_BASE_CNTL , ATC , 0 ) ;
tmp = REG_SET_FIELD ( tmp , CP_CPC_IC_BASE_CNTL , CACHE_POLICY , 0 ) ;
tmp = REG_SET_FIELD ( tmp , CP_CPC_IC_BASE_CNTL , MTYPE , 1 ) ;
WREG32 ( mmCP_CPC_IC_BASE_CNTL , tmp ) ;
reg_data = lower_32_bits ( ucode - > mc_addr ) &
REG_FIELD_MASK ( CP_CPC_IC_BASE_LO , IC_BASE_LO ) ;
WREG32 ( mmCP_CPC_IC_BASE_LO , reg_data ) ;
reg_data = upper_32_bits ( ucode - > mc_addr ) &
REG_FIELD_MASK ( CP_CPC_IC_BASE_HI , IC_BASE_HI ) ;
WREG32 ( mmCP_CPC_IC_BASE_HI , reg_data ) ;
return 0 ;
}
int cz_smu_start ( struct amdgpu_device * adev )
{
int ret = 0 ;
uint32_t fw_to_check = UCODE_ID_RLC_G_MASK |
UCODE_ID_SDMA0_MASK |
UCODE_ID_SDMA1_MASK |
UCODE_ID_CP_CE_MASK |
UCODE_ID_CP_ME_MASK |
UCODE_ID_CP_PFP_MASK |
UCODE_ID_CP_MEC_JT1_MASK |
UCODE_ID_CP_MEC_JT2_MASK ;
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_STONEY )
fw_to_check & = ~ ( UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK ) ;
2015-04-20 17:31:14 -04:00
cz_smu_request_load_fw ( adev ) ;
ret = cz_smu_check_fw_load_finish ( adev , fw_to_check ) ;
if ( ret )
return ret ;
/* manually load MEC firmware for CZ */
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_CARRIZO | | adev - > asic_type = = CHIP_STONEY ) {
2015-04-20 17:31:14 -04:00
ret = cz_load_mec_firmware ( adev ) ;
if ( ret ) {
dev_err ( adev - > dev , " (%d) Mec Firmware load failed \n " , ret ) ;
return ret ;
}
}
/* setup fw load flag */
adev - > smu . fw_flags = AMDGPU_SDMA0_UCODE_LOADED |
AMDGPU_SDMA1_UCODE_LOADED |
AMDGPU_CPCE_UCODE_LOADED |
AMDGPU_CPPFP_UCODE_LOADED |
AMDGPU_CPME_UCODE_LOADED |
AMDGPU_CPMEC1_UCODE_LOADED |
AMDGPU_CPMEC2_UCODE_LOADED |
AMDGPU_CPRLC_UCODE_LOADED ;
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_STONEY )
adev - > smu . fw_flags & = ~ ( AMDGPU_SDMA1_UCODE_LOADED | AMDGPU_CPMEC2_UCODE_LOADED ) ;
2015-04-20 17:31:14 -04:00
return ret ;
}
static uint32_t cz_convert_fw_type ( uint32_t fw_type )
{
enum AMDGPU_UCODE_ID result = AMDGPU_UCODE_ID_MAXIMUM ;
switch ( fw_type ) {
case UCODE_ID_SDMA0 :
result = AMDGPU_UCODE_ID_SDMA0 ;
break ;
case UCODE_ID_SDMA1 :
result = AMDGPU_UCODE_ID_SDMA1 ;
break ;
case UCODE_ID_CP_CE :
result = AMDGPU_UCODE_ID_CP_CE ;
break ;
case UCODE_ID_CP_PFP :
result = AMDGPU_UCODE_ID_CP_PFP ;
break ;
case UCODE_ID_CP_ME :
result = AMDGPU_UCODE_ID_CP_ME ;
break ;
case UCODE_ID_CP_MEC_JT1 :
case UCODE_ID_CP_MEC_JT2 :
result = AMDGPU_UCODE_ID_CP_MEC1 ;
break ;
case UCODE_ID_RLC_G :
result = AMDGPU_UCODE_ID_RLC_G ;
break ;
default :
DRM_ERROR ( " UCode type is out of range! " ) ;
}
return result ;
}
static uint8_t cz_smu_translate_firmware_enum_to_arg (
enum cz_scratch_entry firmware_enum )
{
uint8_t ret = 0 ;
switch ( firmware_enum ) {
case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 :
ret = UCODE_ID_SDMA0 ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1 :
ret = UCODE_ID_SDMA1 ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE :
ret = UCODE_ID_CP_CE ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP :
ret = UCODE_ID_CP_PFP ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME :
ret = UCODE_ID_CP_ME ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 :
ret = UCODE_ID_CP_MEC_JT1 ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2 :
ret = UCODE_ID_CP_MEC_JT2 ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG :
ret = UCODE_ID_GMCON_RENG ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G :
ret = UCODE_ID_RLC_G ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH :
ret = UCODE_ID_RLC_SCRATCH ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM :
ret = UCODE_ID_RLC_SRM_ARAM ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM :
ret = UCODE_ID_RLC_SRM_DRAM ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM :
ret = UCODE_ID_DMCU_ERAM ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM :
ret = UCODE_ID_DMCU_IRAM ;
break ;
case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING :
ret = TASK_ARG_INIT_MM_PWR_LOG ;
break ;
case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT :
case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING :
case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS :
case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT :
case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START :
case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS :
ret = TASK_ARG_REG_MMIO ;
break ;
case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE :
ret = TASK_ARG_INIT_CLK_TABLE ;
break ;
}
return ret ;
}
static int cz_smu_populate_single_firmware_entry ( struct amdgpu_device * adev ,
enum cz_scratch_entry firmware_enum ,
struct cz_buffer_entry * entry )
{
uint64_t gpu_addr ;
uint32_t data_size ;
uint8_t ucode_id = cz_smu_translate_firmware_enum_to_arg ( firmware_enum ) ;
enum AMDGPU_UCODE_ID id = cz_convert_fw_type ( ucode_id ) ;
struct amdgpu_firmware_info * ucode = & adev - > firmware . ucode [ id ] ;
const struct gfx_firmware_header_v1_0 * header ;
if ( ucode - > fw = = NULL )
return - EINVAL ;
gpu_addr = ucode - > mc_addr ;
header = ( const struct gfx_firmware_header_v1_0 * ) ucode - > fw - > data ;
data_size = le32_to_cpu ( header - > header . ucode_size_bytes ) ;
if ( ( firmware_enum = = CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 ) | |
( firmware_enum = = CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2 ) ) {
gpu_addr + = le32_to_cpu ( header - > jt_offset ) < < 2 ;
data_size = le32_to_cpu ( header - > jt_size ) < < 2 ;
}
entry - > mc_addr_low = lower_32_bits ( gpu_addr ) ;
entry - > mc_addr_high = upper_32_bits ( gpu_addr ) ;
entry - > data_size = data_size ;
entry - > firmware_ID = firmware_enum ;
return 0 ;
}
static int cz_smu_populate_single_scratch_entry ( struct amdgpu_device * adev ,
enum cz_scratch_entry scratch_type ,
uint32_t size_in_byte ,
struct cz_buffer_entry * entry )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
uint64_t mc_addr = ( ( ( uint64_t ) priv - > smu_buffer . mc_addr_high ) < < 32 ) |
priv - > smu_buffer . mc_addr_low ;
mc_addr + = size_in_byte ;
priv - > smu_buffer_used_bytes + = size_in_byte ;
entry - > data_size = size_in_byte ;
entry - > kaddr = priv - > smu_buffer . kaddr + priv - > smu_buffer_used_bytes ;
entry - > mc_addr_low = lower_32_bits ( mc_addr ) ;
entry - > mc_addr_high = upper_32_bits ( mc_addr ) ;
entry - > firmware_ID = scratch_type ;
return 0 ;
}
static int cz_smu_populate_single_ucode_load_task ( struct amdgpu_device * adev ,
enum cz_scratch_entry firmware_enum ,
bool is_last )
{
uint8_t i ;
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
struct TOC * toc = ( struct TOC * ) priv - > toc_buffer . kaddr ;
struct SMU_Task * task = & toc - > tasks [ priv - > toc_entry_used_count + + ] ;
task - > type = TASK_TYPE_UCODE_LOAD ;
task - > arg = cz_smu_translate_firmware_enum_to_arg ( firmware_enum ) ;
task - > next = is_last ? END_OF_TASK_LIST : priv - > toc_entry_used_count ;
for ( i = 0 ; i < priv - > driver_buffer_length ; i + + )
if ( priv - > driver_buffer [ i ] . firmware_ID = = firmware_enum )
break ;
if ( i > = priv - > driver_buffer_length ) {
dev_err ( adev - > dev , " Invalid Firmware Type \n " ) ;
return - EINVAL ;
}
task - > addr . low = priv - > driver_buffer [ i ] . mc_addr_low ;
task - > addr . high = priv - > driver_buffer [ i ] . mc_addr_high ;
task - > size_bytes = priv - > driver_buffer [ i ] . data_size ;
return 0 ;
}
static int cz_smu_populate_single_scratch_task ( struct amdgpu_device * adev ,
enum cz_scratch_entry firmware_enum ,
uint8_t type , bool is_last )
{
uint8_t i ;
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
struct TOC * toc = ( struct TOC * ) priv - > toc_buffer . kaddr ;
struct SMU_Task * task = & toc - > tasks [ priv - > toc_entry_used_count + + ] ;
task - > type = type ;
task - > arg = cz_smu_translate_firmware_enum_to_arg ( firmware_enum ) ;
task - > next = is_last ? END_OF_TASK_LIST : priv - > toc_entry_used_count ;
for ( i = 0 ; i < priv - > scratch_buffer_length ; i + + )
if ( priv - > scratch_buffer [ i ] . firmware_ID = = firmware_enum )
break ;
if ( i > = priv - > scratch_buffer_length ) {
dev_err ( adev - > dev , " Invalid Firmware Type \n " ) ;
return - EINVAL ;
}
task - > addr . low = priv - > scratch_buffer [ i ] . mc_addr_low ;
task - > addr . high = priv - > scratch_buffer [ i ] . mc_addr_high ;
task - > size_bytes = priv - > scratch_buffer [ i ] . data_size ;
if ( CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS = = firmware_enum ) {
struct cz_ih_meta_data * pIHReg_restore =
( struct cz_ih_meta_data * ) priv - > scratch_buffer [ i ] . kaddr ;
pIHReg_restore - > command =
METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD ;
}
return 0 ;
}
static int cz_smu_construct_toc_for_rlc_aram_save ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
priv - > toc_entry_aram = priv - > toc_entry_used_count ;
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM ,
TASK_TYPE_UCODE_SAVE , true ) ;
return 0 ;
}
static int cz_smu_construct_toc_for_vddgfx_enter ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
struct TOC * toc = ( struct TOC * ) priv - > toc_buffer . kaddr ;
toc - > JobList [ JOB_GFX_SAVE ] = ( uint8_t ) priv - > toc_entry_used_count ;
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH ,
TASK_TYPE_UCODE_SAVE , false ) ;
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM ,
TASK_TYPE_UCODE_SAVE , true ) ;
return 0 ;
}
static int cz_smu_construct_toc_for_vddgfx_exit ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
struct TOC * toc = ( struct TOC * ) priv - > toc_buffer . kaddr ;
toc - > JobList [ JOB_GFX_RESTORE ] = ( uint8_t ) priv - > toc_entry_used_count ;
/* populate ucode */
if ( adev - > firmware . smu_load ) {
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE , false ) ;
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP , false ) ;
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME , false ) ;
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 , false ) ;
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_STONEY ) {
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 , false ) ;
} else {
cz_smu_populate_single_ucode_load_task ( adev ,
2015-04-20 17:31:14 -04:00
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2 , false ) ;
2015-10-08 16:28:41 -04:00
}
2015-04-20 17:31:14 -04:00
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G , false ) ;
}
/* populate scratch */
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH ,
TASK_TYPE_UCODE_LOAD , false ) ;
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM ,
TASK_TYPE_UCODE_LOAD , false ) ;
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM ,
TASK_TYPE_UCODE_LOAD , true ) ;
return 0 ;
}
static int cz_smu_construct_toc_for_power_profiling ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
priv - > toc_entry_power_profiling_index = priv - > toc_entry_used_count ;
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING ,
TASK_TYPE_INITIALIZE , true ) ;
return 0 ;
}
static int cz_smu_construct_toc_for_bootup ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
priv - > toc_entry_initialize_index = priv - > toc_entry_used_count ;
if ( adev - > firmware . smu_load ) {
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 , false ) ;
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_STONEY ) {
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 , false ) ;
} else {
cz_smu_populate_single_ucode_load_task ( adev ,
2015-04-20 17:31:14 -04:00
CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1 , false ) ;
2015-10-08 16:28:41 -04:00
}
2015-04-20 17:31:14 -04:00
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE , false ) ;
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP , false ) ;
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME , false ) ;
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 , false ) ;
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_STONEY ) {
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 , false ) ;
} else {
cz_smu_populate_single_ucode_load_task ( adev ,
2015-04-20 17:31:14 -04:00
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2 , false ) ;
2015-10-08 16:28:41 -04:00
}
2015-04-20 17:31:14 -04:00
cz_smu_populate_single_ucode_load_task ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G , true ) ;
}
return 0 ;
}
static int cz_smu_construct_toc_for_clock_table ( struct amdgpu_device * adev )
{
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
priv - > toc_entry_clock_table = priv - > toc_entry_used_count ;
cz_smu_populate_single_scratch_task ( adev ,
CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE ,
TASK_TYPE_INITIALIZE , true ) ;
return 0 ;
}
static int cz_smu_initialize_toc_empty_job_list ( struct amdgpu_device * adev )
{
int i ;
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
struct TOC * toc = ( struct TOC * ) priv - > toc_buffer . kaddr ;
for ( i = 0 ; i < NUM_JOBLIST_ENTRIES ; i + + )
toc - > JobList [ i ] = ( uint8_t ) IGNORE_JOB ;
return 0 ;
}
/*
* cz smu uninitialization
*/
int cz_smu_fini ( struct amdgpu_device * adev )
{
amdgpu_bo_unref ( & adev - > smu . toc_buf ) ;
amdgpu_bo_unref ( & adev - > smu . smu_buf ) ;
kfree ( adev - > smu . priv ) ;
adev - > smu . priv = NULL ;
if ( adev - > firmware . smu_load )
amdgpu_ucode_fini_bo ( adev ) ;
return 0 ;
}
int cz_smu_download_pptable ( struct amdgpu_device * adev , void * * table )
{
uint8_t i ;
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
for ( i = 0 ; i < priv - > scratch_buffer_length ; i + + )
if ( priv - > scratch_buffer [ i ] . firmware_ID = =
CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE )
break ;
if ( i > = priv - > scratch_buffer_length ) {
dev_err ( adev - > dev , " Invalid Scratch Type \n " ) ;
return - EINVAL ;
}
* table = ( struct SMU8_Fusion_ClkTable * ) priv - > scratch_buffer [ i ] . kaddr ;
/* prepare buffer for pptable */
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_SetClkTableAddrHi ,
priv - > scratch_buffer [ i ] . mc_addr_high ) ;
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_SetClkTableAddrLo ,
priv - > scratch_buffer [ i ] . mc_addr_low ) ;
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_ExecuteJob ,
priv - > toc_entry_clock_table ) ;
/* actual downloading */
cz_send_msg_to_smc ( adev , PPSMC_MSG_ClkTableXferToDram ) ;
return 0 ;
}
int cz_smu_upload_pptable ( struct amdgpu_device * adev )
{
uint8_t i ;
struct cz_smu_private_data * priv = cz_smu_get_priv ( adev ) ;
for ( i = 0 ; i < priv - > scratch_buffer_length ; i + + )
if ( priv - > scratch_buffer [ i ] . firmware_ID = =
CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE )
break ;
if ( i > = priv - > scratch_buffer_length ) {
dev_err ( adev - > dev , " Invalid Scratch Type \n " ) ;
return - EINVAL ;
}
/* prepare SMU */
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_SetClkTableAddrHi ,
priv - > scratch_buffer [ i ] . mc_addr_high ) ;
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_SetClkTableAddrLo ,
priv - > scratch_buffer [ i ] . mc_addr_low ) ;
cz_send_msg_to_smc_with_parameter ( adev ,
PPSMC_MSG_ExecuteJob ,
priv - > toc_entry_clock_table ) ;
/* actual uploading */
cz_send_msg_to_smc ( adev , PPSMC_MSG_ClkTableXferToSmu ) ;
return 0 ;
}
/*
* cz smumgr functions initialization
*/
static const struct amdgpu_smumgr_funcs cz_smumgr_funcs = {
. check_fw_load_finish = cz_smu_check_finished ,
. request_smu_load_fw = NULL ,
. request_smu_specific_fw = NULL ,
} ;
/*
* cz smu initialization
*/
int cz_smu_init ( struct amdgpu_device * adev )
{
int ret = - EINVAL ;
uint64_t mc_addr = 0 ;
struct amdgpu_bo * * toc_buf = & adev - > smu . toc_buf ;
struct amdgpu_bo * * smu_buf = & adev - > smu . smu_buf ;
void * toc_buf_ptr = NULL ;
void * smu_buf_ptr = NULL ;
struct cz_smu_private_data * priv =
kzalloc ( sizeof ( struct cz_smu_private_data ) , GFP_KERNEL ) ;
if ( priv = = NULL )
return - ENOMEM ;
/* allocate firmware buffers */
if ( adev - > firmware . smu_load )
amdgpu_ucode_init_bo ( adev ) ;
adev - > smu . priv = priv ;
adev - > smu . fw_flags = 0 ;
priv - > toc_buffer . data_size = 4096 ;
priv - > smu_buffer . data_size =
ALIGN ( UCODE_ID_RLC_SCRATCH_SIZE_BYTE , 32 ) +
ALIGN ( UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE , 32 ) +
ALIGN ( UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE , 32 ) +
ALIGN ( sizeof ( struct SMU8_MultimediaPowerLogData ) , 32 ) +
ALIGN ( sizeof ( struct SMU8_Fusion_ClkTable ) , 32 ) ;
/* prepare toc buffer and smu buffer:
* 1. create amdgpu_bo for toc buffer and smu buffer
* 2. pin mc address
* 3. map kernel virtual address
*/
ret = amdgpu_bo_create ( adev , priv - > toc_buffer . data_size , PAGE_SIZE ,
2015-09-03 17:34:59 +02:00
true , AMDGPU_GEM_DOMAIN_GTT , 0 , NULL , NULL ,
toc_buf ) ;
2015-04-20 17:31:14 -04:00
if ( ret ) {
dev_err ( adev - > dev , " (%d) SMC TOC buffer allocation failed \n " , ret ) ;
return ret ;
}
ret = amdgpu_bo_create ( adev , priv - > smu_buffer . data_size , PAGE_SIZE ,
2015-09-03 17:34:59 +02:00
true , AMDGPU_GEM_DOMAIN_GTT , 0 , NULL , NULL ,
smu_buf ) ;
2015-04-20 17:31:14 -04:00
if ( ret ) {
dev_err ( adev - > dev , " (%d) SMC Internal buffer allocation failed \n " , ret ) ;
return ret ;
}
/* toc buffer reserve/pin/map */
ret = amdgpu_bo_reserve ( adev - > smu . toc_buf , false ) ;
if ( ret ) {
amdgpu_bo_unref ( & adev - > smu . toc_buf ) ;
dev_err ( adev - > dev , " (%d) SMC TOC buffer reserve failed \n " , ret ) ;
return ret ;
}
ret = amdgpu_bo_pin ( adev - > smu . toc_buf , AMDGPU_GEM_DOMAIN_GTT , & mc_addr ) ;
if ( ret ) {
amdgpu_bo_unreserve ( adev - > smu . toc_buf ) ;
amdgpu_bo_unref ( & adev - > smu . toc_buf ) ;
dev_err ( adev - > dev , " (%d) SMC TOC buffer pin failed \n " , ret ) ;
return ret ;
}
ret = amdgpu_bo_kmap ( * toc_buf , & toc_buf_ptr ) ;
if ( ret )
goto smu_init_failed ;
amdgpu_bo_unreserve ( adev - > smu . toc_buf ) ;
priv - > toc_buffer . mc_addr_low = lower_32_bits ( mc_addr ) ;
priv - > toc_buffer . mc_addr_high = upper_32_bits ( mc_addr ) ;
priv - > toc_buffer . kaddr = toc_buf_ptr ;
/* smu buffer reserve/pin/map */
ret = amdgpu_bo_reserve ( adev - > smu . smu_buf , false ) ;
if ( ret ) {
amdgpu_bo_unref ( & adev - > smu . smu_buf ) ;
dev_err ( adev - > dev , " (%d) SMC Internal buffer reserve failed \n " , ret ) ;
return ret ;
}
ret = amdgpu_bo_pin ( adev - > smu . smu_buf , AMDGPU_GEM_DOMAIN_GTT , & mc_addr ) ;
if ( ret ) {
amdgpu_bo_unreserve ( adev - > smu . smu_buf ) ;
amdgpu_bo_unref ( & adev - > smu . smu_buf ) ;
dev_err ( adev - > dev , " (%d) SMC Internal buffer pin failed \n " , ret ) ;
return ret ;
}
ret = amdgpu_bo_kmap ( * smu_buf , & smu_buf_ptr ) ;
if ( ret )
goto smu_init_failed ;
amdgpu_bo_unreserve ( adev - > smu . smu_buf ) ;
priv - > smu_buffer . mc_addr_low = lower_32_bits ( mc_addr ) ;
priv - > smu_buffer . mc_addr_high = upper_32_bits ( mc_addr ) ;
priv - > smu_buffer . kaddr = smu_buf_ptr ;
if ( adev - > firmware . smu_load ) {
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_STONEY ) {
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
} else {
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1 ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
}
2015-04-20 17:31:14 -04:00
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
2015-10-08 16:28:41 -04:00
if ( adev - > asic_type = = CHIP_STONEY ) {
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1 ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
} else {
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2 ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
}
2015-04-20 17:31:14 -04:00
if ( cz_smu_populate_single_firmware_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G ,
& priv - > driver_buffer [ priv - > driver_buffer_length + + ] ) )
goto smu_init_failed ;
}
if ( cz_smu_populate_single_scratch_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH ,
UCODE_ID_RLC_SCRATCH_SIZE_BYTE ,
& priv - > scratch_buffer [ priv - > scratch_buffer_length + + ] ) )
goto smu_init_failed ;
if ( cz_smu_populate_single_scratch_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM ,
UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE ,
& priv - > scratch_buffer [ priv - > scratch_buffer_length + + ] ) )
goto smu_init_failed ;
if ( cz_smu_populate_single_scratch_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM ,
UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE ,
& priv - > scratch_buffer [ priv - > scratch_buffer_length + + ] ) )
goto smu_init_failed ;
if ( cz_smu_populate_single_scratch_entry ( adev ,
CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING ,
sizeof ( struct SMU8_MultimediaPowerLogData ) ,
& priv - > scratch_buffer [ priv - > scratch_buffer_length + + ] ) )
goto smu_init_failed ;
if ( cz_smu_populate_single_scratch_entry ( adev ,
CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE ,
sizeof ( struct SMU8_Fusion_ClkTable ) ,
& priv - > scratch_buffer [ priv - > scratch_buffer_length + + ] ) )
goto smu_init_failed ;
cz_smu_initialize_toc_empty_job_list ( adev ) ;
cz_smu_construct_toc_for_rlc_aram_save ( adev ) ;
cz_smu_construct_toc_for_vddgfx_enter ( adev ) ;
cz_smu_construct_toc_for_vddgfx_exit ( adev ) ;
cz_smu_construct_toc_for_power_profiling ( adev ) ;
cz_smu_construct_toc_for_bootup ( adev ) ;
cz_smu_construct_toc_for_clock_table ( adev ) ;
/* init the smumgr functions */
adev - > smu . smumgr_funcs = & cz_smumgr_funcs ;
return 0 ;
smu_init_failed :
amdgpu_bo_unref ( toc_buf ) ;
amdgpu_bo_unref ( smu_buf ) ;
return ret ;
}