Skip to content

intel_adsp: ace: secondary core context save and restore #55182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions soc/xtensa/intel_adsp/ace/multiprocessing.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <zephyr/kernel.h>
#include <zephyr/sys/check.h>
#include <zephyr/arch/cpu.h>
#include <zephyr/pm/pm.h>

#include <soc.h>
#include <adsp_boot.h>
Expand Down Expand Up @@ -85,7 +86,23 @@ void soc_start_core(int cpu_num)
if (cpu_num > 0) {
/* Initialize the ROM jump address */
uint32_t *rom_jump_vector = (uint32_t *) ROM_JUMP_ADDR;
#if CONFIG_PM
extern void dsp_restore_vector(void);

/* We need to find out what type of booting is taking place here. Secondary cores
* can be disabled and enabled multiple times during runtime. During kernel
* initialization, the next pm state is set to ACTIVE. This way we can determine
* whether the core is being turned on again or for the first time.
*/
if (pm_state_next_get(cpu_num)->state == PM_STATE_ACTIVE) {
*rom_jump_vector = (uint32_t) z_soc_mp_asm_entry;
} else {
*rom_jump_vector = (uint32_t) dsp_restore_vector;
}
#else
*rom_jump_vector = (uint32_t) z_soc_mp_asm_entry;
#endif

sys_cache_data_flush_range(rom_jump_vector, sizeof(*rom_jump_vector));
ACE_PWRCTL->wpdsphpxpg |= BIT(cpu_num);

Expand Down
61 changes: 33 additions & 28 deletions soc/xtensa/intel_adsp/ace/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ __imr void power_init(void)

#define ALL_USED_INT_LEVELS_MASK (L2_INTERRUPT_MASK | L3_INTERRUPT_MASK)

__aligned(XCHAL_DCACHE_LINESIZE) uint8_t d0i3_stack[CONFIG_MM_DRV_PAGE_SIZE];

/**
* @brief Power down procedure.
*
Expand Down Expand Up @@ -116,6 +114,7 @@ static ALWAYS_INLINE void _save_core_context(uint32_t core_id)
core_desc[core_id].thread_ptr = XTENSA_RUR("THREADPTR");
__asm__ volatile("mov %0, a0" : "=r"(core_desc[core_id].a0));
__asm__ volatile("mov %0, a1" : "=r"(core_desc[core_id].a1));
sys_cache_data_flush_range(&core_desc[core_id], sizeof(struct core_state));
}

static ALWAYS_INLINE void _restore_core_context(void)
Expand All @@ -135,27 +134,37 @@ void dsp_restore_vector(void);

void power_gate_entry(uint32_t core_id)
{
struct lpsram_header *lpsheader =
(struct lpsram_header *) DT_REG_ADDR(DT_NODELABEL(sram1));

xthal_window_spill();
sys_cache_data_flush_and_invd_all();
_save_core_context(core_id);
lpsheader->adsp_lpsram_magic = LPSRAM_MAGIC_VALUE;
lpsheader->lp_restore_vector = &dsp_restore_vector;
if (core_id == 0) {
struct lpsram_header *lpsheader =
(struct lpsram_header *) DT_REG_ADDR(DT_NODELABEL(sram1));

lpsheader->adsp_lpsram_magic = LPSRAM_MAGIC_VALUE;
lpsheader->lp_restore_vector = &dsp_restore_vector;
sys_cache_data_flush_range(lpsheader, sizeof(struct lpsram_header));
/* Re-enabling interrupts for core 0 because someone has to wake-up us
* from power gaiting.
*/
z_xt_ints_on(ALL_USED_INT_LEVELS_MASK);
}

soc_cpus_active[core_id] = false;
sys_cache_data_flush_and_invd_all();
z_xt_ints_on(ALL_USED_INT_LEVELS_MASK);
sys_cache_data_flush_range(soc_cpus_active, sizeof(soc_cpus_active));
k_cpu_idle();
z_xt_ints_off(0xffffffff);
}

