SAMV7 QSPI: Check if data to be transferred is unaligned; If unaligned, don't use DMA
This commit is contained in:
parent
8554cdbff6
commit
003e022ce9
@ -42,11 +42,12 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <arch/samv7/chip.h> /* For SAMV7_FLASH_SIZE */
|
||||
|
||||
#include "sam_flash.h"
|
||||
#include <arch/samv7/chip.h> /* For SAMV7_ALIGNED_FLASH_SIZE */
|
||||
|
||||
#include "up_arch.h"
|
||||
#include "cache.h"
|
||||
|
||||
#include "sam_flash.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -74,11 +75,14 @@
|
||||
#define ALIGN_UP(v,m) (((v) + (m)) & ~(m))
|
||||
#define ALIGN_DOWN(v,m) ((v) & ~(m))
|
||||
#define SAMV7_ALIGNED_FLASH_BASE ALIGN_UP(SAMV7_FREE_FLASH_BASE)
|
||||
#define SAMV7_FREE_FLASH_SIZE (SAMV7_FLASH_SIZE - SAMV7_ALIGNED_FLASH_BASE)
|
||||
#define SAMV7_FREE_FLASH_SIZE (SAMV7_ALIGNED_FLASH_SIZE - SAMV7_ALIGNED_FLASH_BASE)
|
||||
#define SAMV7_ALIGNED_FLASH_SIZE ALIGN_DOWN(SAMV7_FREE_FLASH_SIZE)
|
||||
#define SAMV7_NSECTORS (SAMV7_ALIGNED_FLASH_SIZE >> SAMV7_SECTOR_SHIFT)
|
||||
#define SAMV7_NPAGES (SAMV7_ALIGNED_FLASH_SIZE >> SAMV7_PAGE_SHIFT)
|
||||
|
||||
#define SAMV7_WRITE_ALIGN (16)
|
||||
#define SAMV7_WRITE_ALIGN_MASK (15)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
@ -102,7 +106,7 @@ static void sam_flash_unlock(void)
|
||||
|
||||
size_t up_progmem_npages(void)
|
||||
{
|
||||
return SAMV7_FLASH_NPAGES;
|
||||
return SAMV7_NPAGES;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -128,7 +132,7 @@ bool up_progmem_isuniform(void)
|
||||
|
||||
size_t up_progmem_pagesize(size_t page)
|
||||
{
|
||||
return SAMV7_FLASH_PAGESIZE;
|
||||
return SAMV7_PAGE_SIZE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -138,7 +142,7 @@ size_t up_progmem_pagesize(size_t page)
|
||||
* Address to page conversion
|
||||
*
|
||||
* Input Parameters:
|
||||
* addr - Address with of without flash offset (absolute or aligned to page0)
|
||||
* addr - Address with or without flash offset (absolute or aligned to page0)
|
||||
*
|
||||
* Returned Value:
|
||||
* Page or negative value on error. The following errors are reported
|
||||
@ -150,17 +154,17 @@ size_t up_progmem_pagesize(size_t page)
|
||||
|
||||
ssize_t up_progmem_getpage(size_t addr)
|
||||
{
|
||||
if (addr >= SAMV7_FLASH_BASE)
|
||||
if (addr >= SAMV7_ALIGNED_FLASH_BASE)
|
||||
{
|
||||
addr -= SAMV7_FLASH_BASE;
|
||||
addr -= SAMV7_ALIGNED_FLASH_BASE;
|
||||
}
|
||||
|
||||
if (addr >= SAMV7_FLASH_SIZE)
|
||||
if (addr >= SAMV7_ALIGNED_FLASH_SIZE)
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return addr / SAMV7_FLASH_PAGESIZE;
|
||||
return addr >> SAMV7_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -179,12 +183,12 @@ ssize_t up_progmem_getpage(size_t addr)
|
||||
|
||||
size_t up_progmem_getaddress(size_t page)
|
||||
{
|
||||
if (page >= SAMV7_FLASH_NPAGES)
|
||||
if (page >= SAMV7_NPAGES)
|
||||
{
|
||||
return SIZE_MAX;
|
||||
return SAMV7_ALIGNED_FLASH_SIZE;
|
||||
}
|
||||
|
||||
return page * SAMV7_FLASH_PAGESIZE + SAMV7_FLASH_BASE;
|
||||
return (page << SAMV7_PAGE_SHIFT) + SAMV7_ALIGNED_FLASH_BASE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -213,30 +217,28 @@ ssize_t up_progmem_erasepage(size_t page)
|
||||
{
|
||||
size_t page_address;
|
||||
|
||||
if (page >= SAMV7_FLASH_NPAGES)
|
||||
if (page >= SAMV7_NPAGES)
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Get flash ready and begin erasing single page */
|
||||
|
||||
if (!(getreg32(SAMV7_RCC_CR) & RCC_CR_HSION))
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
/* Erase a single page */
|
||||
|
||||
sam_flash_unlock();
|
||||
#warning Missing logic
|
||||
|
||||
/* Invalidate I- and D-Cache in this address range */
|
||||
#warning Mising logic
|
||||
|
||||
/* Verify */
|
||||
|
||||
if (up_progmem_ispageerased(page) == 0)
|
||||
{
|
||||
return up_progmem_pagesize(page); /* success */
|
||||
return SAMV7_PAGE_SIZE; /* Success */
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EIO; /* failure */
|
||||
return -EIO; /* Failure */
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,18 +263,24 @@ ssize_t up_progmem_erasepage(size_t page)
|
||||
ssize_t up_progmem_ispageerased(size_t page)
|
||||
{
|
||||
size_t addr;
|
||||
size_t count;
|
||||
size_t bwritten = 0;
|
||||
size_t bwritten;
|
||||
int count;
|
||||
|
||||
if (page >= SAMV7_FLASH_NPAGES)
|
||||
if (page >= SAMV7_NPAGES)
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Verify */
|
||||
/* Invalidate D-Cache for this address range */
|
||||
|
||||
for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page);
|
||||
count; count--, addr++)
|
||||
addr = up_progmem_getaddress(page);
|
||||
arch_invalidate_dcache(addr, addr + SAMV7_PAGE_SIZE);
|
||||
|
||||
/* Verify that the page is erased (i.e., all 0xff) */
|
||||
|
||||
for (count = SAMV7_PAGE_SIZE, bwritten = 0;
|
||||
count > 0;
|
||||
count--, addr++)
|
||||
{
|
||||
if (getreg8(addr) != 0xff)
|
||||
{
|
||||
@ -295,13 +303,13 @@ ssize_t up_progmem_ispageerased(size_t page)
|
||||
* Input Parameters:
|
||||
* addr - Address with or without flash offset (absolute or aligned to page0)
|
||||
* buf - Pointer to buffer
|
||||
* count - Number of bytes to write *
|
||||
* 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 count is not aligned with the flash boundaries (i.e.
|
||||
* EINVAL: If count 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
|
||||
@ -314,42 +322,52 @@ ssize_t up_progmem_ispageerased(size_t page)
|
||||
|
||||
ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
|
||||
{
|
||||
uint16_t *hword = (uint16_t *)buf;
|
||||
uint8_t *src = (uint8_t *)buf;
|
||||
size_t written = count;
|
||||
|
||||
/* SAMV7 requires half-word access */
|
||||
/* SAMV7 requires 128-bit/16-byte aligned access */
|
||||
|
||||
if (count & 1)
|
||||
if ((addr & SAMV7_WRITE_ALIGN_MASK) != 0 ||
|
||||
(count & SAMV7_WRITE_ALIGN_MASK) != 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for valid address range */
|
||||
|
||||
if (addr >= SAMV7_FLASH_BASE)
|
||||
if (addr >= SAMV7_ALIGNED_FLASH_BASE)
|
||||
{
|
||||
addr -= SAMV7_FLASH_BASE;
|
||||
/* Convert address to an offset relative to be beginning of the
|
||||
* writable FLASH region.
|
||||
*/
|
||||
|
||||
addr -= SAMV7_ALIGNED_FLASH_BASE;
|
||||
}
|
||||
|
||||
if ((addr+count) >= SAMV7_FLASH_SIZE)
|
||||
if ((addr + count) >= SAMV7_ALIGNED_FLASH_SIZE)
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Get flash ready and begin flashing */
|
||||
/* Write the data to FLASH */
|
||||
|
||||
sam_flash_unlock();
|
||||
#warning Missing logic
|
||||
|
||||
for (addr += SAMV7_FLASH_BASE; count; count -= 2, hword++, addr += 2)
|
||||
for (addr += SAMV7_ALIGNED_FLASH_BASE;
|
||||
count;
|
||||
count -= SAMV7_WRITE_ALIGN, src += SAMV7_WRITE_ALIGN, addr += SAMV7_WRITE_ALIGN)
|
||||
{
|
||||
/* Write half-word and wait to complete */
|
||||
/* Write 128-bit/16-bytes block to FLASH and wait to complete */
|
||||
#warning Mising logic
|
||||
|
||||
/* Invalidate I- and D-Caches for this address range */
|
||||
#warning Mising logic
|
||||
|
||||
/* Verify */
|
||||
#warning Mising logic
|
||||
|
||||
}
|
||||
|
||||
modifyreg32(SAMV7_FLASH_CR, FLASH_CR_PG, 0);
|
||||
return written;
|
||||
}
|
||||
|
@ -1569,6 +1569,9 @@ static int qspi_memory(struct qspi_dev_s *dev,
|
||||
struct qspi_meminfo_s *meminfo)
|
||||
{
|
||||
struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev;
|
||||
#ifdef CONFIG_SAMV7_QSPI_DMA
|
||||
bool aligned;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(priv != NULL && meminfo != NULL);
|
||||
|
||||
@ -1581,9 +1584,16 @@ static int qspi_memory(struct qspi_dev_s *dev,
|
||||
qspivdbg(" buffer/length: %p/%d\n", meminfo->buffer, meminfo->buflen);
|
||||
|
||||
#ifdef CONFIG_SAMV7_QSPI_DMA
|
||||
/* Check for attempt to do unaligned read */
|
||||
|
||||
aligned = IS_ALIGNED((uintptr_t)meminfo->buffer) &&
|
||||
IS_ALIGNED(meminfo->buflen);
|
||||
|
||||
/* Can we perform DMA? Should we perform DMA? */
|
||||
|
||||
if (priv->candma && meminfo->buflen > CONFIG_SAMV7_QSPI_DMATHRESHOLD)
|
||||
if (priv->candma &&
|
||||
meminfo->buflen > CONFIG_SAMV7_QSPI_DMATHRESHOLD &&
|
||||
aligned)
|
||||
{
|
||||
return qspi_memory_dma(priv, meminfo);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user