mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-18 10:11:57 +00:00
Change-Id: I0b41a50507a09a513a67d13374323d831a0ec86a Signed-off-by: Adam Podogrocki <adam.podogrocki@rndity.com>
160 lines
3.8 KiB
C
160 lines
3.8 KiB
C
/*
|
|
* Copyright (c) 2016 RnDity Sp. z o.o.
|
|
*
|
|
* 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_stm32f3x.h"
|
|
|
|
#include <errno.h>
|
|
#include <misc/__assert.h>
|
|
#include <clock_control/stm32_clock_control.h>
|
|
|
|
static int flash_stm32_erase(struct device *dev, off_t offset, size_t size)
|
|
{
|
|
uint32_t first_page_addr = 0;
|
|
uint32_t last_page_addr = 0;
|
|
uint16_t no_of_pages = size / CONFIG_FLASH_PAGE_SIZE;
|
|
uint16_t page_index = 0;
|
|
|
|
/* Check offset and size alignment. */
|
|
if (((offset % CONFIG_FLASH_PAGE_SIZE) != 0) ||
|
|
((size % CONFIG_FLASH_PAGE_SIZE) != 0) ||
|
|
(no_of_pages == 0)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Find address of the first page to be erased. */
|
|
page_index = offset / CONFIG_FLASH_PAGE_SIZE;
|
|
|
|
first_page_addr = CONFIG_FLASH_BASE_ADDRESS +
|
|
page_index * CONFIG_FLASH_PAGE_SIZE;
|
|
|
|
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(first_page_addr));
|
|
|
|
/* Find address of the last page to be erased. */
|
|
page_index = ((offset + size) / CONFIG_FLASH_PAGE_SIZE) - 1;
|
|
|
|
last_page_addr = CONFIG_FLASH_BASE_ADDRESS +
|
|
page_index * CONFIG_FLASH_PAGE_SIZE;
|
|
|
|
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(last_page_addr));
|
|
|
|
while (no_of_pages) {
|
|
if (flash_stm32_erase_page(dev, first_page_addr)
|
|
!= FLASH_COMPLETE) {
|
|
return -EINVAL;
|
|
}
|
|
no_of_pages--;
|
|
first_page_addr += CONFIG_FLASH_PAGE_SIZE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int flash_stm32_read(struct device *dev, off_t offset,
|
|
void *data, size_t len)
|
|
{
|
|
uint32_t address = CONFIG_FLASH_BASE_ADDRESS + offset;
|
|
|
|
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));
|
|
|
|
flash_stm32_read_data(data, address, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int flash_stm32_write(struct device *dev, off_t offset,
|
|
const void *data, size_t len)
|
|
{
|
|
uint16_t halfword = 0;
|
|
|
|
uint32_t address =
|
|
CONFIG_FLASH_BASE_ADDRESS + offset;
|
|
|
|
uint8_t remainder = 0;
|
|
|
|
if ((len % 2) != 0) {
|
|
remainder = 1;
|
|
}
|
|
|
|
len = len / 2;
|
|
|
|
while (len--) {
|
|
halfword = *((uint8_t *)data++);
|
|
halfword |= *((uint8_t *)data++) << 8;
|
|
if (flash_stm32_program_halfword(dev, address, halfword)
|
|
!= FLASH_COMPLETE) {
|
|
return -EINVAL;
|
|
}
|
|
address += 2;
|
|
}
|
|
|
|
if (remainder) {
|
|
halfword = (*((uint16_t *)data)) & 0x00FF;
|
|
if (flash_stm32_program_halfword(dev, address, halfword)
|
|
!= FLASH_COMPLETE) {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int flash_stm32_protection_set(struct device *dev, bool enable)
|
|
{
|
|
if (enable) {
|
|
flash_stm32_lock(dev);
|
|
} else {
|
|
flash_stm32_unlock(dev);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int flash_stm32_init(struct device *dev)
|
|
{
|
|
const struct flash_stm32_dev_config *cfg = FLASH_CFG(dev);
|
|
|
|
struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
|
|
|
|
if (clock_control_on(clk, cfg->clock_subsys) != 0)
|
|
return -ENODEV;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct flash_driver_api flash_stm32_api = {
|
|
.read = flash_stm32_read,
|
|
.write = flash_stm32_write,
|
|
.erase = flash_stm32_erase,
|
|
.write_protection = flash_stm32_protection_set,
|
|
};
|
|
|
|
static const struct flash_stm32_dev_config flash_device_config = {
|
|
.base = (uint32_t *)FLASH_R_BASE,
|
|
.clock_subsys = UINT_TO_POINTER(STM32F3X_CLOCK_SUBSYS_FLITF),
|
|
};
|
|
|
|
static struct flash_stm32_dev_data flash_device_data = {
|
|
|
|
};
|
|
|
|
DEVICE_AND_API_INIT(flash_stm32, CONFIG_SOC_FLASH_STM32_DEV_NAME,
|
|
flash_stm32_init,
|
|
&flash_device_data,
|
|
&flash_device_config,
|
|
POST_KERNEL,
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
|
&flash_stm32_api);
|