Skip to content

Commit

Permalink
soc: intel_adsp: cavs: start using zephyr power management
Browse files Browse the repository at this point in the history
Start using zephyr power management in cavs platform in a similar way
that is already done in ace. This commit only addresses the power off/on
sequence. Runtime power management is not implemented.

Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
  • Loading branch information
Jaska Uimonen authored and nashif committed Mar 23, 2023
1 parent 59fe77a commit 95168e6
Show file tree
Hide file tree
Showing 7 changed files with 453 additions and 0 deletions.
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

0 comments on commit 95168e6

Please sign in to comment.