mirror of
https://github.com/apache/nuttx.git
synced 2026-10-10 07:40:27 +00:00
mtd/ramtron: Add optional byte-write support.
Implement the MTD write callback when CONFIG_MTD_BYTE_WRITE is enabled, allowing unaligned byte writes without changing existing block operations. Reject ranges outside the physical device and return zero for valid empty writes without SPI traffic. Use the initialized SPI device ID, hold the bus lock across the request, and issue write-enable for each transfer. With CONFIG_RAMTRON_CHUNKING, split writes at the write-buffer boundaries of chunk-limited parts. Document the optional callback and its bounds and chunk behavior. Verified with mocked-SPI host tests, driver compilation with byte writes and chunking enabled/disabled, and a Conductor STM32H743BI hardware test covering single-byte and unaligned writes, surrounding-byte preservation, invalid ranges, and restoration of the original FRAM contents. Hardware coverage is limited to the installed 32 KiB part. Assisted-by: Codex:GPT-6 Signed-off-by: jsanchez-2g <jsanchez@2g-eng.com>
This commit is contained in:
parent
c341f6855b
commit
8e6b925200
2 changed files with 89 additions and 0 deletions
|
|
@ -312,3 +312,18 @@ NuttX provides support for the following MTD devices.
|
|||
:glob:
|
||||
|
||||
devices/*
|
||||
|
||||
RAMTRON SPI FRAM byte writes
|
||||
===========================
|
||||
|
||||
With ``CONFIG_MTD_RAMTRON`` and ``CONFIG_MTD_BYTE_WRITE`` enabled, the
|
||||
RAMTRON driver implements ``MTD_WRITE()`` for arbitrary byte offsets and
|
||||
lengths. Writes need not align to the emulated block or erase geometry.
|
||||
The callback returns the number of bytes written; requests outside the
|
||||
physical device return ``-EINVAL``. A zero-length request within the
|
||||
device, including its end offset, returns zero without SPI traffic.
|
||||
|
||||
When ``CONFIG_RAMTRON_CHUNKING`` is enabled, writes to parts marked as
|
||||
chunk-limited are split at their write-buffer boundaries. Each transfer
|
||||
has its own write-enable and write-command sequence. Existing block-write
|
||||
operations are unchanged.
|
||||
|
|
|
|||
|
|
@ -431,6 +431,10 @@ static ssize_t ramtron_read(FAR struct mtd_dev_s *dev,
|
|||
off_t offset,
|
||||
size_t nbytes,
|
||||
FAR uint8_t *buffer);
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
static ssize_t ramtron_write(FAR struct mtd_dev_s *dev, off_t offset,
|
||||
size_t nbytes, FAR const uint8_t *buffer);
|
||||
#endif
|
||||
static int ramtron_ioctl(FAR struct mtd_dev_s *dev,
|
||||
int cmd,
|
||||
unsigned long arg);
|
||||
|
|
@ -844,6 +848,71 @@ static ssize_t ramtron_read(FAR struct mtd_dev_s *dev,
|
|||
return nbytes;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ramtron_write
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
static ssize_t ramtron_write(FAR struct mtd_dev_s *dev, off_t offset,
|
||||
size_t nbytes, FAR const uint8_t *buffer)
|
||||
{
|
||||
FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev;
|
||||
size_t remaining = nbytes;
|
||||
size_t count;
|
||||
#ifdef CONFIG_RAMTRON_CHUNKING
|
||||
size_t available;
|
||||
#endif
|
||||
|
||||
/* Reject requests that could wrap around the physical device. */
|
||||
|
||||
if (offset < 0 || offset > priv->part->size ||
|
||||
nbytes > priv->part->size - (uint32_t)offset)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nbytes == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGASSERT(buffer != NULL);
|
||||
ramtron_lock(priv);
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
count = remaining;
|
||||
#ifdef CONFIG_RAMTRON_CHUNKING
|
||||
if (priv->part->chunked)
|
||||
{
|
||||
/* Do not cross a write-buffer boundary on chunk-limited parts. */
|
||||
|
||||
available = priv->part->chunksize -
|
||||
offset % priv->part->chunksize;
|
||||
if (count > available)
|
||||
{
|
||||
count = available;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ramtron_writeenable(priv);
|
||||
SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->devid), true);
|
||||
SPI_SEND(priv->dev, RAMTRON_WRITE);
|
||||
ramtron_sendaddr(priv, offset);
|
||||
SPI_SNDBLOCK(priv->dev, buffer, count);
|
||||
SPI_SELECT(priv->dev, SPIDEV_FLASH(priv->devid), false);
|
||||
|
||||
offset += count;
|
||||
buffer += count;
|
||||
remaining -= count;
|
||||
}
|
||||
|
||||
ramtron_unlock(priv->dev);
|
||||
return nbytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ramtron_ioctl
|
||||
****************************************************************************/
|
||||
|
|
@ -863,6 +932,7 @@ static int ramtron_ioctl(FAR struct mtd_dev_s *dev,
|
|||
{
|
||||
FAR struct mtd_geometry_s *geo =
|
||||
(FAR struct mtd_geometry_s *)((uintptr_t)arg);
|
||||
|
||||
if (geo)
|
||||
{
|
||||
memset(geo, 0, sizeof(*geo));
|
||||
|
|
@ -892,6 +962,7 @@ static int ramtron_ioctl(FAR struct mtd_dev_s *dev,
|
|||
{
|
||||
FAR struct partition_info_s *info =
|
||||
(FAR struct partition_info_s *)arg;
|
||||
|
||||
if (info != NULL)
|
||||
{
|
||||
info->numsectors = priv->nsectors *
|
||||
|
|
@ -975,6 +1046,9 @@ FAR struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *dev,
|
|||
priv->mtd.bread = ramtron_bread;
|
||||
priv->mtd.bwrite = ramtron_bwrite;
|
||||
priv->mtd.read = ramtron_read;
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
priv->mtd.write = ramtron_write;
|
||||
#endif
|
||||
priv->mtd.ioctl = ramtron_ioctl;
|
||||
priv->mtd.name = "ramtron";
|
||||
priv->dev = dev;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue