/* * Send a message to the SMC with parameter * @param smumgr: the address of the powerplay hardware manager. * @param msg: the message to send. * @param parameter: the parameter to send * @return Always return 0. */ int vega10_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter) { uint32_t reg; if (!vega10_is_smc_ram_running(smumgr)) return -EINVAL; vega10_wait_for_response(smumgr); reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); cgs_write_register(smumgr->device, reg, 0); reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); cgs_write_register(smumgr->device, reg, parameter); vega10_send_msg_to_smc_without_waiting(smumgr, msg); if (vega10_wait_for_response(smumgr) != 1) pr_err("Failed to send message: 0x%x\n", msg); return 0; }
int smu7_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) { int result; if (PP_CAP(PHM_PlatformCaps_ODFuzzyFanControlSupport)) { cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY); result = smum_send_msg_to_smc(hwmgr, PPSMC_StartFanControl); if (PP_CAP(PHM_PlatformCaps_FanSpeedInTableIsRPM)) hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr, hwmgr->thermal_controller. advanceFanControlParameters.usMaxFanRPM); else hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr, hwmgr->thermal_controller. advanceFanControlParameters.usMaxFanPWM); } else { cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE); result = smum_send_msg_to_smc(hwmgr, PPSMC_StartFanControl); } if (!result && hwmgr->thermal_controller. advanceFanControlParameters.ucTargetTemperature) result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetFanTemperatureTarget, hwmgr->thermal_controller. advanceFanControlParameters.ucTargetTemperature); hwmgr->fan_ctrl_enabled = true; return result; }
static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr) { int result = 0; /* Wait for smc boot up */ /* SMUM_WAIT_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, RCU_UC_EVENTS, boot_seq_done, 0); */ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_RESET_CNTL, rst_reg, 1); result = smu7_upload_smu_firmware_image(smumgr); if (result) return result; /* Clear status */ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMU_STATUS, 0); SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); /* De-assert reset */ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_RESET_CNTL, rst_reg, 0); /* Wait for ROM firmware to initialize interrupt hendler */ /*SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND, SMC_INTR_CNTL_MASK_0, 0x10040, 0xFFFFFFFF); */ /* Set SMU Auto Start */ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_INPUT_DATA, AUTO_START, 1); /* Clear firmware interrupt enable flag */ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, ixFIRMWARE_FLAGS, 0); SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, RCU_UC_EVENTS, INTERRUPTS_ENABLED, 1); cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000); cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test); SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); /* Wait for done bit to be set */ SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, SMU_STATUS, SMU_DONE, 0); /* Check pass/failed indicator */ if (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_STATUS, SMU_PASS) != 1) { PP_ASSERT_WITH_CODE(false, "SMU Firmware start failed!", return -1); }
static int polaris10_setup_pwr_virus(struct pp_smumgr *smumgr) { int i; int result = -1; uint32_t reg, data; const PWR_Command_Table *pvirus = pwr_virus_table; struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); for (i = 0; i < PWR_VIRUS_TABLE_SIZE; i++) { switch (pvirus->command) { case PwrCmdWrite: reg = pvirus->reg; data = pvirus->data; cgs_write_register(smumgr->device, reg, data); break; case PwrCmdEnd: result = 0; break; default: printk("Table Exit with Invalid Command!"); smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL; result = -1; break; } pvirus++; } return result; }
/* * Send a message to the SMC with parameter, do not wait for response * @param smumgr: the address of the powerplay hardware manager. * @param msg: the message to send. * @param parameter: the parameter to send * @return The response that came from the SMC. */ int vega10_send_msg_to_smc_with_parameter_without_waiting( struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter) { uint32_t reg; reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); cgs_write_register(smumgr->device, reg, parameter); return vega10_send_msg_to_smc_without_waiting(smumgr, msg); }
/* power off a tile/block within ACP */ static int acp_suspend_tile(void *cgs_dev, int tile) { u32 val = 0; u32 count = 0; if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) { pr_err("Invalid ACP tile : %d to suspend\n", tile); return -1; } val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); val &= ACP_TILE_ON_MASK; if (val == 0x0) { val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); val = val | (1 << tile); cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG, 0x500 + tile); count = ACP_TIMEOUT_LOOP; while (true) { val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); val = val & ACP_TILE_ON_MASK; if (val == ACP_TILE_OFF_MASK) break; if (--count == 0) { pr_err("Timeout reading ACP PGFSM status\n"); return -ETIMEDOUT; } udelay(100); } val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); val |= ACP_TILE_OFF_RETAIN_REG_MASK; cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); } return 0; }
static int polaris10_perform_btc(struct pp_smumgr *smumgr) { int result = 0; struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); if (0 != smu_data->avfs.avfs_btc_param) { if (0 != smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) { printk("[AVFS][SmuPolaris10_PerformBtc] PerformBTC SMU msg failed"); result = -1; } } if (smu_data->avfs.avfs_btc_param > 1) { /* Soft-Reset to reset the engine before loading uCode */ /* halt */ cgs_write_register(smumgr->device, mmCP_MEC_CNTL, 0x50000000); /* reset everything */ cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0xffffffff); cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0); } return result; }
void smum_wait_for_indirect_register_unequal( struct pp_smumgr *smumgr, uint32_t indirect_port, uint32_t index, uint32_t value, uint32_t mask) { if (smumgr == NULL || smumgr->device == NULL) return; cgs_write_register(smumgr->device, indirect_port, index); smum_wait_for_register_unequal(smumgr, indirect_port + 1, value, mask); }
/* * Returns once the part of the register indicated by the mask * has reached the given value.The indirect space is described by * giving the memory-mapped index of the indirect index register. */ int smum_wait_on_indirect_register(struct pp_smumgr *smumgr, uint32_t indirect_port, uint32_t index, uint32_t value, uint32_t mask) { if (smumgr == NULL || smumgr->device == NULL) return -EINVAL; cgs_write_register(smumgr->device, indirect_port, index); return smum_wait_on_register(smumgr, indirect_port + 1, mask, value); }
/* power on a tile/block within ACP */ static int acp_resume_tile(void *cgs_dev, int tile) { u32 val = 0; u32 count = 0; if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) { pr_err("Invalid ACP tile to resume\n"); return -1; } val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); val = val & ACP_TILE_ON_MASK; if (val != 0x0) { cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG, 0x600 + tile); count = ACP_TIMEOUT_LOOP; while (true) { val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); val = val & ACP_TILE_ON_MASK; if (val == 0x0) break; if (--count == 0) { pr_err("Timeout reading ACP PGFSM status\n"); return -ETIMEDOUT; } udelay(100); } val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); if (tile == ACP_TILE_P1) val = val & (ACP_TILE_P1_MASK); else if (tile == ACP_TILE_P2) val = val & (ACP_TILE_P2_MASK); cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); } return 0; }
int phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr, uint32_t indirect_port, uint32_t index, uint32_t value, uint32_t mask) { if (hwmgr == NULL || hwmgr->device == NULL) return -EINVAL; cgs_write_register(hwmgr->device, indirect_port, index); return phm_wait_for_register_unequal(hwmgr, indirect_port + 1, value, mask); }
/** * Returns once the part of the register indicated by the mask has * reached the given value.The indirect space is described by giving * the memory-mapped index of the indirect index register. */ void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, uint32_t indirect_port, uint32_t index, uint32_t value, uint32_t mask) { if (hwmgr == NULL || hwmgr->device == NULL) { printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!"); return; } cgs_write_register(hwmgr->device, indirect_port, index); phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); }
/* * Send a message to the SMC, and do not wait for its response. * @param smumgr the address of the powerplay hardware manager. * @param msg the message to send. * @return Always return 0. */ int vega10_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg) { uint32_t reg; if (!vega10_is_smc_ram_running(smumgr)) return -EINVAL; reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); cgs_write_register(smumgr->device, reg, msg); return 0; }
/** * Returns once the part of the register indicated by the mask has * reached the given value.The indirect space is described by giving * the memory-mapped index of the indirect index register. */ int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, uint32_t indirect_port, uint32_t index, uint32_t value, uint32_t mask) { if (hwmgr == NULL || hwmgr->device == NULL) { pr_err("Invalid Hardware Manager!"); return -EINVAL; } cgs_write_register(hwmgr->device, indirect_port, index); return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); }
static bool vega10_is_smc_ram_running(struct pp_smumgr *smumgr) { uint32_t mp1_fw_flags, reg; reg = soc15_get_register_offset(NBIF_HWID, 0, mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2); cgs_write_register(smumgr->device, reg, (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); reg = soc15_get_register_offset(NBIF_HWID, 0, mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2); mp1_fw_flags = cgs_read_register(smumgr->device, reg); if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) return true; return false; }