/* * Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "common/board/board.h" #include "pm/pm.h" #include "driver/chip/hal_util.h" /* * retarget for standard output/error */ #if PRJCONF_UART_EN #define STDOUT_WAIT_UART_TX_DONE 1 #if STDOUT_WAIT_UART_TX_DONE #define STDOUT_WAIT_UART_TX_TIME 100 /* wait uart tx done, 100 us for baudrate 115200 */ #else #define STDOUT_WAIT_UART_TX_TIME 0 #endif static uint8_t g_stdout_enable = 1; static UART_ID g_stdout_uart_id = UART_NUM; #ifdef CONFIG_PM #include #include static uint32_t pm_print_index; static uint32_t pm_print_len; static char *pm_print_buf; static int8_t g_stdio_suspending = 0; __nonxip_text static int stdio_suspend(struct soc_device *dev, enum suspend_state_t state) { g_stdio_suspending = 1; #if STDOUT_WAIT_UART_TX_DONE if (g_stdout_enable && g_stdout_uart_id < UART_NUM) { UART_T *uart = HAL_UART_GetInstance(g_stdout_uart_id); while (!HAL_UART_IsTxEmpty(uart)) { } HAL_UDelay(STDOUT_WAIT_UART_TX_TIME); /* wait tx done */ } #endif switch (state) { case PM_MODE_SLEEP: case PM_MODE_STANDBY: case PM_MODE_HIBERNATION: printf("a%s ok\n", __func__); break; default: break; } return 0; } /* BESURE app cpu has run now for nuart use app gpio */ __nonxip_text static int stdio_resume(struct soc_device *dev, enum suspend_state_t state) { switch (state) { case PM_MODE_SLEEP: case PM_MODE_STANDBY: case PM_MODE_HIBERNATION: printf("a%s ok\n", __func__); break; default: break; } g_stdio_suspending = 0; if (pm_print_len > 0 && pm_print_index > 0) { pm_print_buf[pm_print_index] = '\0'; puts(pm_print_buf); pm_print_index = 0; } return 0; } static const struct soc_device_driver stdio_drv = { .name = "astdio", .suspend_noirq = stdio_suspend, .resume_noirq = stdio_resume, .enter_latency = STDOUT_WAIT_UART_TX_TIME + 2, /* at CPU 160MHz */ .exit_latency = 1, /* at CPU 160MHz */ }; static struct soc_device stdio_dev = { .name = "astdio", .driver = &stdio_drv, }; #define STDIO_DEV (&stdio_dev) void uart_set_suspend_record(unsigned int len) { char *buf; if (pm_print_len == len) { return; } if (pm_print_len > 0) { buf = pm_print_buf; pm_print_len = 0; pm_print_buf = NULL; free(buf); } if (len > 0) { buf = malloc(len); if (buf) { pm_print_buf = buf; pm_print_len = len; } } pm_print_index = 0; } #endif /* CONFIG_PM */ void stdout_enable(uint8_t en) { g_stdout_enable = en; } static int stdout_write(const char *buf, int len) { if (!g_stdout_enable || g_stdout_uart_id >= UART_NUM || len <= 0) { return 0; } #ifdef CONFIG_PM if (g_stdio_suspending) { if (pm_print_len > 0 && pm_print_index + len < (pm_print_len - 1)) { memcpy(pm_print_buf + pm_print_index, buf, len); pm_print_index += len; return len; } else { return 0; } } #endif return board_uart_write(g_stdout_uart_id, buf, len); } int stdout_init(void) { if (g_stdout_uart_id < UART_NUM) { return 0; } if (board_uart_init(BOARD_MAIN_UART_ID) == HAL_OK) { g_stdout_uart_id = BOARD_MAIN_UART_ID; #ifdef CONFIG_LIBC_WRAP_STDIO stdio_set_write(stdout_write); #endif #ifdef CONFIG_PM if (!g_stdio_suspending) { pm_register_ops(STDIO_DEV); } #endif #ifdef CONFIG_TRUSTZONE TZ_StdoutInit_NSC(BOARD_MAIN_UART_ID); #endif return 0; } return -1; } int stdout_deinit(void) { if (g_stdout_uart_id >= UART_NUM) { return 0; } #ifdef CONFIG_PM if (!g_stdio_suspending) { pm_unregister_ops(STDIO_DEV); } #endif if (board_uart_deinit(g_stdout_uart_id) == HAL_OK) { g_stdout_uart_id = UART_NUM; #ifdef CONFIG_LIBC_WRAP_STDIO stdio_set_write(NULL); #endif return 0; } return -1; } #ifndef CONFIG_LIBC_WRAP_STDIO #include /* for STDOUT_FILENO and STDERR_FILENO */ #include "compiler.h" #include "driver/chip/hal_cmsis.h" #include "kernel/os/os_mutex.h" static OS_Mutex_t g_stdout_mutex; /* case of critical context * - IRQ disabled * - FIQ disabled * - Execute in ISR context * - Scheduler is not running */ static int stdout_is_critical_context(void) { return (__get_PRIMASK() || __get_FAULTMASK() || __get_IPSR() || !OS_ThreadIsSchedulerRunning()); } static void stdout_mutex_lock(void) { if (stdout_is_critical_context()) { return; } if (!OS_MutexIsValid(&g_stdout_mutex)) { OS_RecursiveMutexCreate(&g_stdout_mutex); } OS_RecursiveMutexLock(&g_stdout_mutex, OS_WAIT_FOREVER); } static void stdout_mutex_unlock(void) { if (stdout_is_critical_context()) { return; } if (OS_MutexIsValid(&g_stdout_mutex)) { OS_RecursiveMutexUnlock(&g_stdout_mutex); } } int _write(int fd, const char *buf, int len) { int ret; if (fd != STDOUT_FILENO && fd != STDERR_FILENO) { return -1; } stdout_mutex_lock(); ret = stdout_write(buf, len); stdout_mutex_unlock(); return ret; } #endif /* CONFIG_LIBC_WRAP_STDIO */ #endif /* PRJCONF_UART_EN */