mtd/mtd_cfi: cfi flash bind to mtd interface

Bind cfi flash driver with the existing mtd interface

Signed-off-by: zhengyu9 <zhengyu9@xiaomi.com>
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
zhengyu9 2024-07-29 16:11:26 +08:00 committed by archer
parent ac019bbfa2
commit 2c4285d9ac
5 changed files with 365 additions and 0 deletions

View file

@ -181,5 +181,10 @@ if(CONFIG_MTD)
target_include_directories(drivers PRIVATE ${CMAKE_CURRENT_LIST_DIR}/dhara)
endif()
if(CONFIG_MTD_CFI)
list(APPEND SRCS mtd_cfi.c)
list(APPEND SRCS cfi.c)
endif()
target_sources(drivers PRIVATE ${SRCS})
endif()

View file

@ -1459,4 +1459,10 @@ config DHARA_READ_NCACHES
default 4
endif
config MTD_CFI
bool "CFI(common flash interface) NOR FLASH"
default n
---help---
Support CFI(common flash interface) NOR FLASH.
endif # MTD

View file

@ -208,6 +208,11 @@ CSRCS += mtd/dhara/dhara/journal.c
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)drivers$(DELIM)mtd$(DELIM)dhara
endif
ifeq ($(CONFIG_MTD_CFI),y)
CSRCS += mtd_cfi.c
CSRCS += cfi.c
endif
# Include MTD driver support
DEPPATH += --dep-path mtd

329
drivers/mtd/mtd_cfi.c Normal file
View file

