From 2c4285d9ac6f20aa30d928262bf8ec6d7235c7fb Mon Sep 17 00:00:00 2001 From: zhengyu9 Date: Mon, 29 Jul 2024 16:11:26 +0800 Subject: [PATCH] mtd/mtd_cfi: cfi flash bind to mtd interface Bind cfi flash driver with the existing mtd interface Signed-off-by: zhengyu9 Signed-off-by: dongjiuzhu1 --- drivers/mtd/CMakeLists.txt | 5 + drivers/mtd/Kconfig | 6 + drivers/mtd/Make.defs | 5 + drivers/mtd/mtd_cfi.c | 329 +++++++++++++++++++++++++++++++++++++ include/nuttx/mtd/mtd.h | 20 +++ 5 files changed, 365 insertions(+) create mode 100644 drivers/mtd/mtd_cfi.c diff --git a/drivers/mtd/CMakeLists.txt b/drivers/mtd/CMakeLists.txt index 46965d40ca..c50988e663 100644 --- a/drivers/mtd/CMakeLists.txt +++ b/drivers/mtd/CMakeLists.txt @@ -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() diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 0ec2c4d98c..38a364f58e 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -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 diff --git a/drivers/mtd/Make.defs b/drivers/mtd/Make.defs index 2a5a7a3153..e357e8c84c 100644 --- a/drivers/mtd/Make.defs +++ b/drivers/mtd/Make.defs @@ -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 diff --git a/drivers/mtd/mtd_cfi.c b/drivers/mtd/mtd_cfi.c new file mode 100644 index 0000000000..96473e2f25 --- /dev/null +++ b/drivers/mtd/mtd_cfi.c @@ -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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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; +} diff --git a/include/nuttx/mtd/mtd.h b/include/nuttx/mtd/mtd.h index 960560a6f8..af9ccd785a 100644 --- a/include/nuttx/mtd/mtd.h +++ b/include/nuttx/mtd/mtd.h @@ -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 }