2016-06-20 00:42:01 +08: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 < ray . huang @ amd . com >
*
*/
2016-12-26 14:05:30 +08:00
# include "pp_debug.h"
2016-06-20 00:42:01 +08:00
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/gfp.h>
# include "smumgr.h"
# include "iceland_smumgr.h"
# include "smu_ucode_xfer_vi.h"
# include "ppsmc.h"
# include "smu/smu_7_1_1_d.h"
# include "smu/smu_7_1_1_sh_mask.h"
# include "cgs_common.h"
2016-08-23 11:58:14 +08:00
# include "iceland_smc.h"
2016-06-20 00:42:01 +08:00
2016-08-23 11:57:30 +08:00
# define ICELAND_SMC_SIZE 0x20000
2016-06-20 00:42:01 +08:00
static int iceland_start_smc ( struct pp_smumgr * smumgr )
{
SMUM_WRITE_INDIRECT_FIELD ( smumgr - > device , CGS_IND_REG__SMC ,
SMC_SYSCON_RESET_CNTL , rst_reg , 0 ) ;
return 0 ;
}
2016-08-23 11:57:30 +08:00
static void iceland_reset_smc ( struct pp_smumgr * smumgr )
2016-06-20 00:42:01 +08:00
{
SMUM_WRITE_INDIRECT_FIELD ( smumgr - > device , CGS_IND_REG__SMC ,
SMC_SYSCON_RESET_CNTL ,
rst_reg , 1 ) ;
}
2016-08-23 11:57:30 +08:00
static void iceland_stop_smc_clock ( struct pp_smumgr * smumgr )
2016-06-20 00:42:01 +08:00
{
SMUM_WRITE_INDIRECT_FIELD ( smumgr - > device , CGS_IND_REG__SMC ,
SMC_SYSCON_CLOCK_CNTL_0 ,
ck_disable , 1 ) ;
}
static void iceland_start_smc_clock ( struct pp_smumgr * smumgr )
{
SMUM_WRITE_INDIRECT_FIELD ( smumgr - > device , CGS_IND_REG__SMC ,
SMC_SYSCON_CLOCK_CNTL_0 ,
ck_disable , 0 ) ;
}
2016-08-23 11:57:30 +08:00
static int iceland_smu_start_smc ( struct pp_smumgr * smumgr )
2016-06-20 00:42:01 +08:00
{
/* set smc instruct start point at 0x0 */
2016-08-23 11:57:30 +08:00
smu7_program_jump_on_start ( smumgr ) ;
2016-06-20 00:42:01 +08:00
/* enable smc clock */
iceland_start_smc_clock ( smumgr ) ;
/* de-assert reset */
iceland_start_smc ( smumgr ) ;
SMUM_WAIT_INDIRECT_FIELD ( smumgr , SMC_IND , FIRMWARE_FLAGS ,
INTERRUPTS_ENABLED , 1 ) ;
return 0 ;
}
2016-08-23 11:57:30 +08:00
static int iceland_upload_smc_firmware_data ( struct pp_smumgr * smumgr ,
uint32_t length , const uint8_t * src ,
uint32_t limit , uint32_t start_addr )
2016-06-20 00:42:01 +08:00
{
2016-08-23 11:57:30 +08:00
uint32_t byte_count = length ;
2016-06-20 00:42:01 +08:00
uint32_t data ;
2016-08-23 11:57:30 +08:00
PP_ASSERT_WITH_CODE ( ( limit > = byte_count ) , " SMC address is beyond the SMC RAM area. " , return - EINVAL ) ;
cgs_write_register ( smumgr - > device , mmSMC_IND_INDEX_0 , start_addr ) ;
SMUM_WRITE_FIELD ( smumgr - > device , SMC_IND_ACCESS_CNTL , AUTO_INCREMENT_IND_0 , 1 ) ;
while ( byte_count > = 4 ) {
data = src [ 0 ] * 0x1000000 + src [ 1 ] * 0x10000 + src [ 2 ] * 0x100 + src [ 3 ] ;
cgs_write_register ( smumgr - > device , mmSMC_IND_DATA_0 , data ) ;
src + = 4 ;
byte_count - = 4 ;
}
SMUM_WRITE_FIELD ( smumgr - > device , SMC_IND_ACCESS_CNTL , AUTO_INCREMENT_IND_0 , 0 ) ;
PP_ASSERT_WITH_CODE ( ( 0 = = byte_count ) , " SMC size must be dividable by 4. " , return - EINVAL ) ;
return 0 ;
}
static int iceland_smu_upload_firmware_image ( struct pp_smumgr * smumgr )
{
uint32_t val ;
2016-06-20 00:42:01 +08:00
struct cgs_firmware_info info = { 0 } ;
if ( smumgr = = NULL | | smumgr - > device = = NULL )
return - EINVAL ;
/* load SMC firmware */
cgs_get_firmware_info ( smumgr - > device ,
2016-08-23 11:57:30 +08:00
smu7_convert_fw_type_to_cgs ( UCODE_ID_SMU ) , & info ) ;
2016-06-20 00:42:01 +08:00
if ( info . image_size & 3 ) {
pr_err ( " [ powerplay ] SMC ucode is not 4 bytes aligned \n " ) ;
return - EINVAL ;
}
if ( info . image_size > ICELAND_SMC_SIZE ) {
pr_err ( " [ powerplay ] SMC address is beyond the SMC RAM area \n " ) ;
return - EINVAL ;
}
/* wait for smc boot up */
SMUM_WAIT_INDIRECT_FIELD_UNEQUAL ( smumgr , SMC_IND ,
RCU_UC_EVENTS , boot_seq_done , 0 ) ;
/* clear firmware interrupt enable flag */
val = cgs_read_ind_register ( smumgr - > device , CGS_IND_REG__SMC ,
ixSMC_SYSCON_MISC_CNTL ) ;
cgs_write_ind_register ( smumgr - > device , CGS_IND_REG__SMC ,
ixSMC_SYSCON_MISC_CNTL , val | 1 ) ;
/* stop smc clock */
2016-08-23 11:57:30 +08:00
iceland_stop_smc_clock ( smumgr ) ;
2016-06-20 00:42:01 +08:00
/* reset smc */
2016-08-23 11:57:30 +08:00
iceland_reset_smc ( smumgr ) ;
iceland_upload_smc_firmware_data ( smumgr , info . image_size ,
( uint8_t * ) info . kptr , ICELAND_SMC_SIZE ,
info . ucode_start_address ) ;
2016-06-20 00:42:01 +08:00
return 0 ;
}
static int iceland_request_smu_load_specific_fw ( struct pp_smumgr * smumgr ,
uint32_t firmwareType )
{
return 0 ;
}
static int iceland_start_smu ( struct pp_smumgr * smumgr )
{
int result ;
result = iceland_smu_upload_firmware_image ( smumgr ) ;
if ( result )
return result ;
result = iceland_smu_start_smc ( smumgr ) ;
if ( result )
return result ;
2016-08-23 11:57:30 +08:00
if ( ! smu7_is_smc_ram_running ( smumgr ) ) {
2016-12-26 15:09:33 +08:00
pr_info ( " smu not running, upload firmware again \n " ) ;
2016-08-23 11:57:30 +08:00
result = iceland_smu_upload_firmware_image ( smumgr ) ;
if ( result )
return result ;
result = iceland_smu_start_smc ( smumgr ) ;
if ( result )
return result ;
}
result = smu7_request_smu_load_fw ( smumgr ) ;
2016-06-20 00:42:01 +08:00
return result ;
}
/**
* Write a 32 bit value to the SMC SRAM space .
* ALL PARAMETERS ARE IN HOST BYTE ORDER .
* @ param smumgr the address of the powerplay hardware manager .
* @ param smcAddress the address in the SMC RAM to access .
* @ param value to write to the SMC SRAM .
*/
static int iceland_smu_init ( struct pp_smumgr * smumgr )
{
2016-08-23 11:58:14 +08:00
int i ;
2016-12-29 15:23:44 +08:00
struct iceland_smumgr * iceland_priv = NULL ;
iceland_priv = kzalloc ( sizeof ( struct iceland_smumgr ) , GFP_KERNEL ) ;
if ( iceland_priv = = NULL )
return - ENOMEM ;
smumgr - > backend = iceland_priv ;
2016-08-23 11:58:14 +08:00
if ( smu7_init ( smumgr ) )
return - EINVAL ;
for ( i = 0 ; i < SMU71_MAX_LEVELS_GRAPHICS ; i + + )
2016-12-29 15:23:44 +08:00
iceland_priv - > activity_target [ i ] = 30 ;
2016-08-23 11:58:14 +08:00
return 0 ;
2016-06-20 00:42:01 +08:00
}
2016-12-29 15:23:44 +08:00
const struct pp_smumgr_func iceland_smu_funcs = {
2016-06-20 00:42:01 +08:00
. smu_init = & iceland_smu_init ,
2016-08-23 11:57:30 +08:00
. smu_fini = & smu7_smu_fini ,
2016-06-20 00:42:01 +08:00
. start_smu = & iceland_start_smu ,
2016-08-23 11:57:30 +08:00
. check_fw_load_finish = & smu7_check_fw_load_finish ,
. request_smu_load_fw = & smu7_reload_firmware ,
2016-06-20 00:42:01 +08:00
. request_smu_load_specific_fw = & iceland_request_smu_load_specific_fw ,
2016-08-23 11:57:30 +08:00
. send_msg_to_smc = & smu7_send_msg_to_smc ,
. send_msg_to_smc_with_parameter = & smu7_send_msg_to_smc_with_parameter ,
2016-06-20 00:42:01 +08:00
. download_pptable_settings = NULL ,
. upload_pptable_settings = NULL ,
2016-08-23 11:58:14 +08:00
. get_offsetof = iceland_get_offsetof ,
. process_firmware_header = iceland_process_firmware_header ,
. init_smc_table = iceland_init_smc_table ,
. update_sclk_threshold = iceland_update_sclk_threshold ,
. thermal_setup_fan_table = iceland_thermal_setup_fan_table ,
. populate_all_graphic_levels = iceland_populate_all_graphic_levels ,
. populate_all_memory_levels = iceland_populate_all_memory_levels ,
. get_mac_definition = iceland_get_mac_definition ,
. initialize_mc_reg_table = iceland_initialize_mc_reg_table ,
. is_dpm_running = iceland_is_dpm_running ,
2016-06-20 00:42:01 +08:00
} ;