예제 #1
0
/*
 * 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;
}
예제 #2
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;
}
예제 #3
0
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);
    }
예제 #4
0
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;
}
예제 #5
0
/*
 * 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);
}
예제 #6
0
파일: amdgpu_acp.c 프로젝트: 020gzh/linux
/* 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;
}
예제 #7
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;
}
예제 #8
0
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);
}
예제 #9
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 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);
}
예제 #10
0
파일: amdgpu_acp.c 프로젝트: 020gzh/linux
/* 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;
}
예제 #11
0
파일: smu_helper.c 프로젝트: krzk/linux
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);
}
예제 #12
0
파일: hwmgr.c 프로젝트: 020gzh/linux
/**
 * 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);
}
예제 #13
0
/*
 * 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;
}
예제 #14
0
파일: smu_helper.c 프로젝트: krzk/linux
/**
 * 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);
}
예제 #15
0
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;
}