power: Add ARC core suspend and resume support
When going into DEEP_SLEEP mode, the ARC core now saves its context. This includes: - All core registers - Stack pointer - Program counter (restored by jumping to the restore code) The arc reset code now checks if the GPS0 bit 2 is set. This is similar to the behavior of the x86 core done by the QMSI bootloader which is setting GPS0 bit 1 in order to call the restore path instead of cold boot path. The sample has been adapted in order to support the ARC. Jira: ZEP-1222 Change-Id: I375f03b16b8a5fd1f07ead55cf7e4947d6290c9f Signed-off-by: Julien Delayen <julien.delayen@intel.com>
This commit is contained in:
parent
d127864366
commit
176d184fb8
@ -4,7 +4,7 @@ ccflags-y +=-I$(srctree)/arch/$(ARCH)/include
|
||||
obj-y += thread.o thread_entry_wrapper.o \
|
||||
cpu_idle.o fast_irq.o fatal.o fault.o \
|
||||
fault_s.o irq_manage.o cache.o \
|
||||
isr_wrapper.o regular_irq.o swap_macros.h swap.o \
|
||||
isr_wrapper.o regular_irq.o swap.o \
|
||||
sys_fatal_error_handler.o
|
||||
|
||||
obj-y += prep_c.o \
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
#include <offsets_short.h>
|
||||
#include <toolchain.h>
|
||||
#include <arch/cpu.h>
|
||||
#include "swap_macros.h"
|
||||
#include <swap_macros.h>
|
||||
|
||||
GTEXT(_firq_enter)
|
||||
GTEXT(_firq_exit)
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
#include <toolchain.h>
|
||||
#include <sections.h>
|
||||
#include <arch/cpu.h>
|
||||
#include "swap_macros.h"
|
||||
#include <swap_macros.h>
|
||||
|
||||
GTEXT(_Fault)
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
#include <offsets_short.h>
|
||||
#include <toolchain.h>
|
||||
#include <arch/cpu.h>
|
||||
#include "swap_macros.h"
|
||||
#include <swap_macros.h>
|
||||
|
||||
GTEXT(_rirq_enter)
|
||||
GTEXT(_rirq_exit)
|
||||
|
||||
@ -99,6 +99,11 @@ invalidate_dcache:
|
||||
|
||||
done_cache_invalidate:
|
||||
|
||||
#if defined(CONFIG_SYS_POWER_DEEP_SLEEP) && \
|
||||
!defined(CONFIG_BOOTLOADER_CONTEXT_RESTORE)
|
||||
jl @_sys_soc_resume_from_deep_sleep
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INIT_STACKS
|
||||
/*
|
||||
* use the main stack to call memset on the interrupt stack and the
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include <toolchain.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <v2/irq.h>
|
||||
#include "swap_macros.h"
|
||||
#include <swap_macros.h>
|
||||
|
||||
GTEXT(_Swap)
|
||||
GTEXT(_get_next_ready_thread)
|
||||
|
||||
@ -155,8 +155,8 @@ extern "C" {
|
||||
*
|
||||
* The pc and status32 values will still be on the stack. We cannot
|
||||
* pop them yet because the callers of _pop_irq_stack_frame must reload
|
||||
* status32 differently depending on the execution context they are running
|
||||
* in (_Swap(), firq or exception).
|
||||
* status32 differently depending on the execution context they are
|
||||
* running in (_Swap(), firq or exception).
|
||||
*/
|
||||
add_s sp, sp, ___isf_t_SIZEOF
|
||||
|
||||
@ -6,4 +6,4 @@ ccflags-$(CONFIG_ADC) +=-I$(srctree)/drivers/adc
|
||||
|
||||
asflags-y := ${ccflags-y}
|
||||
|
||||
obj-y = soc.o soc_config.o power.o
|
||||
obj-y = soc.o soc_config.o soc_power.o power.o
|
||||
|
||||
@ -2,4 +2,5 @@
|
||||
config SOC_QUARK_SE_C1000_SS
|
||||
bool "Intel Quark SE C1000- Sensor Sub System"
|
||||
select SYS_POWER_LOW_POWER_STATE_SUPPORTED
|
||||
select SYS_POWER_DEEP_SLEEP_SUPPORTED
|
||||
select HAS_QMSI
|
||||
|
||||
@ -22,7 +22,30 @@
|
||||
#include <init.h>
|
||||
#include <kernel_structs.h>
|
||||
|
||||
#include "power_states.h"
|
||||
#include "ss_power_states.h"
|
||||
#include "vreg.h"
|
||||
|
||||
#if (defined(CONFIG_SYS_POWER_DEEP_SLEEP))
|
||||
extern void _power_soc_sleep(void);
|
||||
extern void _power_soc_deep_sleep(void);
|
||||
|
||||
static void _deep_sleep(enum power_states state)
|
||||
{
|
||||
power_soc_set_ss_restore_flag();
|
||||
|
||||
switch (state) {
|
||||
case SYS_POWER_STATE_DEEP_SLEEP_1:
|
||||
_power_soc_sleep();
|
||||
break;
|
||||
case SYS_POWER_STATE_DEEP_SLEEP:
|
||||
_power_soc_deep_sleep();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SLEEP_MODE_CORE_OFF (0x0)
|
||||
#define SLEEP_MODE_CORE_TIMERS_RTC_OFF (0x60)
|
||||
@ -57,10 +80,12 @@ void _sys_soc_set_power_state(enum power_states state)
|
||||
case SYS_POWER_STATE_CPU_LPS_2:
|
||||
enter_arc_state(ARC_SS1);
|
||||
break;
|
||||
#if (defined(CONFIG_SYS_POWER_DEEP_SLEEP))
|
||||
case SYS_POWER_STATE_DEEP_SLEEP:
|
||||
case SYS_POWER_STATE_DEEP_SLEEP_1:
|
||||
/* Sleep states are not yet supported for ARC. */
|
||||
_deep_sleep(state);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -78,6 +103,10 @@ void _sys_soc_power_state_post_ops(enum power_states state)
|
||||
limit = _arc_v2_aux_reg_read(_ARC_V2_TMR0_LIMIT);
|
||||
_arc_v2_aux_reg_write(_ARC_V2_TMR0_COUNT, limit - 1);
|
||||
break;
|
||||
case SYS_POWER_STATE_DEEP_SLEEP:
|
||||
case SYS_POWER_STATE_DEEP_SLEEP_1:
|
||||
__builtin_arc_seti(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
93
arch/arc/soc/quark_se_c1000_ss/soc_power.S
Normal file
93
arch/arc/soc/quark_se_c1000_ss/soc_power.S
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define _ASMLANGUAGE
|
||||
|
||||
#include <toolchain.h>
|
||||
#include <arch/arc/v2/aux_regs.h>
|
||||
#include <swap_macros.h>
|
||||
|
||||
#ifdef CONFIG_SYS_POWER_DEEP_SLEEP
|
||||
GDATA(_pm_arc_context)
|
||||
|
||||
GTEXT(_sys_soc_resume_from_deep_sleep)
|
||||
GTEXT(_power_restore_cpu_context)
|
||||
GTEXT(_power_soc_sleep)
|
||||
GTEXT(_power_soc_deep_sleep)
|
||||
|
||||
#define GPS0_REGISTER 0xb0800100
|
||||
#define RESTORE_SS_BIT 2
|
||||
|
||||
SECTION_FUNC(TEXT, _sys_soc_resume_from_deep_sleep)
|
||||
/* Check is this wakeup after sleep event. */
|
||||
ld r0,[GPS0_REGISTER]
|
||||
bbit1 r0,RESTORE_SS_BIT,restore
|
||||
j_s [blink] /* Jump to context of BLINK register. */
|
||||
|
||||
restore:
|
||||
bclr_s r0,r0,RESTORE_SS_BIT
|
||||
st r0,[GPS0_REGISTER]
|
||||
|
||||
/* Enable I-Cache */
|
||||
sr 1, [_ARC_V2_IC_CTRL]
|
||||
|
||||
j @_sys_soc_restore_cpu_context
|
||||
|
||||
SECTION_FUNC(TEXT, save_cpu_context)
|
||||
mov_s r1, _kernel
|
||||
ld_s r2, [r1, _kernel_offset_to_current]
|
||||
|
||||
_save_callee_saved_regs
|
||||
|
||||
j_s [blink] /* Jump to context of BLINK register. */
|
||||
|
||||
SECTION_FUNC(TEXT, _power_soc_sleep)
|
||||
/*
|
||||
* Save the return address.
|
||||
* The restore function will pop this and jump
|
||||
* back to the caller.
|
||||
*/
|
||||
push_s blink
|
||||
|
||||
/* Do not link to preserve blink */
|
||||
jl @save_cpu_context
|
||||
j @power_soc_sleep
|
||||
/* Does not return */
|
||||
|
||||
SECTION_FUNC(TEXT, _power_soc_deep_sleep)
|
||||
/*
|
||||
* Save the return address.
|
||||
* The restore function will pop this and jump
|
||||
* back to the caller.
|
||||
*/
|
||||
push_s blink
|
||||
|
||||
/* Do not link to preserve blink */
|
||||
jl @save_cpu_context
|
||||
j @power_soc_deep_sleep
|
||||
/* Does not return */
|
||||
|
||||
SECTION_FUNC(TEXT, _sys_soc_restore_cpu_context)
|
||||
mov_s r1, _kernel
|
||||
ld_s r2, [r1, _kernel_offset_to_current]
|
||||
|
||||
_load_callee_saved_regs
|
||||
|
||||
/* Restore return address */
|
||||
pop_s blink
|
||||
|
||||
j_s [blink] /* Jump to context of BLINK register. */
|
||||
#endif
|
||||
@ -1,6 +1,7 @@
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += drivers/flash/qm_flash.o
|
||||
ifeq ($(CONFIG_ARC),y)
|
||||
ifeq ($(CONFIG_SOC_QUARK_SE_C1000_SS),y)
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += drivers/clk/ss_clk.o
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/quark_se/drivers/vreg.o
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/quark_se/drivers/ss_power_states.o
|
||||
endif
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/$(patsubst %_ss,%,$(SOC_SERIES))/drivers/power_states.o
|
||||
@ -25,4 +26,4 @@ obj-$(CONFIG_SPI_QMSI_SS) += drivers/spi/qm_ss_spi.o
|
||||
obj-$(CONFIG_GPIO_QMSI_SS) += drivers/gpio/qm_ss_gpio.o
|
||||
obj-$(CONFIG_I2C_QMSI_SS) += drivers/i2c/qm_ss_i2c.o
|
||||
obj-$(CONFIG_ADC_QMSI_SS) += drivers/adc/qm_ss_adc.o
|
||||
obj-$(CONFIG_SOC_WATCH) += drivers/soc_watch.o
|
||||
obj-$(CONFIG_SOC_WATCH) += drivers/soc_watch.o
|
||||
|
||||
@ -351,6 +351,7 @@ static void build_suspend_device_list(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_X86)
|
||||
suspend_device_count = 3;
|
||||
for (i = 0; i < devcount; i++) {
|
||||
if (!strcmp(devices[i].config->name, "loapic")) {
|
||||
@ -364,6 +365,18 @@ static void build_suspend_device_list(void)
|
||||
suspend_devices[suspend_device_count++] = &devices[i];
|
||||
}
|
||||
}
|
||||
#elif (CONFIG_ARC)
|
||||
suspend_device_count = 2;
|
||||
for (i = 0; i < devcount; i++) {
|
||||
if (!strcmp(devices[i].config->name, "arc_v2_irq_unit")) {
|
||||
suspend_devices[0] = &devices[i];
|
||||
} else if (!strcmp(devices[i].config->name, "sys_clock")) {
|
||||
suspend_devices[1] = &devices[i];
|
||||
} else {
|
||||
suspend_devices[suspend_device_count++] = &devices[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void main(void)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user