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;
+}