360 lines
9.7 KiB
C
360 lines
9.7 KiB
C
|
/***************************************************************************
|
||
|
*
|
||
|
* 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.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
#include "plat_types.h"
|
||
|
#include "hal_overlay.h"
|
||
|
#include "hal_sysfreq.h"
|
||
|
#include "hal_cache.h"
|
||
|
#include "hal_trace.h"
|
||
|
#include "cmsis.h"
|
||
|
#ifdef __ARMCC_VERSION
|
||
|
#include "link_sym_armclang.h"
|
||
|
#endif
|
||
|
|
||
|
extern uint32_t __overlay_text_start__[];
|
||
|
extern uint32_t __overlay_text_exec_start__[];
|
||
|
extern uint32_t __load_start_overlay_text0[];
|
||
|
extern uint32_t __load_stop_overlay_text0[];
|
||
|
extern uint32_t __load_start_overlay_text1[];
|
||
|
extern uint32_t __load_stop_overlay_text1[];
|
||
|
extern uint32_t __load_start_overlay_text2[];
|
||
|
extern uint32_t __load_stop_overlay_text2[];
|
||
|
extern uint32_t __load_start_overlay_text3[];
|
||
|
extern uint32_t __load_stop_overlay_text3[];
|
||
|
extern uint32_t __load_start_overlay_text4[];
|
||
|
extern uint32_t __load_stop_overlay_text4[];
|
||
|
extern uint32_t __load_start_overlay_text5[];
|
||
|
extern uint32_t __load_stop_overlay_text5[];
|
||
|
extern uint32_t __load_start_overlay_text6[];
|
||
|
extern uint32_t __load_stop_overlay_text6[];
|
||
|
extern uint32_t __load_start_overlay_text7[];
|
||
|
extern uint32_t __load_stop_overlay_text7[];
|
||
|
extern uint32_t __overlay_text_exec_end__[];
|
||
|
|
||
|
extern uint32_t __overlay_data_start__[];
|
||
|
extern uint32_t __load_start_overlay_data0[];
|
||
|
extern uint32_t __load_stop_overlay_data0[];
|
||
|
extern uint32_t __load_start_overlay_data1[];
|
||
|
extern uint32_t __load_stop_overlay_data1[];
|
||
|
extern uint32_t __load_start_overlay_data2[];
|
||
|
extern uint32_t __load_stop_overlay_data2[];
|
||
|
extern uint32_t __load_start_overlay_data3[];
|
||
|
extern uint32_t __load_stop_overlay_data3[];
|
||
|
extern uint32_t __load_start_overlay_data4[];
|
||
|
extern uint32_t __load_stop_overlay_data4[];
|
||
|
extern uint32_t __load_start_overlay_data5[];
|
||
|
extern uint32_t __load_stop_overlay_data5[];
|
||
|
extern uint32_t __load_start_overlay_data6[];
|
||
|
extern uint32_t __load_stop_overlay_data6[];
|
||
|
extern uint32_t __load_start_overlay_data7[];
|
||
|
extern uint32_t __load_stop_overlay_data7[];
|
||
|
|
||
|
#ifndef NO_OVERLAY
|
||
|
|
||
|
#define OVERLAY_IS_FREE 0
|
||
|
#define OVERLAY_IS_USED 1
|
||
|
|
||
|
#define CHECK_OVERLAY_ID(id) \
|
||
|
do {\
|
||
|
if ((id < 0) || (id >= HAL_OVERLAY_ID_QTY)) { \
|
||
|
ASSERT(0, "overlay id error %d", id); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
static bool segment_state[HAL_OVERLAY_ID_QTY];
|
||
|
|
||
|
static enum HAL_OVERLAY_ID_T cur_overlay_id = HAL_OVERLAY_ID_QTY;
|
||
|
|
||
|
static uint32_t * const text_load_start[HAL_OVERLAY_ID_QTY] = {
|
||
|
__load_start_overlay_text0,
|
||
|
__load_start_overlay_text1,
|
||
|
__load_start_overlay_text2,
|
||
|
__load_start_overlay_text3,
|
||
|
__load_start_overlay_text4,
|
||
|
__load_start_overlay_text5,
|
||
|
__load_start_overlay_text6,
|
||
|
__load_start_overlay_text7,
|
||
|
};
|
||
|
|
||
|
static uint32_t * const text_load_stop[HAL_OVERLAY_ID_QTY] = {
|
||
|
__load_stop_overlay_text0,
|
||
|
__load_stop_overlay_text1,
|
||
|
__load_stop_overlay_text2,
|
||
|
__load_stop_overlay_text3,
|
||
|
__load_stop_overlay_text4,
|
||
|
__load_stop_overlay_text5,
|
||
|
__load_stop_overlay_text6,
|
||
|
__load_stop_overlay_text7,
|
||
|
};
|
||
|
|
||
|
static uint32_t * const data_load_start[HAL_OVERLAY_ID_QTY] = {
|
||
|
__load_start_overlay_data0,
|
||
|
__load_start_overlay_data1,
|
||
|
__load_start_overlay_data2,
|
||
|
__load_start_overlay_data3,
|
||
|
__load_start_overlay_data4,
|
||
|
__load_start_overlay_data5,
|
||
|
__load_start_overlay_data6,
|
||
|
__load_start_overlay_data7,
|
||
|
};
|
||
|
|
||
|
static uint32_t * const data_load_stop[HAL_OVERLAY_ID_QTY] = {
|
||
|
__load_stop_overlay_data0,
|
||
|
__load_stop_overlay_data1,
|
||
|
__load_stop_overlay_data2,
|
||
|
__load_stop_overlay_data3,
|
||
|
__load_stop_overlay_data4,
|
||
|
__load_stop_overlay_data5,
|
||
|
__load_stop_overlay_data6,
|
||
|
__load_stop_overlay_data7,
|
||
|
};
|
||
|
|
||
|
|
||
|
/*must called by lock get */
|
||
|
static void invalid_overlay_cache(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
// TODO: PSRAM is large enough and no need to overlay
|
||
|
return;
|
||
|
|
||
|
#if defined(CHIP_HAS_PSRAM) && defined(PSRAM_ENABLE)
|
||
|
if (((uint32_t)__overlay_text_exec_start__ >= PSRAM_BASE &&
|
||
|
(uint32_t)__overlay_text_exec_start__ < PSRAM_BASE + PSRAM_SIZE) ||
|
||
|
((uint32_t)__overlay_text_exec_start__ >= PSRAMX_BASE &&
|
||
|
(uint32_t)__overlay_text_exec_start__ < PSRAMX_BASE + PSRAM_SIZE)) {
|
||
|
hal_cache_invalidate(HAL_CACHE_ID_I_CACHE,
|
||
|
(uint32_t)__overlay_text_exec_start__,
|
||
|
(uint32_t)text_load_stop[id] - (uint32_t)text_load_start[id]);
|
||
|
}
|
||
|
|
||
|
if (((uint32_t)__overlay_data_start__ >= PSRAM_BASE &&
|
||
|
(uint32_t)__overlay_data_start__ < PSRAM_BASE + PSRAM_SIZE) ||
|
||
|
((uint32_t)__overlay_data_start__ >= PSRAMX_BASE &&
|
||
|
(uint32_t)__overlay_data_start__ < PSRAMX_BASE + PSRAM_SIZE)) {
|
||
|
hal_cache_invalidate(HAL_CACHE_ID_D_CACHE,
|
||
|
(uint32_t)__overlay_data_start__,
|
||
|
(uint32_t)data_load_stop[id] - (uint32_t)data_load_start[id]);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
enum HAL_OVERLAY_RET_T hal_overlay_load(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
enum HAL_OVERLAY_RET_T ret;
|
||
|
|
||
|
CHECK_OVERLAY_ID(id);
|
||
|
ret = HAL_OVERLAY_RET_OK;
|
||
|
|
||
|
uint32_t lock;
|
||
|
uint32_t *dst, *src;
|
||
|
|
||
|
if (hal_overlay_is_used()) {
|
||
|
ASSERT(0, "overlay %d is in use", id);
|
||
|
return HAL_OVERLAY_RET_IN_USE;
|
||
|
}
|
||
|
|
||
|
hal_sysfreq_req(HAL_SYSFREQ_USER_OVERLAY, HAL_CMU_FREQ_52M);
|
||
|
lock = int_lock();
|
||
|
|
||
|
if (cur_overlay_id == HAL_OVERLAY_ID_QTY) {
|
||
|
cur_overlay_id = HAL_OVERLAY_ID_IN_CFG;
|
||
|
} else if (cur_overlay_id == HAL_OVERLAY_ID_IN_CFG) {
|
||
|
ret = HAL_OVERLAY_RET_IN_CFG;
|
||
|
} else {
|
||
|
ret = HAL_OVERLAY_RET_IN_USE;
|
||
|
}
|
||
|
|
||
|
if (ret != HAL_OVERLAY_RET_OK) {
|
||
|
goto _exit;
|
||
|
}
|
||
|
|
||
|
hal_overlay_acquire(id);
|
||
|
|
||
|
for (dst = __overlay_text_start__, src = text_load_start[id];
|
||
|
src < text_load_stop[id];
|
||
|
dst++, src++) {
|
||
|
*dst = *src;
|
||
|
}
|
||
|
|
||
|
for (dst = __overlay_data_start__, src = data_load_start[id];
|
||
|
src < data_load_stop[id];
|
||
|
dst++, src++) {
|
||
|
*dst = *src;
|
||
|
}
|
||
|
|
||
|
cur_overlay_id = id;
|
||
|
segment_state[id] = OVERLAY_IS_USED;
|
||
|
|
||
|
_exit:
|
||
|
int_unlock(lock);
|
||
|
hal_sysfreq_req(HAL_SYSFREQ_USER_OVERLAY, HAL_CMU_FREQ_32K);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
enum HAL_OVERLAY_RET_T hal_overlay_unload(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
enum HAL_OVERLAY_RET_T ret;
|
||
|
|
||
|
CHECK_OVERLAY_ID(id);
|
||
|
ret = HAL_OVERLAY_RET_OK;
|
||
|
|
||
|
uint32_t lock;
|
||
|
|
||
|
lock = int_lock();
|
||
|
if (cur_overlay_id == id) {
|
||
|
cur_overlay_id = HAL_OVERLAY_ID_QTY;
|
||
|
} else if (cur_overlay_id == HAL_OVERLAY_ID_IN_CFG) {
|
||
|
ret = HAL_OVERLAY_RET_IN_CFG;
|
||
|
} else {
|
||
|
ret = HAL_OVERLAY_RET_IN_USE;
|
||
|
}
|
||
|
hal_overlay_release(id);
|
||
|
int_unlock(lock);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* get the overlay's text start address
|
||
|
*/
|
||
|
uint32_t hal_overlay_get_text_address(void)
|
||
|
{
|
||
|
return (uint32_t)__overlay_text_start__;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* get the whole size of the overlay text
|
||
|
*/
|
||
|
uint32_t hal_overlay_get_text_all_size(void)
|
||
|
{
|
||
|
uint32_t text_start, text_end;
|
||
|
|
||
|
text_start = (uint32_t)__overlay_text_exec_start__;
|
||
|
text_end = (uint32_t)__overlay_text_exec_end__;
|
||
|
return text_end - text_start;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* get the segment size of one overlay text
|
||
|
*/
|
||
|
uint32_t hal_overlay_get_text_size(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
CHECK_OVERLAY_ID(id);
|
||
|
|
||
|
return (uint32_t)text_load_stop[id] - (uint32_t)text_load_start[id];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
____________ overlay's text end
|
||
|
| |
|
||
|
| |
|
||
|
| free |
|
||
|
| |
|
||
|
|__________|free_addr ______________________segment text end
|
||
|
| | | |
|
||
|
| | | |
|
||
|
| | | |
|
||
|
| | | |
|
||
|
| | | |
|
||
|
|__________| text's start_addr |__________|segment text start_addr
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Use the free space of one segement, this function
|
||
|
* return the free address of space
|
||
|
*/
|
||
|
uint32_t hal_overlay_get_text_free_addr(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
uint32_t segment_text_sz;
|
||
|
uint32_t start_addr;
|
||
|
uint32_t free_addr;
|
||
|
|
||
|
CHECK_OVERLAY_ID(id);
|
||
|
segment_text_sz = hal_overlay_get_text_size(id);
|
||
|
start_addr = hal_overlay_get_text_address();
|
||
|
free_addr = start_addr + segment_text_sz;
|
||
|
|
||
|
if (free_addr & 0x3 ) {
|
||
|
ASSERT(0, "free addr %p is not aligned to 4", (void *)free_addr);
|
||
|
}
|
||
|
return free_addr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* get the free size for one overlay text
|
||
|
*/
|
||
|
uint32_t hal_overlay_get_text_free_size(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
uint32_t all_text_sz;
|
||
|
uint32_t segment_text_sz;
|
||
|
|
||
|
CHECK_OVERLAY_ID(id);
|
||
|
all_text_sz = hal_overlay_get_text_all_size();
|
||
|
segment_text_sz = hal_overlay_get_text_size(id);
|
||
|
|
||
|
return all_text_sz - segment_text_sz;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* acquire one overlay segment
|
||
|
*/
|
||
|
void hal_overlay_acquire(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
uint32_t lock;
|
||
|
|
||
|
CHECK_OVERLAY_ID(id);
|
||
|
segment_state[id] = OVERLAY_IS_USED;
|
||
|
|
||
|
lock = int_lock();
|
||
|
invalid_overlay_cache(id);
|
||
|
int_unlock(lock);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* release one overlay segment
|
||
|
*/
|
||
|
void hal_overlay_release(enum HAL_OVERLAY_ID_T id)
|
||
|
{
|
||
|
CHECK_OVERLAY_ID(id);
|
||
|
segment_state[id] = OVERLAY_IS_FREE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* check if any overlay segment is used
|
||
|
*/
|
||
|
bool hal_overlay_is_used(void)
|
||
|
{
|
||
|
int i;
|
||
|
uint32_t lock;
|
||
|
|
||
|
lock = int_lock();
|
||
|
for (i = 0; i < HAL_OVERLAY_ID_QTY; i++) {
|
||
|
// if any segment is in use, the overlay is used;
|
||
|
if (segment_state[i] == OVERLAY_IS_USED ) {
|
||
|
int_unlock(lock);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
int_unlock(lock);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|