diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 7f0938bbdd5b..e287e4222195 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -21,6 +21,10 @@ CONFIG_POWER_DOMAIN_INTEL_ADSP=y CONFIG_ADSP_IMR_CONTEXT_SAVE=y +CONFIG_ARCH_CPU_IDLE_CUSTOM=y +CONFIG_ADSP_CPU_DYNAMIC_CLOCK_GATING=y +CONFIG_ADSP_CPU_DYNAMIC_CLOCK_SWITCHING=y + # enable Zephyr drivers CONFIG_ZEPHYR_NATIVE_DRIVERS=y CONFIG_DAI=y diff --git a/app/boards/intel_adsp_ace20_lnl.conf b/app/boards/intel_adsp_ace20_lnl.conf index 99016e3a539c..f0dbac05274c 100644 --- a/app/boards/intel_adsp_ace20_lnl.conf +++ b/app/boards/intel_adsp_ace20_lnl.conf @@ -17,6 +17,10 @@ CONFIG_ADSP_IMR_CONTEXT_SAVE=y CONFIG_POWER_DOMAIN=y CONFIG_POWER_DOMAIN_INTEL_ADSP=y +CONFIG_ARCH_CPU_IDLE_CUSTOM=y +CONFIG_ADSP_CPU_DYNAMIC_CLOCK_GATING=y +CONFIG_ADSP_CPU_DYNAMIC_CLOCK_SWITCHING=y + # enable Zephyr drivers CONFIG_ZEPHYR_NATIVE_DRIVERS=y CONFIG_DAI=y diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 1d92879b32d6..f95e5518ca51 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -43,6 +43,8 @@ #include #include "../audio/copier/ipcgtw_copier.h" +/* QUESTION: call zephyr API directly or add a wrapper in pm_runtime? */ +#include /* Command format errors during fuzzing are reported for virtually all * commands, and the resulting flood of logging becomes a severe @@ -510,13 +512,18 @@ static int ipc_wait_for_compound_msg(void) int try_count = 30; /* timeout out is 30 x 10ms so 300ms for IPC */ while (atomic_read(&msg_data.delayed_reply)) { + /* preventing clock switching in idle */ + pm_policy_state_lock_get(PM_STATE_ACTIVE, 2); k_sleep(Z_TIMEOUT_MS(10)); if (!try_count--) { atomic_set(&msg_data.delayed_reply, 0); ipc_cmd_err(&ipc_tr, "ipc4: failed to wait schedule thread"); + pm_policy_state_lock_put(PM_STATE_ACTIVE, 2); return IPC4_FAILURE; } + + pm_policy_state_lock_put(PM_STATE_ACTIVE, 2); } return IPC4_SUCCESS; diff --git a/src/schedule/zephyr_domain.c b/src/schedule/zephyr_domain.c index 7fb9b4ae0465..a3d32dca1550 100644 --- a/src/schedule/zephyr_domain.c +++ b/src/schedule/zephyr_domain.c @@ -93,6 +93,10 @@ static void zephyr_domain_thread_fn(void *p1, void *p2, void *p3) #endif cycles0 = k_cycle_get_32(); +#if CONFIG_PM_IDLE_POWER_OPTIMIZATIONS + /* If DSP has ben in Idle we may need to restore previous clock. */ + adsp_clock_idle_exit(); +#endif dt->handler(dt->arg); cycles1 = k_cycle_get_32(); diff --git a/zephyr/lib/cpu.c b/zephyr/lib/cpu.c index 3dde19dc38bc..182c3b8cf352 100644 --- a/zephyr/lib/cpu.c +++ b/zephyr/lib/cpu.c @@ -162,7 +162,10 @@ int cpu_enable_core(int id) k_busy_wait(100); atomic_set(&start_flag, 1); - + /* We need to prevent clock switching for each enabled core. Prevent will be removed when + * core enters idle or is disabled. + */ + pm_policy_state_lock_get(PM_STATE_ACTIVE, 2); return 0; } @@ -201,8 +204,12 @@ void cpu_disable_core(int id) return; } - if (soc_adsp_halt_cpu(id) != 0) + if (soc_adsp_halt_cpu(id) != 0) { tr_err(&zephyr_tr, "failed to disable core %d", id); + } else { + /* Core is now down and we can remove prevent for clock switching. */ + pm_policy_state_lock_put(PM_STATE_ACTIVE, 2); + } #endif /* CONFIG_PM */ } diff --git a/zephyr/wrapper.c b/zephyr/wrapper.c index 0d4644ffdfb2..4eaec6deb269 100644 --- a/zephyr/wrapper.c +++ b/zephyr/wrapper.c @@ -232,6 +232,11 @@ int start_complete(void) #if defined(CONFIG_PM) pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); pm_policy_state_lock_get(PM_STATE_SOFT_OFF, PM_ALL_SUBSTATES); + /* Prevent dynamic clock switching during idle time. Prevention must set for all active + * cores, then each core will put the lock again and go into an idle state. The last + * active core will try to switch the clock to the lowest frequency. + */ + pm_policy_state_lock_get(PM_STATE_ACTIVE, 2); #endif return boot_complete(); }