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:
Julien Delayen 2016-11-01 13:07:34 +00:00 committed by Anas Nashif
parent d127864366
commit 176d184fb8
13 changed files with 153 additions and 11 deletions

View File

@ -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 \

View File

@ -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)

View File

@ -26,7 +26,7 @@
#include <toolchain.h>
#include <sections.h>
#include <arch/cpu.h>
#include "swap_macros.h"
#include <swap_macros.h>
GTEXT(_Fault)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View 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

View File

@ -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

View File

@ -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)