@ -0,0 +1,329 @@
/****************************************************************************
* drivers/mtd/mtd_cfi.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 <sys/types.h>
#include <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <debug.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mtd/mtd.h>
#include "cfi.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* MTD driver methods */
static int cfi_mtd_erase(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks);
static ssize_t cfi_mtd_bread(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR uint8_t *buf);
static ssize_t cfi_mtd_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buf);
static ssize_t cfi_mtd_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 cfi_mtd_write(FAR struct mtd_dev_s *dev, off_t offset,
size_t nbytes, FAR const uint8_t *buffer);
#endif
static int cfi_mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd,
unsigned long arg);
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: cfi_mtd_erase
*
* Description:
* Erase several blocks, each of the size previously reported.
*
****************************************************************************/
static int cfi_mtd_erase(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks)
{
FAR struct cfi_dev_s *priv = (FAR struct cfi_dev_s *)dev;
size_t endblock;
/* The interface definition assumes that all erase blocks are the
* same size. If that is not true for this particular device, then
* transform the start block and nblocks as necessary.
*/
endblock = cfi_find_block(priv, (startblock + nblocks) *
cfi_get_blocksize(priv, 0));
startblock = cfi_find_block(priv, startblock *
cfi_get_blocksize(priv, 0));
/* Erase the specified blocks and return status (OK or a negated errno) */
return cfi_erase(priv, startblock, endblock - startblock);
}
/****************************************************************************
* Name: cfi_mtd_bread
*
* Description:
* Read the specified number of blocks into the user provided buffer.
*
****************************************************************************/
static ssize_t cfi_mtd_bread(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR uint8_t *buf)
{
FAR struct cfi_dev_s *priv = (FAR struct cfi_dev_s *)dev;
off_t offset = startpage * priv->page_size;
int ret;
ret = cfi_read(priv, offset, npages * priv->page_size, buf);
return ret < 0 ? ret : npages;
}
/****************************************************************************
* Name: cfi_mtd_bwrite
*
* Description:
* Write the specified number of blocks from the user provided buffer.
*
****************************************************************************/
static ssize_t cfi_mtd_bwrite(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR const uint8_t *buf)
{
FAR struct cfi_dev_s *priv = (FAR struct cfi_dev_s *)dev;
off_t offset = startpage * priv->page_size;
int ret;
ret = cfi_write(priv, offset, npages * priv->page_size, buf);
return ret < 0 ? ret : npages;
}
/****************************************************************************
* Name: cfi_mtd_read
*
* Description:
* Read the specified number of bytes to the user provided buffer.
*
****************************************************************************/
static ssize_t cfi_mtd_read(FAR struct mtd_dev_s *dev, off_t offset,
size_t nbytes, FAR uint8_t *buffer)
{
FAR struct cfi_dev_s *priv = (FAR struct cfi_dev_s *)dev;
int ret;
ret = cfi_read(priv, offset, nbytes, buffer);
return ret < 0 ? ret : nbytes;
}
/****************************************************************************
* Name: cfi_mtd_write
*
* Description:
* Some FLASH parts have the ability to write an arbitrary number of
* bytes to an arbitrary offset on the device. This method should be
* implement only for devices that support such access.
*
****************************************************************************/
#ifdef CONFIG_MTD_BYTE_WRITE
static ssize_t cfi_mtd_write(FAR struct mtd_dev_s *dev, off_t offset,
size_t nbytes, FAR const uint8_t *buffer)
{
FAR struct cfi_dev_s *priv = (FAR struct cfi_dev_s *)dev;
int ret;
ret = cfi_write(priv, offset, nbytes, buffer);
return ret < 0 ? ret : nbytes;
}
#endif
/****************************************************************************
* Name: cfi_mtd_ioctl
****************************************************************************/
static int cfi_mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd,
unsigned long arg)
{
FAR struct cfi_dev_s *priv = (FAR struct cfi_dev_s *)dev;
int ret = OK;
switch (cmd)
{
case MTDIOC_GEOMETRY:
{
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)arg;
DEBUGASSERT(geo != NULL);
memset(geo, 0, sizeof(*geo));
geo->blocksize = priv->page_size;
geo->erasesize = cfi_get_blocksize(priv, 0);
geo->neraseblocks = cfi_get_total_blocknum(priv);
}
break;
case BIOC_PARTINFO:
{
FAR struct partition_info_s *info =
(FAR struct partition_info_s *)arg;
DEBUGASSERT(info != NULL);
info->numsectors = cfi_get_total_blocknum(priv);
info->sectorsize = cfi_get_blocksize(priv, 0);
info->startsector = 0;
info->parent[0] = '\0';
}
break;
case BIOC_XIPBASE:
{
FAR void **ppv = (FAR void**)arg;
DEBUGASSERT(ppv != NULL);
*ppv = (FAR void *)priv->base_addr;
}
break;
case MTDIOC_BULKERASE:
{
ret = cfi_mtd_erase(dev, 0, cfi_get_total_blocknum(priv));
}
break;
case MTDIOC_ERASESECTORS:
{
FAR struct mtd_erase_s *erase = (FAR struct mtd_erase_s *)arg;
ret = cfi_mtd_erase(dev, erase->startblock, erase->nblocks);
}
break;
default:
ret = -ENOTTY;
break;
}
return ret;
}
/****************************************************************************
* Name: cfi_initialize
*
* Description:
* Create and initialize an MTD device instance. MTD devices are not
* registered in the file system, but are created as instances that can
* be bound to other functions (such as a block or character driver front
* end).
*
****************************************************************************/
static FAR struct mtd_dev_s *
cfi_initialize(uintptr_t addr_base, uintptr_t addr_end, uint32_t bankwidth)
{
FAR struct cfi_dev_s *cfi;
/* Create an instance of the CFI MTD device state structure */
cfi = kmm_zalloc(sizeof(struct cfi_dev_s));
if (cfi == NULL)
{
ferr("ERROR: Failed to allocate the CFI MTD state structure\n");
return NULL;
}
cfi->mtd.erase = cfi_mtd_erase;
cfi->mtd.bread = cfi_mtd_bread;
cfi->mtd.bwrite = cfi_mtd_bwrite;
cfi->mtd.read = cfi_mtd_read;
#ifdef CONFIG_MTD_BYTE_WRITE
cfi->mtd.write = cfi_mtd_write;
#endif
cfi->mtd.ioctl = cfi_mtd_ioctl;
cfi->mtd.name = "cfi-flash";
cfi->base_addr = addr_base;
cfi->end_addr = addr_end;
cfi->bankwidth = bankwidth;
/* Check the CFI, and set other parameters */
if (cfi_check(cfi) == OK)
{
return (FAR struct mtd_dev_s *)cfi;
}
ferr("ERROR: Not a CFI device!\n");
kmm_free(cfi);
return NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: register_cfi_driver
*
* Description:
* Initialize cfi MTD device instance and register it to vfs.
*
****************************************************************************/
int register_cfi_driver(uintptr_t addr_base, uintptr_t addr_end,
uint32_t bankwidth, int id)
{
int ret = -ENXIO;
FAR struct mtd_dev_s *mtd;
mtd = cfi_initialize(addr_base, addr_end, bankwidth);
if (mtd != NULL)
{
char devname[32];
snprintf(devname, sizeof(devname), "/dev/cfi-flash%d", id);
ret = register_mtddriver(devname, mtd, 0777, NULL);
if (ret < 0)
{
kmm_free(mtd);
}
}
return ret;
}

View file

@ -805,6 +805,26 @@ int dhara_initialize_by_path(FAR const char *path,
FAR struct mtd_dev_s *mtd);
#endif
/****************************************************************************
* Name: register_cfi_driver
*
* Description:
* Initialize and register a cfi nor flash.
*
* Input Parameters:
* addr_base - The base(start) address of the device.
* addr_end - The end address of the device.
* bankwidth - The bankwidth(port width) of the device.
* id - The device id used for register name.
*
****************************************************************************/
#ifdef CONFIG_MTD_CFI
int register_cfi_driver(volatile uintptr_t addr_base,
volatile uintptr_t addr_end, uint32_t bankwidth,
int id);
#endif
#undef EXTERN
#ifdef __cplusplus
}