mbed-os/hal/TARGET_FLASH_CMSIS_ALGO/flash_common_algo.c

170 lines
4.7 KiB
C

/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flash_api.h"
#include "flash_data.h"
#include "mbed_critical.h"
#define MBED_FLASH_ALGO_ERASE 1UL
#define MBED_FLASH_ALGO_PROGRAM 2UL
extern uint32_t SystemCoreClock;
/*
This binary blob (thumb code) sets r9 (static base) as the code we are jumping to
is PIC (position independent code).
These are the instructions (r0 is a pointer to arg_t):
push {r5, lr, r4}
mov r5, r9
push {r5}
ldr r5, [r0, #20]
ldr r3, [r0, #16]
mov r9, r3
ldr r3, [r0, #12]
ldr r2, [r0, #8]
ldr r1, [r0, #4]
ldr r0, [r0, #0]
blx r5
pop {r5}
mov r9, r5
pop {r4-r5, pc}
bx r14
*/
static uint32_t jump_to_flash_algo[] = {
0x464DB530,
0x6945B420,
0x46996903,
0x688268C3,
0x68006841,
0xBC2047A8,
0xBD3046A9
};
// should be called within critical section
static int32_t flash_algo_init(flash_t *obj, uint32_t address, uint32_t function)
{
args_t arguments = {
.r0 = address,
.r1 = SystemCoreClock,
.r2 = function,
.r3 = 0,
.r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base,
.pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->init
};
return ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments);
}
// should be called within critical section
static int32_t flash_algo_uninit(flash_t *obj, uint32_t address, uint32_t function)
{
args_t arguments = {
.r0 = address,
.r1 = SystemCoreClock,
.r2 = function,
.r3 = 0,
.r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base,
.pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->uninit
};
return ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments);
}
int32_t flash_init(flash_t *obj)
{
flash_set_target_config(obj);
return 0;
}
int32_t flash_free(flash_t *obj)
{
return 0;
}
int32_t flash_erase_sector(flash_t *obj, uint32_t address)
{
core_util_critical_section_enter();
flash_algo_init(obj, address, MBED_FLASH_ALGO_ERASE);
args_t arguments = {
.r0 = address,
.r1 = 0,
.r2 = 0,
.r3 = 0,
.r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base,
.pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->erase_sector
};
int32_t ret = ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments);
flash_algo_uninit(obj, address, MBED_FLASH_ALGO_ERASE);
core_util_critical_section_exit();
return ret ? -1 : 0;
}
int32_t flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size)
{
core_util_critical_section_enter();
flash_algo_init(obj, address, MBED_FLASH_ALGO_PROGRAM);
args_t arguments = {
.r0 = address,
.r1 = size,
.r2 = (uint32_t)data,
.r3 = 0,
.r9 = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->static_base,
.pc = (uint32_t)obj->flash_algo->algo_blob + obj->flash_algo->program_page
};
int32_t ret = ((flash_algo_jump_t)(((uint32_t)&jump_to_flash_algo) | 1))(&arguments);
flash_algo_uninit(obj, address, MBED_FLASH_ALGO_PROGRAM);
core_util_critical_section_exit();
return ret ? -1 : 0;
}
uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address)
{
const sector_info_t *sectors = obj->target_config->sectors;
if (address >= obj->target_config->flash_start + obj->target_config->flash_size) {
return MBED_FLASH_INVALID_SIZE;
}
int sector_index = obj->target_config->sector_info_count - 1;
for (; sector_index >= 0; sector_index--) {
if (address >= sectors[sector_index].start) {
return sectors[sector_index].size;
}
}
return MBED_FLASH_INVALID_SIZE;
}
uint32_t flash_get_page_size(const flash_t *obj)
{
return obj->target_config->page_size;
}
uint32_t flash_get_start_address(const flash_t *obj)
{
return obj->target_config->flash_start;
}
uint32_t flash_get_size(const flash_t *obj)
{
return obj->target_config->flash_size;
}