| /**************************************************************************** |
| * arch/arm/src/nrf91/nrf91_flash.c |
| * |
| * 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. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <errno.h> |
| |
| #include <nuttx/arch.h> |
| #include <nuttx/progmem.h> |
| |
| #include "arm_internal.h" |
| #include "barriers.h" |
| |
| #include "hardware/nrf91_ficr.h" |
| #include "hardware/nrf91_nvmc.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| #define MEMORY_SYNC() ARM_ISB(); ARM_DSB() |
| |
| /* Sizes and masks */ |
| |
| #define NRF91_FLASH_ERASEDVAL (0xff) |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| static inline uint32_t nrf91_get_flash_size(void) |
| { |
| return getreg32(NRF91_FICR_INFO_FLASH) * 1024; |
| } |
| |
| static inline uint32_t nrf91_get_page_size(void) |
| { |
| return getreg32(NRF91_FICR_INFO_CODEPAGESIZE); |
| } |
| |
| static inline uint32_t nrf91_get_pages_num(void) |
| { |
| return getreg32(NRF91_FICR_INFO_CODESIZE); |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: up_progmem_pagesize |
| * |
| * Description: |
| * Return page size |
| * |
| ****************************************************************************/ |
| |
| size_t up_progmem_pagesize(size_t page) |
| { |
| if (page >= up_progmem_neraseblocks()) |
| { |
| return 0; |
| } |
| else |
| { |
| return nrf91_get_page_size(); |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_erasesize |
| * |
| * Description: |
| * Return erase block size |
| * |
| ****************************************************************************/ |
| |
| size_t up_progmem_erasesize(size_t block) |
| { |
| return up_progmem_pagesize(block); |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_getpage |
| * |
| * Description: |
| * Address to page conversion |
| * |
| * Input Parameters: |
| * addr - Address to be converted |
| * |
| * Returned Value: |
| * Page or negative value on error. The following errors are reported |
| * (errno is not set!): |
| * |
| * -EFAULT: On invalid address |
| * |
| ****************************************************************************/ |
| |
| ssize_t up_progmem_getpage(size_t addr) |
| { |
| if (addr >= nrf91_get_flash_size()) |
| { |
| return -EFAULT; |
| } |
| |
| return addr / nrf91_get_page_size(); |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_getaddress |
| * |
| * Description: |
| * Page to address conversion |
| * |
| * Input Parameters: |
| * page - Page to be converted |
| * |
| * Returned Value: |
| * Base address of given page, maximum size if page is not valid. |
| * |
| ****************************************************************************/ |
| |
| size_t up_progmem_getaddress(size_t page) |
| { |
| if (page >= up_progmem_neraseblocks()) |
| { |
| return SIZE_MAX; |
| } |
| |
| return page * nrf91_get_page_size(); |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_neraseblocks |
| * |
| * Description: |
| * Return number of erase blocks in the available FLASH memory. |
| * |
| ****************************************************************************/ |
| |
| size_t up_progmem_neraseblocks(void) |
| { |
| return nrf91_get_flash_size() / nrf91_get_page_size(); |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_isuniform |
| * |
| * Description: |
| * Page size is uniform? Say 'yes' even though that is not strictly |
| * true. |
| * |
| ****************************************************************************/ |
| |
| bool up_progmem_isuniform(void) |
| { |
| return true; |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_eraseblock |
| * |
| * Description: |
| * Erase selected block. |
| * |
| * Input Parameters: |
| * block - Block to be erased |
| * |
| * Returned Value: |
| * Page size or negative value on error. The following errors are reported |
| * (errno is not set!): |
| * |
| * -EFAULT: On invalid page |
| * -EIO: On unsuccessful erase |
| * -EROFS: On access to write protected area |
| * -EACCES: Insufficient permissions (read/write protected) |
| * -EPERM: If operation is not permitted due to some other constraints |
| * (i.e. some internal block is not running etc.) |
| * |
| ****************************************************************************/ |
| |
| ssize_t up_progmem_eraseblock(size_t block) |
| { |
| size_t page_address; |
| |
| if (block >= up_progmem_neraseblocks()) |
| { |
| return -EFAULT; |
| } |
| |
| page_address = up_progmem_getaddress(block); |
| |
| /* Enable erase mode */ |
| |
| putreg32(NVMC_CONFIG_EEN, NRF91_NVMC_CONFIG); |
| |
| /* Memory sync */ |
| |
| MEMORY_SYNC(); |
| |
| /* Erase the page by writting 0xffffffff into the first 32-bit word of |
| * the flash page |
| */ |
| |
| putreg32(0xffffffff, page_address); |
| |
| /* Wait for flash */ |
| |
| while (!(getreg32(NRF91_NVMC_READY) & NVMC_READY_READY)) |
| { |
| } |
| |
| /* Read only access */ |
| |
| putreg32(NVMC_CONFIG_REN, NRF91_NVMC_CONFIG); |
| |
| /* Memory sync */ |
| |
| MEMORY_SYNC(); |
| |
| /* Verify */ |
| |
| if (up_progmem_ispageerased(block) == 0) |
| { |
| return up_progmem_erasesize(block); |
| } |
| else |
| { |
| return -EIO; |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_ispageerased |
| * |
| * Description: |
| * Checks whether a page is erased |
| * |
| * Input Parameters: |
| * page - Page to be checked |
| * |
| * Returned Value: |
| * Returns number of bytes erased or negative value on error. If it |
| * returns zero then complete page is empty (erased). |
| * |
| * The following errors are reported (errno is not set!) |
| * -EFAULT: On invalid page |
| * |
| ****************************************************************************/ |
| |
| ssize_t up_progmem_ispageerased(size_t page) |
| { |
| size_t addr; |
| size_t count; |
| size_t bwritten = 0; |
| |
| if (page >= nrf91_get_pages_num()) |
| { |
| return -EFAULT; |
| } |
| |
| /* Verify */ |
| |
| for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page); |
| count; count--, addr++) |
| { |
| if (getreg8(addr) != NRF91_FLASH_ERASEDVAL) |
| { |
| bwritten++; |
| } |
| } |
| |
| return bwritten; |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_write |
| * |
| * Description: |
| * Program data at given address |
| * |
| * Input Parameters: |
| * addr - Address with or without flash offset |
| * buf - Pointer to buffer |
| * count - Number of bytes to write |
| * |
| * Returned Value: |
| * Bytes written or negative value on error. The following errors are |
| * reported (errno is not set!) |
| * |
| * EINVAL: If buflen is not aligned with the flash boundaries (i.e. |
| * some MCU's require per half-word or even word access) |
| * EFAULT: On invalid address |
| * EIO: On unsuccessful write |
| * EROFS: On access to write protected area |
| * EACCES: Insufficient permissions (read/write protected) |
| * EPERM: If operation is not permitted due to some other constraints |
| * (i.e. some internal block is not running etc.) |
| * |
| ****************************************************************************/ |
| |
| ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) |
| { |
| uint32_t *pword = (uint32_t *)buf; |
| size_t written = count; |
| |
| /* NRF91 requires word access */ |
| |
| if (count & 0x3) |
| { |
| return -EINVAL; |
| } |
| |
| /* Check for valid address range */ |
| |
| if ((addr + count) > nrf91_get_flash_size()) |
| { |
| return -EFAULT; |
| } |
| |
| /* Flash offset */ |
| |
| addr += NRF91_FLASH_BASE; |
| |
| /* Begin flashing */ |
| |
| for (; count; count -= 4, pword++, addr += 4) |
| { |
| /* Enable write */ |
| |
| putreg32(NVMC_CONFIG_WEN, NRF91_NVMC_CONFIG); |
| |
| /* Memory sync */ |
| |
| MEMORY_SYNC(); |
| |
| /* Write the word */ |
| |
| *(uint32_t *)addr = *pword; |
| |
| /* Wait for flash */ |
| |
| while (!(getreg32(NRF91_NVMC_READY) & NVMC_READY_READY)) |
| { |
| } |
| |
| /* Read only access */ |
| |
| putreg32(NVMC_CONFIG_REN, NRF91_NVMC_CONFIG); |
| |
| /* Memory sync */ |
| |
| MEMORY_SYNC(); |
| |
| /* Verify */ |
| |
| if (getreg32(addr) != *pword) |
| { |
| return -EIO; |
| } |
| } |
| |
| return written; |
| } |
| |
| /**************************************************************************** |
| * Name: up_progmem_erasestate |
| * |
| * Description: |
| * Return value of erase state. |
| * |
| ****************************************************************************/ |
| |
| uint8_t up_progmem_erasestate(void) |
| { |
| return NRF91_FLASH_ERASEDVAL; |
| } |