mirror of
https://github.com/apache/nuttx.git
synced 2026-06-05 15:58:59 +08:00
SAMV71 QSPI: Add methods to allocate properly aligned memory.
This commit is contained in:
+108
-10
@@ -54,6 +54,7 @@
|
|||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
#include <nuttx/wdog.h>
|
#include <nuttx/wdog.h>
|
||||||
#include <nuttx/clock.h>
|
#include <nuttx/clock.h>
|
||||||
|
#include <nuttx/kmalloc.h>
|
||||||
#include <nuttx/spi/qspi.h>
|
#include <nuttx/spi/qspi.h>
|
||||||
|
|
||||||
#include "up_internal.h"
|
#include "up_internal.h"
|
||||||
@@ -127,6 +128,16 @@
|
|||||||
|
|
||||||
#define MEMORY_SYNC() do { ARM_DSB();ARM_ISB(); } while (0)
|
#define MEMORY_SYNC() do { ARM_DSB();ARM_ISB(); } while (0)
|
||||||
|
|
||||||
|
/* The SAMV7x QSPI driver insists that transfers be performed in multiples
|
||||||
|
* of 32-bits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ALIGN_SHIFT 2
|
||||||
|
#define ALIGN_MASK 3
|
||||||
|
#define ALIGN_UP(n) (((n)+ALIGN_MASK) & ~ALIGN_MASK)
|
||||||
|
#define ALIGN_WORDS(n) (((n)+ALIGN_MASK) >> ALIGN_SHIFT)
|
||||||
|
#define IS_ALIGNED(n) (((uint32_t)(n) & ALIGN_MASK) == 0)
|
||||||
|
|
||||||
/* Debug *******************************************************************/
|
/* Debug *******************************************************************/
|
||||||
/* Check if QSPI debug is enabled (non-standard.. no support in
|
/* Check if QSPI debug is enabled (non-standard.. no support in
|
||||||
* include/debug.h
|
* include/debug.h
|
||||||
@@ -268,6 +279,8 @@ static int qspi_memory_dma(struct sam_qspidev_s *priv,
|
|||||||
|
|
||||||
static int qspi_memory_nodma(struct sam_qspidev_s *priv,
|
static int qspi_memory_nodma(struct sam_qspidev_s *priv,
|
||||||
struct qspi_meminfo_s *meminfo);
|
struct qspi_meminfo_s *meminfo);
|
||||||
|
static void qspi_memcpy(uint32_t *dest, const uint32_t *src,
|
||||||
|
size_t wordlen);
|
||||||
|
|
||||||
/* Interrupts */
|
/* Interrupts */
|
||||||
|
|
||||||
@@ -288,6 +301,8 @@ static int qspi_command(struct qspi_dev_s *dev,
|
|||||||
struct qspi_cmdinfo_s *cmdinfo);
|
struct qspi_cmdinfo_s *cmdinfo);
|
||||||
static int qspi_memory(struct qspi_dev_s *dev,
|
static int qspi_memory(struct qspi_dev_s *dev,
|
||||||
struct qspi_meminfo_s *meminfo);
|
struct qspi_meminfo_s *meminfo);
|
||||||
|
static FAR void *qspi_alloc(FAR struct qspi_dev_s *dev, size_t buflen);
|
||||||
|
static void qspi_free(FAR struct qspi_dev_s *dev, FAR void *buffer);
|
||||||
|
|
||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
@@ -308,6 +323,8 @@ static const struct qspi_ops_s g_qspi0ops =
|
|||||||
.setbits = qspi_setbits,
|
.setbits = qspi_setbits,
|
||||||
.command = qspi_command,
|
.command = qspi_command,
|
||||||
.memory = qspi_memory,
|
.memory = qspi_memory,
|
||||||
|
.alloc = qspi_alloc,
|
||||||
|
.free = qspi_free,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is the overall state of the QSPI0 controller */
|
/* This is the overall state of the QSPI0 controller */
|
||||||
@@ -971,6 +988,11 @@ static int qspi_memory_nodma(struct sam_qspidev_s *priv,
|
|||||||
struct qspi_meminfo_s *meminfo)
|
struct qspi_meminfo_s *meminfo)
|
||||||
{
|
{
|
||||||
uintptr_t qspimem = SAM_QSPIMEM_BASE + meminfo->addr;
|
uintptr_t qspimem = SAM_QSPIMEM_BASE + meminfo->addr;
|
||||||
|
uint16_t wordlen;
|
||||||
|
|
||||||
|
/* Get the length as an even multiple of 32-bit words. */
|
||||||
|
|
||||||
|
wordlen = ALIGN_WORDS(meminfo->buflen);
|
||||||
|
|
||||||
/* Enable the memory transfer */
|
/* Enable the memory transfer */
|
||||||
|
|
||||||
@@ -980,11 +1002,13 @@ static int qspi_memory_nodma(struct sam_qspidev_s *priv,
|
|||||||
|
|
||||||
if (QSPIMEM_ISWRITE(meminfo->flags))
|
if (QSPIMEM_ISWRITE(meminfo->flags))
|
||||||
{
|
{
|
||||||
memcpy((void *)qspimem, meminfo->buffer, meminfo->buflen);
|
qspi_memcpy((uint32_t *)qspimem,
|
||||||
|
(const uint32_t *)meminfo->buffer, wordlen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(meminfo->buffer, (void *)qspimem, meminfo->buflen);
|
qspi_memcpy((uint32_t *)meminfo->buffer,
|
||||||
|
(const uint32_t *)qspimem, wordlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMORY_SYNC();
|
MEMORY_SYNC();
|
||||||
@@ -1007,6 +1031,30 @@ static int qspi_memory_nodma(struct sam_qspidev_s *priv,
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: qspi_memcpy
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* 32-bit version of memcpy.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* dest - Destination address of the copy
|
||||||
|
* src - Source address of the copy
|
||||||
|
* wordlen - The number of 32-bit words to copy.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void qspi_memcpy(uint32_t *dest, const uint32_t *src, size_t wordlen)
|
||||||
|
{
|
||||||
|
for (; wordlen > 0; wordlen--)
|
||||||
|
{
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: qspi_lock
|
* Name: qspi_lock
|
||||||
*
|
*
|
||||||
@@ -1373,16 +1421,14 @@ static int qspi_command(struct qspi_dev_s *dev,
|
|||||||
|
|
||||||
if (QSPICMD_ISDATA(cmdinfo->flags))
|
if (QSPICMD_ISDATA(cmdinfo->flags))
|
||||||
{
|
{
|
||||||
uint16_t buflen;
|
uint16_t wordlen;
|
||||||
|
|
||||||
DEBUGASSERT(cmdinfo->buffer != NULL && cmdinfo->buflen > 0);
|
DEBUGASSERT(cmdinfo->buffer != NULL && cmdinfo->buflen > 0);
|
||||||
|
DEBUGASSERT(IS_ALIGNED(cmdinfo->buffer));
|
||||||
|
|
||||||
/* Make sure that the length is an even multiple of 32-bit words.
|
/* Get the length as an even multiple of 32-bit words. */
|
||||||
* REVISIT: This could cause access past the end of an allocated
|
|
||||||
* buffer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
buflen = (cmdinfo->buflen + 3) & ~3;
|
wordlen = ALIGN_WORDS(cmdinfo->buflen);
|
||||||
|
|
||||||
/* Write Instruction Frame Register:
|
/* Write Instruction Frame Register:
|
||||||
*
|
*
|
||||||
@@ -1411,7 +1457,8 @@ static int qspi_command(struct qspi_dev_s *dev,
|
|||||||
|
|
||||||
/* Copy the data to write to QSPI_RAM */
|
/* Copy the data to write to QSPI_RAM */
|
||||||
|
|
||||||
memcpy((void *)SAM_QSPIMEM_BASE, cmdinfo->buffer, buflen);
|
qspi_memcpy((uint32_t *)SAM_QSPIMEM_BASE,
|
||||||
|
(const uint32_t *)cmdinfo->buffer, wordlen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1421,7 +1468,9 @@ static int qspi_command(struct qspi_dev_s *dev,
|
|||||||
(void)qspi_getreg(priv, SAM_QSPI_IFR_OFFSET);
|
(void)qspi_getreg(priv, SAM_QSPI_IFR_OFFSET);
|
||||||
|
|
||||||
/* Copy the data from QSPI memory into the user buffer */
|
/* Copy the data from QSPI memory into the user buffer */
|
||||||
memcpy(cmdinfo->buffer, (const void *)SAM_QSPIMEM_BASE, buflen);
|
|
||||||
|
qspi_memcpy((uint32_t *)cmdinfo->buffer,
|
||||||
|
(const uint32_t *)SAM_QSPIMEM_BASE, wordlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMORY_SYNC();
|
MEMORY_SYNC();
|
||||||
@@ -1506,6 +1555,55 @@ static int qspi_memory(struct qspi_dev_s *dev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: QSPI_ALLOC
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Allocate a buffer suitable for DMA data transfer
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* dev - Device-specific state data
|
||||||
|
* buflen - Buffer length to allocate in bytes
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Address of tha allocated memory on success; NULL is returned on any
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static FAR void *qspi_alloc(FAR struct qspi_dev_s *dev, size_t buflen)
|
||||||
|
{
|
||||||
|
/* Here we exploit the internal knowlege the kmm_malloc() will return memory
|
||||||
|
* aligned to 64-bit addresses. The buffer length must be large enough to
|
||||||
|
* hold the rested buflen in units a 32-bits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return kmm_malloc(ALIGN_UP(buflen));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: QSPI_FREE
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Free memory returned by QSPI_ALLOC
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* dev - Device-specific state data
|
||||||
|
* buffer - Buffer previously allocated via QSPI_ALLOC
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void qspi_free(FAR struct qspi_dev_s *dev, FAR void *buffer)
|
||||||
|
{
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
kmm_free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: qspi_hw_initialize
|
* Name: qspi_hw_initialize
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user