/* * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. * * SPDX-License-Identifier: MIT */ #include #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 #include #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); }