You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ad...@apache.org on 2016/06/15 22:04:23 UTC
[40/51] [partial] incubator-mynewt-site git commit: Fixed broken
Quick Start link and added OpenOCD option for Arduino Primo debugging
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/at91sam9.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/at91sam9.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/at91sam9.c
new file mode 100755
index 0000000..3f4e5e2
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/at91sam9.c
@@ -0,0 +1,724 @@
+/*
+ * Copyright (C) 2009 by Dean Glazeski
+ * dnglaze@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <target/arm.h>
+#include <helper/log.h>
+#include "imp.h"
+#include "arm_io.h"
+
+#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */
+#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */
+#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */
+#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */
+#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */
+#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */
+#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */
+
+/**
+ * Representation of a pin on an AT91SAM9 chip.
+ */
+struct at91sam9_pin {
+ /** Address of the PIO controller. */
+ uint32_t pioc;
+
+ /** Pin number. */
+ uint32_t num;
+};
+
+/**
+ * Private data for the controller that is stored in the NAND device structure.
+ */
+struct at91sam9_nand {
+ /** Address of the ECC controller for NAND. */
+ uint32_t ecc;
+
+ /** Address data is written to. */
+ uint32_t data;
+
+ /** Address commands are written to. */
+ uint32_t cmd;
+
+ /** Address addresses are written to. */
+ uint32_t addr;
+
+ /** I/O structure for hosted reads/writes. */
+ struct arm_nand_data io;
+
+ /** Pin representing the ready/~busy line. */
+ struct at91sam9_pin busy;
+
+ /** Pin representing the chip enable. */
+ struct at91sam9_pin ce;
+};
+
+/**
+ * Checks if the target is halted and prints an error message if it isn't.
+ *
+ * @param target Target to be checked.
+ * @param label String label for where function is called from.
+ * @return True if the target is halted.
+ */
+static int at91sam9_halted(struct target *target, const char *label)
+{
+ if (target->state == TARGET_HALTED)
+ return true;
+
+ LOG_ERROR("Target must be halted to use NAND controller (%s)", label);
+ return false;
+}
+
+/**
+ * Initialize the AT91SAM9 NAND controller.
+ *
+ * @param nand NAND device the controller is attached to.
+ * @return Success or failure of initialization.
+ */
+static int at91sam9_init(struct nand_device *nand)
+{
+ struct target *target = nand->target;
+
+ if (!at91sam9_halted(target, "init"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+/**
+ * Enable NAND device attached to a controller.
+ *
+ * @param info NAND controller information for controlling NAND device.
+ * @return Success or failure of the enabling.
+ */
+static int at91sam9_enable(struct nand_device *nand)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num);
+}
+
+/**
+ * Disable NAND device attached to a controller.
+ *
+ * @param info NAND controller information for controlling NAND device.
+ * @return Success or failure of the disabling.
+ */
+static int at91sam9_disable(struct nand_device *nand)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num);
+}
+
+/**
+ * Send a command to the NAND device.
+ *
+ * @param nand NAND device to write the command to.
+ * @param command Command to be written.
+ * @return Success or failure of writing the command.
+ */
+static int at91sam9_command(struct nand_device *nand, uint8_t command)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!at91sam9_halted(target, "command"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ at91sam9_enable(nand);
+
+ return target_write_u8(target, info->cmd, command);
+}
+
+/**
+ * Reset the AT91SAM9 NAND controller.
+ *
+ * @param nand NAND device to be reset.
+ * @return Success or failure of reset.
+ */
+static int at91sam9_reset(struct nand_device *nand)
+{
+ if (!at91sam9_halted(nand->target, "reset"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ return at91sam9_disable(nand);
+}
+
+/**
+ * Send an address to the NAND device attached to an AT91SAM9 NAND controller.
+ *
+ * @param nand NAND device to send the address to.
+ * @param address Address to be sent.
+ * @return Success or failure of sending the address.
+ */
+static int at91sam9_address(struct nand_device *nand, uint8_t address)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!at91sam9_halted(nand->target, "address"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ return target_write_u8(target, info->addr, address);
+}
+
+/**
+ * Read data directly from the NAND device attached to an AT91SAM9 NAND
+ * controller.
+ *
+ * @param nand NAND device to read from.
+ * @param data Pointer to where the data should be put.
+ * @return Success or failure of reading the data.
+ */
+static int at91sam9_read_data(struct nand_device *nand, void *data)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!at91sam9_halted(nand->target, "read data"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ return target_read_u8(target, info->data, data);
+}
+
+/**
+ * Write data directly to the NAND device attached to an AT91SAM9 NAND
+ * controller.
+ *
+ * @param nand NAND device to be written to.
+ * @param data Data to be written.
+ * @return Success or failure of the data write.
+ */
+static int at91sam9_write_data(struct nand_device *nand, uint16_t data)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!at91sam9_halted(target, "write data"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ return target_write_u8(target, info->data, data);
+}
+
+/**
+ * Determine if the NAND device is ready by looking at the ready/~busy pin.
+ *
+ * @param nand NAND device to check.
+ * @param timeout Time in milliseconds to wait for NAND to be ready.
+ * @return True if the NAND is ready in the timeout period.
+ */
+static int at91sam9_nand_ready(struct nand_device *nand, int timeout)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ uint32_t status;
+
+ if (!at91sam9_halted(target, "nand ready"))
+ return 0;
+
+ do {
+ target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status);
+
+ if (status & (1 << info->busy.num))
+ return 1;
+
+ alive_sleep(1);
+ } while (timeout-- > 0);
+
+ return 0;
+}
+
+/**
+ * Read a block of data from the NAND device attached to an AT91SAM9. This
+ * utilizes the ARM hosted NAND read function.
+ *
+ * @param nand NAND device to read from.
+ * @param data Pointer to where the read data should be placed.
+ * @param size Size of the data being read.
+ * @return Success or failure of the hosted read.
+ */
+static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int size)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct arm_nand_data *io = &info->io;
+ int status;
+
+ if (!at91sam9_halted(nand->target, "read block"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ io->chunk_size = nand->page_size;
+ status = arm_nandread(io, data, size);
+
+ return status;
+}
+
+/**
+ * Write a block of data to a NAND device attached to an AT91SAM9. This uses
+ * the ARM hosted write function to write the data.
+ *
+ * @param nand NAND device to write to.
+ * @param data Data to be written to device.
+ * @param size Size of the data being written.
+ * @return Success or failure of the hosted write.
+ */
+static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, int size)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct arm_nand_data *io = &info->io;
+ int status;
+
+ if (!at91sam9_halted(nand->target, "write block"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ io->chunk_size = nand->page_size;
+ status = arm_nandwrite(io, data, size);
+
+ return status;
+}
+
+/**
+ * Initialize the ECC controller on the AT91SAM9.
+ *
+ * @param target Target to configure ECC on.
+ * @param info NAND controller information for where the ECC is.
+ * @return Success or failure of initialization.
+ */
+static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info)
+{
+ if (!info->ecc) {
+ LOG_ERROR("ECC controller address must be set when not reading raw NAND data");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ /* reset ECC parity registers */
+ return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1);
+}
+
+/**
+ * Initialize an area for the OOB based on whether a user is requesting the OOB
+ * data. This determines the size of the OOB and allocates the space in case
+ * the user has not requested the OOB data.
+ *
+ * @param nand NAND device we are creating an OOB for.
+ * @param oob Pointer to the user supplied OOB area.
+ * @param size Size of the OOB.
+ * @return Pointer to an area to store OOB data.
+ */
+static uint8_t *at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size)
+{
+ if (!oob) {
+ /* user doesn't want OOB, allocate it */
+ if (nand->page_size == 512)
+ *size = 16;
+ else if (nand->page_size == 2048)
+ *size = 64;
+
+ oob = malloc(*size);
+ if (!oob) {
+ LOG_ERROR("Unable to allocate space for OOB");
+ return NULL;
+ }
+
+ memset(oob, 0xFF, *size);
+ }
+
+ return oob;
+}
+
+/**
+ * Reads a page from an AT91SAM9 NAND controller and verifies using 1-bit ECC
+ * controller on chip. This makes an attempt to correct any errors that are
+ * encountered while reading the page of data.
+ *
+ * @param nand NAND device to read from
+ * @param page Page to be read.
+ * @param data Pointer to where data should be read to.
+ * @param data_size Size of the data to be read.
+ * @param oob Pointer to where OOB data should be read to.
+ * @param oob_size Size of the OOB data to be read.
+ * @return Success or failure of reading the NAND page.
+ */
+static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ int retval;
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ uint8_t *oob_data;
+ uint32_t status;
+
+ retval = at91sam9_ecc_init(target, info);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (data) {
+ retval = nand_read_data_page(nand, data, data_size);
+ if (ERROR_OK != retval)
+ return retval;
+ }
+
+ oob_data = at91sam9_oob_init(nand, oob, &oob_size);
+ retval = nand_read_data_page(nand, oob_data, oob_size);
+ if (ERROR_OK == retval && data) {
+ target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status);
+ if (status & 1) {
+ LOG_ERROR("Error detected!");
+ if (status & 4)
+ LOG_ERROR("Multiple errors encountered; unrecoverable!");
+ else {
+ /* attempt recovery */
+ uint32_t parity;
+
+ target_read_u32(target,
+ info->ecc + AT91C_ECCx_PR,
+ &parity);
+ uint32_t word = (parity & 0x0000FFF0) >> 4;
+ uint32_t bit = parity & 0x0F;
+
+ data[word] ^= (0x1) << bit;
+ LOG_INFO("Data word %d, bit %d corrected.",
+ (unsigned) word,
+ (unsigned) bit);
+ }
+ }
+
+ if (status & 2) {
+ /* we could write back correct ECC data */
+ LOG_ERROR("Error in ECC bytes detected");
+ }
+ }
+
+ if (!oob) {
+ /* if it wasn't asked for, free it */
+ free(oob_data);
+ }
+
+ return retval;
+}
+
+/**
+ * Write a page of data including 1-bit ECC information to a NAND device
+ * attached to an AT91SAM9 controller. If there is OOB data to be written,
+ * this will ignore the computed ECC from the ECC controller.
+ *
+ * @param nand NAND device to write to.
+ * @param page Page to write.
+ * @param data Pointer to data being written.
+ * @param data_size Size of the data being written.
+ * @param oob Pointer to OOB data being written.
+ * @param oob_size Size of the OOB data.
+ * @return Success or failure of the page write.
+ */
+static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ struct at91sam9_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ int retval;
+ uint8_t *oob_data = oob;
+ uint32_t parity, nparity;
+
+ retval = at91sam9_ecc_init(target, info);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (data) {
+ retval = nand_write_data_page(nand, data, data_size);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write data to NAND device");
+ return retval;
+ }
+ }
+
+ oob_data = at91sam9_oob_init(nand, oob, &oob_size);
+
+ if (!oob) {
+ /* no OOB given, so read in the ECC parity from the ECC controller */
+ target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity);
+ target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity);
+
+ oob_data[0] = (uint8_t) parity;
+ oob_data[1] = (uint8_t) (parity >> 8);
+ oob_data[2] = (uint8_t) nparity;
+ oob_data[3] = (uint8_t) (nparity >> 8);
+ }
+
+ retval = nand_write_data_page(nand, oob_data, oob_size);
+
+ if (!oob)
+ free(oob_data);
+
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write OOB data to NAND");
+ return retval;
+ }
+
+ retval = nand_write_finish(nand);
+
+ return retval;
+}
+
+/**
+ * Handle the initial NAND device command for AT91SAM9 controllers. This
+ * initializes much of the controller information struct to be ready for future
+ * reads and writes.
+ */
+NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command)
+{
+ unsigned long chip = 0, ecc = 0;
+ struct at91sam9_nand *info = NULL;
+
+ LOG_DEBUG("AT91SAM9 NAND Device Command");
+
+ if (CMD_ARGC < 3 || CMD_ARGC > 4) {
+ LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]);
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
+ if (chip == 0) {
+ LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]);
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ if (CMD_ARGC == 4) {
+ COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ecc);
+ if (ecc == 0) {
+ LOG_ERROR("invalid ECC controller address: %s", CMD_ARGV[3]);
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+ }
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ LOG_ERROR("unable to allocate space for controller private data");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ info->data = chip;
+ info->cmd = chip | (1 << 22);
+ info->addr = chip | (1 << 21);
+ info->ecc = ecc;
+
+ nand->controller_priv = info;
+ info->io.target = nand->target;
+ info->io.data = info->data;
+ info->io.op = ARM_NAND_NONE;
+
+ return ERROR_OK;
+}
+
+/**
+ * Handle the AT91SAM9 CLE command for specifying the address line to use for
+ * writing commands to a NAND device.
+ */
+COMMAND_HANDLER(handle_at91sam9_cle_command)
+{
+ struct nand_device *nand = NULL;
+ struct at91sam9_nand *info = NULL;
+ unsigned num, address_line;
+
+ if (CMD_ARGC != 2) {
+ command_print(CMD_CTX, "incorrect number of arguments for 'at91sam9 cle' command");
+ return ERROR_OK;
+ }
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
+ nand = get_nand_device_by_num(num);
+ if (!nand) {
+ command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
+ return ERROR_OK;
+ }
+
+ info = nand->controller_priv;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line);
+ info->cmd = info->data | (1 << address_line);
+
+ return ERROR_OK;
+}
+
+/**
+ * Handle the AT91SAM9 ALE command for specifying the address line to use for
+ * writing addresses to the NAND device.
+ */
+COMMAND_HANDLER(handle_at91sam9_ale_command)
+{
+ struct nand_device *nand = NULL;
+ struct at91sam9_nand *info = NULL;
+ unsigned num, address_line;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
+ nand = get_nand_device_by_num(num);
+ if (!nand) {
+ command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ info = nand->controller_priv;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line);
+ info->addr = info->data | (1 << address_line);
+
+ return ERROR_OK;
+}
+
+/**
+ * Handle the AT91SAM9 RDY/~BUSY command for specifying the pin that watches the
+ * RDY/~BUSY line from the NAND device.
+ */
+COMMAND_HANDLER(handle_at91sam9_rdy_busy_command)
+{
+ struct nand_device *nand = NULL;
+ struct at91sam9_nand *info = NULL;
+ unsigned num, base_pioc, pin_num;
+
+ if (CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
+ nand = get_nand_device_by_num(num);
+ if (!nand) {
+ command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ info = nand->controller_priv;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc);
+ info->busy.pioc = base_pioc;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num);
+ info->busy.num = pin_num;
+
+ return ERROR_OK;
+}
+
+/**
+ * Handle the AT91SAM9 CE command for specifying the pin that is used to enable
+ * or disable the NAND device.
+ */
+COMMAND_HANDLER(handle_at91sam9_ce_command)
+{
+ struct nand_device *nand = NULL;
+ struct at91sam9_nand *info = NULL;
+ unsigned num, base_pioc, pin_num;
+
+ if (CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
+ nand = get_nand_device_by_num(num);
+ if (!nand) {
+ command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ info = nand->controller_priv;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc);
+ info->ce.pioc = base_pioc;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num);
+ info->ce.num = pin_num;
+
+ return ERROR_OK;
+}
+
+static const struct command_registration at91sam9_sub_command_handlers[] = {
+ {
+ .name = "cle",
+ .handler = handle_at91sam9_cle_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set command latch enable address line (default is 22)",
+ .usage = "bank_id address_line",
+ },
+ {
+ .name = "ale",
+ .handler = handle_at91sam9_ale_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set address latch enable address line (default is 21)",
+ .usage = "bank_id address_line",
+ },
+ {
+ .name = "rdy_busy",
+ .handler = handle_at91sam9_rdy_busy_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the GPIO input pin connected to "
+ "the RDY/~BUSY signal (no default)",
+ .usage = "bank_id pio_base_addr pin_num",
+ },
+ {
+ .name = "ce",
+ .handler = handle_at91sam9_ce_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the GPIO output pin connected to "
+ "the chip enable signal (no default)",
+ .usage = "bank_id pio_base_addr pin_num",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration at91sam9_command_handler[] = {
+ {
+ .name = "at91sam9",
+ .mode = COMMAND_ANY,
+ .help = "AT91SAM9 NAND flash controller commands",
+ .usage = "",
+ .chain = at91sam9_sub_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+/**
+ * Structure representing the AT91SAM9 NAND controller.
+ */
+struct nand_flash_controller at91sam9_nand_controller = {
+ .name = "at91sam9",
+ .nand_device_command = at91sam9_nand_device_command,
+ .commands = at91sam9_command_handler,
+ .init = at91sam9_init,
+ .command = at91sam9_command,
+ .reset = at91sam9_reset,
+ .address = at91sam9_address,
+ .read_data = at91sam9_read_data,
+ .write_data = at91sam9_write_data,
+ .nand_ready = at91sam9_nand_ready,
+ .read_block_data = at91sam9_read_block_data,
+ .write_block_data = at91sam9_write_block_data,
+ .read_page = at91sam9_read_page,
+ .write_page = at91sam9_write_page,
+};
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.c
new file mode 100755
index 0000000..815c766
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.c
@@ -0,0 +1,878 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Dominic Rath <Do...@gmx.de> *
+ * Copyright (C) 2002 Thomas Gleixner <tg...@linutronix.de> *
+ * Copyright (C) 2009 Zachary T Welch <zw...@superlucidity.net> *
+ * *
+ * Partially based on drivers/mtd/nand_ids.c from Linux. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+
+/* configured NAND devices and NAND Flash command handler */
+struct nand_device *nand_devices;
+
+void nand_device_add(struct nand_device *c)
+{
+ if (nand_devices) {
+ struct nand_device *p = nand_devices;
+ while (p && p->next)
+ p = p->next;
+ p->next = c;
+ } else
+ nand_devices = c;
+}
+
+
+/* Chip ID list
+ *
+ * Manufacturer, ID code, pagesize, chipsize in MegaByte, eraseblock size,
+ * options, name
+ *
+ * Pagesize; 0, 256, 512
+ * 0 get this information from the extended chip ID
+ * 256 256 Byte page size
+ * 512 512 Byte page size
+ */
+static struct nand_info nand_flash_ids[] = {
+ /* Vendor Specific Entries */
+ { NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS,
+ "K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"},
+ { NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS,
+ "K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"},
+
+ /* start "museum" IDs */
+ { 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"},
+ { 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"},
+ { 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"},
+ { 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
+ { 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
+ { 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"},
+ { 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
+ { 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
+ { 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
+ { 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
+
+ { 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"},
+ { 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
+ { 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"},
+ { 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"},
+ /* end "museum" IDs */
+
+ { 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"},
+ { 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"},
+ { 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 1.8V 16-bit"},
+ { 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 3.3V 16-bit"},
+
+ { 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"},
+ { 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"},
+ { 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 1.8V 16-bit"},
+ { 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 3.3V 16-bit"},
+
+ { 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"},
+ { 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"},
+ { 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 1.8V 16-bit"},
+ { 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 3.3V 16-bit"},
+
+ { 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
+ { 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
+ { 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"},
+ { 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"},
+ { 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"},
+ { 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"},
+ { 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"},
+
+ { 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"},
+
+ { 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"},
+ { 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"},
+ { 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"},
+ { 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"},
+
+ { 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"},
+ { 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"},
+ { 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"},
+ { 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"},
+
+ { 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"},
+ { 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"},
+ { 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"},
+ { 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"},
+
+ { 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"},
+ { 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"},
+ { 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"},
+ { 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"},
+
+ { 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"},
+ { 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"},
+ { 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"},
+ { 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"},
+
+ { 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"},
+ { 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
+ { 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"},
+ { 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"},
+
+ { 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
+
+ {0, 0, 0, 0, 0, 0, NULL}
+};
+
+/* Manufacturer ID list
+ */
+static struct nand_manufacturer nand_manuf_ids[] = {
+ {0x0, "unknown"},
+ {NAND_MFR_TOSHIBA, "Toshiba"},
+ {NAND_MFR_SAMSUNG, "Samsung"},
+ {NAND_MFR_FUJITSU, "Fujitsu"},
+ {NAND_MFR_NATIONAL, "National"},
+ {NAND_MFR_RENESAS, "Renesas"},
+ {NAND_MFR_STMICRO, "ST Micro"},
+ {NAND_MFR_HYNIX, "Hynix"},
+ {NAND_MFR_MICRON, "Micron"},
+ {0x0, NULL},
+};
+
+/*
+ * Define default oob placement schemes for large and small page devices
+ */
+
+#if 0
+static struct nand_ecclayout nand_oob_8 = {
+ .eccbytes = 3,
+ .eccpos = {0, 1, 2},
+ .oobfree = {
+ {.offset = 3,
+ .length = 2},
+ {.offset = 6,
+ .length = 2}
+ }
+};
+#endif
+
+/**
+ * Returns the flash bank specified by @a name, which matches the
+ * driver name and a suffix (option) specify the driver-specific
+ * bank number. The suffix consists of the '.' and the driver-specific
+ * bank number: when two davinci banks are defined, then 'davinci.1' refers
+ * to the second (e.g. DM355EVM).
+ */
+static struct nand_device *get_nand_device_by_name(const char *name)
+{
+ unsigned requested = get_flash_name_index(name);
+ unsigned found = 0;
+
+ struct nand_device *nand;
+ for (nand = nand_devices; NULL != nand; nand = nand->next) {
+ if (strcmp(nand->name, name) == 0)
+ return nand;
+ if (!flash_driver_name_matches(nand->controller->name, name))
+ continue;
+ if (++found < requested)
+ continue;
+ return nand;
+ }
+ return NULL;
+}
+
+struct nand_device *get_nand_device_by_num(int num)
+{
+ struct nand_device *p;
+ int i = 0;
+
+ for (p = nand_devices; p; p = p->next) {
+ if (i++ == num)
+ return p;
+ }
+
+ return NULL;
+}
+
+COMMAND_HELPER(nand_command_get_device, unsigned name_index,
+ struct nand_device **nand)
+{
+ const char *str = CMD_ARGV[name_index];
+ *nand = get_nand_device_by_name(str);
+ if (*nand)
+ return ERROR_OK;
+
+ unsigned num;
+ COMMAND_PARSE_NUMBER(uint, str, num);
+ *nand = get_nand_device_by_num(num);
+ if (!*nand) {
+ command_print(CMD_CTX, "NAND flash device '%s' not found", str);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ return ERROR_OK;
+}
+
+int nand_build_bbt(struct nand_device *nand, int first, int last)
+{
+ uint32_t page;
+ int i;
+ int pages_per_block = (nand->erase_size / nand->page_size);
+ uint8_t oob[6];
+ int ret;
+
+ if ((first < 0) || (first >= nand->num_blocks))
+ first = 0;
+
+ if ((last >= nand->num_blocks) || (last == -1))
+ last = nand->num_blocks - 1;
+
+ page = first * pages_per_block;
+ for (i = first; i <= last; i++) {
+ ret = nand_read_page(nand, page, NULL, 0, oob, 6);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
+ || (((nand->page_size == 512) && (oob[5] != 0xff)) ||
+ ((nand->page_size == 2048) && (oob[0] != 0xff)))) {
+ LOG_WARNING("bad block: %i", i);
+ nand->blocks[i].is_bad = 1;
+ } else
+ nand->blocks[i].is_bad = 0;
+
+ page += pages_per_block;
+ }
+
+ return ERROR_OK;
+}
+
+int nand_read_status(struct nand_device *nand, uint8_t *status)
+{
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+
+ /* Send read status command */
+ nand->controller->command(nand, NAND_CMD_STATUS);
+
+ alive_sleep(1);
+
+ /* read status */
+ if (nand->device->options & NAND_BUSWIDTH_16) {
+ uint16_t data;
+ nand->controller->read_data(nand, &data);
+ *status = data & 0xff;
+ } else
+ nand->controller->read_data(nand, status);
+
+ return ERROR_OK;
+}
+
+static int nand_poll_ready(struct nand_device *nand, int timeout)
+{
+ uint8_t status;
+
+ nand->controller->command(nand, NAND_CMD_STATUS);
+ do {
+ if (nand->device->options & NAND_BUSWIDTH_16) {
+ uint16_t data;
+ nand->controller->read_data(nand, &data);
+ status = data & 0xff;
+ } else
+ nand->controller->read_data(nand, &status);
+ if (status & NAND_STATUS_READY)
+ break;
+ alive_sleep(1);
+ } while (timeout--);
+
+ return (status & NAND_STATUS_READY) != 0;
+}
+
+int nand_probe(struct nand_device *nand)
+{
+ uint8_t manufacturer_id, device_id;
+ uint8_t id_buff[6];
+ int retval;
+ int i;
+
+ /* clear device data */
+ nand->device = NULL;
+ nand->manufacturer = NULL;
+
+ /* clear device parameters */
+ nand->bus_width = 0;
+ nand->address_cycles = 0;
+ nand->page_size = 0;
+ nand->erase_size = 0;
+
+ /* initialize controller (device parameters are zero, use controller default) */
+ retval = nand->controller->init(nand);
+ if (retval != ERROR_OK) {
+ switch (retval) {
+ case ERROR_NAND_OPERATION_FAILED:
+ LOG_DEBUG("controller initialization failed");
+ return ERROR_NAND_OPERATION_FAILED;
+ case ERROR_NAND_OPERATION_NOT_SUPPORTED:
+ LOG_ERROR(
+ "BUG: controller reported that it doesn't support default parameters");
+ return ERROR_NAND_OPERATION_FAILED;
+ default:
+ LOG_ERROR("BUG: unknown controller initialization failure");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+ }
+
+ nand->controller->command(nand, NAND_CMD_RESET);
+ nand->controller->reset(nand);
+
+ nand->controller->command(nand, NAND_CMD_READID);
+ nand->controller->address(nand, 0x0);
+
+ if (nand->bus_width == 8) {
+ nand->controller->read_data(nand, &manufacturer_id);
+ nand->controller->read_data(nand, &device_id);
+ } else {
+ uint16_t data_buf;
+ nand->controller->read_data(nand, &data_buf);
+ manufacturer_id = data_buf & 0xff;
+ nand->controller->read_data(nand, &data_buf);
+ device_id = data_buf & 0xff;
+ }
+
+ for (i = 0; nand_flash_ids[i].name; i++) {
+ if (nand_flash_ids[i].id == device_id &&
+ (nand_flash_ids[i].mfr_id == manufacturer_id ||
+ nand_flash_ids[i].mfr_id == 0)) {
+ nand->device = &nand_flash_ids[i];
+ break;
+ }
+ }
+
+ for (i = 0; nand_manuf_ids[i].name; i++) {
+ if (nand_manuf_ids[i].id == manufacturer_id) {
+ nand->manufacturer = &nand_manuf_ids[i];
+ break;
+ }
+ }
+
+ if (!nand->manufacturer) {
+ nand->manufacturer = &nand_manuf_ids[0];
+ nand->manufacturer->id = manufacturer_id;
+ }
+
+ if (!nand->device) {
+ LOG_ERROR(
+ "unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
+ manufacturer_id,
+ device_id);
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ LOG_DEBUG("found %s (%s)", nand->device->name, nand->manufacturer->name);
+
+ /* initialize device parameters */
+
+ /* bus width */
+ if (nand->device->options & NAND_BUSWIDTH_16)
+ nand->bus_width = 16;
+ else
+ nand->bus_width = 8;
+
+ /* Do we need extended device probe information? */
+ if (nand->device->page_size == 0 ||
+ nand->device->erase_size == 0) {
+ if (nand->bus_width == 8) {
+ nand->controller->read_data(nand, id_buff + 3);
+ nand->controller->read_data(nand, id_buff + 4);
+ nand->controller->read_data(nand, id_buff + 5);
+ } else {
+ uint16_t data_buf;
+
+ nand->controller->read_data(nand, &data_buf);
+ id_buff[3] = data_buf;
+
+ nand->controller->read_data(nand, &data_buf);
+ id_buff[4] = data_buf;
+
+ nand->controller->read_data(nand, &data_buf);
+ id_buff[5] = data_buf >> 8;
+ }
+ }
+
+ /* page size */
+ if (nand->device->page_size == 0)
+ nand->page_size = 1 << (10 + (id_buff[4] & 3));
+ else if (nand->device->page_size == 256) {
+ LOG_ERROR("NAND flashes with 256 byte pagesize are not supported");
+ return ERROR_NAND_OPERATION_FAILED;
+ } else
+ nand->page_size = nand->device->page_size;
+
+ /* number of address cycles */
+ if (nand->page_size <= 512) {
+ /* small page devices */
+ if (nand->device->chip_size <= 32)
+ nand->address_cycles = 3;
+ else if (nand->device->chip_size <= 8*1024)
+ nand->address_cycles = 4;
+ else {
+ LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered");
+ nand->address_cycles = 5;
+ }
+ } else {
+ /* large page devices */
+ if (nand->device->chip_size <= 128)
+ nand->address_cycles = 4;
+ else if (nand->device->chip_size <= 32*1024)
+ nand->address_cycles = 5;
+ else {
+ LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered");
+ nand->address_cycles = 6;
+ }
+ }
+
+ /* erase size */
+ if (nand->device->erase_size == 0) {
+ switch ((id_buff[4] >> 4) & 3) {
+ case 0:
+ nand->erase_size = 64 << 10;
+ break;
+ case 1:
+ nand->erase_size = 128 << 10;
+ break;
+ case 2:
+ nand->erase_size = 256 << 10;
+ break;
+ case 3:
+ nand->erase_size = 512 << 10;
+ break;
+ }
+ } else
+ nand->erase_size = nand->device->erase_size;
+
+ /* initialize controller, but leave parameters at the controllers default */
+ retval = nand->controller->init(nand);
+ if (retval != ERROR_OK) {
+ switch (retval) {
+ case ERROR_NAND_OPERATION_FAILED:
+ LOG_DEBUG("controller initialization failed");
+ return ERROR_NAND_OPERATION_FAILED;
+ case ERROR_NAND_OPERATION_NOT_SUPPORTED:
+ LOG_ERROR(
+ "controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",
+ nand->bus_width,
+ nand->address_cycles,
+ nand->page_size);
+ return ERROR_NAND_OPERATION_FAILED;
+ default:
+ LOG_ERROR("BUG: unknown controller initialization failure");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+ }
+
+ nand->num_blocks = (nand->device->chip_size * 1024) / (nand->erase_size / 1024);
+ nand->blocks = malloc(sizeof(struct nand_block) * nand->num_blocks);
+
+ for (i = 0; i < nand->num_blocks; i++) {
+ nand->blocks[i].size = nand->erase_size;
+ nand->blocks[i].offset = i * nand->erase_size;
+ nand->blocks[i].is_erased = -1;
+ nand->blocks[i].is_bad = -1;
+ }
+
+ return ERROR_OK;
+}
+
+int nand_erase(struct nand_device *nand, int first_block, int last_block)
+{
+ int i;
+ uint32_t page;
+ uint8_t status;
+ int retval;
+
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+
+ if ((first_block < 0) || (last_block >= nand->num_blocks))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* make sure we know if a block is bad before erasing it */
+ for (i = first_block; i <= last_block; i++) {
+ if (nand->blocks[i].is_bad == -1) {
+ nand_build_bbt(nand, i, last_block);
+ break;
+ }
+ }
+
+ for (i = first_block; i <= last_block; i++) {
+ /* Send erase setup command */
+ nand->controller->command(nand, NAND_CMD_ERASE1);
+
+ page = i * (nand->erase_size / nand->page_size);
+
+ /* Send page address */
+ if (nand->page_size <= 512) {
+ /* row */
+ nand->controller->address(nand, page & 0xff);
+ nand->controller->address(nand, (page >> 8) & 0xff);
+
+ /* 3rd cycle only on devices with more than 32 MiB */
+ if (nand->address_cycles >= 4)
+ nand->controller->address(nand, (page >> 16) & 0xff);
+
+ /* 4th cycle only on devices with more than 8 GiB */
+ if (nand->address_cycles >= 5)
+ nand->controller->address(nand, (page >> 24) & 0xff);
+ } else {
+ /* row */
+ nand->controller->address(nand, page & 0xff);
+ nand->controller->address(nand, (page >> 8) & 0xff);
+
+ /* 3rd cycle only on devices with more than 128 MiB */
+ if (nand->address_cycles >= 5)
+ nand->controller->address(nand, (page >> 16) & 0xff);
+ }
+
+ /* Send erase confirm command */
+ nand->controller->command(nand, NAND_CMD_ERASE2);
+
+ retval = nand->controller->nand_ready ?
+ nand->controller->nand_ready(nand, 1000) :
+ nand_poll_ready(nand, 1000);
+ if (!retval) {
+ LOG_ERROR("timeout waiting for NAND flash block erase to complete");
+ return ERROR_NAND_OPERATION_TIMEOUT;
+ }
+
+ retval = nand_read_status(nand, &status);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("couldn't read status");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ if (status & 0x1) {
+ LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
+ (nand->blocks[i].is_bad == 1)
+ ? "bad " : "",
+ i, status);
+ /* continue; other blocks might still be erasable */
+ }
+
+ nand->blocks[i].is_erased = 1;
+ }
+
+ return ERROR_OK;
+}
+
+#if 0
+static int nand_read_plain(struct nand_device *nand,
+ uint32_t address,
+ uint8_t *data,
+ uint32_t data_size)
+{
+ uint8_t *page;
+
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+
+ if (address % nand->page_size) {
+ LOG_ERROR("reads need to be page aligned");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ page = malloc(nand->page_size);
+
+ while (data_size > 0) {
+ uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
+ uint32_t page_address;
+
+
+ page_address = address / nand->page_size;
+
+ nand_read_page(nand, page_address, page, nand->page_size, NULL, 0);
+
+ memcpy(data, page, thisrun_size);
+
+ address += thisrun_size;
+ data += thisrun_size;
+ data_size -= thisrun_size;
+ }
+
+ free(page);
+
+ return ERROR_OK;
+}
+
+static int nand_write_plain(struct nand_device *nand,
+ uint32_t address,
+ uint8_t *data,
+ uint32_t data_size)
+{
+ uint8_t *page;
+
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+
+ if (address % nand->page_size) {
+ LOG_ERROR("writes need to be page aligned");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ page = malloc(nand->page_size);
+
+ while (data_size > 0) {
+ uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
+ uint32_t page_address;
+
+ memset(page, 0xff, nand->page_size);
+ memcpy(page, data, thisrun_size);
+
+ page_address = address / nand->page_size;
+
+ nand_write_page(nand, page_address, page, nand->page_size, NULL, 0);
+
+ address += thisrun_size;
+ data += thisrun_size;
+ data_size -= thisrun_size;
+ }
+
+ free(page);
+
+ return ERROR_OK;
+}
+#endif
+
+int nand_write_page(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size,
+ uint8_t *oob, uint32_t oob_size)
+{
+ uint32_t block;
+
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+
+ block = page / (nand->erase_size / nand->page_size);
+ if (nand->blocks[block].is_erased == 1)
+ nand->blocks[block].is_erased = 0;
+
+ if (nand->use_raw || nand->controller->write_page == NULL)
+ return nand_write_page_raw(nand, page, data, data_size, oob, oob_size);
+ else
+ return nand->controller->write_page(nand, page, data, data_size, oob, oob_size);
+}
+
+int nand_read_page(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size,
+ uint8_t *oob, uint32_t oob_size)
+{
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+
+ if (nand->use_raw || nand->controller->read_page == NULL)
+ return nand_read_page_raw(nand, page, data, data_size, oob, oob_size);
+ else
+ return nand->controller->read_page(nand, page, data, data_size, oob, oob_size);
+}
+
+int nand_page_command(struct nand_device *nand, uint32_t page,
+ uint8_t cmd, bool oob_only)
+{
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+
+ if (oob_only && NAND_CMD_READ0 == cmd && nand->page_size <= 512)
+ cmd = NAND_CMD_READOOB;
+
+ nand->controller->command(nand, cmd);
+
+ if (nand->page_size <= 512) {
+ /* small page device */
+
+ /* column (always 0, we start at the beginning of a page/OOB area) */
+ nand->controller->address(nand, 0x0);
+
+ /* row */
+ nand->controller->address(nand, page & 0xff);
+ nand->controller->address(nand, (page >> 8) & 0xff);
+
+ /* 4th cycle only on devices with more than 32 MiB */
+ if (nand->address_cycles >= 4)
+ nand->controller->address(nand, (page >> 16) & 0xff);
+
+ /* 5th cycle only on devices with more than 8 GiB */
+ if (nand->address_cycles >= 5)
+ nand->controller->address(nand, (page >> 24) & 0xff);
+ } else {
+ /* large page device */
+
+ /* column (0 when we start at the beginning of a page,
+ * or 2048 for the beginning of OOB area)
+ */
+ nand->controller->address(nand, 0x0);
+ if (oob_only)
+ nand->controller->address(nand, 0x8);
+ else
+ nand->controller->address(nand, 0x0);
+
+ /* row */
+ nand->controller->address(nand, page & 0xff);
+ nand->controller->address(nand, (page >> 8) & 0xff);
+
+ /* 5th cycle only on devices with more than 128 MiB */
+ if (nand->address_cycles >= 5)
+ nand->controller->address(nand, (page >> 16) & 0xff);
+
+ /* large page devices need a start command if reading */
+ if (NAND_CMD_READ0 == cmd)
+ nand->controller->command(nand, NAND_CMD_READSTART);
+ }
+
+ if (nand->controller->nand_ready) {
+ if (!nand->controller->nand_ready(nand, 100))
+ return ERROR_NAND_OPERATION_TIMEOUT;
+ } else {
+ /* nand_poll_read() cannot be used during nand read */
+ alive_sleep(1);
+ }
+
+ return ERROR_OK;
+}
+
+int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
+{
+ int retval = ERROR_NAND_NO_BUFFER;
+
+ if (nand->controller->read_block_data != NULL)
+ retval = (nand->controller->read_block_data)(nand, data, size);
+
+ if (ERROR_NAND_NO_BUFFER == retval) {
+ uint32_t i;
+ int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1;
+
+ retval = ERROR_OK;
+ for (i = 0; retval == ERROR_OK && i < size; i += incr) {
+ retval = nand->controller->read_data(nand, data);
+ data += incr;
+ }
+ }
+
+ return retval;
+}
+
+int nand_read_page_raw(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size,
+ uint8_t *oob, uint32_t oob_size)
+{
+ int retval;
+
+ retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (data)
+ nand_read_data_page(nand, data, data_size);
+
+ if (oob)
+ nand_read_data_page(nand, oob, oob_size);
+
+ return ERROR_OK;
+}
+
+int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
+{
+ int retval = ERROR_NAND_NO_BUFFER;
+
+ if (nand->controller->write_block_data != NULL)
+ retval = (nand->controller->write_block_data)(nand, data, size);
+
+ if (ERROR_NAND_NO_BUFFER == retval) {
+ bool is16bit = nand->device->options & NAND_BUSWIDTH_16;
+ uint32_t incr = is16bit ? 2 : 1;
+ uint16_t write_data;
+ uint32_t i;
+
+ for (i = 0; i < size; i += incr) {
+ if (is16bit)
+ write_data = le_to_h_u16(data);
+ else
+ write_data = *data;
+
+ retval = nand->controller->write_data(nand, write_data);
+ if (ERROR_OK != retval)
+ break;
+
+ data += incr;
+ }
+ }
+
+ return retval;
+}
+
+int nand_write_finish(struct nand_device *nand)
+{
+ int retval;
+ uint8_t status;
+
+ nand->controller->command(nand, NAND_CMD_PAGEPROG);
+
+ retval = nand->controller->nand_ready ?
+ nand->controller->nand_ready(nand, 100) :
+ nand_poll_ready(nand, 100);
+ if (!retval)
+ return ERROR_NAND_OPERATION_TIMEOUT;
+
+ retval = nand_read_status(nand, &status);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("couldn't read status");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ if (status & NAND_STATUS_FAIL) {
+ LOG_ERROR("write operation didn't pass, status: 0x%2.2x",
+ status);
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+int nand_write_page_raw(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size,
+ uint8_t *oob, uint32_t oob_size)
+{
+ int retval;
+
+ retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (data) {
+ retval = nand_write_data_page(nand, data, data_size);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write data to NAND device");
+ return retval;
+ }
+ }
+
+ if (oob) {
+ retval = nand_write_data_page(nand, oob, oob_size);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write OOB data to NAND device");
+ return retval;
+ }
+ }
+
+ return nand_write_finish(nand);
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.h
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.h b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.h
new file mode 100755
index 0000000..308859b
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/core.h
@@ -0,0 +1,234 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Dominic Rath <Do...@gmx.de> *
+ * Copyright (C) 2009 Zachary T Welch <zw...@superlucidity.net> *
+ * *
+ * Partially based on linux/include/linux/mtd/nand.h *
+ * Copyright (C) 2000 David Woodhouse <dw...@mvhi.com> *
+ * Copyright (C) 2000 Steven J. Hill <sj...@realitydiluted.com> *
+ * Copyright (C) 2000 Thomas Gleixner <tg...@linutronix.de> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifndef FLASH_NAND_CORE_H
+#define FLASH_NAND_CORE_H
+
+#include <flash/common.h>
+
+/**
+ * Representation of a single NAND block in a NAND device.
+ */
+struct nand_block {
+ /** Offset to the block. */
+ uint32_t offset;
+
+ /** Size of the block. */
+ uint32_t size;
+
+ /** True if the block has been erased. */
+ int is_erased;
+
+ /** True if the block is bad. */
+ int is_bad;
+};
+
+struct nand_oobfree {
+ int offset;
+ int length;
+};
+
+struct nand_ecclayout {
+ int eccbytes;
+ int eccpos[64];
+ int oobavail;
+ struct nand_oobfree oobfree[2];
+};
+
+struct nand_device {
+ const char *name;
+ struct target *target;
+ struct nand_flash_controller *controller;
+ void *controller_priv;
+ struct nand_manufacturer *manufacturer;
+ struct nand_info *device;
+ int bus_width;
+ int address_cycles;
+ int page_size;
+ int erase_size;
+ int use_raw;
+ int num_blocks;
+ struct nand_block *blocks;
+ struct nand_device *next;
+};
+
+/* NAND Flash Manufacturer ID Codes
+ */
+enum {
+ NAND_MFR_TOSHIBA = 0x98,
+ NAND_MFR_SAMSUNG = 0xec,
+ NAND_MFR_FUJITSU = 0x04,
+ NAND_MFR_NATIONAL = 0x8f,
+ NAND_MFR_RENESAS = 0x07,
+ NAND_MFR_STMICRO = 0x20,
+ NAND_MFR_HYNIX = 0xad,
+ NAND_MFR_MICRON = 0x2c,
+};
+
+struct nand_manufacturer {
+ int id;
+ const char *name;
+};
+
+struct nand_info {
+ int mfr_id;
+ int id;
+ int page_size;
+ int chip_size;
+ int erase_size;
+ int options;
+ const char *name;
+};
+
+/* Option constants for bizarre disfunctionality and real features
+ */
+enum {
+ /* Chip can not auto increment pages */
+ NAND_NO_AUTOINCR = 0x00000001,
+
+ /* Buswitdh is 16 bit */
+ NAND_BUSWIDTH_16 = 0x00000002,
+
+ /* Device supports partial programming without padding */
+ NAND_NO_PADDING = 0x00000004,
+
+ /* Chip has cache program function */
+ NAND_CACHEPRG = 0x00000008,
+
+ /* Chip has copy back function */
+ NAND_COPYBACK = 0x00000010,
+
+ /* AND Chip which has 4 banks and a confusing page / block
+ * assignment. See Renesas datasheet for further information */
+ NAND_IS_AND = 0x00000020,
+
+ /* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+ NAND_4PAGE_ARRAY = 0x00000040,
+
+ /* Chip requires that BBT is periodically rewritten to prevent
+ * bits from adjacent blocks from 'leaking' in altering data.
+ * This happens with the Renesas AG-AND chips, possibly others. */
+ BBT_AUTO_REFRESH = 0x00000080,
+
+ /* Chip does not require ready check on read. True
+ * for all large page devices, as they do not support
+ * autoincrement.*/
+ NAND_NO_READRDY = 0x00000100,
+
+ /* Options valid for Samsung large page devices */
+ NAND_SAMSUNG_LP_OPTIONS = (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK),
+
+ /* Options for new chips with large page size. The pagesize and the
+ * erasesize is determined from the extended id bytes
+ */
+ LP_OPTIONS = (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR),
+ LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16),
+};
+
+enum {
+ /* Standard NAND flash commands */
+ NAND_CMD_READ0 = 0x0,
+ NAND_CMD_READ1 = 0x1,
+ NAND_CMD_RNDOUT = 0x5,
+ NAND_CMD_PAGEPROG = 0x10,
+ NAND_CMD_READOOB = 0x50,
+ NAND_CMD_ERASE1 = 0x60,
+ NAND_CMD_STATUS = 0x70,
+ NAND_CMD_STATUS_MULTI = 0x71,
+ NAND_CMD_SEQIN = 0x80,
+ NAND_CMD_RNDIN = 0x85,
+ NAND_CMD_READID = 0x90,
+ NAND_CMD_ERASE2 = 0xd0,
+ NAND_CMD_RESET = 0xff,
+
+ /* Extended commands for large page devices */
+ NAND_CMD_READSTART = 0x30,
+ NAND_CMD_RNDOUTSTART = 0xE0,
+ NAND_CMD_CACHEDPROG = 0x15,
+};
+
+/* Status bits */
+enum {
+ NAND_STATUS_FAIL = 0x01,
+ NAND_STATUS_FAIL_N1 = 0x02,
+ NAND_STATUS_TRUE_READY = 0x20,
+ NAND_STATUS_READY = 0x40,
+ NAND_STATUS_WP = 0x80,
+};
+
+/* OOB (spare) data formats */
+enum oob_formats {
+ NAND_OOB_NONE = 0x0, /* no OOB data at all */
+ NAND_OOB_RAW = 0x1, /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for
+ *2048b page sizes) */
+ NAND_OOB_ONLY = 0x2, /* only OOB data */
+ NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */
+ NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
+ NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */
+ NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */
+ NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
+};
+
+
+struct nand_device *get_nand_device_by_num(int num);
+
+int nand_page_command(struct nand_device *nand, uint32_t page,
+ uint8_t cmd, bool oob_only);
+
+int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size);
+int nand_write_data_page(struct nand_device *nand,
+ uint8_t *data, uint32_t size);
+
+int nand_write_finish(struct nand_device *nand);
+
+int nand_read_page_raw(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
+int nand_write_page_raw(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
+
+int nand_read_status(struct nand_device *nand, uint8_t *status);
+
+int nand_calculate_ecc(struct nand_device *nand,
+ const uint8_t *dat, uint8_t *ecc_code);
+int nand_calculate_ecc_kw(struct nand_device *nand,
+ const uint8_t *dat, uint8_t *ecc_code);
+
+int nand_register_commands(struct command_context *cmd_ctx);
+
+/** helper for parsing a nand device command argument string */
+COMMAND_HELPER(nand_command_get_device, unsigned name_index,
+ struct nand_device **nand);
+
+
+#define ERROR_NAND_DEVICE_INVALID (-1100)
+#define ERROR_NAND_OPERATION_FAILED (-1101)
+#define ERROR_NAND_OPERATION_TIMEOUT (-1102)
+#define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103)
+#define ERROR_NAND_DEVICE_NOT_PROBED (-1104)
+#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
+#define ERROR_NAND_NO_BUFFER (-1106)
+
+#endif /* FLASH_NAND_CORE_H */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/davinci.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/davinci.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/davinci.c
new file mode 100755
index 0000000..c88046d
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/davinci.c
@@ -0,0 +1,795 @@
+/***************************************************************************
+ * Copyright (C) 2009 by David Brownell *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+/*
+ * DaVinci family NAND controller support for OpenOCD.
+ *
+ * This driver uses hardware ECC (1-bit or 4-bit) unless
+ * the chip is accessed in "raw" mode.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "arm_io.h"
+#include <target/target.h>
+
+enum ecc {
+ HWECC1, /* all controllers support 1-bit ECC */
+ HWECC4, /* newer chips also have 4-bit ECC hardware */
+ HWECC4_INFIX, /* avoid this layout, except maybe for boot code */
+};
+
+struct davinci_nand {
+ uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
+ uint8_t eccmode;
+
+ /* Async EMIF controller base */
+ uint32_t aemif;
+
+ /* NAND chip addresses */
+ uint32_t data; /* without CLE or ALE */
+ uint32_t cmd; /* with CLE */
+ uint32_t addr; /* with ALE */
+
+ /* write acceleration */
+ struct arm_nand_data io;
+
+ /* page i/o for the relevant flavor of hardware ECC */
+ int (*read_page)(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
+ int (*write_page)(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
+};
+
+#define NANDFCR 0x60 /* flash control register */
+#define NANDFSR 0x64 /* flash status register */
+#define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */
+#define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */
+#define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */
+#define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */
+#define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */
+
+static int halted(struct target *target, const char *label)
+{
+ if (target->state == TARGET_HALTED)
+ return true;
+
+ LOG_ERROR("Target must be halted to use NAND controller (%s)", label);
+ return false;
+}
+
+static int davinci_init(struct nand_device *nand)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ uint32_t nandfcr;
+
+ if (!halted(target, "init"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ /* We require something else to have configured AEMIF to talk
+ * to NAND chip in this range (including timings and width).
+ */
+ target_read_u32(target, info->aemif + NANDFCR, &nandfcr);
+ if (!(nandfcr & (1 << info->chipsel))) {
+ LOG_ERROR("chip address %08" PRIx32 " not NAND-enabled?", info->data);
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ /* REVISIT verify: AxCR must be in 8-bit mode, since that's all we
+ * tested. 16 bit support should work too; but not with 4-bit ECC.
+ */
+
+ return ERROR_OK;
+}
+
+static int davinci_reset(struct nand_device *nand)
+{
+ return ERROR_OK;
+}
+
+static int davinci_nand_ready(struct nand_device *nand, int timeout)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ uint32_t nandfsr;
+
+ /* NOTE: return code is zero/error, else success; not ERROR_* */
+
+ if (!halted(target, "ready"))
+ return 0;
+
+ do {
+ target_read_u32(target, info->aemif + NANDFSR, &nandfsr);
+
+ if (nandfsr & 0x01)
+ return 1;
+
+ alive_sleep(1);
+ } while (timeout-- > 0);
+
+ return 0;
+}
+
+static int davinci_command(struct nand_device *nand, uint8_t command)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!halted(target, "command"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ target_write_u8(target, info->cmd, command);
+ return ERROR_OK;
+}
+
+static int davinci_address(struct nand_device *nand, uint8_t address)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!halted(target, "address"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ target_write_u8(target, info->addr, address);
+ return ERROR_OK;
+}
+
+static int davinci_write_data(struct nand_device *nand, uint16_t data)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!halted(target, "write_data"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ target_write_u8(target, info->data, data);
+ return ERROR_OK;
+}
+
+static int davinci_read_data(struct nand_device *nand, void *data)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ if (!halted(target, "read_data"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ target_read_u8(target, info->data, data);
+ return ERROR_OK;
+}
+
+/* REVISIT a bit of native code should let block reads be MUCH faster */
+
+static int davinci_read_block_data(struct nand_device *nand,
+ uint8_t *data, int data_size)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ uint32_t nfdata = info->data;
+ uint32_t tmp;
+
+ if (!halted(target, "read_block"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ while (data_size >= 4) {
+ target_read_u32(target, nfdata, &tmp);
+
+ data[0] = tmp;
+ data[1] = tmp >> 8;
+ data[2] = tmp >> 16;
+ data[3] = tmp >> 24;
+
+ data_size -= 4;
+ data += 4;
+ }
+
+ while (data_size > 0) {
+ target_read_u8(target, nfdata, data);
+
+ data_size -= 1;
+ data += 1;
+ }
+
+ return ERROR_OK;
+}
+
+static int davinci_write_block_data(struct nand_device *nand,
+ uint8_t *data, int data_size)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ uint32_t nfdata = info->data;
+ uint32_t tmp;
+ int status;
+
+ if (!halted(target, "write_block"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ /* try the fast way first */
+ status = arm_nandwrite(&info->io, data, data_size);
+ if (status != ERROR_NAND_NO_BUFFER)
+ return status;
+
+ /* else do it slowly */
+ while (data_size >= 4) {
+ tmp = le_to_h_u32(data);
+ target_write_u32(target, nfdata, tmp);
+
+ data_size -= 4;
+ data += 4;
+ }
+
+ while (data_size > 0) {
+ target_write_u8(target, nfdata, *data);
+
+ data_size -= 1;
+ data += 1;
+ }
+
+ return ERROR_OK;
+}
+
+static int davinci_write_page(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ uint8_t *ooballoc = NULL;
+ int status;
+
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+ if (!halted(nand->target, "write_page"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ /* Always write both data and OOB ... we are not "raw" I/O! */
+ if (!data) {
+ LOG_ERROR("Missing NAND data; try 'nand raw_access enable'");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ /* If we're not given OOB, write 0xff where we don't write ECC codes. */
+ switch (nand->page_size) {
+ case 512:
+ oob_size = 16;
+ break;
+ case 2048:
+ oob_size = 64;
+ break;
+ case 4096:
+ oob_size = 128;
+ break;
+ default:
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+ if (!oob) {
+ ooballoc = malloc(oob_size);
+ if (!ooballoc)
+ return ERROR_NAND_OPERATION_FAILED;
+ oob = ooballoc;
+ memset(oob, 0x0ff, oob_size);
+ }
+
+ /* REVISIT avoid wasting SRAM: unless nand->use_raw is set,
+ * use 512 byte chunks. Read side support will often want
+ * to include oob_size ...
+ */
+ info->io.chunk_size = nand->page_size;
+
+ status = info->write_page(nand, page, data, data_size, oob, oob_size);
+ free(ooballoc);
+ return status;
+}
+
+static int davinci_read_page(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ struct davinci_nand *info = nand->controller_priv;
+
+ if (!nand->device)
+ return ERROR_NAND_DEVICE_NOT_PROBED;
+ if (!halted(nand->target, "read_page"))
+ return ERROR_NAND_OPERATION_FAILED;
+
+ return info->read_page(nand, page, data, data_size, oob, oob_size);
+}
+
+static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ int page3 = nand->address_cycles - (nand->page_size == 512);
+
+ /* write command ({page,otp}x{read,program} */
+ target_write_u8(target, info->cmd, cmd);
+
+ /* column address (beginning-of-page) */
+ target_write_u8(target, info->addr, 0);
+ if (nand->page_size > 512)
+ target_write_u8(target, info->addr, 0);
+
+ /* page address */
+ target_write_u8(target, info->addr, page);
+ target_write_u8(target, info->addr, page >> 8);
+ if (page3)
+ target_write_u8(target, info->addr, page >> 16);
+ if (page3 == 2)
+ target_write_u8(target, info->addr, page >> 24);
+}
+
+static int davinci_seek_column(struct nand_device *nand, uint16_t column)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+
+ /* Random read, we must have issued a page read already */
+ target_write_u8(target, info->cmd, NAND_CMD_RNDOUT);
+
+ target_write_u8(target, info->addr, column);
+
+ if (nand->page_size > 512) {
+ target_write_u8(target, info->addr, column >> 8);
+ target_write_u8(target, info->cmd, NAND_CMD_RNDOUTSTART);
+ }
+
+ if (!davinci_nand_ready(nand, 100))
+ return ERROR_NAND_OPERATION_TIMEOUT;
+
+ return ERROR_OK;
+}
+
+static int davinci_writepage_tail(struct nand_device *nand,
+ uint8_t *oob, uint32_t oob_size)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ uint8_t status;
+
+ if (oob_size)
+ davinci_write_block_data(nand, oob, oob_size);
+
+ /* non-cachemode page program */
+ target_write_u8(target, info->cmd, NAND_CMD_PAGEPROG);
+
+ if (!davinci_nand_ready(nand, 100))
+ return ERROR_NAND_OPERATION_TIMEOUT;
+
+ if (nand_read_status(nand, &status) != ERROR_OK) {
+ LOG_ERROR("couldn't read status");
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ if (status & NAND_STATUS_FAIL) {
+ LOG_ERROR("write operation failed, status: 0x%02x", status);
+ return ERROR_NAND_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+/*
+ * All DaVinci family chips support 1-bit ECC on a per-chipselect basis.
+ */
+static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ unsigned oob_offset;
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ const uint32_t fcr_addr = info->aemif + NANDFCR;
+ const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
+ uint32_t fcr, ecc1;
+
+ /* Write contiguous ECC bytes starting at specified offset.
+ * NOTE: Linux reserves twice as many bytes as we need; and
+ * for 16-bit OOB, those extra bytes are discontiguous.
+ */
+ switch (nand->page_size) {
+ case 512:
+ oob_offset = 0;
+ break;
+ case 2048:
+ oob_offset = 40;
+ break;
+ default:
+ oob_offset = 80;
+ break;
+ }
+
+ davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
+
+ /* scrub any old ECC state */
+ target_read_u32(target, ecc1_addr, &ecc1);
+
+ target_read_u32(target, fcr_addr, &fcr);
+ fcr |= 1 << (8 + info->chipsel);
+
+ do {
+ /* set "start csX 1bit ecc" bit */
+ target_write_u32(target, fcr_addr, fcr);
+
+ /* write 512 bytes */
+ davinci_write_block_data(nand, data, 512);
+ data += 512;
+ data_size -= 512;
+
+ /* read the ecc, pack to 3 bytes, and invert so the ecc
+ * in an erased block is correct
+ */
+ target_read_u32(target, ecc1_addr, &ecc1);
+ ecc1 = (ecc1 & 0x0fff) | ((ecc1 & 0x0fff0000) >> 4);
+ ecc1 = ~ecc1;
+
+ /* save correct ECC code into oob data */
+ oob[oob_offset++] = (uint8_t)(ecc1);
+ oob[oob_offset++] = (uint8_t)(ecc1 >> 8);
+ oob[oob_offset++] = (uint8_t)(ecc1 >> 16);
+
+ } while (data_size);
+
+ /* write OOB into spare area */
+ return davinci_writepage_tail(nand, oob, oob_size);
+}
+
+/*
+ * Preferred "new style" ECC layout for use with 4-bit ECC. This somewhat
+ * slows down large page reads done with error correction (since the OOB
+ * is read first, so its ECC data can be used incrementally), but the
+ * manufacturer bad block markers are safe. Contrast: old "infix" style.
+ */
+static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ static const uint8_t ecc512[] = {
+ 0, 1, 2, 3, 4, /* 5== mfr badblock */
+ 6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15,
+ };
+ static const uint8_t ecc2048[] = {
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ };
+ static const uint8_t ecc4096[] = {
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ };
+
+ struct davinci_nand *info = nand->controller_priv;
+ const uint8_t *l;
+ struct target *target = nand->target;
+ const uint32_t fcr_addr = info->aemif + NANDFCR;
+ const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
+ uint32_t fcr, ecc4;
+
+ /* Use the same ECC layout Linux uses. For small page chips
+ * it's a bit cramped.
+ *
+ * NOTE: at this writing, 4KB pages have issues in Linux
+ * because they need more than 64 bytes of ECC data, which
+ * the standard ECC logic can't handle.
+ */
+ switch (nand->page_size) {
+ case 512:
+ l = ecc512;
+ break;
+ case 2048:
+ l = ecc2048;
+ break;
+ default:
+ l = ecc4096;
+ break;
+ }
+
+ davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
+
+ /* scrub any old ECC state */
+ target_read_u32(target, info->aemif + NANDERRVAL, &ecc4);
+
+ target_read_u32(target, fcr_addr, &fcr);
+ fcr &= ~(0x03 << 4);
+ fcr |= (1 << 12) | (info->chipsel << 4);
+
+ do {
+ uint32_t raw_ecc[4], *p;
+ int i;
+
+ /* start 4bit ecc on csX */
+ target_write_u32(target, fcr_addr, fcr);
+
+ /* write 512 bytes */
+ davinci_write_block_data(nand, data, 512);
+ data += 512;
+ data_size -= 512;
+
+ /* read the ecc, then save it into 10 bytes in the oob */
+ for (i = 0; i < 4; i++) {
+ target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]);
+ raw_ecc[i] &= 0x03ff03ff;
+ }
+ for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
+ oob[*l++] = p[0] & 0xff;
+ oob[*l++] = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc);
+ oob[*l++] = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0);
+ oob[*l++] = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0);
+ oob[*l++] = (p[1] >> 18) & 0xff;
+ }
+
+ } while (data_size);
+
+ /* write OOB into spare area */
+ return davinci_writepage_tail(nand, oob, oob_size);
+}
+
+/*
+ * "Infix" OOB ... like Linux ECC_HW_SYNDROME. Avoided because it trashes
+ * manufacturer bad block markers, except on small page chips. Once you
+ * write to a page using this scheme, you need specialized code to update
+ * it (code which ignores now-invalid bad block markers).
+ *
+ * This is needed *only* to support older firmware. Older ROM Boot Loaders
+ * need it to read their second stage loader (UBL) into SRAM, but from then
+ * on the whole system can use the cleaner non-infix layouts. Systems with
+ * older second stage loaders (ABL/U-Boot, etc) or other system software
+ * (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally.
+ */
+static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ struct davinci_nand *info = nand->controller_priv;
+ struct target *target = nand->target;
+ const uint32_t fcr_addr = info->aemif + NANDFCR;
+ const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
+ uint32_t fcr, ecc4;
+
+ davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
+
+ /* scrub any old ECC state */
+ target_read_u32(target, info->aemif + NANDERRVAL, &ecc4);
+
+ target_read_u32(target, fcr_addr, &fcr);
+ fcr &= ~(0x03 << 4);
+ fcr |= (1 << 12) | (info->chipsel << 4);
+
+ do {
+ uint32_t raw_ecc[4], *p;
+ uint8_t *l;
+ int i;
+
+ /* start 4bit ecc on csX */
+ target_write_u32(target, fcr_addr, fcr);
+
+ /* write 512 bytes */
+ davinci_write_block_data(nand, data, 512);
+ data += 512;
+ data_size -= 512;
+
+ /* read the ecc */
+ for (i = 0; i < 4; i++) {
+ target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]);
+ raw_ecc[i] &= 0x03ff03ff;
+ }
+
+ /* skip 6 bytes of prepad, then pack 10 packed ecc bytes */
+ for (i = 0, l = oob + 6, p = raw_ecc; i < 2; i++, p += 2) {
+ *l++ = p[0] & 0xff;
+ *l++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc);
+ *l++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0);
+ *l++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0);
+ *l++ = (p[1] >> 18) & 0xff;
+ }
+
+ /* write this "out-of-band" data -- infix */
+ davinci_write_block_data(nand, oob, 16);
+ oob += 16;
+ oob_size -= 16;
+
+ } while (data_size);
+
+ /* the last data and OOB writes included the spare area */
+ return davinci_writepage_tail(nand, NULL, 0);
+}
+
+static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+{
+ int read_size;
+ int want_col, at_col;
+ int ret;
+
+ davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
+
+ /* large page devices need a start command */
+ if (nand->page_size > 512)
+ davinci_command(nand, NAND_CMD_READSTART);
+
+ if (!davinci_nand_ready(nand, 100))
+ return ERROR_NAND_OPERATION_TIMEOUT;
+
+ /* NOTE: not bothering to compute and use ECC data for now */
+
+ want_col = 0;
+ at_col = 0;
+ while ((data && data_size) || (oob && oob_size)) {
+
+ if (data && data_size) {
+ if (want_col != at_col) {
+ /* Reads are slow, so seek past them when we can */
+ ret = davinci_seek_column(nand, want_col);
+ if (ret != ERROR_OK)
+ return ret;
+ at_col = want_col;
+ }
+ /* read 512 bytes or data_size, whichever is smaller*/
+ read_size = data_size > 512 ? 512 : data_size;
+ davinci_read_block_data(nand, data, read_size);
+ data += read_size;
+ data_size -= read_size;
+ at_col += read_size;
+ }
+ want_col += 512;
+
+ if (oob && oob_size) {
+ if (want_col != at_col) {
+ ret = davinci_seek_column(nand, want_col);
+ if (ret != ERROR_OK)
+ return ret;
+ at_col = want_col;
+ }
+ /* read this "out-of-band" data -- infix */
+ read_size = oob_size > 16 ? 16 : oob_size;
+ davinci_read_block_data(nand, oob, read_size);
+ oob += read_size;
+ oob_size -= read_size;
+ at_col += read_size;
+ }
+ want_col += 16;
+ }
+ return ERROR_OK;
+}
+
+NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
+{
+ struct davinci_nand *info;
+ unsigned long chip, aemif;
+ enum ecc eccmode;
+ int chipsel;
+
+ /* arguments:
+ * - "davinci"
+ * - target
+ * - nand chip address
+ * - ecc mode
+ * - aemif address
+ * Plus someday, optionally, ALE and CLE masks.
+ */
+ if (CMD_ARGC < 5)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
+ if (chip == 0) {
+ LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]);
+ goto fail;
+ }
+
+ if (strcmp(CMD_ARGV[3], "hwecc1") == 0)
+ eccmode = HWECC1;
+ else if (strcmp(CMD_ARGV[3], "hwecc4") == 0)
+ eccmode = HWECC4;
+ else if (strcmp(CMD_ARGV[3], "hwecc4_infix") == 0)
+ eccmode = HWECC4_INFIX;
+ else {
+ LOG_ERROR("Invalid ecc mode %s", CMD_ARGV[3]);
+ goto fail;
+ }
+
+ COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[4], aemif);
+ if (aemif == 0) {
+ LOG_ERROR("Invalid AEMIF controller address %s", CMD_ARGV[4]);
+ goto fail;
+ }
+
+ /* REVISIT what we'd *like* to do is look up valid ranges using
+ * target-specific declarations, and not even need to pass the
+ * AEMIF controller address.
+ */
+ if (aemif == 0x01e00000 /* dm6446, dm357 */
+ || aemif == 0x01e10000 /* dm335, dm355 */
+ || aemif == 0x01d10000 /* dm365 */
+ ) {
+ if (chip < 0x02000000 || chip >= 0x0a000000) {
+ LOG_ERROR("NAND address %08lx out of range?", chip);
+ goto fail;
+ }
+ chipsel = (chip - 0x02000000) >> 25;
+ } else {
+ LOG_ERROR("unrecognized AEMIF controller address %08lx", aemif);
+ goto fail;
+ }
+
+ info = calloc(1, sizeof *info);
+ if (info == NULL)
+ goto fail;
+
+ info->eccmode = eccmode;
+ info->chipsel = chipsel;
+ info->aemif = aemif;
+ info->data = chip;
+ info->cmd = chip | 0x10;
+ info->addr = chip | 0x08;
+
+ nand->controller_priv = info;
+
+ info->io.target = nand->target;
+ info->io.data = info->data;
+ info->io.op = ARM_NAND_NONE;
+
+ /* NOTE: for now we don't do any error correction on read.
+ * Nothing else in OpenOCD currently corrects read errors,
+ * and in any case it's *writing* that we care most about.
+ */
+ info->read_page = nand_read_page_raw;
+
+ switch (eccmode) {
+ case HWECC1:
+ /* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */
+ info->write_page = davinci_write_page_ecc1;
+ break;
+ case HWECC4:
+ /* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */
+ info->write_page = davinci_write_page_ecc4;
+ break;
+ case HWECC4_INFIX:
+ /* Same 4-bit ECC HW, with problematic page/ecc layout */
+ info->read_page = davinci_read_page_ecc4infix;
+ info->write_page = davinci_write_page_ecc4infix;
+ break;
+ }
+
+ return ERROR_OK;
+
+fail:
+ return ERROR_NAND_OPERATION_FAILED;
+}
+
+struct nand_flash_controller davinci_nand_controller = {
+ .name = "davinci",
+ .usage = "chip_addr hwecc_mode aemif_addr",
+ .nand_device_command = davinci_nand_device_command,
+ .init = davinci_init,
+ .reset = davinci_reset,
+ .command = davinci_command,
+ .address = davinci_address,
+ .write_data = davinci_write_data,
+ .read_data = davinci_read_data,
+ .write_page = davinci_write_page,
+ .read_page = davinci_read_page,
+ .write_block_data = davinci_write_block_data,
+ .read_block_data = davinci_read_block_data,
+ .nand_ready = davinci_nand_ready,
+};
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/driver.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/driver.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/driver.c
new file mode 100755
index 0000000..49e13c0
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/driver.c
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath <Do...@gmx.de> *
+ * Copyright (C) 2007,2008 �yvind Harboe <oy...@zylin.com> *
+ * Copyright (C) 2008 by Spencer Oliver <sp...@spen-soft.co.uk> *
+ * Copyright (C) 2009 Zachary T Welch <zw...@superlucidity.net> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "core.h"
+#include "driver.h"
+
+/* NAND flash controller
+ */
+extern struct nand_flash_controller nonce_nand_controller;
+extern struct nand_flash_controller davinci_nand_controller;
+extern struct nand_flash_controller lpc3180_nand_controller;
+extern struct nand_flash_controller lpc32xx_nand_controller;
+extern struct nand_flash_controller orion_nand_controller;
+extern struct nand_flash_controller s3c2410_nand_controller;
+extern struct nand_flash_controller s3c2412_nand_controller;
+extern struct nand_flash_controller s3c2440_nand_controller;
+extern struct nand_flash_controller s3c2443_nand_controller;
+extern struct nand_flash_controller s3c6400_nand_controller;
+extern struct nand_flash_controller mxc_nand_flash_controller;
+extern struct nand_flash_controller imx31_nand_flash_controller;
+extern struct nand_flash_controller at91sam9_nand_controller;
+extern struct nand_flash_controller nuc910_nand_controller;
+
+/* extern struct nand_flash_controller boundary_scan_nand_controller; */
+
+static struct nand_flash_controller *nand_flash_controllers[] = {
+ &nonce_nand_controller,
+ &davinci_nand_controller,
+ &lpc3180_nand_controller,
+ &lpc32xx_nand_controller,
+ &orion_nand_controller,
+ &s3c2410_nand_controller,
+ &s3c2412_nand_controller,
+ &s3c2440_nand_controller,
+ &s3c2443_nand_controller,
+ &s3c6400_nand_controller,
+ &mxc_nand_flash_controller,
+ &imx31_nand_flash_controller,
+ &at91sam9_nand_controller,
+ &nuc910_nand_controller,
+/* &boundary_scan_nand_controller, */
+ NULL
+};
+
+struct nand_flash_controller *nand_driver_find_by_name(const char *name)
+{
+ for (unsigned i = 0; nand_flash_controllers[i]; i++) {
+ struct nand_flash_controller *controller = nand_flash_controllers[i];
+ if (strcmp(name, controller->name) == 0)
+ return controller;
+ }
+ return NULL;
+}
+int nand_driver_walk(nand_driver_walker_t f, void *x)
+{
+ for (unsigned i = 0; nand_flash_controllers[i]; i++) {
+ int retval = (*f)(nand_flash_controllers[i], x);
+ if (ERROR_OK != retval)
+ return retval;
+ }
+ return ERROR_OK;
+}