| /** |
| * 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); |
| } |