blob: aa6d134695b85777caf3c91069b9fb12c468a2f2 [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr.h>
#include <kernel.h>
#include <power.h>
#include <misc/printk.h>
#include <power.h>
#include <soc_power.h>
#include <rtc.h>
#include <ipm.h>
#include <ipm/ipm_quark_se.h>
#ifdef TEST_CASE_SLEEP_SUCCESS
#define TASK_TIME_IN_SEC 15
#define IDLE_TIME_IN_SEC 5
#else
#define TASK_TIME_IN_SEC 5
#define IDLE_TIME_IN_SEC 15
#endif /* TEST_CASE_SLEEP_SUCCESS */
#define MAX_SUSPEND_DEVICE_COUNT 15
static struct device *suspended_devices[MAX_SUSPEND_DEVICE_COUNT];
static int suspend_device_count;
static struct k_fifo fifo;
static struct device *ipm;
QUARK_SE_IPM_DEFINE(alarm_notification, 0, QUARK_SE_IPM_OUTBOUND);
static void suspend_devices(void)
{
for (int i = suspend_device_count - 1; i >= 0; i--) {
device_set_power_state(suspended_devices[i],
DEVICE_PM_SUSPEND_STATE);
}
}
static void resume_devices(void)
{
for (int i = 0; i < suspend_device_count; i++) {
device_set_power_state(suspended_devices[i],
DEVICE_PM_ACTIVE_STATE);
}
}
int _sys_soc_suspend(s32_t ticks)
{
printk("LMT: Try to put the system in SYS_POWER_STATE_DEEP_SLEEP_2"
" state\n");
if (!_sys_soc_power_state_is_arc_ready()) {
printk("LMT: Failed. ARC is busy.\n");
return SYS_PM_NOT_HANDLED;
}
suspend_devices();
_sys_soc_set_power_state(SYS_POWER_STATE_DEEP_SLEEP_2);
resume_devices();
printk("LMT: Succeed.\n");
_sys_soc_power_state_post_ops(SYS_POWER_STATE_DEEP_SLEEP_2);
return SYS_PM_DEEP_SLEEP;
}
static void build_suspend_device_list(void)
{
int i, devcount;
struct device *devices;
device_list_get(&devices, &devcount);
if (devcount > MAX_SUSPEND_DEVICE_COUNT) {
printk("Error: List of devices exceeds what we can track "
"for suspend. Built: %d, Max: %d\n",
devcount, MAX_SUSPEND_DEVICE_COUNT);
return;
}
suspend_device_count = 3;
for (i = 0; i < devcount; i++) {
if (!strcmp(devices[i].config->name, "loapic")) {
suspended_devices[0] = &devices[i];
} else if (!strcmp(devices[i].config->name, "ioapic")) {
suspended_devices[1] = &devices[i];
} else if (!strcmp(devices[i].config->name,
CONFIG_UART_CONSOLE_ON_DEV_NAME)) {
suspended_devices[2] = &devices[i];
} else {
suspended_devices[suspend_device_count++] = &devices[i];
}
}
}
static void alarm_handler(struct device *dev)
{
/* Unblock LMT application thread. */
k_fifo_put(&fifo, NULL);
/* Send a dummy message to ARC so the ARC application
* thread can be unblocked.
*/
ipm_send(ipm, 0, 0, NULL, 0);
}
void main(void)
{
struct device *rtc_dev;
struct rtc_config config;
u32_t now;
printk("LMT: Quark SE PM Multicore Demo\n");
k_fifo_init(&fifo);
build_suspend_device_list();
ipm = device_get_binding("alarm_notification");
if (!ipm) {
printk("Error: Failed to get IPM device\n");
return;
}
rtc_dev = device_get_binding("RTC_0");
if (!rtc_dev) {
printk("Error: Failed to get RTC device\n");
return;
}
rtc_enable(rtc_dev);
/* In QMSI, in order to save the alarm callback we must set
* 'alarm_enable = 1' during configuration. However, this
* automatically triggers the alarm underneath. So, to avoid
* the alarm being fired any time soon, we set the 'init_val'
* to 1 and the 'alarm_val' to 0.
*/
config.init_val = 1;
config.alarm_val = 0;
config.alarm_enable = 1;
config.cb_fn = alarm_handler;
rtc_set_config(rtc_dev, &config);
while (1) {
/* Simulate some task handling by busy waiting. */
printk("LMT: busy\n");
k_busy_wait(TASK_TIME_IN_SEC * 1000 * 1000);
now = rtc_read(rtc_dev);
rtc_set_alarm(rtc_dev,
now + (RTC_ALARM_SECOND * IDLE_TIME_IN_SEC));
printk("LMT: idle\n");
k_fifo_get(&fifo, K_FOREVER);
}
}