Exemple #1
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		lib54xx_voltage_set
 * @BRIEF		change voltage of a given voltage domain, switching
 *			CPUFreq governor to "userspace" & disabling smart-reflex
 * @RETURNS		0 on success
 *			OMAPCONF_ERR_CPU
 *			OMAPCONF_ERR_ARG
 *			OMAPCONF_ERR_NOT_AVAILABLE
 *			OMAPCONF_ERR_REG_ACCESS
 *			OMAPCONF_ERR_INTERNAL
 * @param[in]		vdd_id: voltage domain ID
 * @param[in]		volt: new supply voltage (in volt)
 * @DESCRIPTION		change voltage of a given voltage domain, switching
 *			CPUFreq governor to "userspace" & disabling smart-reflex
 *//*------------------------------------------------------------------------ */
int lib54xx_voltage_set(voltdm54xx_id vdd_id, double volt)
{
	int ret, ret_cpufreq;
	char prev_gov[CPUFREQ_GOV_MAX_NAME_LENGTH];
	sr54xx_mod_id sr_id;

	CHECK_CPU(54xx, OMAPCONF_ERR_CPU);
	CHECK_ARG_LESS_THAN(vdd_id, VDD54XX_ID_MAX, OMAPCONF_ERR_ARG);

	/*
	 * Switch governor to 'userspace' otherwise voltage change will be
	 * overriden in case of OPP change.
	 */
	printf("Warning: switching CPUFreq governor to 'userspace', otherwise "
		"voltage change will be overriden...\n");
	ret_cpufreq = cpufreq_scaling_governor_set("userspace", prev_gov);
	if (ret_cpufreq < 0)
		printf("Warning: failed to switch governor. Voltage will be "
			"overriden in case of OPP change.\n");
	else
		printf("CPUFreq governor switched to 'userspace'.\n");
	/*
	 * Disable Smart-Reflex (if running) otherwise voltage change will be
	 * overriden.
	 */
	sr_id = sr54xx_vddid2srid(vdd_id);
	if (sr54xx_avs_is_enabled(sr_id)) {
		printf("Warning: %s Smart-Reflex AVS is enabled. "
			"Disabling it...\n", voltdm54xx_name_get(vdd_id));
		ret = sr54xx_avs_enable(sr_id, 0);
		if (ret == 0)
			printf("Smartreflex disabled.\n\n");
		else
			printf("Warning: Could not disable Smart-Reflex AVS. "
				"Voltage may be overriden.\n\n");
	} else {
		printf("Smartreflex disabled.\n\n");
	}

	ret = voltdm54xx_voltage_set(vdd_id,
		(unsigned long) (volt * 1000000));
	if (ret != 0) {
		fprintf(stderr, "Oups, could not change %s voltage to "
			"%.3lfV ... (%d)\n\n",
			voltdm54xx_name_get(vdd_id), volt, ret);
	} else {
		printf("%s supply voltage set to %1.3lfV (vsel = 0x%02X).\n\n",
			voltdm54xx_name_get(vdd_id), volt,
			smps_uvolt2vsel(vdd_id2smps_id(vdd_id),
				(unsigned long) (volt * 1000000)));
		printf("Warning:\n"
			"  - Do not re-enable %s smartreflex or new voltage "
			"will be overriden.\n"
			"  - Do not change OPP (or use CPUFREQ) or new voltage"
			" will be overriden.\n\n", voltdm54xx_name_get(vdd_id));
	}

	return ret;
}
Exemple #2
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		voltdm54xx_opp_get
 * @BRIEF		find the current voltage domain OPP
 * @RETURNS		valid OPP ID in case of success
 *			OPP54XX_ID_MAX in case of error
 * @param[in]		id: voltage domain ID
 * @DESCRIPTION		find the current voltage domain OPP
 *//*------------------------------------------------------------------------ */
opp54xx_id voltdm54xx_opp_get(voltdm54xx_id id)
{
	opp54xx_id opp_id;
	double volt = 0.0, volt_por = 0.0;

	CHECK_CPU(54xx, OPP54XX_ID_MAX);
	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, OPP54XX_ID_MAX);

	if (id == VDD54XX_WKUP) {
		/* Only 1 OPP for WKUP voltage domain */
		opp_id = OPP54XX_NOM;
	} else {
		/*
		 * In VDD_MM there are 3 independent modules (GPU, IVA, DSP)
		 * that may be running at different clock rates.
		 * Furthermore, these modules may or may not be running, so
		 * module's clock rate may not be relevant.
		 * Use nominal voltage instead.
		 */
		volt = voltdm54xx_nominal_voltage_get(id);
		if (volt < 0.0)
			return OPP54XX_ID_MAX;

		dprintf("%s(%s): nominal voltage is %lfV\n", __func__,
			voltdm54xx_name_get(id), volt);

		for (opp_id = OPP54XX_DPLL_CASC; opp_id < OPP54XX_ID_MAX;
			opp_id++) {
			volt_por = voltdm54xx_por_nominal_voltage_get(
				id, opp_id);
			if (volt_por < 0.0)
				return OPP54XX_ID_MAX;
			dprintf("%s(%s): POR nominal voltage for %s is %lfV\n",
				__func__, voltdm54xx_name_get(id),
				opp54xx_name_get(opp_id), volt_por);
			if (volt == volt_por)
				break;
		}
	}

	#ifdef VOLTDM54XX_DEBUG
	if (opp_id != OPP54XX_ID_MAX) {
		dprintf("%s(%s): OPP found: %s\n", __func__,
			voltdm54xx_name_get(id), opp54xx_name_get(opp_id));
	} else {
		dprintf("%s(%s): OPP not found!\n", __func__,
			voltdm54xx_name_get(id));
	}
	#endif

	return opp_id;
}
Exemple #3
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		voltdm54xx_voltage_get
 * @BRIEF		find the current supply voltage of a domain
 * @RETURNS		supply voltage in case of success (>= 0.0)
 *			OMAPCONF_ERR_ARG
 *			OMAPCONF_ERR_CPU
 *			OMAPCONF_ERR_REG_ACCESS
 *			OMAPCONF_ERR_NOT_AVAILABLE
 * @param[in]		id: valid voltage domain ID
 * @DESCRIPTION		find the current supply voltage of a domain,
 *			taking care of the voltage domain state
 *			(ON/ON_LP/RET/OFF)
 *			NB: use PRCM VP VOLTAGE register to retrieve ON voltage.
 *			Hence SR/VP/VC have to be at least initialized
 *			(SR could be disabled)
 *//*------------------------------------------------------------------------ */