void power_gate_exit(void)
{
cpu_early_init();
sys_cache_data_flush_and_invd_all();
_restore_core_context();
}

__asm__(".align 4\n\t"
".global dsp_restore_vector\n\t"
"dsp_restore_vector:\n\t"
" movi a0, 0\n\t"
" movi a1, 1\n\t"
Expand All @@ -164,9 +173,12 @@ __asm__(".align 4\n\t"
" wsr a1, WINDOWSTART\n\t"
" wsr a0, WINDOWBASE\n\t"
" rsync\n\t"
" movi sp, d0i3_stack\n\t"
" movi a2, 0x1000\n\t"
" add sp, sp, a2\n\t"
" movi a1, z_interrupt_stacks\n\t"
" rsr a2, PRID\n\t"
" movi a3, " STRINGIFY(CONFIG_ISR_STACK_SIZE) "\n\t"
" mull a2, a2, a3\n\t"
" add a2, a2, a3\n\t"
" add a1, a1, a2\n\t"
" call0 power_gate_exit\n\t");

#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
Expand Down Expand Up @@ -205,15 +217,15 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
ARG_UNUSED(substate_id);
uint32_t cpu = arch_proc_id();

/* save interrupt state and turn off all interrupts */
core_desc[cpu].intenable = XTENSA_RSR("INTENABLE");
z_xt_ints_off(0xffffffff);

if (state == PM_STATE_SOFT_OFF) {
/* save interrupt state and turn off all interrupts */
core_desc[cpu].intenable = XTENSA_RSR("INTENABLE");
z_xt_ints_off(0xffffffff);
core_desc[cpu].bctl = DSPCS.bootctl[cpu].bctl;
DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPCG;
soc_cpus_active[cpu] = false;
sys_cache_data_flush_and_invd_all();
if (cpu == 0) {
soc_cpus_active[cpu] = false;
#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
/* save storage and restore information to imr */
__ASSERT_NO_MSG(global_imr_ram_storage != NULL);
Expand All @@ -222,6 +234,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)

imr_layout->imr_state.header.adsp_imr_magic = ADSP_IMR_MAGIC_VALUE;
#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE
sys_cache_data_flush_and_invd_all();
imr_layout->imr_state.header.imr_restore_vector =
(void *)boot_entry_d3_restore;
imr_layout->imr_state.header.imr_ram_storage = global_imr_ram_storage;
Expand Down Expand Up @@ -265,16 +278,9 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
power_down(true, uncache_to_cache(&hpsram_mask),
true);
} else {
/* Temporary re-enabling interrupts before going to waiti. Right now
* secondary cores don't have proper context restore flow and after leaving
* D3 state core will return here and stuck.
*/
z_xt_ints_on(core_desc[cpu].intenable);
k_cpu_idle();
power_gate_entry(cpu);
}
} else if (state == PM_STATE_RUNTIME_IDLE) {
core_desc[cpu].intenable = XTENSA_RSR("INTENABLE");
z_xt_ints_off(0xffffffff);
DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPPG;
DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPCG;
ACE_PWRCTL->wpdsphpxpg &= ~BIT(cpu);
Expand Down Expand Up @@ -312,10 +318,8 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
imr_layout->imr_state.header.imr_ram_storage = NULL;
}
#endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */

soc_cpus_active[cpu] = true;
sys_cache_data_flush_and_invd_all();
z_xt_ints_on(core_desc[cpu].intenable);
} else if (state == PM_STATE_RUNTIME_IDLE) {
if (cpu != 0) {
/* NOTE: HW should support dynamic power gating on secondary cores.
Expand All @@ -342,10 +346,11 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)

soc_cpus_active[cpu] = true;
sys_cache_data_flush_and_invd_all();
z_xt_ints_on(core_desc[cpu].intenable);
} else {
__ASSERT(false, "invalid argument - unsupported power state");
}

z_xt_ints_on(core_desc[cpu].intenable);
}

#endif