Skip to content

Commit

Permalink
power: add pm_idle_exit function
Browse files Browse the repository at this point in the history
The purpose of the newly added function is to perform operations that
reverse the effects of changes introduced by pm_idle_entry.

This particular implementation includes dynamic clock swiching done for
Intel ADSP. As explained in commit fd65c04, the DSP can dynamically
change the clock to save power.

Signed-off-by: Tomasz Leman <[email protected]>
  • Loading branch information
tmleman committed Oct 27, 2023
1 parent 8670767 commit a066641
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
5 changes: 4 additions & 1 deletion kernel/idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,11 @@ void idle(void *unused1, void *unused2, void *unused3)
if (k_is_pre_kernel() || !pm_system_suspend(_kernel.idle)) {
#ifdef CONFIG_PM_IDLE_POWER_OPTIMIZATIONS
pm_idle_entry();
#endif
k_cpu_idle();
pm_idle_exit();
#else
k_cpu_idle();
#endif
}
#else
k_cpu_idle();
Expand Down
15 changes: 15 additions & 0 deletions soc/xtensa/intel_adsp/ace/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,11 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)

#ifdef CONFIG_PM_IDLE_POWER_OPTIMIZATIONS

#include <zephyr/pm/policy.h>

extern void adsp_clock_idle_entry(void);
extern void adsp_clock_idle_exit(void);

void pm_idle_entry(void)
{
/* NOTE: Decreasing a power state lock counter before entering idle. Primary core is
Expand All @@ -389,6 +394,16 @@ void pm_idle_entry(void)
} else {
DSPCS.bootctl[arch_proc_id()].bctl &= ~DSPBR_BCTL_WAITIPCG;
}

if (pm_policy_state_lock_is_active(PM_STATE_ACTIVE, 2)) {
adsp_clock_idle_entry();
}
}

void pm_idle_exit(void)
{
pm_policy_state_lock_get(PM_STATE_ACTIVE, 2);
adsp_clock_idle_exit();
}

#endif
Expand Down
49 changes: 49 additions & 0 deletions soc/xtensa/intel_adsp/common/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,52 @@ uint32_t adsp_clock_source_frequency(int source)

return adsp_clk_src_info[source].frequency;
}

#ifdef CONFIG_PM_IDLE_POWER_OPTIMIZATIONS
/**
* @brief Clock change counter.
*
* A atomic variable that counts how many times the clock has been tried to be lowered.
*/
atomic_t clock_change_count;

/**
* @brief Clock switch on idle entry.
*
* This function should be called in Idle thread. Intel ADSP can change clock according to
* its needs. But in idle, when core is waiting for interrupt, clock can be change to
* lower frequanze.
*
* @see adsp_clock_idle_exit()
*/
void adsp_clock_idle_entry(void)
{
/* we are already at the lowest clock, there is no need to do anything */
if (platform_cpu_clocks[0].current_freq != platform_cpu_clocks[0].lowest_freq) {
select_cpu_clock_hw(platform_cpu_clocks[0].lowest_freq);
(void)atomic_inc(&clock_change_count);
}
}

/**
* @brief Clock restore on idle exit.
*
* This function must be called when exiting the idle state. During idle entry core could switch
* clock to the lowest frequency and we need to restore previous settings.
*

Check failure on line 188 in soc/xtensa/intel_adsp/common/clk.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

TRAILING_WHITESPACE

soc/xtensa/intel_adsp/common/clk.c:188 trailing whitespace
* @see adsp_clock_idle_entry()
*/
void adsp_clock_idle_exit(void)
{
/* clock has not been changed */
if (!atomic_get(&clock_change_count))
return;

/* If the DSP should run at a higher clock than the lowest, restore this setting */
if (platform_cpu_clocks[0].current_freq != platform_cpu_clocks[0].lowest_freq) {
select_cpu_clock_hw(platform_cpu_clocks[0].current_freq);
(void)atomic_clear(&clock_change_count);
}
}

#endif

0 comments on commit a066641

Please sign in to comment.