This section is solely of interest to those who want to implement a NAND Flash Controller device driver. Application programs will use only the public ANC API. This section focuses on the information that is necessary for creating or instantiating a device driver.
The NAND Flash Controller library consists of a common upper part and device-specific lower parts. The common part translates API calls from the ANC to calls to the internal API of the device-specific parts. This internal API is called the NAND Flash Controller Command API, in this section abbreviated to the Command API. Any device driver must implement that Command API.
The common API is called from the ANC library. It resembles the ANC API, except that its functions operate on a NAND Controller. Its main functions are briefly documented here for completeness; in normal use, they are solely called from the ANC library.
The NAND Flash Controller Common API is specified in cyg/io/flash_nand_ctl.h.
int cyg_nand_ctl_dev_lookup(cyg_uint32 devno, cyg_uint32 anc_dev, cyg_nand_t *nand, cyg_nand_ctl_t **p_ctl); int cyg_nand_ctl_init(cyg_nand_ctl_t *ctl); int cyg_nand_ctl_chip_select(cyg_nand_ctl_t *ctl, int chip, int on); int cyg_nand_ctl_block_erase(cyg_nand_ctl_t *ctl, size_t page_addr); int cyg_nand_ctl_page_program(cyg_nand_ctl_t *ctl, const void *data, size_t column, size_t page, size_t len, const void *spare, size_t spare_len, int use_cache, int direct); int cyg_nand_ctl_page_read(cyg_nand_ctl_t *ctl, void *data, size_t column, size_t page, size_t len, void *spare, size_t spare_len, int use_cache, int direct); |
Functions cyg_nand_ctl_page_program()
and
cyg_nand_ctl_page_read()
take an extra parameter
direct
. If it is 1, spare
matches the spare area without any processing. If it is 0, the
spare
parameter is folded into the application fields
in the chip's spare area layout.
#ifdef CYGPKG_KERNEL int cyg_nand_ctl_mutex_lock(cyg_nand_ctl_t *ctl); int cyg_nand_ctl_mutex_unlock(cyg_nand_ctl_t *ctl); #endif |
Concurrency control is done at the controller level: each controller has its lock.
This is the Controller device driver struct:
/** ADT for the Controller Command functions */ typedef struct CYG_NAND_CTL_FUNS cyg_nand_ctl_funs_t; struct CYG_NAND_CTL { const cyg_nand_ctl_funs_t *funs; /**< Function pointers */ cyg_uint32 devno; /**< Controller devno */ cyg_uint32 anc_devno; /**< Owning ANC devno */ int n_chip; cyg_nand_chip_t **chip; /**< My flash chips */ void *priv; /**< Device-specific data */ void *platform_priv; /**< Platform-specific data */ cyg_nand_ctl_info_t info; /**< For this controller */ cyg_nand_chip_t *current_chip; /**< Selected flash chip */ int initialized; /**< Device has been inited */ cyg_nand_t *anc; /**< My owner */ #ifdef CYGPKG_KERNEL cyg_mutex_t mutex; /**< Thread safeness */ #endif cyg_uint8 stored_ecc[CYGNUM_NAND_ECC_BUFFER]; cyg_uint8 device_ecc[CYGNUM_NAND_ECC_BUFFER]; cyg_uint8 spare_buffer[CYGNUM_NAND_SPARE_MAX]; } CYG_HAL_TABLE_TYPE; #define CYG_NAND_DRIVER_CTL(name, i_funs, i_devno, i_anc, i_n_chip, i_priv) \ \ static cyg_nand_chip_t *name ## _chips[i_n_chip]; \ \ cyg_nand_ctl_t name CYG_HAL_TABLE_ENTRY(cyg_nand_dev_ctl) = { \ .funs = i_funs, \ .devno = i_devno, \ .anc_devno = i_anc, \ .n_chip = i_n_chip, \ .chip = name ## _chips, \ .priv = i_priv, \ } |
The Controller Common API also contains a macro
CYG_NAND_DRIVER_CTL
to instantiate a Controller
device driver. Its parameters anc
(global ANC
device number), devno
(per-ANC NAND controller
device number), n_chip
(number of chips attached to
this controller) are usually specified in the CDL for the target. Parameter
priv
is a generic pointer that can be used to point to
a device-specific data structure. funs
is the function
dispatch block that is implemented by the Command part of the device driver.
The macro also instantiates an array chip[n_chip]
;
therefore, n_chip must be a compile-time constant.