double voltdm54xx_voltage_get(voltdm54xx_id id)
{
	double volt;

	CHECK_CPU(54xx, (double) OMAPCONF_ERR_CPU);
	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, (double) OMAPCONF_ERR_ARG);

	switch (id) {
	case VDD54XX_WKUP:
		return (double) OMAPCONF_ERR_NOT_AVAILABLE;

	case VDD54XX_MPU:
		volt = smps_voltage_get(PMIC_SMPS_MPU);
		break;
	case VDD54XX_MM:
		volt = smps_voltage_get(PMIC_SMPS_MM);
		break;
	case VDD54XX_CORE:
		volt = smps_voltage_get(PMIC_SMPS_CORE);
		break;

	default:
		return (double) OMAPCONF_ERR_ARG;
	}

	dprintf("%s(%s): volt=%lfV\n", __func__, voltdm54xx_name_get(id), volt);

	return volt;
}
Exemple #4
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		voltdm54xx_nominal_voltage_get
 * @BRIEF		return the nominal voltage of a given voltage domain
 * @RETURNS		supply voltage in case of success (>= 0.0)
 *			OMAPCONF_ERR_ARG
 *			OMAPCONF_ERR_CPU
 *			OMAPCONF_ERR_NOT_AVAILABLE
 * @param[in]		id: valid voltage domain ID
 * @DESCRIPTION		return the nominal voltage of a given voltage domain.
 *//*------------------------------------------------------------------------ */
double voltdm54xx_nominal_voltage_get(voltdm54xx_id id)
{
	int ret;
	double volt;
	vc54xx_registers vc_regs;
	unsigned char cmd_on, cmd_onlp, cmd_ret, cmd_off;

	CHECK_CPU(54xx, (double) OMAPCONF_ERR_CPU);
	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, (double) OMAPCONF_ERR_ARG);

	ret = vc54xx_registers_get(&vc_regs);
	if (ret != 0)
		return (double) ret;
	ret = vc54xx_cmd_values_get(id, &vc_regs,
			&cmd_on, &cmd_onlp, &cmd_ret, &cmd_off);
	if (ret != 0)
		return (double) ret;

	volt = smps_vsel2volt(vdd_id2smps_id(id), cmd_on);

	dprintf("%s(%s): nominal volt=%lfV\n", __func__,
		voltdm54xx_name_get(id), volt);

	return volt;
}
Exemple #5
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		vr54xx_vsel2volt
 * @BRIEF		for a given rail, convert SMPS vsel command into voltage
 *			(in VOLTS).
 * @RETURNS		voltage in VOLTS corresponding to SMPS vsel command
 * @param[in]		id: voltage rail
 * @param[in]		vsel: SMPS vsel command
 * @DESCRIPTION		for a given rail, convert SMPS vsel command into voltage
 *			(in VOLTS).
 *//*------------------------------------------------------------------------ */
double vr54xx_vsel2volt(voltdm54xx_id id, unsigned char vsel)
{
	double volt;

	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, 0);

	volt = (double) vr54xx_vsel2uv(id, vsel);
	volt /= (double) 1000000.0;

	dprintf("%s(%s, 0x%X) = %lfV\n", __func__,
		voltdm54xx_name_get(id), vsel, volt);

	return volt;
}
Exemple #6
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		vr54xx_vsel2uv
 * @BRIEF		for a given rail, convert SMPS vsel command into voltage
 *			in microvolts.
 * @RETURNS		voltage in microvolts corresponding to SMPS vsel command
 * @param[in]		id: valid voltage rail
 * @param[in]		vsel: SMPS vsel command
 * @DESCRIPTION		for a given rail, convert SMPS vsel command into voltage
 *			in microvolts.
 *//*------------------------------------------------------------------------ */
unsigned long vr54xx_vsel2uv(voltdm54xx_id id, unsigned char vsel)
{
	unsigned long uv = 0;

	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, 0);

	dprintf("%s(%s, 0x%X) = %luuV\n", __func__,
		voltdm54xx_name_get(id), vsel, uv);
	/* FIXME */
	/* just to remove "unused parameter" warnings ... */
	vsel = vsel;

	return uv;
}
Exemple #7
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		voltdm54xx_por_nominal_voltage_get
 * @BRIEF		return the Plan of Record (POR) nominal voltage
 *			of a given voltage domain for a given OPP.
 * @RETURNS		supply voltage in case of success (>= 0.0)
 *			OMAPCONF_ERR_ARG
 *			OMAPCONF_ERR_CPU
 * @param[in]		id: valid voltage domain ID
 * @DESCRIPTION		return the Plan of Record (POR) nominal voltage
 *			of a given voltage domain for a given OPP.
 *//*------------------------------------------------------------------------ */
double voltdm54xx_por_nominal_voltage_get(voltdm54xx_id id, opp54xx_id opp_id)
{
	double volt;

	CHECK_CPU(54xx, (double) OMAPCONF_ERR_CPU);
	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, (double) OMAPCONF_ERR_ARG);
	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, (double) OMAPCONF_ERR_ARG);

	volt = voltdm54xx_por_nominal_voltages_table_es1[id][opp_id];

	dprintf("%s(%s): %s POR nominal volt=%lfV\n", __func__,
		opp54xx_name_get(opp_id),
		voltdm54xx_name_get(id), volt);

	return volt;
}
Exemple #8
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		smps_id2vdd_id
 * @BRIEF		convert SMPS ID into VDD ID (for a given platform)
 * @RETURNS		valid VDD ID in case of success
 *			OMAP4_VD_ID_MAX in case of error (OMAP4)
 *			VDD54XX_ID_MAX in case of error (OMAP5)
 * @param[in]		smps_id: valid SMPS ID
 * @DESCRIPTION		convert SMPS ID into VDD ID (for a given platform)
 *//*------------------------------------------------------------------------ */
unsigned short smps_id2vdd_id(pmic_smps_id smps_id)
{
	unsigned short vdd_id;
	char name[16];

	switch (cpu_get()) {
	case OMAP_4430:
	case OMAP_4460:
	case OMAP_4470:
		if (smps_id > PMIC_SMPS_ID_MAX) {
			fprintf(stderr, "%s(): incorrect smps_id! (%u)\n",
				__func__, smps_id);
			vdd_id =  (unsigned short) OMAP4_VD_ID_MAX;
			strncpy(name, "FIXME", 16);
		} else {
			vdd_id = smps_id + 1;
			voltdm44xx_get_name(vdd_id, name);
		}
		break;

	case OMAP_5430:
	case OMAP_5432:
		if (smps_id > PMIC_SMPS_ID_MAX) {
			fprintf(stderr, "%s(): incorrect smps_id! (%u)\n",
				__func__, smps_id);
			vdd_id =  (unsigned short) VDD54XX_ID_MAX;
			strncpy(name, "FIXME", 16);

		} else {
			vdd_id = smps_id + 1;
			strncpy(name, voltdm54xx_name_get(vdd_id), 16);
		}
		break;
	case DRA_75X:
		if (smps_id > PMIC_SMPS_ID_MAX) {
			fprintf(stderr, "%s(): incorrect smps_id! (%u)\n",
				__func__, smps_id);
			vdd_id =  (unsigned short) VDD_DRA7XX_ID_MAX;
			strncpy(name, "FIXME", 16);

		} else {
			switch (smps_id) {
			case PMIC_SMPS_MPU:
				vdd_id = VDD_DRA7XX_MPU;
				break;
			case PMIC_SMPS_CORE:
				vdd_id = VDD_DRA7XX_CORE;
				break;
			case PMIC_SMPS_MM:
				vdd_id = VDD_DRA7XX_IVA;
				break;
			case PMIC_SMPS_DSPEVE:
				vdd_id = VDD_DRA7XX_DSPEVE;
				break;
			case PMIC_SMPS_GPU:
				vdd_id = VDD_DRA7XX_GPU;
				break;
			default:
				vdd_id = VDD_DRA7XX_ID_MAX;
			}
			strncpy(name, voltdm54xx_name_get(vdd_id), 16);
		}
		break;

	case AM_3352:
	case AM_3354:
	case AM_3356:
	case AM_3357:
	case AM_3358:
	case AM_3359:
		if (smps_id > PMIC_SMPS_ID_MAX) {
			fprintf(stderr, "%s(): incorrect smps_id! (%u)\n",
				__func__, smps_id);
			vdd_id =  (unsigned short) VDD_AM335X_ID_MAX;
			strncpy(name, "FIXME", 16);

		} else {
			switch (smps_id) {
			case PMIC_SMPS_MPU:
				vdd_id = VDD_AM335X_MPU;
				break;
			case PMIC_SMPS_CORE:
				vdd_id = VDD_AM335X_CORE;
				break;
			default:
				vdd_id = VDD_AM335X_ID_MAX;
			}
			strncpy(name, voltdm_am335x_name_get(vdd_id), 16);
		}
		break;

	default:
		fprintf(stderr, "%s(): unsupported CPU! (%s)\n",
			__func__, cpu_gets(name));
		vdd_id = (unsigned short) VDD54XX_ID_MAX;
		strncpy(name, "FIXME", 16);
	}

	dprintf("%s(): smps_id=%s => vdd_id=%s\n", __func__,
		smps_name_get(smps_id), name);

	return vdd_id;
}
Exemple #9
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		vdd_id2smps_id
 * @BRIEF		convert VDD ID into SMPS ID (for a given platform)
 * @RETURNS		valid SMPS ID in case of success
 *			PMIC_SMPS_ID_MAX in case of error
 * @param[in]		vdd_id: valid VDD ID
 * @DESCRIPTION		convert VDD ID into SMPS ID (for a given platform)
 *//*------------------------------------------------------------------------ */
