diff --git a/arch/arm/src/tiva/tiva_flash.c b/arch/arm/src/tiva/tiva_flash.c index 952cf215cd5..e95b5fc1792 100644 --- a/arch/arm/src/tiva/tiva_flash.c +++ b/arch/arm/src/tiva/tiva_flash.c @@ -2,7 +2,7 @@ * arch/arm/src/tiva/tiva_flash.c * * Copyright (c) 2013 Max Holtzberg. All rights reserved. - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2013, 2018 Gregory Nutt. All rights reserved. * * Authors: Max Holtzberg * Gregory Nutt @@ -64,8 +64,8 @@ ****************************************************************************/ #define TIVA_VIRTUAL_NPAGES (TIVA_FLASH_NPAGES - CONFIG_TIVA_FLASH_STARTPAGE) -#define TIVA_VIRTUAL_BASE (TIVA_FLASH_BASE \ - + CONFIG_TIVA_FLASH_STARTPAGE * TIVA_FLASH_PAGESIZE) +#define TIVA_VIRTUAL_OFFSET (CONFIG_TIVA_FLASH_STARTPAGE * TIVA_FLASH_PAGESIZE) +#define TIVA_VIRTUAL_BASE (TIVA_FLASH_BASE + TIVA_VIRTUAL_OFFSET) /**************************************************************************** * Private Types @@ -120,6 +120,7 @@ static struct tiva_dev_s g_lmdev = #endif tiva_ioctl }, + /* Initialization of any other implementation specific data goes here */ }; @@ -138,12 +139,15 @@ static struct tiva_dev_s g_lmdev = static int tiva_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) { - int curpage; + off_t endblock; uint32_t pageaddr; + uint32_t regval; + int curpage; - DEBUGASSERT(nblocks <= TIVA_VIRTUAL_NPAGES); + endblock = startblock + nblocks; + DEBUGASSERT(endblock <= TIVA_VIRTUAL_NPAGES); - for (curpage = startblock; curpage < nblocks; curpage++) + for (curpage = startblock; curpage < endblock; curpage++) { pageaddr = TIVA_VIRTUAL_BASE + curpage * TIVA_FLASH_PAGESIZE; @@ -160,7 +164,19 @@ static int tiva_erase(FAR struct mtd_dev_s *dev, off_t startblock, /* wait until erase has finished */ - while (getreg32(TIVA_FLASH_FMC) & FLASH_FMC_ERASE); + while (getreg32(TIVA_FLASH_FMC) & FLASH_FMC_ERASE) + { + } + + /* Return an error if an access violation or erase error occurred. */ + + regval = getreg32(TIVA_FLASH_FCRIS); + regval &= (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS | FLASH_FCRIS_ERRIS); + + if (regval != 0) + { + return -EACCES; + } } return OK; @@ -255,7 +271,90 @@ static ssize_t tiva_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, static ssize_t tiva_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR const uint8_t *buf) { - return -ENOSYS; + FAR const uint32_t *src = (uint32_t *)((uintptr_t)buf & ~3); + ssize_t remaining; + uint32_t regval; + + DEBUGASSERT(dev != NULL && buf != NULL); + DEBUGASSERT(((uintptr_t)buf & 3) == 0 && (offset & 3) == 0 && (nbytes && 3) == 0); + + /* Clear the flash access and error interrupts. */ + + putreg32(FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC | FLASH_FCMISC_ERMISC, + TIVA_FLASH_FCMISC); + + /* Adjust the offset to the start of the partition. + * REVISIT: If we really wanted to gracefully handler unaligned addresses, + * offsets, and sizes we would have to do a little more than this. + */ + + offset &= ~3; + offset += TIVA_VIRTUAL_OFFSET; + nbytes &= ~3; + remaining = nbytes; + +#if defined(CONFIG_ARCH_CHIP_TM4C1294NC) + while (remaining > 0) + { + /* Set the address of this block of words. */ + + putreg32((offset & ~(0x7f)), TIVA_FLASH_FMA); + + /* Loop over the words in this 32-word block. */ + + while(((offset & 0x7c) || (getreg32(TIVA_FLASH_FWBN) == 0)) && + (remaining > 0)) + { + /* Write this word into the write buffer. */ + + putreg32(*src++, (TIVA_FLASH_FWBN + (offset & 0x7c))); + offset += 4; + remaining -= 4; + } + + /* Program the contents of the write buffer into flash. */ + + putreg32(FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF, TIVA_FLASH_FMC2); + + /* Wait until the write buffer has been programmed. */ + + while(getreg32(TIVA_FLASH_FMC2) & FLASH_FMC2_WRBUF) + { + } + } +#else + while (remaining > 0) + { + /* Program the next word. */ + + putreg32(offset, TIVA_FLASH_FMA); + putreg32(*src, TIVA_FLASH_FMD); + putreg32(FLASH_FMC_WRKEY | FLASH_FMC_WRITE, TIVA_FLASH_FMC); + + /* Wait until the word has been programmed. */ + + while(getreg32(TIVA_FLASH_FMC) & FLASH_FMC_WRITE); + + /* Increment to the next word. */ + + src++; + offset += 4; + remaining -= 4; + } +#endif + + /* Return an error if an access violation or erase error occurred. */ + + regval = getreg32(TIVA_FLASH_FCRIS); + regval &= (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS | FLASH_FCRIS_INVDRIS | + FLASH_FCRIS_PROGRIS); + + if (regval != 0) + { + return -EACCES; + } + + return nbytes; } #endif