Controller Command API

The Controller Command API must be implemented by a device-specific part of a NAND controller. The Controller Command API is specified in include file cyg/io/flash_nand_ctl_cmd.h. It essentially consists of a function dispatch table with pointers to device-specific functions.

struct CYG_NAND_CTL_FUNS {
    int   (*init)(cyg_nand_ctl_t *ctl);
                /** invoked from cyg_nand_ctl_chip_select() */
    int   (*chip_select)(cyg_nand_ctl_t *ctl, int chip, int on);
    int   (*cmd)(cyg_nand_ctl_t *ctl, cyg_uint8 cmd);
                /** writes the appropriate bytes of (col, page); col in words */
    int   (*page_addr)(cyg_nand_ctl_t *ctl, size_t column, size_t page);
                /** writes at most 4 bytes, either col (words) or page */
    int   (*addr)(cyg_nand_ctl_t *ctl, cyg_uint32 addr, size_t bytes);
    int   (*data_write)(cyg_nand_ctl_t *ctl,
                        const void *data, size_t bytes,
                        cyg_uint8 *device_ecc);
            /** read a byte at a time, even with x16 chips. Some commands
             * require this. */
    int   (*data_read_8)(cyg_nand_ctl_t *ctl, void *data, size_t len);
    int   (*data_read)(cyg_nand_ctl_t *ctl,
                       void *data, size_t bytes,
                       cyg_uint8 *device_ecc);
            /** Wait until RnB (a.k.a. SR[6]) has had a rising flank */
    int   (*await_ready)(cyg_nand_ctl_t *ctl);
    int   (*ecc_calc)(cyg_nand_ctl_t *ctl,
                      const cyg_uint8 *data,
                      cyg_uint8 *ecc);
    int   (*ecc_repair)(cyg_nand_ctl_t *ctl,
                        cyg_uint8 *data,
                        cyg_uint8 *stored_ecc,
                        cyg_uint8 *calc_ecc);
};

The init() function must initialize the controller. Besides doing the physical initialization, it must set the info.flags field of the device driver to indicate whether the device has hardware ECC support.

A controller can be used to manage multiple chips. This chip is not a parameter of the functions; the chip is explicitly (de)selected by the ANC library with cyg_nand_ctl_chip_select(ctl, chipno, on/off) calls around a group of calls to the controller. If a chip is selected, the Command API function chip_select() is invoked. It should manipulate the nCE lines to physically (de)select the chip. As a side effect, the controller common library sets the field controller->current_chip of the controller device struct to point to the currently selected chip.

The function cmd() has the controller write a (wire) command.

There are two functions to have the controller write an address. Function page_addr() takes a column address (in words) and a row address, and writes the address (column, row) in the format that is specified by the chip. The number of bytes written may exceed 4. Function addr() services those commands that require a column or a row address only, by having the controller write at most 4 bytes.

Functions data_write() and data_read() have the controller program/read data on the nand chip. These functions program/read their data a word at a time, so for x16 chips, the implementation must perform one program/read cycle per two bytes. If the controller supports hardware ECC calculation, the implementation of these functions should also fill out the ECC bytes that are calculated by the controller in argument device_ecc. The expectation is that there are 3 ECC bytes per 256 bytes of data. Whether ECC calculation is done in hardware by the controller or in software, the controller common library applies ECC correction to data read by invoking functions ecc_repair() and ecc_calc().

There is another function to read data from the controller. Some commands are specified to use only 8 bits of the chip's data bus, even in the case of x16 chips. For those commands, data_read_8() is invoked by the controller common library. Note that those commands never read application data, so ECC handling is unnecessary.

The wire specification uses a rising flank of the nR/B wire as a signal that an operation has completed. Function await_ready() must be implemented to return after occurrence of a rising flank (or timeout). Hardware NFCs often have a status bit that indicates occurrence of a rising flank. If the NFC is implemented through GPIOs, the safe way to monitor that wire is to attach an interrupt handler to it that fires on a rising flank, then performs condition synchronization with the implementation of await_ready().

Functions ecc_calc() and ecc_repair() are invoked by the controller common library to perform ECC calculation and repair respectively. They may be set to one of the bundled ECC functions, see below. If the controller has ECC hardware, ecc_calc() is only invoked for debugging or verification. If the ECC calculation by the controller hardware is incompatible with the bundled ECC functions, (at least) ecc_repair() must be implemented to match the hardware functionality.

An example implementation of what the cmd() function in terms of GPIO pins might look like:

static int
nfc_gpio_cmd(cyg_nand_ctl_t *ctl, cyg_uint8 cmd)
{
    time    t_start;

    cyg_gpio_set(GPIO_nCLE, 1);
    *reg_DATA = cmd;            /* the data bus is memory-mapped to reg_DATA */
    cyg_gpio_set(GPIO_nWE, 1);
    t_start = current_time();
    while (current_time() - t_start < ctl->current_chip->info.t_write_pulse) {
	/* await the write pulse width */
    }
    cyg_gpio_set(GPIO_nWE, 0);
    cyg_gpio_set(GPIO_nCLE, 0);

    return CYG_NAND_ERR_OK;     /* Success */
}

NAND Flash Controller ECC support

The NAND Flash Controller library bundles two algorithms for ECC error detection/correction: the "Toshiba" algorithm and the "Samsung" algorithm. If ECC is enabled, application data that is written to the flash has its ECC calculated and then written to the spare area by the controller common library, according to the spare layout descriptor for the chip. Application data that is read from the chip has its ECC calculated and compared to the ECC in the spare area. If there is at most one bit error per 256 bytes, the data can be corrected.

The ECC functions are defined in file cyg/io/flash_nand_ctl_ecc.h:

/**
 * @param ctl controller
 * @param data 256 bytes of data
 * @param ecc 3 bytes of ECC for 256 bytes of data
 */
__externC int cyg_nand_ctl_ecc_toshiba_calc(cyg_nand_ctl_t *ctl,
                                            const cyg_uint8 *data,
                                            cyg_uint8 *ecc);

/**
 * @param ctl controller
 * @param data 256 bytes of data
 * @param ecc 3 bytes of ECC for 256 bytes of data
 */
__externC int cyg_nand_ctl_ecc_toshiba_repair(cyg_nand_ctl_t *ctl,
                                              cyg_uint8 *data,
                                              cyg_uint8 *stored_ecc,
                                              cyg_uint8 *calc_ecc);

/**
 * @param ctl controller
 * @param data 256 bytes of data
 * @param ecc 3 bytes of ECC for 256 bytes of data
 */
__externC int cyg_nand_ctl_ecc_samsung_calc(cyg_nand_ctl_t *ctl,
                                            const cyg_uint8 *data,
                                            cyg_uint8 *ecc);

/**
 * @param ctl controller
 * @param data 256 bytes of data
 * @param ecc 3 bytes of ECC for 256 bytes of data
 */
__externC int cyg_nand_ctl_ecc_samsung_repair(cyg_nand_ctl_t *ctl,
                                              cyg_uint8 *data,
                                              cyg_uint8 *stored_ecc,
                                              cyg_uint8 *calc_ecc);

Flash controllers can have hardware support for ECC calculation. While the data flows through their data path, ECC information is gathered. When the application data has been written or read, the calculated ECC values can be retrieved from the Flash controller. It is not unusual that the ECC generation can be configured to match one of the bundled ECC algorithms, so that a bundled repair function can be used.