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:19 UTC

[36/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/s3c24xx_regs.h
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/s3c24xx_regs.h b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/s3c24xx_regs.h
new file mode 100755
index 0000000..fc0f96f
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/s3c24xx_regs.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+ *   Copyright (C) 2004, 2005 by Simtec Electronics                        *
+ *   linux@simtec.co.uk                                                    *
+ *   http://www.simtec.co.uk/products/SWLINUX/                             *
+ *                                                                         *
+ *   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; version 2 of the License.               *
+ *                                                                         *
+ *   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.           *
+ ***************************************************************************/
+
+/*
+ * S3C2410 NAND register definitions
+ */
+
+#ifndef __ASM_ARM_REGS_NAND
+#define __ASM_ARM_REGS_NAND
+
+#define S3C2410_NFREG(x) (x)
+
+#define S3C2410_NFCONF  S3C2410_NFREG(0x00)
+#define S3C2410_NFCMD   S3C2410_NFREG(0x04)
+#define S3C2410_NFADDR  S3C2410_NFREG(0x08)
+#define S3C2410_NFDATA  S3C2410_NFREG(0x0C)
+#define S3C2410_NFSTAT  S3C2410_NFREG(0x10)
+#define S3C2410_NFECC   S3C2410_NFREG(0x14)
+
+#define S3C2440_NFCONT   S3C2410_NFREG(0x04)
+#define S3C2440_NFCMD    S3C2410_NFREG(0x08)
+#define S3C2440_NFADDR   S3C2410_NFREG(0x0C)
+#define S3C2440_NFDATA   S3C2410_NFREG(0x10)
+#define S3C2440_NFECCD0  S3C2410_NFREG(0x14)
+#define S3C2440_NFECCD1  S3C2410_NFREG(0x18)
+#define S3C2440_NFECCD   S3C2410_NFREG(0x1C)
+#define S3C2440_NFSTAT   S3C2410_NFREG(0x20)
+#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24)
+#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
+#define S3C2440_NFMECC0  S3C2410_NFREG(0x2C)
+#define S3C2440_NFMECC1  S3C2410_NFREG(0x30)
+#define S3C2440_NFSECC   S3C2410_NFREG(0x34)
+#define S3C2440_NFSBLK   S3C2410_NFREG(0x38)
+#define S3C2440_NFEBLK   S3C2410_NFREG(0x3C)
+
+#define S3C2412_NFSBLK		S3C2410_NFREG(0x20)
+#define S3C2412_NFEBLK		S3C2410_NFREG(0x24)
+#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
+#define S3C2412_NFMECC_ERR0	S3C2410_NFREG(0x2C)
+#define S3C2412_NFMECC_ERR1	S3C2410_NFREG(0x30)
+#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
+#define S3C2412_NFMECC1		S3C2410_NFREG(0x38)
+#define S3C2412_NFSECC		S3C2410_NFREG(0x3C)
+
+#define S3C2410_NFCONF_EN          (1 << 15)
+#define S3C2410_NFCONF_512BYTE     (1 << 14)
+#define S3C2410_NFCONF_4STEP       (1 << 13)
+#define S3C2410_NFCONF_INITECC     (1 << 12)
+#define S3C2410_NFCONF_nFCE        (1 << 11)
+#define S3C2410_NFCONF_TACLS(x)    ((x) << 8)
+#define S3C2410_NFCONF_TWRPH0(x)   ((x) << 4)
+#define S3C2410_NFCONF_TWRPH1(x)   ((x) << 0)
+
+#define S3C2410_NFSTAT_BUSY        (1 << 0)
+
+#define S3C2440_NFCONF_BUSWIDTH_8	(0 << 0)
+#define S3C2440_NFCONF_BUSWIDTH_16	(1 << 0)
+#define S3C2440_NFCONF_ADVFLASH		(1 << 3)
+#define S3C2440_NFCONF_TACLS(x)		((x) << 12)
+#define S3C2440_NFCONF_TWRPH0(x)	((x) << 8)
+#define S3C2440_NFCONF_TWRPH1(x)	((x) << 4)
+
+#define S3C2440_NFCONT_LOCKTIGHT	(1 << 13)
+#define S3C2440_NFCONT_SOFTLOCK		(1 << 12)
+#define S3C2440_NFCONT_ILLEGALACC_EN	(1 << 10)
+#define S3C2440_NFCONT_RNBINT_EN	(1 << 9)
+#define S3C2440_NFCONT_RN_FALLING	(1 << 8)
+#define S3C2440_NFCONT_SPARE_ECCLOCK	(1 << 6)
+#define S3C2440_NFCONT_MAIN_ECCLOCK	(1 << 5)
+#define S3C2440_NFCONT_INITECC		(1 << 4)
+#define S3C2440_NFCONT_nFCE			(1 << 1)
+#define S3C2440_NFCONT_ENABLE		(1 << 0)
+
+#define S3C2440_NFSTAT_READY		(1 << 0)
+#define S3C2440_NFSTAT_nCE			(1 << 1)
+#define S3C2440_NFSTAT_RnB_CHANGE	(1 << 2)
+#define S3C2440_NFSTAT_ILLEGAL_ACCESS	(1 << 3)
+
+#define S3C2412_NFCONF_NANDBOOT		(1 << 31)
+#define S3C2412_NFCONF_ECCCLKCON	(1 << 30)
+#define S3C2412_NFCONF_ECC_MLC		(1 << 24)
+#define S3C2412_NFCONF_TACLS_MASK	(7 << 12)	/* 1 extra bit of Tacls */
+
+#define S3C2412_NFCONT_ECC4_DIRWR	(1 << 18)
+#define S3C2412_NFCONT_LOCKTIGHT	(1 << 17)
+#define S3C2412_NFCONT_SOFTLOCK		(1 << 16)
+#define S3C2412_NFCONT_ECC4_ENCINT	(1 << 13)
+#define S3C2412_NFCONT_ECC4_DECINT	(1 << 12)
+#define S3C2412_NFCONT_MAIN_ECC_LOCK	(1 << 7)
+#define S3C2412_NFCONT_INIT_MAIN_ECC	(1 << 5)
+#define S3C2412_NFCONT_nFCE1		(1 << 2)
+#define S3C2412_NFCONT_nFCE0		(1 << 1)
+
+#define S3C2412_NFSTAT_ECC_ENCDONE	(1 << 7)
+#define S3C2412_NFSTAT_ECC_DECDONE	(1 << 6)
+#define S3C2412_NFSTAT_ILLEGAL_ACCESS	(1 << 5)
+#define S3C2412_NFSTAT_RnB_CHANGE	(1 << 4)
+#define S3C2412_NFSTAT_nFCE1		(1 << 3)
+#define S3C2412_NFSTAT_nFCE0		(1 << 2)
+#define S3C2412_NFSTAT_Res1			(1 << 1)
+#define S3C2412_NFSTAT_READY		(1 << 0)
+
+#define S3C2412_NFECCERR_SERRDATA(x)	(((x) >> 21) & 0xf)
+#define S3C2412_NFECCERR_SERRBIT(x)		(((x) >> 18) & 0x7)
+#define S3C2412_NFECCERR_MERRDATA(x)	(((x) >> 7) & 0x3ff)
+#define S3C2412_NFECCERR_MERRBIT(x)		(((x) >> 4) & 0x7)
+#define S3C2412_NFECCERR_SPARE_ERR(x)	(((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_MAIN_ERR(x)	(((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_NONE		(0)
+#define S3C2412_NFECCERR_1BIT		(1)
+#define S3C2412_NFECCERR_MULTIBIT	(2)
+#define S3C2412_NFECCERR_ECCAREA	(3)
+
+#endif /* __ASM_ARM_REGS_NAND */
+

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/s3c6400.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/s3c6400.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/s3c6400.c
new file mode 100755
index 0000000..abbfb25
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/s3c6400.c
@@ -0,0 +1,74 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Peter Korsgaard <ja...@sunsite.dk>             *
+ *   Heavily based on s3c2412.c by Ben Dooks <be...@fluff.org>               *
+ *                                                                         *
+ *   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 "s3c24xx.h"
+/* s3c64xx uses another base address for the nand controller than 24xx */
+#undef S3C2410_NFREG
+#define S3C2410_NFREG(x) ((x) + 0x70200000)
+
+NAND_DEVICE_COMMAND_HANDLER(s3c6400_nand_device_command)
+{
+	struct s3c24xx_nand_controller *info;
+	CALL_S3C24XX_DEVICE_COMMAND(nand, &info);
+
+	/* fill in the address fields for the core device */
+	info->cmd = S3C2440_NFCMD;
+	info->addr = S3C2440_NFADDR;
+	info->data = S3C2440_NFDATA;
+	info->nfstat = S3C2412_NFSTAT;
+
+	return ERROR_OK;
+}
+
+static int s3c6400_init(struct nand_device *nand)
+{
+	struct target *target = nand->target;
+
+	target_write_u32(target, S3C2410_NFCONF,
+			 S3C2440_NFCONF_TACLS(3) |
+			 S3C2440_NFCONF_TWRPH0(7) |
+			 S3C2440_NFCONF_TWRPH1(7) | 4);
+
+	target_write_u32(target, S3C2440_NFCONT,
+			 S3C2412_NFCONT_INIT_MAIN_ECC |
+			 S3C2440_NFCONT_ENABLE);
+
+	return ERROR_OK;
+}
+
+struct nand_flash_controller s3c6400_nand_controller = {
+	.name = "s3c6400",
+	.nand_device_command = &s3c6400_nand_device_command,
+	.init = &s3c6400_init,
+	.reset = &s3c24xx_reset,
+	.command = &s3c24xx_command,
+	.address = &s3c24xx_address,
+	.write_data = &s3c24xx_write_data,
+	.read_data = &s3c24xx_read_data,
+	.write_page = s3c24xx_write_page,
+	.read_page = s3c24xx_read_page,
+	.write_block_data = &s3c2440_write_block_data,
+	.read_block_data = &s3c2440_read_block_data,
+	.nand_ready = &s3c2440_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/tcl.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/tcl.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/tcl.c
new file mode 100755
index 0000000..d238e7a
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nand/tcl.c
@@ -0,0 +1,628 @@
+/***************************************************************************
+ *   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 "core.h"
+#include "imp.h"
+#include "fileio.h"
+#include <target/target.h>
+
+/* to be removed */
+extern struct nand_device *nand_devices;
+
+COMMAND_HANDLER(handle_nand_list_command)
+{
+	struct nand_device *p;
+	int i;
+
+	if (!nand_devices) {
+		command_print(CMD_CTX, "no NAND flash devices configured");
+		return ERROR_OK;
+	}
+
+	for (p = nand_devices, i = 0; p; p = p->next, i++) {
+		if (p->device)
+			command_print(CMD_CTX, "#%i: %s (%s) "
+				"pagesize: %i, buswidth: %i,\n\t"
+				"blocksize: %i, blocks: %i",
+				i, p->device->name, p->manufacturer->name,
+				p->page_size, p->bus_width,
+				p->erase_size, p->num_blocks);
+		else
+			command_print(CMD_CTX, "#%i: not probed", i);
+	}
+
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nand_info_command)
+{
+	int i = 0;
+	int j = 0;
+	int first = -1;
+	int last = -1;
+
+	switch (CMD_ARGC) {
+		default:
+			return ERROR_COMMAND_SYNTAX_ERROR;
+		case 1:
+			first = 0;
+			last = INT32_MAX;
+			break;
+		case 2:
+			COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i);
+			first = last = i;
+			i = 0;
+			break;
+		case 3:
+			COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
+			COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
+			break;
+	}
+
+	struct nand_device *p;
+	int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
+	if (ERROR_OK != retval)
+		return retval;
+
+	if (NULL == p->device) {
+		command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
+		return ERROR_OK;
+	}
+
+	if (first >= p->num_blocks)
+		first = p->num_blocks - 1;
+
+	if (last >= p->num_blocks)
+		last = p->num_blocks - 1;
+
+	command_print(CMD_CTX,
+		"#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
+		i++,
+		p->device->name,
+		p->manufacturer->name,
+		p->page_size,
+		p->bus_width,
+		p->erase_size);
+
+	for (j = first; j <= last; j++) {
+		char *erase_state, *bad_state;
+
+		if (p->blocks[j].is_erased == 0)
+			erase_state = "not erased";
+		else if (p->blocks[j].is_erased == 1)
+			erase_state = "erased";
+		else
+			erase_state = "erase state unknown";
+
+		if (p->blocks[j].is_bad == 0)
+			bad_state = "";
+		else if (p->blocks[j].is_bad == 1)
+			bad_state = " (marked bad)";
+		else
+			bad_state = " (block condition unknown)";
+
+		command_print(CMD_CTX,
+			"\t#%i: 0x%8.8" PRIx32 " (%" PRId32 "kB) %s%s",
+			j,
+			p->blocks[j].offset,
+			p->blocks[j].size / 1024,
+			erase_state,
+			bad_state);
+	}
+
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nand_probe_command)
+{
+	if (CMD_ARGC != 1)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	struct nand_device *p;
+	int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
+	if (ERROR_OK != retval)
+		return retval;
+
+	retval = nand_probe(p);
+	if (retval == ERROR_OK) {
+		command_print(CMD_CTX, "NAND flash device '%s (%s)' found",
+			p->device->name, p->manufacturer->name);
+	}
+
+	return retval;
+}
+
+COMMAND_HANDLER(handle_nand_erase_command)
+{
+	if (CMD_ARGC != 1 && CMD_ARGC != 3)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	struct nand_device *p;
+	int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
+	if (ERROR_OK != retval)
+		return retval;
+
+	unsigned long offset;
+	unsigned long length;
+
+	/* erase specified part of the chip; or else everything */
+	if (CMD_ARGC == 3) {
+		unsigned long size = p->erase_size * p->num_blocks;
+
+		COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
+		if ((offset % p->erase_size) != 0 || offset >= size)
+			return ERROR_COMMAND_SYNTAX_ERROR;
+
+		COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
+		if ((length == 0) || (length % p->erase_size) != 0
+		    || (length + offset) > size)
+			return ERROR_COMMAND_SYNTAX_ERROR;
+
+		offset /= p->erase_size;
+		length /= p->erase_size;
+	} else {
+		offset = 0;
+		length = p->num_blocks;
+	}
+
+	retval = nand_erase(p, offset, offset + length - 1);
+	if (retval == ERROR_OK) {
+		command_print(CMD_CTX, "erased blocks %lu to %lu "
+			"on NAND flash device #%s '%s'",
+			offset, offset + length - 1,
+			CMD_ARGV[0], p->device->name);
+	}
+
+	return retval;
+}
+
+COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
+{
+	int first = -1;
+	int last = -1;
+
+	if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2))
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	struct nand_device *p;
+	int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
+	if (ERROR_OK != retval)
+		return retval;
+
+	if (CMD_ARGC == 3) {
+		unsigned long offset;
+		unsigned long length;
+
+		COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
+		if (offset % p->erase_size)
+			return ERROR_COMMAND_SYNTAX_ERROR;
+		offset /= p->erase_size;
+
+		COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
+		if (length % p->erase_size)
+			return ERROR_COMMAND_SYNTAX_ERROR;
+
+		length -= 1;
+		length /= p->erase_size;
+
+		first = offset;
+		last = offset + length;
+	}
+
+	retval = nand_build_bbt(p, first, last);
+	if (retval == ERROR_OK) {
+		command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
+			"use \"nand info\" command to list blocks");
+	}
+
+	return retval;
+}
+
+COMMAND_HANDLER(handle_nand_write_command)
+{
+	struct nand_device *nand = NULL;
+	struct nand_fileio_state s;
+	int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
+			&s, &nand, FILEIO_READ, false, true);
+	if (ERROR_OK != retval)
+		return retval;
+
+	uint32_t total_bytes = s.size;
+	while (s.size > 0) {
+		int bytes_read = nand_fileio_read(nand, &s);
+		if (bytes_read <= 0) {
+			command_print(CMD_CTX, "error while reading file");
+			return nand_fileio_cleanup(&s);
+		}
+		s.size -= bytes_read;
+
+		retval = nand_write_page(nand, s.address / nand->page_size,
+				s.page, s.page_size, s.oob, s.oob_size);
+		if (ERROR_OK != retval) {
+			command_print(CMD_CTX, "failed writing file %s "
+				"to NAND flash %s at offset 0x%8.8" PRIx32,
+				CMD_ARGV[1], CMD_ARGV[0], s.address);
+			return nand_fileio_cleanup(&s);
+		}
+		s.address += s.page_size;
+	}
+
+	if (nand_fileio_finish(&s) == ERROR_OK) {
+		command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
+			"offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
+			CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
+			duration_kbps(&s.bench, total_bytes));
+	}
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nand_verify_command)
+{
+	struct nand_device *nand = NULL;
+	struct nand_fileio_state file;
+	int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
+			&file, &nand, FILEIO_READ, false, true);
+	if (ERROR_OK != retval)
+		return retval;
+
+	struct nand_fileio_state dev;
+	nand_fileio_init(&dev);
+	dev.address = file.address;
+	dev.size = file.size;
+	dev.oob_format = file.oob_format;
+	retval = nand_fileio_start(CMD_CTX, nand, NULL, FILEIO_NONE, &dev);
+	if (ERROR_OK != retval)
+		return retval;
+
+	while (file.size > 0) {
+		retval = nand_read_page(nand, dev.address / dev.page_size,
+				dev.page, dev.page_size, dev.oob, dev.oob_size);
+		if (ERROR_OK != retval) {
+			command_print(CMD_CTX, "reading NAND flash page failed");
+			nand_fileio_cleanup(&dev);
+			nand_fileio_cleanup(&file);
+			return retval;
+		}
+
+		int bytes_read = nand_fileio_read(nand, &file);
+		if (bytes_read <= 0) {
+			command_print(CMD_CTX, "error while reading file");
+			nand_fileio_cleanup(&dev);
+			nand_fileio_cleanup(&file);
+			return ERROR_FAIL;
+		}
+
+		if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
+				(dev.oob && memcmp(dev.oob, file.oob, dev.oob_size))) {
+			command_print(CMD_CTX, "NAND flash contents differ "
+				"at 0x%8.8" PRIx32, dev.address);
+			nand_fileio_cleanup(&dev);
+			nand_fileio_cleanup(&file);
+			return ERROR_FAIL;
+		}
+
+		file.size -= bytes_read;
+		dev.address += nand->page_size;
+	}
+
+	if (nand_fileio_finish(&file) == ERROR_OK) {
+		command_print(CMD_CTX, "verified file %s in NAND flash %s "
+			"up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
+			CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
+			duration_kbps(&file.bench, dev.size));
+	}
+
+	return nand_fileio_cleanup(&dev);
+}
+
+COMMAND_HANDLER(handle_nand_dump_command)
+{
+	size_t filesize;
+	struct nand_device *nand = NULL;
+	struct nand_fileio_state s;
+	int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
+			&s, &nand, FILEIO_WRITE, true, false);
+	if (ERROR_OK != retval)
+		return retval;
+
+	while (s.size > 0) {
+		size_t size_written;
+		retval = nand_read_page(nand, s.address / nand->page_size,
+				s.page, s.page_size, s.oob, s.oob_size);
+		if (ERROR_OK != retval) {
+			command_print(CMD_CTX, "reading NAND flash page failed");
+			nand_fileio_cleanup(&s);
+			return retval;
+		}
+
+		if (NULL != s.page)
+			fileio_write(s.fileio, s.page_size, s.page, &size_written);
+
+		if (NULL != s.oob)
+			fileio_write(s.fileio, s.oob_size, s.oob, &size_written);
+
+		s.size -= nand->page_size;
+		s.address += nand->page_size;
+	}
+
+	retval = fileio_size(s.fileio, &filesize);
+	if (retval != ERROR_OK)
+		return retval;
+
+	if (nand_fileio_finish(&s) == ERROR_OK) {
+		command_print(CMD_CTX, "dumped %zu bytes in %fs (%0.3f KiB/s)",
+			filesize, duration_elapsed(&s.bench),
+			duration_kbps(&s.bench, filesize));
+	}
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nand_raw_access_command)
+{
+	if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	struct nand_device *p;
+	int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
+	if (ERROR_OK != retval)
+		return retval;
+
+	if (NULL == p->device) {
+		command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
+		return ERROR_OK;
+	}
+
+	if (CMD_ARGC == 2)
+		COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->use_raw);
+
+	const char *msg = p->use_raw ? "enabled" : "disabled";
+	command_print(CMD_CTX, "raw access is %s", msg);
+
+	return ERROR_OK;
+}
+
+static const struct command_registration nand_exec_command_handlers[] = {
+	{
+		.name = "list",
+		.handler = handle_nand_list_command,
+		.mode = COMMAND_EXEC,
+		.help = "list configured NAND flash devices",
+	},
+	{
+		.name = "info",
+		.handler = handle_nand_info_command,
+		.mode = COMMAND_EXEC,
+		.usage = "[banknum | first_bank_num last_bank_num]",
+		.help = "print info about one or more NAND flash devices",
+	},
+	{
+		.name = "probe",
+		.handler = handle_nand_probe_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id",
+		.help = "identify NAND flash device",
+	},
+	{
+		.name = "check_bad_blocks",
+		.handler = handle_nand_check_bad_blocks_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id [offset length]",
+		.help = "check all or part of NAND flash device for bad blocks",
+	},
+	{
+		.name = "erase",
+		.handler = handle_nand_erase_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id [offset length]",
+		.help = "erase all or subset of blocks on NAND flash device",
+	},
+	{
+		.name = "dump",
+		.handler = handle_nand_dump_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id filename offset length "
+			"['oob_raw'|'oob_only']",
+		.help = "dump from NAND flash device",
+	},
+	{
+		.name = "verify",
+		.handler = handle_nand_verify_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id filename offset "
+			"['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
+		.help = "verify NAND flash device",
+	},
+	{
+		.name = "write",
+		.handler = handle_nand_write_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id filename offset "
+			"['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
+		.help = "write to NAND flash device",
+	},
+	{
+		.name = "raw_access",
+		.handler = handle_nand_raw_access_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id ['enable'|'disable']",
+		.help = "raw access to NAND flash device",
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+static int nand_init(struct command_context *cmd_ctx)
+{
+	if (!nand_devices)
+		return ERROR_OK;
+	struct command *parent = command_find_in_context(cmd_ctx, "nand");
+	return register_commands(cmd_ctx, parent, nand_exec_command_handlers);
+}
+
+COMMAND_HANDLER(handle_nand_init_command)
+{
+	if (CMD_ARGC != 0)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	static bool nand_initialized;
+	if (nand_initialized) {
+		LOG_INFO("'nand init' has already been called");
+		return ERROR_OK;
+	}
+	nand_initialized = true;
+
+	LOG_DEBUG("Initializing NAND devices...");
+	return nand_init(CMD_CTX);
+}
+
+static int nand_list_walker(struct nand_flash_controller *c, void *x)
+{
+	struct command_context *cmd_ctx = x;
+	command_print(cmd_ctx, "  %s", c->name);
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nand_list_drivers)
+{
+	command_print(CMD_CTX, "Available NAND flash controller drivers:");
+	return nand_driver_walk(&nand_list_walker, CMD_CTX);
+}
+
+static COMMAND_HELPER(create_nand_device, const char *bank_name,
+	struct nand_flash_controller *controller)
+{
+	struct nand_device *c;
+	struct target *target;
+	int retval;
+
+	if (CMD_ARGC < 2)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+	target = get_target(CMD_ARGV[1]);
+	if (!target) {
+		LOG_ERROR("invalid target %s", CMD_ARGV[1]);
+		return ERROR_COMMAND_ARGUMENT_INVALID;
+	}
+
+	if (NULL != controller->commands) {
+		retval = register_commands(CMD_CTX, NULL,
+				controller->commands);
+		if (ERROR_OK != retval)
+			return retval;
+	}
+	c = malloc(sizeof(struct nand_device));
+	if (c == NULL) {
+		LOG_ERROR("End of memory");
+		return ERROR_FAIL;
+	}
+
+	c->name = strdup(bank_name);
+	c->target = target;
+	c->controller = controller;
+	c->controller_priv = NULL;
+	c->manufacturer = NULL;
+	c->device = NULL;
+	c->bus_width = 0;
+	c->address_cycles = 0;
+	c->page_size = 0;
+	c->use_raw = 0;
+	c->next = NULL;
+
+	retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
+	if (ERROR_OK != retval) {
+		LOG_ERROR("'%s' driver rejected nand flash. Usage: %s",
+			controller->name,
+			controller->usage);
+		free(c);
+		return retval;
+	}
+
+	if (controller->usage == NULL)
+		LOG_DEBUG("'%s' driver usage field missing", controller->name);
+
+	nand_device_add(c);
+
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nand_device_command)
+{
+	if (CMD_ARGC < 2)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	/* save name and increment (for compatibility) with drivers */
+	const char *bank_name = *CMD_ARGV++;
+	CMD_ARGC--;
+
+	const char *driver_name = CMD_ARGV[0];
+	struct nand_flash_controller *controller;
+	controller = nand_driver_find_by_name(CMD_ARGV[0]);
+	if (NULL == controller) {
+		LOG_ERROR("No valid NAND flash driver found (%s)", driver_name);
+		return CALL_COMMAND_HANDLER(handle_nand_list_drivers);
+	}
+	return CALL_COMMAND_HANDLER(create_nand_device, bank_name, controller);
+}
+
+static const struct command_registration nand_config_command_handlers[] = {
+	{
+		.name = "device",
+		.handler = &handle_nand_device_command,
+		.mode = COMMAND_CONFIG,
+		.help = "defines a new NAND bank",
+		.usage = "bank_id driver target [driver_options ...]",
+	},
+	{
+		.name = "drivers",
+		.handler = &handle_nand_list_drivers,
+		.mode = COMMAND_ANY,
+		.help = "lists available NAND drivers",
+		.usage = ""
+	},
+	{
+		.name = "init",
+		.mode = COMMAND_CONFIG,
+		.handler = &handle_nand_init_command,
+		.help = "initialize NAND devices",
+		.usage = ""
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration nand_command_handlers[] = {
+	{
+		.name = "nand",
+		.mode = COMMAND_ANY,
+		.help = "NAND flash command group",
+		.usage = "",
+		.chain = nand_config_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+int nand_register_commands(struct command_context *cmd_ctx)
+{
+	return register_commands(cmd_ctx, NULL, nand_command_handlers);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am
new file mode 100755
index 0000000..b6a2be3
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am
@@ -0,0 +1,70 @@
+include $(top_srcdir)/common.mk
+
+noinst_LTLIBRARIES = libocdflashnor.la
+libocdflashnor_la_SOURCES = \
+	core.c \
+	tcl.c \
+	$(NOR_DRIVERS) \
+	drivers.c
+
+NOR_DRIVERS = \
+	aduc702x.c \
+	aducm360.c \
+	ambiqmicro.c \
+	at91sam4.c \
+	at91sam4l.c \
+	at91samd.c \
+	at91sam3.c \
+	at91sam7.c \
+	atsamv.c \
+	avrf.c \
+	cfi.c \
+	dsp5680xx_flash.c \
+	efm32.c \
+	em357.c \
+	faux.c \
+	fm3.c \
+	fm4.c \
+	jtagspi.c \
+	kinetis.c \
+	kinetis_ke.c \
+	lpc2000.c \
+	lpc288x.c \
+	lpc2900.c \
+	lpcspifi.c \
+	mdr.c \
+	mrvlqspi.c \
+	niietcm4.c \
+	non_cfi.c \
+	nrf51.c \
+	nrf52.c \
+	numicro.c \
+	ocl.c \
+	pic32mx.c \
+	psoc4.c \
+	sim3x.c \
+	spi.c \
+	stmsmi.c \
+	stellaris.c \
+	stm32f1x.c \
+	stm32f2x.c \
+	stm32lx.c \
+	stm32l4x.c \
+	str7x.c \
+	str9x.c \
+	str9xpec.c \
+	tms470.c \
+	virtual.c \
+	xmc1xxx.c \
+	xmc4xxx.c
+
+noinst_HEADERS = \
+	core.h \
+	cfi.h \
+	driver.h \
+	imp.h \
+	non_cfi.h \
+	ocl.h \
+	spi.h
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am.orig
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am.orig b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am.orig
new file mode 100755
index 0000000..b6a2be3
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/Makefile.am.orig
@@ -0,0 +1,70 @@
+include $(top_srcdir)/common.mk
+
+noinst_LTLIBRARIES = libocdflashnor.la
+libocdflashnor_la_SOURCES = \
+	core.c \
+	tcl.c \
+	$(NOR_DRIVERS) \
+	drivers.c
+
+NOR_DRIVERS = \
+	aduc702x.c \
+	aducm360.c \
+	ambiqmicro.c \
+	at91sam4.c \
+	at91sam4l.c \
+	at91samd.c \
+	at91sam3.c \
+	at91sam7.c \
+	atsamv.c \
+	avrf.c \
+	cfi.c \
+	dsp5680xx_flash.c \
+	efm32.c \
+	em357.c \
+	faux.c \
+	fm3.c \
+	fm4.c \
+	jtagspi.c \
+	kinetis.c \
+	kinetis_ke.c \
+	lpc2000.c \
+	lpc288x.c \
+	lpc2900.c \
+	lpcspifi.c \
+	mdr.c \
+	mrvlqspi.c \
+	niietcm4.c \
+	non_cfi.c \
+	nrf51.c \
+	nrf52.c \
+	numicro.c \
+	ocl.c \
+	pic32mx.c \
+	psoc4.c \
+	sim3x.c \
+	spi.c \
+	stmsmi.c \
+	stellaris.c \
+	stm32f1x.c \
+	stm32f2x.c \
+	stm32lx.c \
+	stm32l4x.c \
+	str7x.c \
+	str9x.c \
+	str9xpec.c \
+	tms470.c \
+	virtual.c \
+	xmc1xxx.c \
+	xmc4xxx.c
+
+noinst_HEADERS = \
+	core.h \
+	cfi.h \
+	driver.h \
+	imp.h \
+	non_cfi.h \
+	ocl.h \
+	spi.h
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aduc702x.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aduc702x.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aduc702x.c
new file mode 100755
index 0000000..8852245
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aduc702x.c
@@ -0,0 +1,406 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by Kevin McGuire                                   *
+ *   Copyright (C) 2008 by Marcel Wijlaars                                 *
+ *   Copyright (C) 2009 by Michael Ashton                                  *
+ *                                                                         *
+ *   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"
+#include <helper/binarybuffer.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/arm.h>
+
+static int aduc702x_build_sector_list(struct flash_bank *bank);
+static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms);
+static int aduc702x_set_write_enable(struct target *target, int enable);
+
+#define ADUC702x_FLASH                          0xfffff800
+#define ADUC702x_FLASH_FEESTA           (0*4)
+#define ADUC702x_FLASH_FEEMOD           (1*4)
+#define ADUC702x_FLASH_FEECON           (2*4)
+#define ADUC702x_FLASH_FEEDAT           (3*4)
+#define ADUC702x_FLASH_FEEADR           (4*4)
+#define ADUC702x_FLASH_FEESIGN          (5*4)
+#define ADUC702x_FLASH_FEEPRO           (6*4)
+#define ADUC702x_FLASH_FEEHIDE          (7*4)
+
+/* flash bank aduc702x 0 0 0 0 <target#>
+ * The ADC7019-28 devices all have the same flash layout */
+FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
+{
+	bank->base = 0x80000;
+	bank->size = 0xF800;	/* top 4k not accessible */
+
+	aduc702x_build_sector_list(bank);
+
+	return ERROR_OK;
+}
+
+static int aduc702x_build_sector_list(struct flash_bank *bank)
+{
+	/* aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv; */
+
+	int i = 0;
+	uint32_t offset = 0;
+
+	/* sector size is 512 */
+	bank->num_sectors = bank->size / 512;
+	bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+	for (i = 0; i < bank->num_sectors; ++i) {
+		bank->sectors[i].offset = offset;
+		bank->sectors[i].size = 512;
+		offset += bank->sectors[i].size;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = 0;
+	}
+
+	return ERROR_OK;
+}
+
+static int aduc702x_protect_check(struct flash_bank *bank)
+{
+	printf("aduc702x_protect_check not implemented yet.\n");
+	return ERROR_OK;
+}
+
+static int aduc702x_erase(struct flash_bank *bank, int first, int last)
+{
+	/* int res; */
+	int x;
+	int count;
+	/* uint32_t v; */
+	struct target *target = bank->target;
+
+	aduc702x_set_write_enable(target, 1);
+
+	/* mass erase */
+	if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
+		LOG_DEBUG("performing mass erase.");
+		target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff);
+		target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
+		target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
+
+		if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK) {
+			LOG_ERROR("mass erase failed");
+			aduc702x_set_write_enable(target, 0);
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+
+		LOG_DEBUG("mass erase successful.");
+		return ERROR_OK;
+	} else {
+		unsigned long adr;
+
+		count = last - first + 1;
+		for (x = 0; x < count; ++x) {
+			adr = bank->base + ((first + x) * 512);
+
+			target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr);
+			target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05);
+
+			if (aduc702x_check_flash_completion(target, 50) != ERROR_OK) {
+				LOG_ERROR("failed to erase sector at address 0x%08lX", adr);
+				aduc702x_set_write_enable(target, 0);
+				return ERROR_FLASH_SECTOR_NOT_ERASED;
+			}
+
+			LOG_DEBUG("erased sector at address 0x%08lX", adr);
+		}
+	}
+
+	aduc702x_set_write_enable(target, 0);
+
+	return ERROR_OK;
+}
+
+static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+	printf("aduc702x_protect not implemented yet.\n");
+	return ERROR_FLASH_OPERATION_FAILED;
+}
+
+/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
+ * back to another mechanism that does not require onboard RAM
+ *
+ * Caller should not check for other return values specifically
+ */
+static int aduc702x_write_block(struct flash_bank *bank,
+	const uint8_t *buffer,
+	uint32_t offset,
+	uint32_t count)
+{
+	struct target *target = bank->target;
+	uint32_t buffer_size = 7000;
+	struct working_area *write_algorithm;
+	struct working_area *source;
+	uint32_t address = bank->base + offset;
+	struct reg_param reg_params[6];
+	struct arm_algorithm arm_algo;
+	int retval = ERROR_OK;
+
+	if (((count%2) != 0) || ((offset%2) != 0)) {
+		LOG_ERROR("write block must be multiple of two bytes in offset & length");
+		return ERROR_FAIL;
+	}
+
+	/* parameters:
+
+	r0 - address of source data (absolute)
+	r1 - number of halfwords to be copied
+	r2 - start address in flash (offset from beginning of flash memory)
+	r3 - exit code
+	r4 - base address of flash controller (0xFFFFF800)
+
+	registers:
+
+	r5 - scratch
+	r6 - set to 2, used to write flash command
+
+	*/
+	static const uint32_t aduc702x_flash_write_code[] = {
+		/* <_start>: */
+		0xe3a05008,	/* mov	r5, #8	; 0x8 */
+		0xe5845004,	/* str	r5, [r4, #4] */
+		0xe3a06002,	/* mov	r6, #2	; 0x2 */
+		/* <next>: */
+		0xe1c421b0,	/* strh	r2, [r4, #16] */
+		0xe0d050b2,	/* ldrh	r5, [r0], #2 */
+		0xe1c450bc,	/* strh	r5, [r4, #12] */
+		0xe5c46008,	/* strb	r6, [r4, #8] */
+		/* <wait_complete>: */
+		0xe1d430b0,	/* ldrh	r3, [r4] */
+		0xe3130004,	/* tst	r3, #4	; 0x4 */
+		0x1afffffc,	/* bne	1001c <wait_complete> */
+		0xe2822002,	/* add	r2, r2, #2	; 0x2 */
+		0xe2511001,	/* subs	r1, r1, #1	; 0x1 */
+		0x0a000001,	/* beq	1003c <done> */
+		0xe3130001,	/* tst	r3, #1	; 0x1 */
+		0x1afffff3,	/* bne	1000c <next> */
+		/* <done>: */
+		0xeafffffe	/* b	1003c <done> */
+	};
+
+	/* flash write code */
+	if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code),
+			&write_algorithm) != ERROR_OK) {
+		LOG_WARNING("no working area available, can't do block memory writes");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+
+	uint8_t code[sizeof(aduc702x_flash_write_code)];
+	target_buffer_set_u32_array(target, code, ARRAY_SIZE(aduc702x_flash_write_code),
+			aduc702x_flash_write_code);
+	retval = target_write_buffer(target, write_algorithm->address, sizeof(code), code);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* memory buffer */
+	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+		buffer_size /= 2;
+		if (buffer_size <= 256) {
+			/* we already allocated the writing code, but failed to get a buffer,
+			 *free the algorithm */
+			target_free_working_area(target, write_algorithm);
+
+			LOG_WARNING("no large enough working area available, can't do block memory writes");
+			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+		}
+	}
+
+	arm_algo.common_magic = ARM_COMMON_MAGIC;
+	arm_algo.core_mode = ARM_MODE_SVC;
+	arm_algo.core_state = ARM_STATE_ARM;
+
+	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
+	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
+
+	while (count > 0) {
+		uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
+
+		retval = target_write_buffer(target, source->address, thisrun_count, buffer);
+		if (retval != ERROR_OK)
+			break;
+
+		buf_set_u32(reg_params[0].value, 0, 32, source->address);
+		buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2);
+		buf_set_u32(reg_params[2].value, 0, 32, address);
+		buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800);
+
+		retval = target_run_algorithm(target, 0, NULL, 5,
+				reg_params, write_algorithm->address,
+				write_algorithm->address +
+				sizeof(aduc702x_flash_write_code) - 4,
+				10000, &arm_algo);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("error executing aduc702x flash write algorithm");
+			break;
+		}
+
+		if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) {
+			/* FIX!!!! what does this mean??? replace w/sensible error message */
+			LOG_ERROR("aduc702x detected error writing flash");
+			retval = ERROR_FAIL;
+			break;
+		}
+
+		buffer += thisrun_count;
+		address += thisrun_count;
+		count -= thisrun_count;
+	}
+
+	target_free_working_area(target, source);
+	target_free_working_area(target, write_algorithm);
+
+	destroy_reg_param(&reg_params[0]);
+	destroy_reg_param(&reg_params[1]);
+	destroy_reg_param(&reg_params[2]);
+	destroy_reg_param(&reg_params[3]);
+	destroy_reg_param(&reg_params[4]);
+
+	return retval;
+}
+
+/* All-JTAG, single-access method.  Very slow.  Used only if there is no
+ * working area available. */
+static int aduc702x_write_single(struct flash_bank *bank,
+	const uint8_t *buffer,
+	uint32_t offset,
+	uint32_t count)
+{
+	uint32_t x;
+	uint8_t b;
+	struct target *target = bank->target;
+
+	aduc702x_set_write_enable(target, 1);
+
+	for (x = 0; x < count; x += 2) {
+		/* FEEADR = address */
+		target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, offset + x);
+
+		/* set up data */
+		if ((x + 1) == count) {
+			/* last byte */
+			target_read_u8(target, offset + x + 1, &b);
+		} else
+			b = buffer[x + 1];
+
+		target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, buffer[x] | (b << 8));
+
+		/* do single-write command */
+		target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x02);
+
+		if (aduc702x_check_flash_completion(target, 1) != ERROR_OK) {
+			LOG_ERROR("single write failed for address 0x%08lX",
+				(unsigned long)(offset + x));
+			aduc702x_set_write_enable(target, 0);
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+
+	}
+	LOG_DEBUG("wrote %d bytes at address 0x%08lX", (int)count, (unsigned long)(offset + x));
+
+	aduc702x_set_write_enable(target, 0);
+
+	return ERROR_OK;
+}
+
+static int aduc702x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+	int retval;
+
+	/* try using a block write */
+	retval = aduc702x_write_block(bank, buffer, offset, count);
+	if (retval != ERROR_OK) {
+		if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+			/* if block write failed (no sufficient working area),
+			 * use normal (slow) JTAG method */
+			LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+
+			retval = aduc702x_write_single(bank, buffer, offset, count);
+			if (retval != ERROR_OK) {
+				LOG_ERROR("slow write failed");
+				return ERROR_FLASH_OPERATION_FAILED;
+			}
+		}
+	}
+
+	return retval;
+}
+
+static int aduc702x_probe(struct flash_bank *bank)
+{
+	return ERROR_OK;
+}
+
+/* sets FEEMOD bit 3
+ * enable = 1 enables writes & erases, 0 disables them */
+static int aduc702x_set_write_enable(struct target *target, int enable)
+{
+	/* don't bother to preserve int enable bit here */
+	target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0);
+
+	return ERROR_OK;
+}
+
+/* wait up to timeout_ms for controller to not be busy,
+ * then check whether the command passed or failed.
+ *
+ * this function sleeps 1ms between checks (after the first one),
+ * so in some cases may slow things down without a usleep after the first read */
+static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms)
+{
+	uint8_t v = 4;
+
+	long long endtime = timeval_ms() + timeout_ms;
+	while (1) {
+		target_read_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEESTA, &v);
+		if ((v & 4) == 0)
+			break;
+		alive_sleep(1);
+		if (timeval_ms() >= endtime)
+			break;
+	}
+
+	if (v & 2)
+		return ERROR_FAIL;
+	/* if a command is ignored, both the success and fail bits may be 0 */
+	else if ((v & 3) == 0)
+		return ERROR_FAIL;
+	else
+		return ERROR_OK;
+}
+
+struct flash_driver aduc702x_flash = {
+	.name = "aduc702x",
+	.flash_bank_command = aduc702x_flash_bank_command,
+	.erase = aduc702x_erase,
+	.protect = aduc702x_protect,
+	.write = aduc702x_write,
+	.read = default_flash_read,
+	.probe = aduc702x_probe,
+	.auto_probe = aduc702x_probe,
+	.erase_check = default_flash_blank_check,
+	.protect_check = aduc702x_protect_check,
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aducm360.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aducm360.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aducm360.c
new file mode 100755
index 0000000..3e446f5
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/aducm360.c
@@ -0,0 +1,580 @@
+/***************************************************************************
+ *   Copyright (C) 2015 by Ivan Buliev                                     *
+ *   i.buliev@mikrosistemi.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.                          *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ *  This version for ADuCM360 is largely based on the following flash      *
+ *  drivers:                                                               *
+ *    - aduc702x.c                                                         *
+ *          Copyright (C) 2008 by Kevin McGuire                            *
+ *          Copyright (C) 2008 by Marcel Wijlaars                          *
+ *          Copyright (C) 2009 by Michael Ashton                           *
+ *   and                                                                   *
+ *    - stm32f1x.c                                                         *
+ *          Copyright (C) 2005 by Dominic Rath                             *
+ *          Dominic.Rath@gmx.de                                            *
+ *                                                                         *
+ *          Copyright (C) 2008 by Spencer Oliver                           *
+ *          spen@spen-soft.co.uk                                           *
+ *                                                                         *
+ *          Copyright (C) 2011 by Andreas Fritiofson                       *
+ *          andreas.fritiofson@gmail.com                                   *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+static int aducm360_build_sector_list(struct flash_bank *bank);
+static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms);
+static int aducm360_set_write_enable(struct target *target, int enable);
+
+#define ADUCM360_FLASH_BASE             0x40002800
+#define ADUCM360_FLASH_FEESTA           0x0000
+#define ADUCM360_FLASH_FEECON0          0x0004
+#define ADUCM360_FLASH_FEECMD           0x0008
+#define ADUCM360_FLASH_FEEADR0L         0x0010
+#define ADUCM360_FLASH_FEEADR0H         0x0014
+#define ADUCM360_FLASH_FEEADR1L         0x0018
+#define ADUCM360_FLASH_FEEADR1H         0x001C
+#define ADUCM360_FLASH_FEEKEY           0x0020
+#define ADUCM360_FLASH_FEEPROL          0x0028
+#define ADUCM360_FLASH_FEEPROH          0x002C
+#define ADUCM360_FLASH_FEESIGL          0x0030
+#define ADUCM360_FLASH_FEESIGH          0x0034
+#define ADUCM360_FLASH_FEECON1          0x0038
+#define ADUCM360_FLASH_FEEADRAL         0x0048
+#define ADUCM360_FLASH_FEEADRAH         0x004C
+#define ADUCM360_FLASH_FEEAEN0          0x0078
+#define ADUCM360_FLASH_FEEAEN1          0x007C
+#define ADUCM360_FLASH_FEEAEN2          0x0080
+
+/* flash bank aducm360 0 0 0 0 <target#> */
+FLASH_BANK_COMMAND_HANDLER(aducm360_flash_bank_command)
+{
+	bank->base = 0x00000000;
+	bank->size = 0x00020000;
+
+	aducm360_build_sector_list(bank);
+
+	return ERROR_OK;
+}
+
+#define FLASH_SECTOR_SIZE	512
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_build_sector_list(struct flash_bank *bank)
+{
+	int i = 0;
+	uint32_t offset = 0;
+
+	/* sector size is 512 */
+	bank->num_sectors = bank->size / FLASH_SECTOR_SIZE;
+	bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+	for (i = 0; i < bank->num_sectors; ++i) {
+		bank->sectors[i].offset = offset;
+		bank->sectors[i].size = FLASH_SECTOR_SIZE;
+		offset += bank->sectors[i].size;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = 0;
+	}
+
+	return ERROR_OK;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_protect_check(struct flash_bank *bank)
+{
+	LOG_WARNING("aducm360_protect_check not implemented.");
+	return ERROR_OK;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_mass_erase(struct target *target)
+{
+	uint32_t		value;
+	int				res = ERROR_OK;
+
+	/* Clear any old status */
+	target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
+
+	/* Enable the writing to the flash*/
+	aducm360_set_write_enable(target, 1);
+
+	/* Unlock for writing */
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
+	/* Issue the 'MASSERASE' command */
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000003);
+
+	/* Check the result */
+	res = aducm360_check_flash_completion(target, 3500);
+	if (res != ERROR_OK) {
+		LOG_ERROR("mass erase failed.");
+		aducm360_set_write_enable(target, 0);
+		res = ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	return res;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_page_erase(struct target *target, uint32_t padd)
+{
+	uint32_t		value;
+	int				res = ERROR_OK;
+
+	/* Clear any old status */
+	target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
+
+	/* Enable the writing to the flash*/
+	aducm360_set_write_enable(target, 1);
+
+	/* Unlock for writing */
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
+	/* Write the sector address */
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0L, padd & 0xFFFF);
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0H, (padd>>16) & 0xFFFF);
+	/* Issue the 'ERASEPAGE' command */
+	target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000001);
+
+	/* Check the result */
+	res = aducm360_check_flash_completion(target, 50);
+	if (res != ERROR_OK) {
+		LOG_ERROR("page erase failed at 0x%08" PRIx32, padd);
+		aducm360_set_write_enable(target, 0);
+		res = ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	return res;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_erase(struct flash_bank *bank, int first, int last)
+{
+	int             res = ERROR_OK;
+	int             i;
+	int             count;
+	struct target   *target = bank->target;
+	uint32_t        padd;
+
+	if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
+		res = aducm360_mass_erase(target);
+	} else {
+		count = last - first + 1;
+		for (i = 0; i < count; ++i) {
+			padd = bank->base + ((first+i)*FLASH_SECTOR_SIZE);
+			res = aducm360_page_erase(target, padd);
+			if (res != ERROR_OK)
+				break;
+		}
+	}
+
+	return res;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_protect(struct flash_bank *bank, int set, int first, int last)
+{
+	LOG_ERROR("aducm360_protect not implemented.");
+	return ERROR_FLASH_OPERATION_FAILED;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_write_block_sync(
+		struct flash_bank *bank,
+		const uint8_t *buffer,
+		uint32_t offset,
+		uint32_t count)
+{
+	struct target           *target = bank->target;
+	uint32_t                target_buffer_size = 8192;
+	struct working_area     *helper;
+	struct working_area     *target_buffer;
+	uint32_t                address = bank->base + offset;
+	struct reg_param        reg_params[8];
+	int                     retval = ERROR_OK;
+	uint32_t                entry_point = 0, exit_point = 0;
+	uint32_t                res;
+	struct armv7m_algorithm armv7m_algo;
+
+	static const uint32_t aducm360_flash_write_code[] = {
+			/* helper.code */
+			0x88AF4D10, 0x0704F047, 0x682F80AF, 0x600E6806,
+			0xF017882F, 0xF43F0F08, 0xF851AFFB, 0x42B77B04,
+			0x800DF040, 0x0004F100, 0xF47F3A04, 0x686FAFEF,
+			0x0704F027, 0xF04F80AF, 0xF0000400, 0xF04FB802,
+			0xBE000480, 0x40002800, 0x00015000, 0x20000000,
+			0x00013000
+	};
+
+	LOG_DEBUG("'aducm360_write_block_sync' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
+			address, count);
+
+	/*  ----- Check the destination area for a Long Word alignment -----  */
+	if (((count%4) != 0) || ((offset%4) != 0)) {
+		LOG_ERROR("write block must be multiple of four bytes in offset & length");
+		return ERROR_FAIL;
+	}
+
+	/*  ----- Allocate space in the target's RAM for the helper code -----  */
+	if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
+			&helper) != ERROR_OK) {
+		LOG_WARNING("no working area available, can't do block memory writes");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+
+	/*  ----- Upload the helper code to the space in the target's RAM -----  */
+	uint8_t code[sizeof(aducm360_flash_write_code)];
+	target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
+			aducm360_flash_write_code);
+	retval = target_write_buffer(target, helper->address, sizeof(code), code);
+	if (retval != ERROR_OK)
+		return retval;
+	entry_point = helper->address;
+
+	/*  ----- Allocate space in the target's RAM for the user application's object code -----  */
+	while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
+		LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
+				target_buffer_size);
+		target_buffer_size /= 2;
+		if (target_buffer_size <= 256) {		/* No room available */
+			LOG_WARNING("no large enough working area available, can't do block memory writes");
+			target_free_working_area(target, helper);
+			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+		}
+	}
+
+	/* ----- Prepare the target for the helper ----- */
+	armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_algo.core_mode = ARM_MODE_THREAD;
+
+	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRC      */
+	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*DST      */
+	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*COUNT    */
+	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*not used */
+	init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);	 /*RESULT   */
+
+	/*  ===== Execute the Main Programming Loop! ===== */
+	while (count > 0) {
+		uint32_t thisrun_count = (count > target_buffer_size) ? target_buffer_size : count;
+
+		/* ----- Upload the chunk ----- */
+		retval = target_write_buffer(target, target_buffer->address, thisrun_count, buffer);
+		if (retval != ERROR_OK)
+			break;
+		/* Set the arguments for the helper */
+		buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address);	/*SRC     */
+		buf_set_u32(reg_params[1].value, 0, 32, address);					/*DST     */
+		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);				/*COUNT   */
+		buf_set_u32(reg_params[3].value, 0, 32, 0);							/*NOT USED*/
+
+		retval = target_run_algorithm(target, 0, NULL, 5,
+				reg_params,	entry_point, exit_point, 10000, &armv7m_algo);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("error executing aducm360 flash write algorithm");
+			break;
+		}
+
+		res = buf_get_u32(reg_params[4].value, 0, 32);
+		if (res) {
+			LOG_ERROR("aducm360 fast sync algorithm reports an error (%02X)", res);
+			retval = ERROR_FAIL;
+			break;
+		}
+
+		buffer += thisrun_count;
+		address += thisrun_count;
+		count -= thisrun_count;
+	}
+
+	target_free_working_area(target, target_buffer);
+	target_free_working_area(target, helper);
+
+	destroy_reg_param(&reg_params[0]);
+	destroy_reg_param(&reg_params[1]);
+	destroy_reg_param(&reg_params[2]);
+	destroy_reg_param(&reg_params[3]);
+	destroy_reg_param(&reg_params[4]);
+
+	return retval;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_write_block_async(
+		struct flash_bank *bank,
+		const uint8_t *buffer,
+		uint32_t offset,
+		uint32_t count)
+{
+	struct target           *target = bank->target;
+	uint32_t                target_buffer_size = 1024;
+	struct working_area     *helper;
+	struct working_area     *target_buffer;
+	uint32_t                address = bank->base + offset;
+	struct reg_param        reg_params[9];
+	int                     retval = ERROR_OK;
+	uint32_t                entry_point = 0, exit_point = 0;
+	uint32_t                res;
+	uint32_t                wcount;
+	struct armv7m_algorithm armv7m_algo;
+
+	static const uint32_t aducm360_flash_write_code[] = {
+			/* helper.code */
+			0x4050F8DF,	0xF04588A5,	0x80A50504,	0x8000F8D0,
+			0x0F00F1B8, 0x8016F000,	0x45476847,	0xAFF6F43F,
+			0x6B04F857, 0x6B04F842,	0xF0158825,	0xF43F0F08,
+			0x428FAFFB, 0xF100BF28,	0x60470708,	0xB10B3B01,
+			0xBFE4F7FF, 0xF02588A5,	0x80A50504,	0x0900F04F,
+			0xBE00BF00, 0x40002800,	0x20000000,	0x20000100,
+			0x00013000
+	};
+
+	LOG_DEBUG("'aducm360_write_block_async' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
+			address, count);
+
+	/*  ----- Check the destination area for a Long Word alignment -----  */
+	if (((count%4) != 0) || ((offset%4) != 0)) {
+		LOG_ERROR("write block must be multiple of four bytes in offset & length");
+		return ERROR_FAIL;
+	}
+	wcount = count/4;
+
+	/*  ----- Allocate space in the target's RAM for the helper code -----  */
+	if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
+			&helper) != ERROR_OK) {
+		LOG_WARNING("no working area available, can't do block memory writes");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+
+	/*  ----- Upload the helper code to the space in the target's RAM -----  */
+	uint8_t code[sizeof(aducm360_flash_write_code)];
+	target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
+			aducm360_flash_write_code);
+	retval = target_write_buffer(target, helper->address, sizeof(code), code);
+	if (retval != ERROR_OK)
+		return retval;
+	entry_point = helper->address;
+
+	/*  ----- Allocate space in the target's RAM for the user application's object code ----- */
+	while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
+		LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
+				target_buffer_size);
+		target_buffer_size /= 2;
+		if (target_buffer_size <= 256) {		/* No room available */
+			LOG_WARNING("no large enough working area available, can't do block memory writes");
+			target_free_working_area(target, helper);
+			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+		}
+	}
+
+	/* ----- Prepare the target for the helper ----- */
+	armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_algo.core_mode = ARM_MODE_THREAD;
+
+	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRCBEG     */
+	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*SRCEND     */
+	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*DST        */
+	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*COUNT (LWs)*/
+	init_reg_param(&reg_params[4], "r9", 32, PARAM_IN);  /*RESULT     */
+
+	buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address);
+	buf_set_u32(reg_params[1].value, 0, 32, target_buffer->address + target_buffer->size);
+	buf_set_u32(reg_params[2].value, 0, 32, address);
+	buf_set_u32(reg_params[3].value, 0, 32, wcount);
+
+	retval = target_run_flash_async_algorithm(target, buffer, wcount, 4,
+			0, NULL,
+			5, reg_params,
+			target_buffer->address, target_buffer->size,
+			entry_point, exit_point,
+			&armv7m_algo);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("error executing aducm360 flash write algorithm");
+	} else {
+		res = buf_get_u32(reg_params[4].value, 0, 32);	/*RESULT*/
+		if (res) {
+			LOG_ERROR("aducm360 fast async algorithm reports an error (%02X)", res);
+			retval = ERROR_FAIL;
+		}
+	}
+
+	target_free_working_area(target, target_buffer);
+	target_free_working_area(target, helper);
+
+	destroy_reg_param(&reg_params[0]);
+	destroy_reg_param(&reg_params[1]);
+	destroy_reg_param(&reg_params[2]);
+	destroy_reg_param(&reg_params[3]);
+	destroy_reg_param(&reg_params[4]);
+
+	return retval;
+}
+
+/* ----------------------------------------------------------------------- */
+/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
+ * back to another mechanism that does not require onboard RAM
+ *
+ * Caller should not check for other return values specifically
+ */
+static int aducm360_write_block(struct flash_bank *bank,
+	const uint8_t *buffer,
+	uint32_t offset,
+	uint32_t count)
+{
+	int	choice = 0;
+
+	switch (choice) {
+	case 0:
+		return aducm360_write_block_sync(bank, buffer, offset, count);
+		break;
+	case 1:
+		return aducm360_write_block_async(bank, buffer, offset, count);
+		break;
+	default:
+		LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+#define FEESTA_WRDONE	0x00000008
+
+static int aducm360_write_modified(struct flash_bank *bank,
+		const uint8_t *buffer,
+		uint32_t offset,
+		uint32_t count)
+{
+	uint32_t		value;
+	int				res = ERROR_OK;
+	uint32_t        i, j, a, d;
+	struct target   *target = bank->target;
+
+	LOG_DEBUG("performing slow write (offset=0x%08" PRIx32 ", count=0x%08" PRIx32 ")...",
+			offset, count);
+
+	/* Enable the writing to the flash */
+	aducm360_set_write_enable(target, 1);
+
+	/* Clear any old status */
+	target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
+
+	for (i = 0; i < count; i += 4) {
+		a = offset+i;
+		for (j = 0; i < 4; i += 1)
+			*((uint8_t *)(&d) + j) = buffer[i+j];
+		target_write_u32(target, a, d);
+		do {
+			target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
+		} while (!(value & FEESTA_WRDONE));
+	}
+	aducm360_set_write_enable(target, 0);
+
+	return res;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+	int retval;
+
+	/* try using a block write */
+	retval = aducm360_write_block(bank, buffer, offset, count);
+	if (retval != ERROR_OK) {
+		if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+			/* if block write failed (no sufficient working area),
+			 * use normal (slow) JTAG method */
+			LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+
+			retval = aducm360_write_modified(bank, buffer, offset, count);
+			if (retval != ERROR_OK) {
+				LOG_ERROR("slow write failed");
+				return ERROR_FLASH_OPERATION_FAILED;
+			}
+		}
+	}
+	return retval;
+}
+
+/* ----------------------------------------------------------------------- */
+static int aducm360_probe(struct flash_bank *bank)
+{
+	return ERROR_OK;
+}
+
+/* ----------------------------------------------------------------------- */
+/* sets FEECON0 bit 2
+ * enable = 1 enables writes & erases, 0 disables them */
+static int aducm360_set_write_enable(struct target *target, int enable)
+{
+	/* don't bother to preserve int enable bit here */
+	uint32_t	value;
+
+	target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, &value);
+	if (enable)
+		value |= 0x00000004;
+	else
+		value &= ~0x00000004;
+	target_write_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, value);
+
+	return ERROR_OK;
+}
+
+/* ----------------------------------------------------------------------- */
+/* wait up to timeout_ms for controller to not be busy,
+ * then check whether the command passed or failed.
+ *
+ * this function sleeps 1ms between checks (after the first one),
+ * so in some cases may slow things down without a usleep after the first read */
+static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms)
+{
+	uint32_t v = 1;
+
+	long long endtime = timeval_ms() + timeout_ms;
+	while (1) {
+		target_read_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEESTA, &v);
+		if ((v & 0x00000001) == 0)
+			break;
+		alive_sleep(1);
+		if (timeval_ms() >= endtime)
+			break;
+	}
+
+	if (!(v & 0x00000004))	/* b2 */
+		return ERROR_FAIL;
+
+	return ERROR_OK;
+}
+
+/* ----------------------------------------------------------------------- */
+struct flash_driver aducm360_flash = {
+	.name = "aducm360",
+	.flash_bank_command = aducm360_flash_bank_command,
+	.erase = aducm360_erase,
+	.protect = aducm360_protect,
+	.write = aducm360_write,
+	.read = default_flash_read,
+	.probe = aducm360_probe,
+	.auto_probe = aducm360_probe,
+	.erase_check = default_flash_blank_check,
+	.protect_check = aducm360_protect_check,
+};