blob: ea050d0f885648d6d4d42f6a69b0d88c6b5c2782 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "os/mynewt.h"
#include <am_hal_flash.h>
#include <hal/hal_flash_int.h>
#include <hal/hal_flash.h>
#include <mcu/system_apollo2.h>
static int
apollo2_flash_read(const struct hal_flash *dev, uint32_t address, void *dst,
uint32_t num_bytes);
static int
apollo2_flash_write(const struct hal_flash *dev, uint32_t address,
const void *src, uint32_t num_bytes);
static int
apollo2_flash_erase_sector(const struct hal_flash *dev, uint32_t sector_addr);
static int
apollo2_flash_sector_info(const struct hal_flash *dev, int idx, uint32_t *addr,
uint32_t *sz);
static int
apollo2_flash_init(const struct hal_flash *dev);
static const struct hal_flash_funcs apollo2_flash_funcs = {
.hff_read = apollo2_flash_read,
.hff_write = apollo2_flash_write,
.hff_erase_sector = apollo2_flash_erase_sector,
.hff_sector_info = apollo2_flash_sector_info,
.hff_init = apollo2_flash_init
};
const struct hal_flash apollo2_flash_dev = {
.hf_itf = &apollo2_flash_funcs,
.hf_base_addr = 0x00000000,
.hf_size = 1024 * 1024,
.hf_sector_cnt = 128,
.hf_align = 1,
.hf_erased_val = 0xff,
};
static int
apollo2_flash_read(const struct hal_flash *dev, uint32_t address, void *dst,
uint32_t num_bytes)
{
memcpy(dst, (void *) address, num_bytes);
return (0);
}
static int
apollo2_flash_write_odd(const struct hal_flash *dev, uint32_t address,
const void *src, uint32_t num_bytes)
{
uint32_t *base;
uint32_t word;
uint8_t *u8p;
int offset;
int rc;
offset = address % 4;
assert(offset + num_bytes <= 4);
base = (uint32_t *)(address - offset);
word = *base;
u8p = (uint8_t *)&word;
u8p += offset;
memcpy(u8p, src, num_bytes);
rc = am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY, &word,
base, 1);
return rc;
}
static int
apollo2_flash_write(const struct hal_flash *dev, uint32_t address,
const void *src, uint32_t num_bytes)
{
const uint8_t *u8p;
int lead_size;
int lead_off;
int words;
int sr;
int remainder;
int rc;
int i;
__HAL_DISABLE_INTERRUPTS(sr);
u8p = src;
/* Write leading partial word, if any. */
lead_off = address % 4;
if (lead_off != 0) {
lead_size = 4 - lead_off;
if (lead_size > num_bytes) {
lead_size = num_bytes;
}
rc = apollo2_flash_write_odd(dev, address, u8p, lead_size);
if (rc != 0) {
goto done;
}
u8p += lead_size;
num_bytes -= lead_size;
address += lead_size;
}
if (num_bytes == 0) {
rc = 0;
goto done;
}
/* Write aligned words in the middle. */
words = num_bytes / 4;
if ((uint32_t)u8p % 4 == 0) {
rc = am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY,
(uint32_t *)u8p, (uint32_t *)address,
words);
if (rc != 0) {
goto done;
}
} else {
for (i = 0; i < words; i++) {
rc = apollo2_flash_write_odd(dev, address + i * 4, u8p + i * 4, 4);
if (rc != 0) {
goto done;
}
}
}
/* Write trailing partial word, if any. */
remainder = num_bytes - (words * 4);
if (remainder > 0) {
rc = apollo2_flash_write_odd(dev,
address + num_bytes - remainder,
u8p + num_bytes - remainder,
remainder);
if (rc != 0) {
goto done;
}
}
rc = 0;
done:
__HAL_ENABLE_INTERRUPTS(sr);
return rc;
}
static int
apollo2_flash_erase_sector(const struct hal_flash *dev, uint32_t sector_addr)
{
uint32_t inst;
uint32_t page;
int rc;
inst = AM_HAL_FLASH_ADDR2INST(sector_addr);
page = AM_HAL_FLASH_ADDR2PAGE(sector_addr);
rc = am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, inst, page);
if (rc != 0) {
goto err;
}
return (0);
err:
return (rc);
}
static int
apollo2_flash_sector_info(const struct hal_flash *dev, int idx, uint32_t *addr,
uint32_t *sz)
{
*addr = idx * AM_HAL_FLASH_PAGE_SIZE;
*sz = AM_HAL_FLASH_PAGE_SIZE;
return (0);
}
static int
apollo2_flash_init(const struct hal_flash *dev)
{
return (0);
}