pmic_smps_id vdd_id2smps_id(unsigned short vdd_id)
{
	pmic_smps_id smps_id;
	char smps_name[16];
	char vdd_name[16];

	switch (cpu_get()) {
	case OMAP_4430:
	case OMAP_4460:
	case OMAP_4470:
		voltdm44xx_get_name(vdd_id, vdd_name);
		if ((vdd_id == OMAP4_LDO_WKUP) || (vdd_id > OMAP4_VDD_CORE)) {
			fprintf(stderr, "%s(): incorrect vdd_id! (%u)\n",
				__func__, vdd_id);
			smps_id =  PMIC_SMPS_ID_MAX;
			strncpy(smps_name, "FIXME", 16);
		} else {
			smps_id = vdd_id - 1;
			strncpy(smps_name, smps_name_get(smps_id), 16);
		}
		break;

	case OMAP_5430:
	case OMAP_5432:
		strncpy(vdd_name, voltdm54xx_name_get(vdd_id), 16);
		if ((vdd_id == VDD54XX_WKUP) || (vdd_id > VDD54XX_CORE)) {
			fprintf(stderr, "%s(): incorrect vdd_id! (%u)\n",
				__func__, vdd_id);
			smps_id =  PMIC_SMPS_ID_MAX;
			strncpy(smps_name, "FIXME", 16);
		} else {
			smps_id = vdd_id - 1;
			strncpy(smps_name, smps_name_get(smps_id), 16);
		}
		break;
	case DRA_75X:
		strncpy(vdd_name, voltdm_dra7xx_name_get(vdd_id), 16);
		if (vdd_id > VDD_DRA7XX_RTC) {
			fprintf(stderr, "%s(): incorrect vdd_id! (%u)\n",
				__func__, vdd_id);
			smps_id =  PMIC_SMPS_ID_MAX;
			strncpy(smps_name, "FIXME", 16);
		} else {
			switch (vdd_id) {
			case VDD_DRA7XX_MPU:
				smps_id = PMIC_SMPS_MPU;
				break;
			case VDD_DRA7XX_CORE:
				smps_id = PMIC_SMPS_CORE;
				break;
			case VDD_DRA7XX_IVA:
				smps_id = PMIC_SMPS_MM;
				break;
			case VDD_DRA7XX_DSPEVE:
				smps_id = PMIC_SMPS_DSPEVE;
				break;
			case VDD_DRA7XX_GPU:
				smps_id = PMIC_SMPS_GPU;
				break;
			default:
				smps_id = PMIC_SMPS_ID_MAX;
			}
			strncpy(smps_name, smps_name_get(smps_id), 16);
		}
		break;

	case AM_3352:
	case AM_3354:
	case AM_3356:
	case AM_3357:
	case AM_3358:
	case AM_3359:
		strncpy(vdd_name, voltdm_am335x_name_get(vdd_id), 16);
		if (vdd_id > VDD_AM335X_RTC) {
			fprintf(stderr, "%s(): incorrect vdd_id! (%u)\n",
				__func__, vdd_id);
			smps_id =  PMIC_SMPS_ID_MAX;
			strncpy(smps_name, "FIXME", 16);
		} else {
			switch (vdd_id) {
			case VDD_AM335X_MPU:
				smps_id = PMIC_SMPS_MPU;
				break;
			case VDD_AM335X_CORE:
				smps_id = PMIC_SMPS_CORE;
				break;
			default:
				smps_id = PMIC_SMPS_ID_MAX;
			}
			strncpy(smps_name, smps_name_get(smps_id), 16);
		}
		break;

	default:
		fprintf(stderr, "%s(): unsupported CPU! (%s)\n",
			__func__, cpu_gets(smps_name));
		smps_id =  PMIC_SMPS_ID_MAX;
		strncpy(smps_name, "FIXME", 16);
	}

	dprintf("%s(): vdd_id=%s => smps_id=%s\n", __func__,
		vdd_name, smps_name);

	return smps_id;
}
Exemple #10
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		opp54xx_init
 * @BRIEF		initialize internal data
 * @DESCRIPTION		initialize internal data (architecture dependent)
 *//*------------------------------------------------------------------------ */
void opp54xx_init(void)
{
	opp_t opp;

	/* ES1.0 */
	static const opp_t mpu_opp_low_es1  = {OPP_LOW,	 950000,  400000};
	static const opp_t mpu_opp_nom_es1  = {OPP_NOM,	 1040000, 800000};
	static const opp_t mpu_opp_high_es1 = {OPP_HIGH, 1220000, 1100000};

	static const opp_t mm_opp_low_es1 =  {OPP_LOW,	950000,  177333};
	static const opp_t mm_opp_nom_es1 =  {OPP_NOM,	1040000, 354667};
	static const opp_t mm_opp_high_es1 = {OPP_HIGH,	1220000, 532000};

	static const opp_t core_opp_low_es1 = {OPP_LOW,	950000,  133000};
	static const opp_t core_opp_nom_es1 = {OPP_NOM,	1040000, 2660000};

	/* ES2.0 */
	static const opp_t mpu_opp_low  = {OPP_LOW,	880000,  500000};
	static const opp_t mpu_opp_nom  = {OPP_NOM,	1060000, 1000000};
	static const opp_t mpu_opp_high = {OPP_HIGH,	1250000, 1500000};
	static const opp_t mpu_opp_sb =   {OPP_SB,	1290000, 1700000};

	static const opp_t mm_opp_low =  {OPP_LOW,	880000,  195000};
	static const opp_t mm_opp_nom =  {OPP_NOM,	1030000, 389000};
	static const opp_t mm_opp_high = {OPP_HIGH,	1120000, 532000};

	static const opp_t core_opp_low = {OPP_LOW,	880000,  133000};
	static const opp_t core_opp_nom = {OPP_NOM,	1040000, 2660000};

	#ifdef OPP54XX_DEBUG
	int i, count;
	voltdm54xx_id vdd;
	#endif

	if (!opp54xx_init_done) {
		genlist_init(&vdd54xx_wkup_opp_list);
		opp.name = OPP_NOM;
		opp.voltage = 1.0;
		opp.rate = clk54xx_sysclk_rate_get();
		genlist_addtail(&vdd54xx_wkup_opp_list,
			(void *) &opp, sizeof(opp_t));

		genlist_init(&vdd54xx_mpu_opp_list);
		if (cpu_revision_get() == REV_ES1_0) {
			genlist_addtail(&vdd54xx_mpu_opp_list,
				(void *) &mpu_opp_low_es1, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mpu_opp_list,
				(void *) &mpu_opp_nom_es1, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mpu_opp_list,
				(void *) &mpu_opp_high_es1, sizeof(opp_t));

			genlist_init(&vdd54xx_mm_opp_list);
			genlist_addtail(&vdd54xx_mm_opp_list,
				(void *) &mm_opp_low_es1, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mm_opp_list,
				(void *) &mm_opp_nom_es1, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mm_opp_list,
				(void *) &mm_opp_high_es1, sizeof(opp_t));

			genlist_init(&vdd54xx_core_opp_list);
			genlist_addtail(&vdd54xx_core_opp_list,
				(void *) &core_opp_low_es1, sizeof(opp_t));
			genlist_addtail(&vdd54xx_core_opp_list,
				(void *) &core_opp_nom_es1, sizeof(opp_t));
		} else {
			genlist_addtail(&vdd54xx_mpu_opp_list,
				(void *) &mpu_opp_low, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mpu_opp_list,
				(void *) &mpu_opp_nom, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mpu_opp_list,
				(void *) &mpu_opp_high, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mpu_opp_list,
				(void *) &mpu_opp_sb, sizeof(opp_t));

			genlist_init(&vdd54xx_mm_opp_list);
			genlist_addtail(&vdd54xx_mm_opp_list,
				(void *) &mm_opp_low, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mm_opp_list,
				(void *) &mm_opp_nom, sizeof(opp_t));
			genlist_addtail(&vdd54xx_mm_opp_list,
				(void *) &mm_opp_high, sizeof(opp_t));

			genlist_init(&vdd54xx_core_opp_list);
			genlist_addtail(&vdd54xx_core_opp_list,
				(void *) &core_opp_low, sizeof(opp_t));
			genlist_addtail(&vdd54xx_core_opp_list,
				(void *) &core_opp_nom, sizeof(opp_t));
		}

		opp54xx_init_done = 1;
		#ifdef OPP54XX_DEBUG
		printf("%s(): init done.\n", __func__);
		printf("OPP List:\n");
		for (vdd = VDD54XX_WKUP; vdd <= VDD54XX_CORE; vdd++) {
			count = genlist_getcount(
				(genlist *) opp54xx_list_table_es1[vdd]);
			printf("  %s (%d): ", voltdm54xx_name_get(vdd), count);
			for (i = 0; i < count; i++) {
				genlist_get(
					(genlist *) opp54xx_list_table_es1[vdd],
					i, (void *) &opp);
				printf("%s (%.1lfMHz, %.3lfV)",
					opp.name, khz2mhz(opp.rate),
					uv2v(opp.voltage));
				if (i != count - 1)
					printf(", ");
			}
			printf(".\n");
		}
		#endif
	}
}
Exemple #11
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		opp54xx_by_rate_get
 * @BRIEF		return the current voltage domain OPP name,
 *			searched by clock rates.
 * @RETURNS		current voltage domain OPP name (as defined in opp.h)
 *			NULL pointer in case of error or not found
 * @param[in]		vdd_id: voltage domain ID
 * @DESCRIPTION		return the current voltage domain OPP name,
 *			searched by clock rates.
 *//*------------------------------------------------------------------------ */
const char *opp54xx_by_rate_get(voltdm54xx_id vdd_id)
{
	const char *opp_name = NULL;
	int opp_id;
	const char *module_name;
	double rate = 0.0, rate_por = 0.0;
	double rate_dsp = 0.0, rate_dsp_por = 0.0;
	double rate_gpu = 0.0, rate_gpu_por = 0.0;
	opp_t opp;
	const genlist *opp_list;
	int i, ret, opp_count;

	CHECK_CPU(54xx, NULL);
	CHECK_ARG_LESS_THAN(vdd_id, VDD54XX_ID_MAX, NULL);

	/*
	 * Determine current OPPs by getting MPU / IVA / L3 / SARRAM rate
	 * and comparing it to POR rate.
	 */
	switch (vdd_id) {
	case VDD54XX_WKUP:
		module_name = MOD_L4_WKUP_INTERCONNECT;
		break;

	case VDD54XX_MPU:
		module_name = MOD_MPU;
		break;

	case VDD54XX_MM:
		module_name = MOD_IVA;
		break;

	case VDD54XX_CORE:
		module_name = MOD_L3_MAIN1_INTERCONNECT;
		break;

	default:
		return NULL;
	}

	/*
	 * If the DPLL clocking the selected module is stopped,
	 * reported speed will be 0 and OPP cannot be detected.
	 * Hence, ignore DPLL status.
	 */
	rate = (double) module_clk_rate_get(module_name, 1) / 1000.0;
	if (rate < 0.0) {
		dprintf("%s(): could not retrieve clock speed!\n", __func__);
		goto opp54xx_by_rate_get_end;
	}
	dprintf("%s(%s): %s rate is %lfMHz\n", __func__,
		voltdm54xx_name_get(vdd_id),
		clk54xx_name_get(module_clk_get(module_name)), rate);
	if (vdd_id == VDD54XX_MM) {
		rate_dsp = (double) module_clk_rate_get(MOD_DSP, 1) / 1000.0;
		if (rate_dsp < 0.0) {
			dprintf("%s(): could not retrieve clock speed!\n",
				__func__);
			goto opp54xx_by_rate_get_end;
		}
		dprintf("%s(%s): DSP rate is %lfMHz\n", __func__,
			voltdm54xx_name_get(vdd_id), rate_dsp);
		rate_gpu = (double) module_clk_rate_get(MOD_GPU, 1) / 1000.0;
		if (rate_gpu < 0.0) {
			dprintf("%s(): could not retrieve clock speed!\n",
				__func__);
			goto opp54xx_by_rate_get_end;
		}
		dprintf("%s(%s): GPU rate is %lfMHz\n", __func__,
			voltdm54xx_name_get(vdd_id), rate_gpu);
	}

	opp_list = opp54xx_list_get(vdd_id);
	if (opp_list == NULL) {
		dprintf("%s(): could not retrieve OPP list!\n", __func__);
		goto opp54xx_by_rate_get_end;
	}

	opp_count = opp54xx_count_get(vdd_id);
	if (opp_count <= 0) {
		dprintf("%s(): could not retrieve OPP count!\n", __func__);
		goto opp54xx_by_rate_get_end;
	}


	for (i = 0; i < opp_count; i++) {
		ret = genlist_get((genlist *) opp_list, i, (opp_t *) &opp);
		if (ret != 0) {
			dprintf("%s(): could not retrieve OPP from list!\n",
				__func__);
			goto opp54xx_by_rate_get_end;
		}

		opp_id = opp54xx_id_get(opp.name);
		if (opp_id < 0) {
			dprintf(
				"%s(): could not retrieve OPP ID from OPP name!\n",
				__func__);
			goto opp54xx_by_rate_get_end;
		}

		rate_por = (double) module_por_clk_rate_get(module_name, opp.name) / 1000.0;
		if (rate_por < 0) {
			dprintf(
				"%s(): could not get %s %s POR speed! (%d)\n",
				__func__, module_name,
				opp.name, ret);
			goto opp54xx_by_rate_get_end;
		}
		dprintf("%s(%s): %s POR rate for %s is %lf\n",
			__func__, voltdm54xx_name_get(vdd_id),
			module_name, opp.name, rate_por);
		if (vdd_id == VDD54XX_MM) {
			rate_dsp_por =
				(double) module_por_clk_rate_get(MOD_DSP, opp.name) / 1000.0;
			if (rate_dsp_por < 0) {
				dprintf(
					"%s(): could not get DSP %s POR speed! (%d)\n",
					__func__, opp.name, ret);
				goto opp54xx_by_rate_get_end;
			}
			dprintf("%s(%s): DSP POR rate for %s is %lf\n",
				__func__, voltdm54xx_name_get(vdd_id),
				opp.name, rate_dsp_por);
			rate_gpu_por =
				(double) module_por_clk_rate_get(MOD_GPU, opp.name) / 1000.0;
			if (rate_gpu_por < 0) {
				dprintf(
					"%s(): could not get GPU %s POR speed! (%d)\n",
					__func__, opp.name, ret);
				goto opp54xx_by_rate_get_end;
			}
			dprintf("%s(%s): GPU POR rate for %s is %lf\n",
				__func__, voltdm54xx_name_get(vdd_id),
				opp.name, rate_gpu_por);

			if (((int) rate <= (int) rate_por) &&
				 ((int) rate_dsp <= (int) rate_dsp_por) &&
				 ((int) rate_gpu <= (int) rate_gpu_por)) {
				opp_name = opp.name;
				goto opp54xx_by_rate_get_end;
			}
		} else {
			if ((int) rate <= (int) rate_por) {
				opp_name = opp.name;
				goto opp54xx_by_rate_get_end;
			}
		}
	}

	dprintf("%s(%s): OPP not found!\n",
		__func__, voltdm54xx_name_get(vdd_id));

opp54xx_by_rate_get_end:
	#ifdef OPP54XX_DEBUG
	if (opp_name == NULL)
		printf("%s(%s): OPP not found!\n", __func__,
			voltdm54xx_name_get(vdd_id));
	else
		printf("%s(%s): OPP found: %s\n", __func__,
			voltdm54xx_name_get(vdd_id), opp_name);
	#endif
	return opp_name;
}
Exemple #12
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		lib54xx_vminsearch
 * @BRIEF		search minimum supply voltage by decreasing voltage
 *			step by step  until it breaks.
 * @RETURNS		0 on success
 *			OMAPCONF_ERR_CPU
 *			OMAPCONF_ERR_ARG
 *			OMAPCONF_ERR_NOT_AVAILABLE
 *			OMAPCONF_ERR_REG_ACCESS
 *			OMAPCONF_ERR_INTERNAL
 * @param[in]		argc: shell input argument number (must be == 3)
 * @param[in]		argv: shell input argument(s)
 *				argv[0]="voltage domain" ("mpu", "mm", "core")
 *				argv[1]="initial voltage" (in volts)
 *				argv[2]="delay" between steps (in milliseconds)
 * @DESCRIPTION		search minimum supply voltage by decreasing voltage
 *			step by step  until it breaks.
 *			NB: switch CPUFreq governor to "userspace" &
 *			disable smart-reflex
 *//*------------------------------------------------------------------------ */
