diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index 0a199dd17e4f..c904f9a89f80 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -16,6 +16,7 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <0>; + cpu-power-states = <&d3>; i-cache-line-size = <64>; d-cache-line-size = <64>; }; @@ -24,18 +25,33 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <1>; + cpu-power-states = <&d3>; }; cpu2: cpu@2 { device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <2>; + cpu-power-states = <&d3>; }; cpu3: cpu@3 { device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <3>; + cpu-power-states = <&d3>; + }; + }; + + power-states { + /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. + * The procedure is triggered by IPC from the HOST (SET_DX). + */ + d3: off { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2147483647>; + exit-latency-us = <0>; }; }; diff --git a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi index 205574193676..246c026f7446 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi @@ -16,6 +16,7 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <0>; + cpu-power-states = <&d3>; i-cache-line-size = <64>; d-cache-line-size = <64>; }; @@ -24,6 +25,19 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <1>; + cpu-power-states = <&d3>; + }; + }; + + power-states { + /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. + * The procedure is triggered by IPC from the HOST (SET_DX). + */ + d3: off { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2147483647>; + exit-latency-us = <0>; }; }; diff --git a/soc/xtensa/intel_adsp/cavs/CMakeLists.txt b/soc/xtensa/intel_adsp/cavs/CMakeLists.txt index a691ba31363b..2a0cbdc463c6 100644 --- a/soc/xtensa/intel_adsp/cavs/CMakeLists.txt +++ b/soc/xtensa/intel_adsp/cavs/CMakeLists.txt @@ -9,6 +9,7 @@ zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) zephyr_library_sources( sram.c power.c + power_down_cavs.S ) if(CONFIG_SMP OR CONFIG_MP_MAX_NUM_CPUS GREATER 1) diff --git a/soc/xtensa/intel_adsp/cavs/asm_ldo_management.h b/soc/xtensa/intel_adsp/cavs/asm_ldo_management.h new file mode 100644 index 000000000000..4ac6b378a080 --- /dev/null +++ b/soc/xtensa/intel_adsp/cavs/asm_ldo_management.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ZEPHYR_CAVS_LIB_ASM_LDO_MANAGEMENT_H__ +#define __ZEPHYR_CAVS_LIB_ASM_LDO_MANAGEMENT_H__ + +#ifdef _ASMLANGUAGE + +#define SHIM_BASE 0x00071F00 +#define SHIM_LDOCTL 0xA4 +#define SHIM_LDOCTL_HPSRAM_MASK (3 << 0 | 3 << 16) +#define SHIM_LDOCTL_LPSRAM_MASK (3 << 2) +#define SHIM_LDOCTL_HPSRAM_LDO_ON (3 << 0 | 3 << 16) +#define SHIM_LDOCTL_LPSRAM_LDO_ON (3 << 2) +#define SHIM_LDOCTL_HPSRAM_LDO_OFF (0 << 0) +#define SHIM_LDOCTL_LPSRAM_LDO_OFF (0 << 2) +#define SHIM_LDOCTL_HPSRAM_LDO_BYPASS (BIT(0) | BIT(16)) +#define SHIM_LDOCTL_LPSRAM_LDO_BYPASS BIT(2) + +.macro m_cavs_set_ldo_state state, ax +movi \ax, (SHIM_BASE + SHIM_LDOCTL) +s32i \state, \ax, 0 +memw +/* wait loop > 300ns (min 100ns required) */ +movi \ax, 128 +1 : +addi \ax, \ax, -1 +nop +bnez \ax, 1b +.endm + +.macro m_cavs_set_hpldo_state state, ax, ay +movi \ax, (SHIM_BASE + SHIM_LDOCTL) +l32i \ay, \ax, 0 + +movi \ax, ~(SHIM_LDOCTL_HPSRAM_MASK) +and \ay, \ax, \ay +or \state, \ay, \state + +m_cavs_set_ldo_state \state, \ax +.endm + +.macro m_cavs_set_lpldo_state state, ax, ay +movi \ax, (SHIM_BASE + SHIM_LDOCTL) +l32i \ay, \ax, 0 +/* LP SRAM mask */ +movi \ax, ~(SHIM_LDOCTL_LPSRAM_MASK) +and \ay, \ax, \ay +or \state, \ay, \state + +m_cavs_set_ldo_state \state, \ax +.endm + +.macro m_cavs_set_ldo_on_state ax, ay, az +movi \ay, (SHIM_BASE + SHIM_LDOCTL) +l32i \az, \ay, 0 + +movi \ax, ~(SHIM_LDOCTL_HPSRAM_MASK | SHIM_LDOCTL_LPSRAM_MASK) +and \az, \ax, \az +movi \ax, (SHIM_LDOCTL_HPSRAM_LDO_ON | SHIM_LDOCTL_LPSRAM_LDO_ON) +or \ax, \az, \ax + +m_cavs_set_ldo_state \ax, \ay +.endm + +.macro m_cavs_set_ldo_off_state ax, ay, az +/* wait loop > 300ns (min 100ns required) */ +movi \ax, 128 +1 : + addi \ax, \ax, -1 + nop + bnez \ax, 1b +movi \ay, (SHIM_BASE + SHIM_LDOCTL) +l32i \az, \ay, 0 + +movi \ax, ~(SHIM_LDOCTL_HPSRAM_MASK | SHIM_LDOCTL_LPSRAM_MASK) +and \az, \az, \ax + +movi \ax, (SHIM_LDOCTL_HPSRAM_LDO_OFF | SHIM_LDOCTL_LPSRAM_LDO_OFF) +or \ax, \ax, \az + +s32i \ax, \ay, 0 +l32i \ax, \ay, 0 +.endm + +.macro m_cavs_set_ldo_bypass_state ax, ay, az +/* wait loop > 300ns (min 100ns required) */ +movi \ax, 128 +1 : + addi \ax, \ax, -1 + nop + bnez \ax, 1b +movi \ay, (SHIM_BASE + SHIM_LDOCTL) +l32i \az, \ay, 0 + +movi \ax, ~(SHIM_LDOCTL_HPSRAM_MASK | SHIM_LDOCTL_LPSRAM_MASK) +and \az, \az, \ax + +movi \ax, (SHIM_LDOCTL_HPSRAM_LDO_BYPASS | SHIM_LDOCTL_LPSRAM_LDO_BYPASS) +or \ax, \ax, \az + +s32i \ax, \ay, 0 +l32i \ax, \ay, 0 +.endm + +#endif +#endif /* __ZEPHYR_CAVS_LIB_ASM_LDO_MANAGEMENT_H__ */ diff --git a/soc/xtensa/intel_adsp/cavs/asm_memory_management.h b/soc/xtensa/intel_adsp/cavs/asm_memory_management.h new file mode 100644 index 000000000000..1b247094fb04 --- /dev/null +++ b/soc/xtensa/intel_adsp/cavs/asm_memory_management.h @@ -0,0 +1,76 @@ +/* Copyright (c) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ZEPHYR_CAVS_LIB_ASM_MEMORY_MANAGEMENT_H__ +#define __ZEPHYR_CAVS_LIB_ASM_MEMORY_MANAGEMENT_H__ + +#ifdef _ASMLANGUAGE + +#define HSPGCTL0 0x71D10 +#define HSRMCTL0 0x71D14 +#define HSPGISTS0 0x71D18 + +#define LSPGCTL 0x71D50 +#define LSRMCTL 0x71D54 +#define LSPGISTS 0x71D58 + +#define SHIM_HSPGCTL(x) (HSPGCTL0 + 0x10 * (x)) +#define SHIM_HSPGISTS(x) (HSPGISTS0 + 0x10 * (x)) + +#define LPSRAM_MASK 0x1 +/** + * Macro powers down entire HPSRAM. On entry literals and code for section from + * where this code is executed need to be placed in memory which is not + * HPSRAM (in case when this code is located in HPSRAM, lock memory in L1$ or + * L1 SRAM) + */ +.macro m_cavs_hpsram_power_down_entire ax, ay, az + /* SEGMENT #0 */ + movi \az, SHIM_HSPGCTL(0) + movi \ax, SHIM_HSPGISTS(0) + movi \ay, 0x1FFFFFFF /* HPSRAM_MASK(0) */ + s32i \ay, \ax, 0 + memw +1 : + l32i \ax, \az, 0 + bne \ax, \ay, 1b + + /* SEGMENT #1 */ + movi \az, SHIM_HSPGCTL(1) + movi \ax, SHIM_HSPGISTS(1) + movi \ay, 0x0FFFFFFF /* HPSRAM_MASK(1) */ + s32i \ay, \ax, 0 + memw +1 : + l32i \ax, \az, 0 + bne \ax, \ay, 1b +.endm + +.macro m_cavs_hpsram_power_change segment_index, mask, ax, ay, az + movi \ax, SHIM_HSPGCTL(\segment_index) + movi \ay, SHIM_HSPGISTS(\segment_index) + s32i \mask, \ax, 0 + memw + /* assumed that HDA shared dma buffer will be in LPSRAM */ +1 : + l32i \ax, \ay, 0 + bne \ax, \mask, 1b +.endm + +.macro m_cavs_lpsram_power_down_entire ax, ay, az, loop_cnt_addr + movi \az, LSPGISTS + movi \ax, LSPGCTL + movi \ay, LPSRAM_MASK + s32i \ay, \ax, 0 + memw + /* assumed that HDA shared dma buffer will be in LPSRAM */ + movi \ax, \loop_cnt_addr + l32i \ax, \ax, 0 +1 : + addi \ax, \ax, -1 + bnez \ax, 1b +.endm + +#endif +#endif diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index ce4e20695004..df0f4eed8ce7 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include @@ -32,6 +35,84 @@ LOG_MODULE_REGISTER(soc); #endif +#ifdef CONFIG_PM + +#define SRAM_ALIAS_BASE 0x9E000000 +#define SRAM_ALIAS_MASK 0xFF000000 +#define EBB_BANKS_IN_SEGMENT 32 +#define SRAM_ALIAS_OFFSET 0x20000000 + +#define L2_INTERRUPT_NUMBER 4 +#define L2_INTERRUPT_MASK (1<= 0; + * --seg_index) { + * cavs_hpsram_power_change(seg_index, mask[seg_index]); + * } + * where mask is given in pu32_hpsram_mask register + */ + + .set seg_index, MAX_MEMORY_SEGMENTS - 1 + .rept MAX_MEMORY_SEGMENTS + l32i temp_reg0, pu32_hpsram_mask, 4 * seg_index + m_cavs_hpsram_power_change\ + /*segment_index=*/ seg_index,\ + /*mask=*/ temp_reg0,\ + temp_reg1,\ + temp_reg2,\ + temp_reg3 + .set seg_index, seg_index - 1 + .endr + + +/* mandatory sequence for LDO OFF - effectively executes: + * WAIT_300NS(); + * m_cavs_set_ldo_hpsram_on_state() + */ + movi temp_reg0, 128 +1 : + addi temp_reg0, temp_reg0, -1 + bnez temp_reg0, 1b + + movi temp_reg0, SHIM_LDOCTL_HPSRAM_LDO_OFF + m_cavs_set_hpldo_state temp_reg0, temp_reg1, temp_reg2 + +_PD_SEND_IPC: +/* Send IPC reply for SET_DX message */ + movi temp_reg1, 0 + s32i temp_reg1, host_base, IPC_DIPCIDD + + movi temp_reg1, set_dx_reply + l32i temp_reg1, temp_reg1, 0 + s32i temp_reg1, host_base, IPC_DIPCIDR + +_PD_SLEEP: +/* effecfively executes: + * xmp_spin() + * waiti 5 + */ + movi temp_reg0, 128 +loop: + addi temp_reg0, temp_reg0, -1 + bnez temp_reg0, loop + + extw + extw + waiti 5 + 1: + j 1b + +.size power_down_cavs , . - power_down_cavs + +