forked from len0rd/rockbox
i.MX31: Add a debug menu to play around with DVFS/DPTC settings for fun, testing or benchmarking purposes. Can set the CPU frequency working point, whether DPTC voltage scaling is enabled and change the software-programmable load tracking weights.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29113 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
aed6205831
commit
98246b82b9
6 changed files with 412 additions and 118 deletions
|
|
@ -2345,6 +2345,9 @@ static const struct the_menu_item menuitems[] = {
|
||||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||||
{ "CPU frequency", dbg_cpufreq },
|
{ "CPU frequency", dbg_cpufreq },
|
||||||
#endif
|
#endif
|
||||||
|
#if CONFIG_CPU == IMX31L
|
||||||
|
{ "DVFS/DPTC", __dbg_dvfs_dptc },
|
||||||
|
#endif
|
||||||
#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR)
|
#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR)
|
||||||
{ "S/PDIF analyzer", dbg_spdif },
|
{ "S/PDIF analyzer", dbg_spdif },
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
#include "ccm-imx31.h"
|
#include "ccm-imx31.h"
|
||||||
#include "dvfs_dptc-imx31.h"
|
#include "dvfs_dptc-imx31.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
bool __dbg_hw_info(void)
|
bool __dbg_hw_info(void)
|
||||||
{
|
{
|
||||||
|
|
@ -243,3 +244,147 @@ bool dbg_ports(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool __dbg_dvfs_dptc(void)
|
||||||
|
{
|
||||||
|
int ltwlevel;
|
||||||
|
unsigned long ltdetect;
|
||||||
|
int dvfs_wp, dvfs_mask;
|
||||||
|
bool dptc_on;
|
||||||
|
int i;
|
||||||
|
char buf[32];
|
||||||
|
unsigned long ltw[4];
|
||||||
|
bool ltwassert[4];
|
||||||
|
|
||||||
|
lcd_clear_display();
|
||||||
|
lcd_setfont(FONT_SYSFIXED);
|
||||||
|
|
||||||
|
dvfs_mask = dvfs_level_mask();
|
||||||
|
|
||||||
|
dvfs_wp = dvfs_enabled() ? -1 : (int)dvfs_get_level();
|
||||||
|
dptc_on = dptc_enabled();
|
||||||
|
dvfs_get_gp_sense(<wlevel, <detect);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int line = 0;
|
||||||
|
|
||||||
|
int button = button_get_w_tmo(HZ/10);
|
||||||
|
|
||||||
|
if (dvfs_wp < 0)
|
||||||
|
strcpy(buf, "Auto");
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "%d", dvfs_wp);
|
||||||
|
|
||||||
|
lcd_puts(0, line, "[DVFS/DPTC]");
|
||||||
|
line += 2;
|
||||||
|
lcd_putsf(0, line, "CPU freq. point (Up/Dn) : %s", buf);
|
||||||
|
line += 2;
|
||||||
|
lcd_putsf(0, line, "DPTC volt. scale (Play) : %s",
|
||||||
|
dptc_on ? "Enabled" : "Disabled");
|
||||||
|
line += 2;
|
||||||
|
lcd_putsf(0, line, "GP load level (Vol +/-) : %d", ltwlevel);
|
||||||
|
line += 2;
|
||||||
|
lcd_puts(0, line, "----------------------------------------");
|
||||||
|
line += 2;
|
||||||
|
lcd_putsf(0, line++, "Frequency: %dHz", cpu_frequency);
|
||||||
|
i = dvfs_dptc_get_voltage();
|
||||||
|
lcd_putsf(0, line++, "Voltage : %d.%03d V", i / 1000, i % 1000);
|
||||||
|
|
||||||
|
for (i = 0; i <= 3; i++)
|
||||||
|
{
|
||||||
|
ltw[i] = dvfs_get_lt_weight(i + DVFS_LT_SIG_DVGP0);
|
||||||
|
ltwassert[i] = dvfs_get_gp_bit(i + DVFS_DVGP_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lcd_putsf(0, line++, "GPW (3-0): %lu%lu%lu%lu %c%c%c%c",
|
||||||
|
ltw[3], ltw[2], ltw[1], ltw[0],
|
||||||
|
ltwassert[3] ? 'y' : 'n',
|
||||||
|
ltwassert[2] ? 'y' : 'n',
|
||||||
|
ltwassert[1] ? 'y' : 'n',
|
||||||
|
ltwassert[0] ? 'y' : 'n');
|
||||||
|
|
||||||
|
line += 2;
|
||||||
|
lcd_puts(8, line, "(Press SELECT to revert)");
|
||||||
|
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case DEBUG_CANCEL|BUTTON_REL:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* CPU frequency */
|
||||||
|
case BUTTON_UP:
|
||||||
|
if (++dvfs_wp >= DVFS_NUM_LEVELS)
|
||||||
|
{
|
||||||
|
/* Going back to automatic */
|
||||||
|
dvfs_wp = -1;
|
||||||
|
dvfs_start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dvfs_wp == 0)
|
||||||
|
{
|
||||||
|
/* Going to manual setting */
|
||||||
|
dvfs_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip gaps in mask */
|
||||||
|
while (((1 << dvfs_wp) & dvfs_mask) == 0) dvfs_wp++;
|
||||||
|
dvfs_set_level(dvfs_wp);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_DOWN:
|
||||||
|
if (--dvfs_wp == -1)
|
||||||
|
{
|
||||||
|
/* Going back to automatic */
|
||||||
|
dvfs_start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dvfs_wp <= -2)
|
||||||
|
{
|
||||||
|
/* Going to manual setting */
|
||||||
|
dvfs_stop();
|
||||||
|
dvfs_wp = DVFS_NUM_LEVELS - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip gaps in mask */
|
||||||
|
while (((1 << dvfs_wp) & dvfs_mask) == 0) dvfs_wp--;
|
||||||
|
dvfs_set_level(dvfs_wp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* GP Load tracking */
|
||||||
|
case BUTTON_VOL_UP:
|
||||||
|
if (ltwlevel < 28)
|
||||||
|
dvfs_set_gp_sense(++ltwlevel, ltdetect);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_VOL_DOWN:
|
||||||
|
if (ltwlevel > 0)
|
||||||
|
dvfs_set_gp_sense(--ltwlevel, ltdetect);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_PLAY:
|
||||||
|
dptc_on = !dptc_enabled();
|
||||||
|
dptc_on ? dptc_start() : dptc_stop();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_SELECT:
|
||||||
|
dvfs_start();
|
||||||
|
dptc_start();
|
||||||
|
dvfs_set_gp_sense(-1, 0);
|
||||||
|
|
||||||
|
dvfs_wp = dvfs_enabled() ? -1 : (int)dvfs_get_level();
|
||||||
|
dptc_on = dptc_enabled();
|
||||||
|
dvfs_get_gp_sense(<wlevel, <detect);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcd_update();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,5 +24,6 @@
|
||||||
#define DEBUG_CANCEL BUTTON_BACK
|
#define DEBUG_CANCEL BUTTON_BACK
|
||||||
bool __dbg_hw_info(void);
|
bool __dbg_hw_info(void);
|
||||||
bool dbg_ports(void);
|
bool dbg_ports(void);
|
||||||
|
bool __dbg_dvfs_dptc(void);
|
||||||
|
|
||||||
#endif /* DEBUG_TARGET_H */
|
#endif /* DEBUG_TARGET_H */
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,6 @@ unsigned int dvfs_nr_up = 0;
|
||||||
unsigned int dvfs_nr_pnc = 0;
|
unsigned int dvfs_nr_pnc = 0;
|
||||||
unsigned int dvfs_nr_no = 0;
|
unsigned int dvfs_nr_no = 0;
|
||||||
|
|
||||||
static void dvfs_stop(void);
|
|
||||||
|
|
||||||
|
|
||||||
/* Wait for the UPDTEN flag to be set so that all bits may be written */
|
/* Wait for the UPDTEN flag to be set so that all bits may be written */
|
||||||
static inline void wait_for_dvfs_update_en(void)
|
static inline void wait_for_dvfs_update_en(void)
|
||||||
|
|
@ -280,6 +278,9 @@ static void INIT_ATTR dvfs_init(void)
|
||||||
IOMUXC_MUX_OUT_FUNCTIONAL | IOMUXC_MUX_IN_FUNCTIONAL);
|
IOMUXC_MUX_OUT_FUNCTIONAL | IOMUXC_MUX_IN_FUNCTIONAL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* GP load bits disabled */
|
||||||
|
bitclr32(&CCM_PMCR1, 0xf);
|
||||||
|
|
||||||
/* Initialize DVFS signal weights and detection modes. */
|
/* Initialize DVFS signal weights and detection modes. */
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
|
|
@ -321,66 +322,6 @@ static void INIT_ATTR dvfs_init(void)
|
||||||
logf("DVFS: Initialized");
|
logf("DVFS: Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Start the DVFS hardware */
|
|
||||||
static void dvfs_start(void)
|
|
||||||
{
|
|
||||||
int oldlevel;
|
|
||||||
|
|
||||||
/* Have to wait at least 3 div3 clocks before enabling after being
|
|
||||||
* stopped. */
|
|
||||||
udelay(1500);
|
|
||||||
|
|
||||||
oldlevel = disable_irq_save();
|
|
||||||
|
|
||||||
if (!dvfs_running)
|
|
||||||
{
|
|
||||||
dvfs_running = true;
|
|
||||||
|
|
||||||
/* Unmask DVFS interrupt source and enable DVFS. */
|
|
||||||
avic_enable_int(INT_CCM_DVFS, INT_TYPE_IRQ, INT_PRIO_DVFS,
|
|
||||||
CCM_DVFS_HANDLER);
|
|
||||||
|
|
||||||
CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_FSVAIM) | CCM_PMCR0_DVFEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_irq(oldlevel);
|
|
||||||
|
|
||||||
logf("DVFS: started");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Stop the DVFS hardware and return to default frequency */
|
|
||||||
static void dvfs_stop(void)
|
|
||||||
{
|
|
||||||
int oldlevel = disable_irq_save();
|
|
||||||
|
|
||||||
if (dvfs_running)
|
|
||||||
{
|
|
||||||
/* Mask DVFS interrupts. */
|
|
||||||
CCM_PMCR0 |= CCM_PMCR0_FSVAIM | CCM_PMCR0_LBMI;
|
|
||||||
avic_disable_int(INT_CCM_DVFS);
|
|
||||||
|
|
||||||
if (((CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS) !=
|
|
||||||
DVFS_LEVEL_DEFAULT)
|
|
||||||
{
|
|
||||||
/* Set default frequency level */
|
|
||||||
wait_for_dvfs_update_en();
|
|
||||||
do_dvfs_update(DVFS_LEVEL_DEFAULT, false);
|
|
||||||
wait_for_dvfs_update_en();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable DVFS. */
|
|
||||||
CCM_PMCR0 &= ~CCM_PMCR0_DVFEN;
|
|
||||||
dvfs_running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_irq(oldlevel);
|
|
||||||
|
|
||||||
logf("DVFS: stopped");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** DPTC **/
|
/** DPTC **/
|
||||||
|
|
||||||
/* Request tracking since boot */
|
/* Request tracking since boot */
|
||||||
|
|
@ -540,52 +481,6 @@ static void INIT_ATTR dptc_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Start DPTC module */
|
|
||||||
static void dptc_start(void)
|
|
||||||
{
|
|
||||||
int oldlevel = disable_irq_save();
|
|
||||||
|
|
||||||
if (!dptc_running)
|
|
||||||
{
|
|
||||||
dptc_running = true;
|
|
||||||
|
|
||||||
/* Enable DPTC and unmask interrupt. */
|
|
||||||
avic_enable_int(INT_CCM_CLK, INT_TYPE_IRQ, INT_PRIO_DPTC,
|
|
||||||
CCM_CLK_HANDLER);
|
|
||||||
|
|
||||||
update_dptc_counts(dvfs_level, dptc_wp);
|
|
||||||
enable_dptc();
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_irq(oldlevel);
|
|
||||||
|
|
||||||
logf("DPTC: started");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Stop the DPTC hardware if running and go back to default working point */
|
|
||||||
static void dptc_stop(void)
|
|
||||||
{
|
|
||||||
int oldlevel = disable_irq_save();
|
|
||||||
|
|
||||||
if (dptc_running)
|
|
||||||
{
|
|
||||||
dptc_running = false;
|
|
||||||
|
|
||||||
/* Disable DPTC and mask interrupt. */
|
|
||||||
CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_DPTEN) | CCM_PMCR0_PTVAIM;
|
|
||||||
avic_disable_int(INT_CCM_CLK);
|
|
||||||
|
|
||||||
/* Go back to default working point. */
|
|
||||||
dptc_new_wp(DPTC_WP_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_irq(oldlevel);
|
|
||||||
|
|
||||||
logf("DPTC: stopped");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Main module interface **/
|
/** Main module interface **/
|
||||||
|
|
||||||
/* Initialize DVFS and DPTC */
|
/* Initialize DVFS and DPTC */
|
||||||
|
|
@ -611,6 +506,64 @@ void dvfs_dptc_stop(void)
|
||||||
dvfs_stop();
|
dvfs_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start the DVFS hardware */
|
||||||
|
void dvfs_start(void)
|
||||||
|
{
|
||||||
|
int oldlevel;
|
||||||
|
|
||||||
|
/* Have to wait at least 3 div3 clocks before enabling after being
|
||||||
|
* stopped. */
|
||||||
|
udelay(1500);
|
||||||
|
|
||||||
|
oldlevel = disable_irq_save();
|
||||||
|
|
||||||
|
if (!dvfs_running)
|
||||||
|
{
|
||||||
|
dvfs_running = true;
|
||||||
|
|
||||||
|
/* Unmask DVFS interrupt source and enable DVFS. */
|
||||||
|
avic_enable_int(INT_CCM_DVFS, INT_TYPE_IRQ, INT_PRIO_DVFS,
|
||||||
|
CCM_DVFS_HANDLER);
|
||||||
|
|
||||||
|
CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_FSVAIM) | CCM_PMCR0_DVFEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_irq(oldlevel);
|
||||||
|
|
||||||
|
logf("DVFS: started");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Stop the DVFS hardware and return to default frequency */
|
||||||
|
void dvfs_stop(void)
|
||||||
|
{
|
||||||
|
int oldlevel = disable_irq_save();
|
||||||
|
|
||||||
|
if (dvfs_running)
|
||||||
|
{
|
||||||
|
/* Mask DVFS interrupts. */
|
||||||
|
CCM_PMCR0 |= CCM_PMCR0_FSVAIM | CCM_PMCR0_LBMI;
|
||||||
|
avic_disable_int(INT_CCM_DVFS);
|
||||||
|
|
||||||
|
if (((CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS) !=
|
||||||
|
DVFS_LEVEL_DEFAULT)
|
||||||
|
{
|
||||||
|
/* Set default frequency level */
|
||||||
|
wait_for_dvfs_update_en();
|
||||||
|
do_dvfs_update(DVFS_LEVEL_DEFAULT, false);
|
||||||
|
wait_for_dvfs_update_en();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable DVFS. */
|
||||||
|
CCM_PMCR0 &= ~CCM_PMCR0_DVFEN;
|
||||||
|
dvfs_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_irq(oldlevel);
|
||||||
|
|
||||||
|
logf("DVFS: stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Mask the DVFS interrupt without affecting running status */
|
/* Mask the DVFS interrupt without affecting running status */
|
||||||
void dvfs_int_mask(bool mask)
|
void dvfs_int_mask(bool mask)
|
||||||
|
|
@ -648,6 +601,26 @@ void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return a signal load tracking weight */
|
||||||
|
unsigned long dvfs_get_lt_weight(enum DVFS_LT_SIGS index)
|
||||||
|
{
|
||||||
|
volatile unsigned long *reg_p = &CCM_LTR2;
|
||||||
|
unsigned int shift = 3 * index;
|
||||||
|
|
||||||
|
if (index < 9)
|
||||||
|
{
|
||||||
|
reg_p = &CCM_LTR3;
|
||||||
|
shift += 5; /* Bits 7:5, 10:8 ... 31:29 */
|
||||||
|
}
|
||||||
|
else if (index < 16)
|
||||||
|
{
|
||||||
|
shift -= 16; /* Bits 13:11, 16:14 ... 31:29 */
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*reg_p & (0x7 << shift)) >> shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set a signal load detection mode */
|
/* Set a signal load detection mode */
|
||||||
void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge)
|
void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge)
|
||||||
{
|
{
|
||||||
|
|
@ -662,6 +635,21 @@ void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns a signal load detection mode */
|
||||||
|
bool dvfs_get_lt_detect(enum DVFS_LT_SIGS index)
|
||||||
|
{
|
||||||
|
unsigned int shift = 32;
|
||||||
|
|
||||||
|
if ((unsigned)index < 13)
|
||||||
|
shift = index + 3;
|
||||||
|
else if ((unsigned)index < 16)
|
||||||
|
shift = index + 29;
|
||||||
|
|
||||||
|
return !!((CCM_LTR0 & (1ul << shift)) >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set/clear the general-purpose load tracking bit */
|
||||||
void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert)
|
void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert)
|
||||||
{
|
{
|
||||||
if ((unsigned)dvgp <= 3)
|
if ((unsigned)dvgp <= 3)
|
||||||
|
|
@ -672,6 +660,82 @@ void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the general-purpose load tracking bit */
|
||||||
|
bool dvfs_get_gp_bit(enum DVFS_DVGPS dvgp)
|
||||||
|
{
|
||||||
|
if ((unsigned)dvgp <= 3)
|
||||||
|
return (CCM_PMCR1 & (1ul << dvgp)) != 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set GP load tracking by code.
|
||||||
|
* level_code:
|
||||||
|
* lt 0 =defaults
|
||||||
|
* 0 =all off ->
|
||||||
|
* 28 =highest load
|
||||||
|
* gte 28=highest load
|
||||||
|
* detect_mask bits:
|
||||||
|
* b[3:0]: 1=LTn edge detect, 0=LTn level detect
|
||||||
|
*/
|
||||||
|
void dvfs_set_gp_sense(int level_code, unsigned long detect_mask)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i <= 3; i++)
|
||||||
|
{
|
||||||
|
int ltsig_num = DVFS_LT_SIG_DVGP0 + i;
|
||||||
|
int gpw_num = DVFS_DVGP_0 + i;
|
||||||
|
unsigned long weight;
|
||||||
|
bool edge;
|
||||||
|
bool assert;
|
||||||
|
|
||||||
|
if (level_code < 0)
|
||||||
|
{
|
||||||
|
/* defaults */
|
||||||
|
detect_mask = 0;
|
||||||
|
assert = 0;
|
||||||
|
weight = lt_signals[ltsig_num].weight;
|
||||||
|
edge = lt_signals[ltsig_num].detect != 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
weight = MIN(level_code, 7);
|
||||||
|
edge = !!(detect_mask & 1);
|
||||||
|
assert = weight > 0;
|
||||||
|
detect_mask >>= 1;
|
||||||
|
level_code -= 7;
|
||||||
|
if (level_code < 0)
|
||||||
|
level_code = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dvfs_set_lt_weight(ltsig_num, weight); /* set weight */
|
||||||
|
dvfs_set_lt_detect(ltsig_num, edge); /* set detect mode */
|
||||||
|
dvfs_set_gp_bit(gpw_num, assert); /* set activity */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return GP weight settings */
|
||||||
|
void dvfs_get_gp_sense(int *level_code, unsigned long *detect_mask)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int code = 0;
|
||||||
|
unsigned long mask = 0;
|
||||||
|
|
||||||
|
for (i = DVFS_LT_SIG_DVGP0; i <= DVFS_LT_SIG_DVGP3; i++)
|
||||||
|
{
|
||||||
|
code += dvfs_get_lt_weight(i);
|
||||||
|
mask = (mask << 1) | (dvfs_get_lt_detect(i) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level_code)
|
||||||
|
*level_code = code;
|
||||||
|
|
||||||
|
if (detect_mask)
|
||||||
|
*detect_mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Turn the wait-for-interrupt monitoring on or off */
|
/* Turn the wait-for-interrupt monitoring on or off */
|
||||||
void dvfs_wfi_monitor(bool on)
|
void dvfs_wfi_monitor(bool on)
|
||||||
{
|
{
|
||||||
|
|
@ -700,21 +764,83 @@ unsigned int dvfs_get_level(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Is DVFS enabled? */
|
||||||
|
bool dvfs_enabled(void)
|
||||||
|
{
|
||||||
|
return dvfs_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Get bitmask of levels supported */
|
||||||
|
unsigned int dvfs_level_mask(void)
|
||||||
|
{
|
||||||
|
return DVFS_LEVEL_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If DVFS is disabled, set the level explicitly */
|
/* If DVFS is disabled, set the level explicitly */
|
||||||
void dvfs_set_level(unsigned int level)
|
void dvfs_set_level(unsigned int level)
|
||||||
{
|
{
|
||||||
int oldlevel = disable_irq_save();
|
int oldlevel = disable_irq_save();
|
||||||
|
|
||||||
|
if (!dvfs_running && level < DVFS_NUM_LEVELS)
|
||||||
|
{
|
||||||
unsigned int currlevel =
|
unsigned int currlevel =
|
||||||
(CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS;
|
(CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS;
|
||||||
|
if (level != currlevel && ((1 << level) & DVFS_LEVEL_MASK))
|
||||||
if (!dvfs_running && level < DVFS_NUM_LEVELS && level != currlevel)
|
|
||||||
set_current_dvfs_level(level);
|
set_current_dvfs_level(level);
|
||||||
|
}
|
||||||
|
|
||||||
restore_irq(oldlevel);
|
restore_irq(oldlevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Start DPTC module */
|
||||||
|
void dptc_start(void)
|
||||||
|
{
|
||||||
|
int oldlevel = disable_irq_save();
|
||||||
|
|
||||||
|
if (!dptc_running)
|
||||||
|
{
|
||||||
|
dptc_running = true;
|
||||||
|
|
||||||
|
/* Enable DPTC and unmask interrupt. */
|
||||||
|
avic_enable_int(INT_CCM_CLK, INT_TYPE_IRQ, INT_PRIO_DPTC,
|
||||||
|
CCM_CLK_HANDLER);
|
||||||
|
|
||||||
|
update_dptc_counts(dvfs_level, dptc_wp);
|
||||||
|
enable_dptc();
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_irq(oldlevel);
|
||||||
|
|
||||||
|
logf("DPTC: started");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Stop the DPTC hardware if running and go back to default working point */
|
||||||
|
void dptc_stop(void)
|
||||||
|
{
|
||||||
|
int oldlevel = disable_irq_save();
|
||||||
|
|
||||||
|
if (dptc_running)
|
||||||
|
{
|
||||||
|
dptc_running = false;
|
||||||
|
|
||||||
|
/* Disable DPTC and mask interrupt. */
|
||||||
|
CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_DPTEN) | CCM_PMCR0_PTVAIM;
|
||||||
|
avic_disable_int(INT_CCM_CLK);
|
||||||
|
|
||||||
|
/* Go back to default working point. */
|
||||||
|
dptc_new_wp(DPTC_WP_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_irq(oldlevel);
|
||||||
|
|
||||||
|
logf("DPTC: stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get the current DPTC working point */
|
/* Get the current DPTC working point */
|
||||||
unsigned int dptc_get_wp(void)
|
unsigned int dptc_get_wp(void)
|
||||||
{
|
{
|
||||||
|
|
@ -722,6 +848,13 @@ unsigned int dptc_get_wp(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Is DPTC enabled? */
|
||||||
|
bool dptc_enabled(void)
|
||||||
|
{
|
||||||
|
return dptc_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If DPTC is not running, set the working point explicitly */
|
/* If DPTC is not running, set the working point explicitly */
|
||||||
void dptc_set_wp(unsigned int wp)
|
void dptc_set_wp(unsigned int wp)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -124,16 +124,28 @@ void dvfs_dptc_init(void);
|
||||||
void dvfs_dptc_start(void);
|
void dvfs_dptc_start(void);
|
||||||
void dvfs_dptc_stop(void);
|
void dvfs_dptc_stop(void);
|
||||||
|
|
||||||
|
void dvfs_start(void);
|
||||||
|
void dvfs_stop(void);
|
||||||
|
bool dvfs_enabled(void);
|
||||||
void dvfs_wfi_monitor(bool on);
|
void dvfs_wfi_monitor(bool on);
|
||||||
void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value);
|
void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value);
|
||||||
|
unsigned long dvfs_get_lt_weight(enum DVFS_LT_SIGS index);
|
||||||
void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge);
|
void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge);
|
||||||
|
bool dvfs_get_lt_detect(enum DVFS_LT_SIGS index);
|
||||||
void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert);
|
void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert);
|
||||||
|
bool dvfs_get_gp_bit(enum DVFS_DVGPS dvgp);
|
||||||
void dvfs_int_mask(bool mask);
|
void dvfs_int_mask(bool mask);
|
||||||
|
void dvfs_set_gp_sense(int level_code, unsigned long detect_mask);
|
||||||
|
void dvfs_get_gp_sense(int *level_code, unsigned long *detect_mask);
|
||||||
|
unsigned int dvfs_level_mask(void);
|
||||||
|
|
||||||
unsigned int dvfs_dptc_get_voltage(void);
|
unsigned int dvfs_dptc_get_voltage(void);
|
||||||
unsigned int dvfs_get_level(void);
|
unsigned int dvfs_get_level(void);
|
||||||
void dvfs_set_level(unsigned int level);
|
void dvfs_set_level(unsigned int level);
|
||||||
|
|
||||||
|
void dptc_start(void);
|
||||||
|
void dptc_stop(void);
|
||||||
|
bool dptc_enabled(void);
|
||||||
unsigned int dptc_get_wp(void);
|
unsigned int dptc_get_wp(void);
|
||||||
void dptc_set_wp(unsigned int wp);
|
void dptc_set_wp(unsigned int wp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -241,10 +241,10 @@ static const struct dvfs_lt_signal_descriptor lt_signals[16] =
|
||||||
{ 0, 0 }, /* DVFS_LT_SIG_ARM11_P_FIQ_B_RBT_GATE */
|
{ 0, 0 }, /* DVFS_LT_SIG_ARM11_P_FIQ_B_RBT_GATE */
|
||||||
{ 0, 0 }, /* DVFS_LT_SIG_IPI_GPIO1_INT0 */
|
{ 0, 0 }, /* DVFS_LT_SIG_IPI_GPIO1_INT0 */
|
||||||
{ 0, 0 }, /* DVFS_LT_SIG_IPI_INT_IPU_FUNC */
|
{ 0, 0 }, /* DVFS_LT_SIG_IPI_INT_IPU_FUNC */
|
||||||
{ 7, 0 }, /* DVFS_LT_SIG_DVGP0 */
|
{ 0, 0 }, /* DVFS_LT_SIG_DVGP0 */
|
||||||
{ 7, 0 }, /* DVFS_LT_SIG_DVGP1 */
|
{ 0, 0 }, /* DVFS_LT_SIG_DVGP1 */
|
||||||
{ 7, 0 }, /* DVFS_LT_SIG_DVGP2 */
|
{ 0, 0 }, /* DVFS_LT_SIG_DVGP2 */
|
||||||
{ 7, 0 }, /* DVFS_LT_SIG_DVGP3 */
|
{ 0, 0 }, /* DVFS_LT_SIG_DVGP3 */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _DVFS_DPTC_TARGET_H_ */
|
#endif /* _DVFS_DPTC_TARGET_H_ */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue