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:
parent
ac019bbfa2
commit
2c4285d9ac
5 changed files with 365 additions and 0 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
329
drivers/mtd/mtd_cfi.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue