/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #ifdef CHIP_HAS_CP #include "cp_accel.h" #include "app_utils.h" #include "cmsis.h" #include "cmsis_os.h" #include "hal_cmu.h" #include "hal_location.h" #include "hal_mcu2cp.h" #include "hal_memsc.h" #include "hal_timer.h" #include "hal_trace.h" #include "mpu.h" #include "stdarg.h" #include "string.h" #include "system_cp.h" #ifdef CP_ACCEL_DEBUG #define CP_ACCEL_TRACE(s, ...) TRACE(s, ##__VA_ARGS__) #else #define CP_ACCEL_TRACE(s, ...) #endif #define CP_NO_FLASH_ACCESS #define CP_CRASH_START_TIMEOUT MS_TO_TICKS(100) #define CP_TRACE_FLUSH_TIMEOUT MS_TO_TICKS(200) #define CP_CRASH_DUMP_TIMEOUT MS_TO_TICKS(500) #define CP_TRACE_BUF_FULL_INTVL MS_TO_TICKS(50) enum CP_SYS_EVENT_T { CP_SYS_EVENT_NONE = 0, CP_SYS_EVENT_CRASH_START, CP_SYS_EVENT_CRASH_END, CP_SYS_EVENT_TRACE_FLUSH, CP_SYS_EVENT_TRACE_BUF_FULL, }; static bool ram_inited; static bool cp_accel_inited = false; static struct cp_task_env_tag cp_task_env; static CP_BSS_LOC volatile struct cp_env_tag cp_env; static CP_BSS_LOC volatile enum CP_SYS_EVENT_T cp_sys_evt; static CP_BSS_LOC bool cp_in_crash; static CP_BSS_LOC volatile uint8_t cp_in_sleep; static CP_BSS_LOC uint32_t cp_buf_full_time; static CP_BSS_LOC uint8_t req_event = 0, pending_event = 0; static CP_TEXT_SRAM_LOC int send_sys_ctrl_cp2mcu(uint32_t event) { return hal_mcu2cp_send_cp(HAL_MCU2CP_ID_1, HAL_MCU2CP_MSG_TYPE_0, (unsigned char *)event, 0); } static CP_TEXT_SRAM_LOC void cp_trace_crash_notify(enum HAL_TRACE_STATE_T state) { uint32_t time; if (state == HAL_TRACE_STATE_CRASH_ASSERT_START || state == HAL_TRACE_STATE_CRASH_FAULT_START) { cp_in_crash = true; cp_sys_evt = CP_SYS_EVENT_CRASH_START; mpu_close(); send_sys_ctrl_cp2mcu(0); time = hal_sys_timer_get(); while (cp_sys_evt == CP_SYS_EVENT_CRASH_START && hal_sys_timer_get() - time < CP_CRASH_START_TIMEOUT) ; } else { cp_sys_evt = CP_SYS_EVENT_CRASH_END; } } static CP_TEXT_SRAM_LOC void cp_trace_buffer_ctrl(enum HAL_TRACE_BUF_STATE_T buf_state) { uint32_t time; if (cp_sys_evt != CP_SYS_EVENT_NONE) { return; } time = hal_sys_timer_get(); if (buf_state == HAL_TRACE_BUF_STATE_FLUSH) { cp_sys_evt = CP_SYS_EVENT_TRACE_FLUSH; if (!cp_in_crash) { send_sys_ctrl_cp2mcu(0); } while (cp_sys_evt == CP_SYS_EVENT_TRACE_FLUSH && hal_sys_timer_get() - time < CP_TRACE_FLUSH_TIMEOUT) ; } else if (buf_state == HAL_TRACE_BUF_STATE_FULL || buf_state == HAL_TRACE_BUF_STATE_NEAR_FULL) { if (time - cp_buf_full_time >= CP_TRACE_BUF_FULL_INTVL) { cp_buf_full_time = time; if (!cp_in_crash) { cp_sys_evt = CP_SYS_EVENT_TRACE_BUF_FULL; send_sys_ctrl_cp2mcu(0); } } } } static SRAM_TEXT_LOC unsigned int cp2mcu_sys_arrived(const unsigned char *data, unsigned int len) { uint32_t time; uint8_t task_id = 0; if (cp_sys_evt == CP_SYS_EVENT_TRACE_FLUSH) { TRACE_FLUSH(); cp_sys_evt = CP_SYS_EVENT_NONE; } else if (cp_sys_evt == CP_SYS_EVENT_TRACE_BUF_FULL) { TRACE(0, " "); cp_sys_evt = CP_SYS_EVENT_NONE; } else if (cp_sys_evt == CP_SYS_EVENT_CRASH_START) { cp_sys_evt = CP_SYS_EVENT_NONE; TRACE(0, " "); TRACE(0, "CP Crash starts ..."); UNLOCK_CP_PROCESS(); // Forced release lock // Wait CP crash dump finishes in interrupt context time = hal_sys_timer_get(); while (cp_sys_evt != CP_SYS_EVENT_CRASH_END && hal_sys_timer_get() - time < CP_CRASH_DUMP_TIMEOUT) { if (cp_sys_evt == CP_SYS_EVENT_TRACE_FLUSH) { TRACE_FLUSH(); cp_sys_evt = CP_SYS_EVENT_NONE; } } for (task_id = 0; task_id < CP_TASK_MAX; task_id++) { if (cp_task_env.p_desc[task_id].mcu_sys_ctrl_hdlr) { cp_task_env.p_desc[task_id].mcu_sys_ctrl_hdlr(CP_SYS_EVENT_CRASH_END); } } TRACE(0, "CP Crash ends ..."); TRACE(0, " "); } return len; } static CP_TEXT_SRAM_LOC unsigned int mcu2cp_msg_arrived(const unsigned char *data, unsigned int len) { uint8_t task_id = CP_TASK_ID_GET(*data); uint8_t event_type = CP_EVENT_GET(*data); cp_env.cp_msg[task_id][event_type] = 1; cp_env.cp_msg_recv = true; if (cp_task_env.p_desc[task_id].cp_evt_hdlr) { cp_task_env.p_desc[task_id].cp_evt_hdlr((uint32_t)data); } return len; } static CP_TEXT_SRAM_LOC void mcu2cp_msg_sent(const unsigned char *data, unsigned int len) { // TRACE(1, "mcu2cp_msg_sent,pending count = %d", cp_env.mcu2cp_tx_count); if (cp_env.mcu2cp_tx_count > 1) { cp_env.mcu2cp_tx_count--; pending_event = cp_env.mcu2cp_tx_pending[0]; hal_mcu2cp_send_mcu(HAL_MCU2CP_ID_0, HAL_MCU2CP_MSG_TYPE_0, &pending_event, 1); for (uint8_t index = 0; index < cp_env.mcu2cp_tx_count - 1; index++) { cp_env.mcu2cp_tx_pending[index] = cp_env.mcu2cp_tx_pending[index + 1]; } } else { cp_env.mcu2cp_tx_count = 0; } } #if defined(__ARM_ARCH_8M_MAIN__) #define CP_CODE_MAP_BASE (ROM_BASE + 0x800) #define CP_CODE_MAP_SIZE (RAMX_BASE + RAM_TOTAL_SIZE - CP_CODE_MAP_BASE) static CP_DATA_LOC const mpu_regions_t mpu_table_cp[] = { {CP_CODE_MAP_BASE, CP_CODE_MAP_SIZE, MPU_ATTR_EXEC, MAIR_ATTR_INT_SRAM}, {RAM_BASE, RAM_TOTAL_SIZE, MPU_ATTR_READ_WRITE, MAIR_ATTR_INT_SRAM}, {CMU_BASE, 0x01000000, MPU_ATTR_READ_WRITE, MAIR_ATTR_DEVICE}, }; #else static CP_DATA_LOC const mpu_regions_t mpu_table_cp[] = { {0, 0x800, MPU_ATTR_NO_ACCESS}, {FLASHX_BASE, 0x4000000, MPU_ATTR_NO_ACCESS}, {FLASH_BASE, 0x4000000, MPU_ATTR_NO_ACCESS}, {FLASH_NC_BASE, 0x4000000, MPU_ATTR_NO_ACCESS}, }; #endif static CP_TEXT_SRAM_LOC NOINLINE void accel_loop(void) { uint32_t lock; uint8_t task_index = 0, event_index = 0; bool msg_flag = false; uint8_t msg[CP_TASK_MAX][CP_EVENT_MAX]; mpu_setup_cp(mpu_table_cp, ARRAY_SIZE(mpu_table_cp)); while (1) { lock = int_lock_global(); msg_flag = cp_env.cp_msg_recv; cp_env.cp_msg_recv = false; memcpy(msg, (uint8_t *)cp_env.cp_msg, sizeof(cp_env.cp_msg)); memset((uint8_t *)cp_env.cp_msg, 0, sizeof(cp_env.cp_msg)); if (false == msg_flag) { cp_in_sleep = true; __WFI(); cp_in_sleep = false; } int_unlock_global(lock); if (msg_flag) { for (task_index = 0; task_index < CP_TASK_MAX; task_index++) { for (event_index = 0; event_index < CP_EVENT_MAX; event_index++) { LOCK_CP_PROCESS(); if ((msg[task_index][event_index]) && (cp_task_env.p_desc[task_index].cp_work_main)) { cp_task_env.p_desc[task_index].cp_work_main(event_index); } UNLOCK_CP_PROCESS(); } } } } } static void accel_main(void) { system_cp_init(!ram_inited); TRACE(1, "%s", __func__); ram_inited = true; memset((uint8_t *)&cp_env, 0, sizeof(cp_env)); hal_trace_open_cp(); hal_mcu2cp_open_cp(HAL_MCU2CP_ID_0, HAL_MCU2CP_MSG_TYPE_0, mcu2cp_msg_arrived, NULL, false); hal_mcu2cp_open_cp(HAL_MCU2CP_ID_1, HAL_MCU2CP_MSG_TYPE_0, NULL, NULL, false); hal_mcu2cp_start_recv_cp(HAL_MCU2CP_ID_0); // hal_mcu2cp_start_recv_cp(HAL_MCU2CP_ID_1); cp_accel_inited = true; accel_loop(); } static SRAM_TEXT_LOC unsigned int cp2mcu_msg_arrived(const unsigned char *data, unsigned int len) { uint8_t task_id = CP_TASK_ID_GET((uint32_t)data); // TRACE(2, "%s, task_id = %d", __func__, task_id); if (task_id >= CP_TASK_MAX) { return -1; } if (cp_task_env.p_desc[task_id].mcu_evt_hdlr) { cp_task_env.p_desc[task_id].mcu_evt_hdlr((uint32_t)data); } return len; } int cp_accel_open(enum CP_TASK_TYPE task_id, struct cp_task_desc const *p_task_desc) { TRACE(4, "%s, task id = %d, cp_state = %d init %d", __func__, task_id, cp_task_env.p_desc[task_id].cp_accel_state, cp_accel_inited); if ((task_id >= CP_TASK_MAX) || (p_task_desc == NULL)) { TRACE(1, "%s task id error", __func__); return -1; } if (cp_task_env.p_desc[task_id].cp_accel_state != CP_ACCEL_STATE_CLOSED) { TRACE(1, "%s cp_accel_state error", __func__); return -1; } cp_task_env.p_desc[task_id].cp_accel_state = CP_ACCEL_STATE_OPENING; cp_task_env.p_desc[task_id].cp_work_main = p_task_desc->cp_work_main; cp_task_env.p_desc[task_id].cp_evt_hdlr = p_task_desc->cp_evt_hdlr; cp_task_env.p_desc[task_id].mcu_evt_hdlr = p_task_desc->mcu_evt_hdlr; cp_task_env.p_desc[task_id].mcu_sys_ctrl_hdlr = p_task_desc->mcu_sys_ctrl_hdlr; if (false == cp_accel_inited) { hal_trace_cp_register(cp_trace_crash_notify, cp_trace_buffer_ctrl); hal_cmu_cp_enable(RAMCP_BASE + RAMCP_SIZE, (uint32_t)accel_main); hal_mcu2cp_open_mcu(HAL_MCU2CP_ID_0, HAL_MCU2CP_MSG_TYPE_0, cp2mcu_msg_arrived, mcu2cp_msg_sent, false); hal_mcu2cp_open_mcu(HAL_MCU2CP_ID_1, HAL_MCU2CP_MSG_TYPE_0, cp2mcu_sys_arrived, NULL, false); hal_mcu2cp_start_recv_mcu(HAL_MCU2CP_ID_0); hal_mcu2cp_start_recv_mcu(HAL_MCU2CP_ID_1); } cp_task_env.p_desc[task_id].cp_accel_state = CP_ACCEL_STATE_OPENED; return 0; } int cp_accel_close(enum CP_TASK_TYPE task_id) { uint8_t i = 0; TRACE(4, "%s, task id = %d, cp_state = %d init %d", __func__, task_id, cp_task_env.p_desc[task_id].cp_accel_state, cp_accel_inited); LOCK_CP_PROCESS(); // avoid hangup if (cp_task_env.p_desc[task_id].cp_accel_state == CP_ACCEL_STATE_CLOSED) { goto accel_close_end; } cp_task_env.p_desc[task_id].cp_accel_state = CP_ACCEL_STATE_CLOSING; cp_task_env.p_desc[task_id].cp_work_main = NULL; cp_task_env.p_desc[task_id].cp_evt_hdlr = NULL; cp_task_env.p_desc[task_id].mcu_evt_hdlr = NULL; for (i = 0; i < CP_TASK_MAX; i++) { if (cp_task_env.p_desc[i].cp_accel_state == CP_ACCEL_STATE_OPENED || cp_task_env.p_desc[i].cp_accel_state == CP_ACCEL_STATE_OPENING) { goto accel_close_end; } } if (cp_accel_inited) { cp_accel_inited = false; hal_mcu2cp_close_mcu(HAL_MCU2CP_ID_0, HAL_MCU2CP_MSG_TYPE_0); hal_mcu2cp_close_mcu(HAL_MCU2CP_ID_1, HAL_MCU2CP_MSG_TYPE_0); hal_cmu_cp_disable(); system_cp_term(); hal_mcu2cp_close_cp(HAL_MCU2CP_ID_0, HAL_MCU2CP_MSG_TYPE_0); hal_mcu2cp_close_cp(HAL_MCU2CP_ID_1, HAL_MCU2CP_MSG_TYPE_0); hal_trace_cp_register(NULL, NULL); } accel_close_end: cp_task_env.p_desc[task_id].cp_accel_state = CP_ACCEL_STATE_CLOSED; UNLOCK_CP_PROCESS(); return 0; } int SRAM_TEXT_LOC cp_accel_init_done(void) { // TRACE(2, "%s, cp_inited = %d", __func__, cp_accel_inited); return cp_accel_inited; } int cp_accel_send_event_mcu2cp(uint8_t event) { if ((false == cp_accel_inited) || (cp_env.mcu2cp_tx_count > MAX_CP_MSG_NUM)) { TRACE(2, "send_evt error, cp_accel_inited = %d, event pending count = %d", cp_accel_inited, cp_env.mcu2cp_tx_count); TRACE(2, "send evt task_id = %d, event = %d", CP_TASK_ID_GET(event), CP_EVENT_GET(event)); return -1; } // TRACE(1, "current CP tx count:%d", cp_env.mcu2cp_tx_count); if (cp_env.mcu2cp_tx_count > 0) { cp_env.mcu2cp_tx_pending[cp_env.mcu2cp_tx_count - 1] = event; cp_env.mcu2cp_tx_count++; } else { req_event = event; cp_env.mcu2cp_tx_count = 1; hal_mcu2cp_send_mcu(HAL_MCU2CP_ID_0, HAL_MCU2CP_MSG_TYPE_0, &req_event, 1); } return 0; } int CP_TEXT_SRAM_LOC cp_accel_send_event_cp2mcu(uint8_t event) { return hal_mcu2cp_send_cp(HAL_MCU2CP_ID_0, HAL_MCU2CP_MSG_TYPE_0, (unsigned char *)(uint32_t)event, 0); } int SRAM_TEXT_LOC cp_accel_busy(enum CP_TASK_TYPE task_id) { if (cp_task_env.p_desc[task_id].cp_accel_state != CP_ACCEL_STATE_CLOSED) { if (cp_task_env.p_desc[task_id].cp_accel_state == CP_ACCEL_STATE_OPENED && cp_in_sleep && !hal_mcu2cp_local_irq_pending_cp(HAL_MCU2CP_ID_0)) { return false; } return true; } return false; } #endif