pinebuds/platform/hal/hal_overlay.c

328 lines
9.6 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 "hal_overlay.h"
#include "cmsis.h"
#include "hal_cache.h"
#include "hal_sysfreq.h"
#include "hal_trace.h"
#include "plat_types.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