blob: d8e7bf24df58945de661bd45cec3f5d1597385bd [file] [log] [blame] [edit]
/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include "FreeRTOS.h" /* Must come first. */
#include "task.h" /* RTOS task related API prototypes. */
#include "queue.h" /* RTOS queue related API prototypes. */
#include "timers.h" /* Software timer related API prototypes. */
#include "semphr.h" /* Semaphore related API prototypes. */
#include <unistd.h>
#include <string.h>
#include "n200_func.h"
#include "common.h"
#include "riscv_encoding.h"
#include "gcc_compiler_attributes.h"
#include "suspend.h"
#include "power.h"
#include "hdmi_cec.h"
#include "vrtc.h"
#include "rtc.h"
#include "mailbox-api.h"
#include "eth.h"
#include "wakeup.h"
#include "stick_mem.h"
#include "pm.h"
#include "suspend_debug.h"
#include "uart.h"
SemaphoreHandle_t xSTRSemaphore;
QueueHandle_t xSTRQueue;
SemaphoreHandle_t xSTRFlagSem;
uint32_t suspend_flag;
#if BL30_SUSPEND_DEBUG_EN
uint32_t suspend_debug_flag;
#endif
uint32_t power_mode;
struct WakeUp_Reason vWakeupReason[] = {
[UDEFINED_WAKEUP] = { .name = "undefine" },
[CHARGING_WAKEUP] = { .name = "charging" },
[REMOTE_WAKEUP] = { .name = "remote" },
[RTC_WAKEUP] = { .name = "rtc" },
[BT_WAKEUP] = { .name = "bt" },
[WIFI_WAKEUP] = { .name = "wifi" },
[POWER_KEY_WAKEUP] = { .name = "powerkey" },
[AUTO_WAKEUP] = { .name = "auto" },
[CEC_WAKEUP] = { .name = "cec" },
[REMOTE_CUS_WAKEUP] = { .name = "remote_cus" },
[ETH_PMT_WAKEUP] = { .name = "eth" },
[CECB_WAKEUP] = { .name = "cecb" },
[ETH_PHY_GPIO] = { .name = "eth_gpio" },
[VAD_WAKEUP] = { .name = "vad" },
[HDMI_RX_WAKEUP] = { .name = "hdmirx_plugin" },
};
void set_suspend_flag(void)
{
taskENTER_CRITICAL();
suspend_flag = 1;
vETHEnableIrq();
taskEXIT_CRITICAL();
}
__weak void vDDR_suspend(uint32_t st_f)
{
(void)st_f;
}
__weak void vDDR_resume(uint32_t st_f)
{
(void)st_f;
}
__weak void alarm_set(void)
{
}
__weak void alarm_clr(void)
{
}
__weak void vRTC_update(void)
{
}
__weak void vCreat_alarm_timer(void)
{
}
__weak void store_rtc(void)
{
}
__weak void vCLK_suspend(uint32_t st_f)
{
(void)st_f;
}
__weak void vCLK_resume(uint32_t st_f)
{
(void)st_f;
}
__weak void check_poweroff_status(void)
{
vTaskDelay(pdMS_TO_TICKS(500));
}
#if BL30_SUSPEND_DEBUG_EN
inline void split_suspend_debug_flag(uint32_t *temp)
{
suspend_debug_flag = (*temp) & SUSPEND_DEBUG_MASK;
*temp = (*temp) & ~SUSPEND_DEBUG_MASK;
}
inline uint32_t get_suspend_debug_flag(void)
{
return suspend_debug_flag;
}
void vDebugPrintTask(void *pvParameters)
{
/*make compiler happy*/
(void) pvParameters;
for ( ;; ) {
printf("vPTask1...\n");
vTaskDelay(pdMS_TO_TICKS(TEST_TASK1_DELAY));
}
}
#endif
void system_resume(uint32_t pm)
{
uint32_t shutdown_flag = 0;
#if BL30_SUSPEND_DEBUG_EN
enter_func_print();
#endif
if (pm == POWER_MODE_POWER_OFF)
shutdown_flag = 1;
vCLK_resume(shutdown_flag);
/*Need clr alarm ASAP*/
alarm_clr();
str_power_on(shutdown_flag);
#if BL30_SUSPEND_DEBUG_EN
if (!IS_EN(BL30_SKIP_DDR_SUSPEND))
#endif
vDDR_resume(shutdown_flag);
str_hw_disable();
vRTC_update();
wakeup_ap();
clear_wakeup_trigger();
/*Shutdown*/
if (shutdown_flag) {
/* Store RTC time for a5 temporarily*/
store_rtc();
watchdog_reset_system();
}
#if BL30_SUSPEND_DEBUG_EN
stop_debug_task();
exit_func_print();
#endif
}
void system_suspend(uint32_t pm)
{
uint32_t shutdown_flag = 0;
#if BL30_SUSPEND_DEBUG_EN
split_suspend_debug_flag(&pm);
enter_func_print();
start_debug_task();
#endif
if (pm == POWER_MODE_POWER_OFF)
shutdown_flag = 1;
/*Need set alarm ASAP*/
alarm_set();
str_hw_init();
/*Set flag befor delay. It can be wakeup during delay*/
set_suspend_flag();
/*Wait for FSM switch to off*/
check_poweroff_status();
#if BL30_SUSPEND_DEBUG_EN
if (!IS_EN(BL30_SKIP_DDR_SUSPEND))
#endif
vDDR_suspend(shutdown_flag);
str_power_off(shutdown_flag);
vCLK_suspend(shutdown_flag);
#if BL30_SUSPEND_DEBUG_EN
exit_func_print();
#endif
}
void set_reason_flag(char exit_reason)
{
uint32_t val;
val = REG32(WAKEUP_REASON_STICK_REG) & ~0xff;
val |= EXIT_REASON_EXTENSION_FLAG;
val |= (exit_reason & 0x7f);
REG32(WAKEUP_REASON_STICK_REG) = val;
}
uint32_t get_reason_flag(void)
{
return REG32(WAKEUP_REASON_STICK_REG) & 0x7f;
}
void *xMboxGetWakeupReason(void *msg)
{
*(uint32_t *)msg = get_reason_flag();
return NULL;
}
void *xMboxClrWakeupReason(void *msg)
{
(void)msg;
return NULL;
}
void *xMboxGetStickRebootFlag(void *msg)
{
#ifdef CONFIG_STICK_MEM
*(uint32_t *)msg = get_stick_reboot_flag();
#else
printf("Don't support stick memory!\r\n");
#endif
return NULL;
}
void STR_Start_Sem_Give_FromISR(void)
{
BaseType_t xHigherPriorityTaskWoken;
xSemaphoreGiveFromISR(xSTRSemaphore, &xHigherPriorityTaskWoken);
}
void STR_Start_Sem_Give(void)
{
xSemaphoreGive(xSTRSemaphore);
}
void STR_Wakeup_src_Queue_Send_FromISR(uint32_t *src)
{
BaseType_t xHigherPriorityTaskWoken;
uint32_t flag = 0;
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
if (suspend_flag) {
suspend_flag = 0;
flag = 1;
}
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
if (flag)
xQueueSendFromISR(xSTRQueue, src, &xHigherPriorityTaskWoken);
}
void STR_Wakeup_src_Queue_Send(uint32_t *src)
{
uint32_t flag = 0;
taskENTER_CRITICAL();
if (suspend_flag) {
suspend_flag = 0;
flag = 1;
}
taskEXIT_CRITICAL();
if (flag)
xQueueSend(xSTRQueue, src, portMAX_DELAY);
}
void *xMboxSuspend_Sem(void *msg)
{
power_mode = *(uint32_t *)msg;
#ifdef ACS_DIS_PRINT_FLAG
enable_bl30_print(1);
#endif
switch (power_mode & POWER_MODE_MASK) {
case POWER_MODE_SUSPEND_1:
case POWER_MODE_SUSPEND_2:
printf("power_mode: SUSPEND\n");
break;
case POWER_MODE_POWER_OFF:
printf("power_mode: POWER OFF\n");
break;
default:
printf("power_mode: UNKNOWN\n");
break;
}
STR_Start_Sem_Give();
return NULL;
}
#define FREEZE_ENTER 0x01
#define FREEZE_EXIT 0x02
void *xMboxpm_sem(void *msg);
void *xMboxpm_sem(void *msg)
{
uint32_t mode = *(uint32_t *)msg;
#ifdef ACS_DIS_PRINT_FLAG
enable_bl30_print(1);
#endif
#ifdef CONFIG_PM
if (mode == FREEZE_ENTER)
pm_enter();
else if (mode == FREEZE_EXIT)
wakeup_ap_from_kernel();
#endif
return NULL;
}
static void vSTRTask(void *pvParameters)
{
/*make compiler happy*/
uint32_t buffer = UDEFINED_WAKEUP;
uint32_t exit_reason = 0;
(void)pvParameters;
xSTRQueue = xQueueCreate(STR_QUEUE_LENGTH, STR_QUEUE_ITEM_SIZE);
configASSERT(xSTRQueue);
xSTRSemaphore = xSemaphoreCreateBinary();
configASSERT(xSTRSemaphore);
while (1) {
xSemaphoreTake(xSTRSemaphore, portMAX_DELAY);
system_suspend(power_mode);
while (xQueueReceive(xSTRQueue, &buffer, portMAX_DELAY)) {
switch (buffer) {
case REMOTE_WAKEUP:
exit_reason = REMOTE_WAKEUP;
break;
case RTC_WAKEUP:
exit_reason = RTC_WAKEUP;
break;
case BT_WAKEUP:
exit_reason = BT_WAKEUP;
break;
case CEC_WAKEUP:
exit_reason = CEC_WAKEUP;
break;
case CECB_WAKEUP:
exit_reason = CECB_WAKEUP;
break;
case REMOTE_CUS_WAKEUP:
exit_reason = REMOTE_CUS_WAKEUP;
break;
case POWER_KEY_WAKEUP:
exit_reason = POWER_KEY_WAKEUP;
break;
case ETH_PMT_WAKEUP:
exit_reason = ETH_PMT_WAKEUP;
break;
case WIFI_WAKEUP:
exit_reason = WIFI_WAKEUP;
break;
case ETH_PHY_GPIO:
exit_reason = ETH_PHY_GPIO;
printf("wzh eth gpio\n");
break;
case VAD_WAKEUP:
exit_reason = VAD_WAKEUP;
break;
case HDMI_RX_WAKEUP:
exit_reason = HDMI_RX_WAKEUP;
break;
case UART_RX_WAKEUP:
exit_reason = UART_RX_WAKEUP;
break;
default:
printf("unknown exit_reason %d\n", exit_reason);
set_suspend_flag();
break;
}
if (exit_reason) {
printf("exit_reason=%d, %s\n", exit_reason,
vWakeupReason[exit_reason].name);
set_reason_flag((char)exit_reason);
exit_reason = 0;
system_resume(power_mode);
goto loop;
}
}
loop:
continue;
}
}
void create_str_task(void)
{
if (xTaskCreate(vSTRTask, "STR_task", configMINIMAL_STACK_SIZE, NULL, 3, NULL) < 0)
printf("STR_task create fail!!\n");
vCreat_alarm_timer();
xInstallRemoteMessageCallbackFeedBack(AOTEE_CHANNEL,
MBX_CMD_SUSPEND, xMboxSuspend_Sem, 0);
xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL,
MBX_CMD_GET_WAKEUP_REASON, xMboxGetWakeupReason, 1);
xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL,
MBX_CMD_CLR_WAKEUP_REASON, xMboxClrWakeupReason, 0);
xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL,
MBX_CMD_GET_STICK_REBOOT_FLAG, xMboxGetStickRebootFlag, 1);
xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL,
MBX_CMD_PM_FREEZE, xMboxpm_sem, 1);
}