int lib54xx_vminsearch(int argc, char *argv[])
{
	long uv;
	double v, prev_v;
	int ret, temp;
	unsigned long vstep;
	unsigned char vsel;
	voltdm54xx_id vdd_id;
	sr54xx_mod_id sr_id;
	unsigned int ms;
	char prev_gov[CPUFREQ_GOV_MAX_NAME_LENGTH];

	CHECK_CPU(54xx, OMAPCONF_ERR_CPU);

	/* Retrieve arguments */
	if (argc != 3)
		goto lib54xx_vminsearch_arg_err;
	if (strcmp(argv[0], "mpu") == 0)
		vdd_id = VDD54XX_MPU;
	else if (strcmp(argv[0], "mm") == 0)
		vdd_id = VDD54XX_MM;
	else if (strcmp(argv[0], "core") == 0)
		vdd_id = VDD54XX_CORE;
	else
		goto lib54xx_vminsearch_arg_err;
	ret = sscanf(argv[1], "%lf", &v);
	if (ret != 1)
		goto lib54xx_vminsearch_arg_err;
	ret = sscanf(argv[2], "%d", &ms);
	if (ret != 1)
		goto lib54xx_vminsearch_arg_err;
	if (ms <= 0)
		goto lib54xx_vminsearch_arg_err;

	/*
	 * Switch governor to 'userspace' otherwise voltage change will be
	 * overriden in case of OPP change.
	 */
	printf("Warning: switching CPUFreq governor to 'userspace', otherwise "
		"voltage change will be overriden...\n");
	ret = cpufreq_scaling_governor_set("userspace", prev_gov);
	if (ret < 0)
		printf("Warning: failed to switch governor. Voltage will be "
			"overriden in case of OPP change.\n");
	else
		printf("CPUFreq governor switched to 'userspace'.\n");

	/*
	 * Disable Smart-Reflex (if running) otherwise voltage change will be
	 * overriden.
	 */
	sr_id = sr54xx_vddid2srid(vdd_id);
	if (sr54xx_avs_is_enabled(sr_id)) {
		printf("Warning: %s Smart-Reflex AVS is enabled. "
			"Disabling it...\n", voltdm54xx_name_get(vdd_id));
		ret = sr54xx_avs_enable(sr_id, 0);
		if (ret == 0)
			printf("Smartreflex disabled.\n\n");
		else
			printf("Warning: Could not disable Smart-Reflex AVS. "
				"Voltage may be overriden.\n\n");
	} else {
		printf("Smartreflex disabled.\n\n");
	}

	/* Show current OPP for reference */
	printf("Current OPP configuration for reference:\n\n");
	opp_show(stdout);

	/* Retrieving SMPS voltage step */
	vstep = smps_step_get(vdd_id2smps_id(vdd_id));
	dprintf("%s(): vstep=%luuV\n", __func__, vstep);

	printf("Vmin SEARCH on %s domain scaling voltage down from %1.3lfV in "
		"steps of %lumV, waiting %dms between each step.\n",
		voltdm54xx_name_get(vdd_id), v, vstep / 1000, ms);
	printf("LAST voltage displayed with OK status before crash "
		"will be the Vmin for %s domain.\n\n",
		voltdm54xx_name_get(vdd_id));
	printf("NB:\n  - Make sure your load generator application is "
		"running in background during the whole procedure.\n");
	printf("  - PLATFORM MUST BE REBOOTED AFTER USE "
		"(NO POSSIBLE RECOVERY).\n\n");

	/* Rounding requested initial voltage */
	vsel = smps_uvolt2vsel(vdd_id2smps_id(vdd_id),
		(unsigned long) (v * 1000000));
	prev_v = v;
	v = (double) smps_vsel2uvolt(vdd_id2smps_id(vdd_id), vsel);
	v = v / 1000000;
	if (v != prev_v)
		printf("Note: rounded up initial voltage to %.3lfV.\n\n", v);

	/* Decreasing voltage step by step until it breaks */
	printf("Starting Vmin SEARCH...\n");

	for (uv = (unsigned long) (v * 1000000); uv >= 0; uv = uv - vstep) {
		/* Get vsel corresponding to target voltage */
		vsel = smps_uvolt2vsel(vdd_id2smps_id(vdd_id), uv);
		temp = temp54xx_get(voltdm2sensor_id(vdd_id));
		if (temp != TEMP_ABSOLUTE_ZERO)
			printf("Trying %1.3lfV (SMPS code: 0x%02X, temperature: %dC/%dF)...",
				smps_vsel2volt(vdd_id2smps_id(vdd_id), vsel),
				vsel, temp, celcius2fahrenheit(temp));
		else
			printf("Trying %1.3lfV (SMPS code: 0x%02X, temperature: N/A)...",
				smps_vsel2volt(vdd_id2smps_id(vdd_id), vsel),
				vsel);
		fflush(stdout);
		ret = smps_voltage_set(vdd_id2smps_id(vdd_id), uv);
		if (ret != 0) {
			fprintf(stderr, "Error: could not set %s voltage!\n\n",
				voltdm54xx_name_get(vdd_id));
			return ret;
		}
		usleep(1000 * ms);
		printf("OK!\n");
	}
	fprintf(stderr, "Shouldn't have reached this point... "
		"please check voltage is really scaling down.\n\n");
	return 0;

lib54xx_vminsearch_arg_err:
	return err_arg_msg_show(HELP_VOLT);
	return OMAPCONF_ERR_ARG;
}
Exemple #13
0
/* ------------------------------------------------------------------------*//**
 * @FUNCTION		voltdm54xx_opp_get
 * @BRIEF		find the current voltage domain OPP
 * @RETURNS		valid OPP ID in case of success
 *			OPP54XX_ID_MAX in case of error
 * @param[in]		id: voltage domain ID
 * @DESCRIPTION		find the current voltage domain OPP
 *//*------------------------------------------------------------------------ */
