Skip to content
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

soc: intel_adsp: cavs: start using zephyr power management #55667

Merged
merged 1 commit into from
Mar 23, 2023
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
16 changes: 16 additions & 0 deletions dts/xtensa/intel/intel_adsp_cavs25.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
};
Expand All @@ -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>;
};
};

Expand Down
14 changes: 14 additions & 0 deletions dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
};
Expand All @@ -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>;
};
};

Expand Down
1 change: 1 addition & 0 deletions soc/xtensa/intel_adsp/cavs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
108 changes: 108 additions & 0 deletions soc/xtensa/intel_adsp/cavs/asm_ldo_management.h
Original file line number Diff line number Diff line change
@@ -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__ */
76 changes: 76 additions & 0 deletions soc/xtensa/intel_adsp/cavs/asm_memory_management.h
Original file line number Diff line number Diff line change
@@ -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
81 changes: 81 additions & 0 deletions soc/xtensa/intel_adsp/cavs/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <xtensa/hal.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>
#include <zephyr/device.h>
#include <cpu_init.h>

#include <adsp_shim.h>
#include <adsp_clk.h>
Expand All @@ -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<<L2_INTERRUPT_NUMBER)

#define L3_INTERRUPT_NUMBER 6
#define L3_INTERRUPT_MASK (1<<L3_INTERRUPT_NUMBER)

#define ALL_USED_INT_LEVELS_MASK (L2_INTERRUPT_MASK | L3_INTERRUPT_MASK)

struct core_state {
uint32_t intenable;
};

static struct core_state core_desc[CONFIG_MP_MAX_NUM_CPUS] = {{0}};

/**
* @brief Power down procedure.
*
* Locks its code in L1 cache and shuts down memories.
* NOTE: there's no return from this function.
*
* @param disable_lpsram flag if LPSRAM is to be disabled (whole)
* @param hpsram_pg_mask pointer to memory segments power gating mask
* (each bit corresponds to one ebb)
*/
extern void power_down_cavs(bool disable_lpsram, uint32_t *hpsram_pg_mask);

static inline void __sparse_cache *uncache_to_cache(void *address)
{
return (void __sparse_cache *)((uintptr_t)(address) | SRAM_ALIAS_OFFSET);
}

__weak void pm_state_set(enum pm_state state, uint8_t substate_id)
{
ARG_UNUSED(substate_id);
uint32_t cpu = arch_proc_id();

if (state == PM_STATE_SOFT_OFF) {
core_desc[cpu].intenable = XTENSA_RSR("INTENABLE");
z_xt_ints_off(0xffffffff);
soc_cpus_active[cpu] = false;
z_xtensa_cache_flush_inv_all();
if (cpu == 0) {
uint32_t ebb = EBB_BANKS_IN_SEGMENT;
/* turn off all HPSRAM banks - get a full bitmap */
uint32_t hpsram_mask = (1 << ebb) - 1;
/* do power down - this function won't return */
power_down_cavs(true, uncache_to_cache(&hpsram_mask));
} else {
z_xt_ints_on(core_desc[cpu].intenable);
k_cpu_idle();
}
} else {
__ASSERT(false, "invalid argument - unsupported power state");
}
}

/* Handle SOC specific activity after Low Power Mode Exit */
__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
{
ARG_UNUSED(substate_id);
uint32_t cpu = arch_proc_id();

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

__imr void power_init(void)
{
Expand Down
Loading