Files
BPI-CM9-Linux/aml-comp/uboot/bl30/rtos_sdk/drivers_aocpu/str/suspend.c
T

524 lines
10 KiB
C

/*
* 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"
#if CONFIG_WIFI_BT_WAKE
#include "wifi_bt_wake.h"
#endif
#ifdef CONFIG_ALIVE_CHECK
#include "alive_check.h"
#endif
SemaphoreHandle_t xSTRSemaphore;
QueueHandle_t xSTRQueue;
SemaphoreHandle_t xSTRFlagSem;
static uint8_t suspend_flag;
#if BL30_SUSPEND_DEBUG_EN
uint32_t suspend_debug_flag;
TaskHandle_t printTask;
#endif
uint32_t power_mode;
uint8_t ddr_is_asr_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_pmt" },
[CECB_WAKEUP] = { .name = "cecb" },
[ETH_PHY_GPIO] = { .name = "eth_gpio" },
[VAD_WAKEUP] = { .name = "vad" },
[HDMI_RX_WAKEUP] = { .name = "hdmirx_plugin" },
[UART_RX_WAKEUP] = { .name = "uart_rx" },
[RADAR_GPIO_WAKEUP] = { .name = "radar_gpio" },
[ETH_WAKEUP] = { .name = "eth_apf" },
[SED_WAKEUP] = { .name = "sed"},
};
static void set_suspend_flag(void)
{
taskENTER_CRITICAL();
suspend_flag = 1;
taskEXIT_CRITICAL();
#ifdef CONFIG_ETHERNET
vETHEnableIrq();
#endif
}
uint8_t get_suspend_flag(void)
{
return suspend_flag;
}
__weak void vDDR_suspend(uint32_t st_f)
{
(void)st_f;
}
__weak void vDDR_resume(uint32_t st_f)
{
(void)st_f;
}
__weak void vRtcAlarmSet(void)
{
}
__weak void vRtcAlarmClr(void)
{
}
__weak void vStoreRtc(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));
}
__weak void vDSP_suspend(uint32_t st_f)
{
(void)st_f;
}
__weak void vDSP_resume(uint32_t st_f)
{
(void)st_f;
}
#if BL30_SUSPEND_DEBUG_EN
inline void split_suspend_debug_flag(uint32_t *temp)
{
suspend_debug_flag = (*temp) & SUSPEND_DEBUG_MASK;
*temp = (*temp) & POWER_MODE_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
static void update_ddr_asr_mode(uint32_t *temp)
{
ddr_is_asr_mode = ((*temp) & DDR_IS_ASR_MODE) ? 1 : 0;
*temp = (*temp) & ~DDR_IS_ASR_MODE;
}
static void system_resume(uint32_t pm)
{
uint32_t shutdown_flag = 0, err = 0;
#if BL30_SUSPEND_DEBUG_EN
split_suspend_debug_flag(&pm);
enter_func_print();
#endif
if (pm == POWER_MODE_POWER_OFF)
shutdown_flag = 1;
vDSP_resume(shutdown_flag);
vCLK_resume(shutdown_flag);
/*Need clr alarm ASAP*/
vRtcAlarmClr();
vUartEnTxBuf();
err = str_power_on(shutdown_flag);
if (err)
printf("[%s]str err:%u.\n", __func__, err);
#if BL30_SUSPEND_DEBUG_EN
if (!IS_EN(BL30_SKIP_DDR_SUSPEND))
#endif
vDDR_resume(shutdown_flag);
#if CONFIG_WIFI_BT_WAKE
#if BL30_SUSPEND_DEBUG_EN
if (!IS_EN(BL30_BT_WAKEUP_MASK))
#endif
wifi_bt_wakeup_deinit();
#endif
str_hw_disable();
wakeup_ap();
clear_wakeup_trigger();
/*Shutdown*/
if (shutdown_flag) {
/* Store RTC time for a5 temporarily*/
vStoreRtc();
watchdog_reset_system();
}
#if BL30_SUSPEND_DEBUG_EN
stop_debug_task();
exit_func_print();
#endif
#ifdef CONFIG_ALIVE_CHECK
vARMAliveCheckReset();
#endif
}
static void system_suspend(uint32_t pm)
{
uint32_t shutdown_flag = 0, err = 0;
#ifdef CONFIG_ALIVE_CHECK
vARMAliveCheckStop();
#endif
update_ddr_asr_mode(&pm);
#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*/
vRtcAlarmSet();
vUartDisTxBuf();
str_hw_init();
/*Set flag befor delay. It can be wakeup during delay*/
set_suspend_flag();
#if CONFIG_WIFI_BT_WAKE
#if BL30_SUSPEND_DEBUG_EN
if (IS_EN(BL30_BT_WAKEUP_MASK))
printf("skip WIFI/BT wakeup\n");
else
#endif
wifi_bt_wakeup_init();
#endif
/*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);
err = str_power_off(shutdown_flag);
if (err)
printf("[%s]str err:%u.\n", __func__, err);
vCLK_suspend(shutdown_flag);
vDSP_suspend(shutdown_flag);
#if BL30_SUSPEND_DEBUG_EN
exit_func_print();
#endif
}
static 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;
}
#if defined(CONFIG_WATCHDOG)
void vSetWdtFlag(void)
{
uint32_t val;
val = REG32(WAKEUP_REASON_STICK_REG);
val |= AO_WDT_FLAG;
REG32(WAKEUP_REASON_STICK_REG) = val;
}
void vClrWdtFlag(void)
{
uint32_t val;
val = REG32(WAKEUP_REASON_STICK_REG);
val &= ~AO_WDT_FLAG;
REG32(WAKEUP_REASON_STICK_REG) = val;
}
#endif
static void *xMboxGetWakeupReason(void *msg)
{
*(uint32_t *)msg = get_reason_flag();
return NULL;
}
static void *xMboxClrWakeupReason(void *msg)
{
(void)msg;
return NULL;
}
static void *xMboxGetStickRebootFlag(void *msg)
{
#ifdef CONFIG_STICK_MEM
*(uint32_t *)msg = get_stick_reboot_flag();
#else
(void)msg;
printf("no 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("mode: SUSPEND\n");
break;
case POWER_MODE_POWER_OFF:
printf("mode: POWER OFF\n");
break;
default:
printf("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)
{
#ifdef CONFIG_PM
uint32_t mode = *(uint32_t *)msg;
#else
(void)msg;
#endif
#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;
case RADAR_GPIO_WAKEUP:
exit_reason = RADAR_GPIO_WAKEUP;
break;
case ETH_WAKEUP:
exit_reason = ETH_WAKEUP;
break;
case SED_WAKEUP:
exit_reason = SED_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_tsk", configMINIMAL_STACK_SIZE, NULL, 3, NULL) < 0)
printf("STR_tsk create fail!\n");
xInstallRemoteMessageCallbackFeedBack(TEE2AO_CHANNEL,
MBX_CMD_SUSPEND, xMboxSuspend_Sem, 0);
xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL,
MBX_CMD_GET_WAKEUP_REASON, xMboxGetWakeupReason, 1);
xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL,
MBX_CMD_CLR_WAKEUP_REASON, xMboxClrWakeupReason, 0);
xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL,
MBX_CMD_GET_STICK_REBOOT_FLAG, xMboxGetStickRebootFlag, 1);
xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL,
MBX_CMD_PM_FREEZE, xMboxpm_sem, 1);
}