opp54xx_id voltdm54xx_opp_get(voltdm54xx_id id)
{
	opp54xx_id opp_id;
	mod54xx_id module_id;
	dpll54xx_id dpll_id;
	dpll_status status;
	double rate = 0.0, rate_por = 0.0;

	CHECK_CPU(54xx, OPP54XX_ID_MAX);
	CHECK_ARG_LESS_THAN(id, VDD54XX_ID_MAX, OPP54XX_ID_MAX);

	/*
	 * Determine current OPPs by getting MPU / IVA / L3 / SARRAM rate
	 * and comparing it to POR rate.
	 */
	switch (id) {
	case VDD54XX_WKUP:
		module_id = OMAP5_L4WKUP_INTERCONNECT;
		dpll_id = DPLL54XX_CORE;
		break;

	case VDD54XX_MPU:
		module_id = OMAP5_MPU;
		dpll_id = DPLL54XX_MPU;
		break;

	case VDD54XX_MM:
		module_id = OMAP5_IVA;
		dpll_id = DPLL54XX_IVA;
		break;

	case VDD54XX_CORE:
		module_id = OMAP5_L3_MAIN1_INTERCONNECT;
		dpll_id = DPLL54XX_CORE;
		break;

	default:
		return OPP54XX_ID_MAX;
	}

	/* if the DPLL clocking the selected module is stopped,
	 * reported speed will be 0 and OPP cannot be detected.
	 * Hence, if DPLL is stopped, ignore DPLL status to get
	 * the speed when the DPLL is running.
	 */
	status = dpll54xx_status_get(dpll_id);
	if (status == DPLL_STATUS_STOPPED)
		rate = mod54xx_clk_rate_get(module_id, 1);
	else
		rate = mod54xx_clk_rate_get(module_id, 0);

	dprintf("%s(%s): %s rate is %lfMHz\n", __func__,
		voltdm54xx_name_get(id),
		clk54xx_name_get(mod54xx_clk_get(module_id)), rate);

	for (opp_id = OPP54XX_DPLL_CASC; opp_id < OPP54XX_ID_MAX; opp_id++) {
		rate_por = mod54xx_por_clk_rate_get(module_id, opp_id);
		dprintf("%s(%s): %s POR rate for %s is %lf\n",
			__func__, voltdm54xx_name_get(id),
			mod54xx_name_get(module_id),
			opp54xx_name_get(opp_id), rate_por);
		if ((int) rate == (int) rate_por) {
			dprintf("%s(%s): OPP found: %s\n",
				__func__, voltdm54xx_name_get(id),
				opp54xx_name_get(opp_id));
			return opp_id;
		}
	}

	dprintf("%s(%s): OPP not found!\n", __func__, voltdm54xx_name_get(id));

	return OPP54XX_ID_MAX;
}