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

[27/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/nor/fm3.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/fm3.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/fm3.c
new file mode 100755
index 0000000..d3d143f
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/fm3.c
@@ -0,0 +1,1002 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Marc Willam, Holger Wech                        *
+ *       openOCD.fseu(AT)de.fujitsu.com                                    *
+ *   Copyright (C) 2011 Ronny Strutz                                       *
+ *                                                                         *
+ *   Copyright (C) 2013 Nemui Trinomius                                    *
+ *   nemuisan_kawausogasuki@live.jp                                        *
+ *                                                                         *
+ *   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 <target/algorithm.h>
+#include <target/armv7m.h>
+
+#define FLASH_DQ6 0x40		/* Data toggle flag bit (TOGG) position */
+#define FLASH_DQ5 0x20		/* Time limit exceeding flag bit (TLOV) position */
+
+enum fm3_variant {
+	mb9bfxx1,	/* Flash Type '1' */
+	mb9bfxx2,
+	mb9bfxx3,
+	mb9bfxx4,
+	mb9bfxx5,
+	mb9bfxx6,
+	mb9bfxx7,
+	mb9bfxx8,
+
+	mb9afxx1,	/* Flash Type '2' */
+	mb9afxx2,
+	mb9afxx3,
+	mb9afxx4,
+	mb9afxx5,
+	mb9afxx6,
+	mb9afxx7,
+	mb9afxx8,
+};
+
+enum fm3_flash_type {
+	fm3_no_flash_type = 0,
+	fm3_flash_type1   = 1,
+	fm3_flash_type2   = 2
+};
+
+struct fm3_flash_bank {
+	enum fm3_variant variant;
+	enum fm3_flash_type flashtype;
+	int probed;
+};
+
+FLASH_BANK_COMMAND_HANDLER(fm3_flash_bank_command)
+{
+	struct fm3_flash_bank *fm3_info;
+
+	if (CMD_ARGC < 6)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	fm3_info = malloc(sizeof(struct fm3_flash_bank));
+	bank->driver_priv = fm3_info;
+
+	/* Flash type '1' */
+	if (strcmp(CMD_ARGV[5], "mb9bfxx1.cpu") == 0) {
+		fm3_info->variant = mb9bfxx1;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9bfxx2.cpu") == 0) {
+		fm3_info->variant = mb9bfxx2;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9bfxx3.cpu") == 0) {
+		fm3_info->variant = mb9bfxx3;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9bfxx4.cpu") == 0) {
+		fm3_info->variant = mb9bfxx4;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9bfxx5.cpu") == 0) {
+		fm3_info->variant = mb9bfxx5;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9bfxx6.cpu") == 0) {
+		fm3_info->variant = mb9bfxx6;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9bfxx7.cpu") == 0) {
+		fm3_info->variant = mb9bfxx7;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9bfxx8.cpu") == 0) {
+		fm3_info->variant = mb9bfxx8;
+		fm3_info->flashtype = fm3_flash_type1;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx1.cpu") == 0) {	/* Flash type '2' */
+		fm3_info->variant = mb9afxx1;
+		fm3_info->flashtype = fm3_flash_type2;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx2.cpu") == 0) {
+		fm3_info->variant = mb9afxx2;
+		fm3_info->flashtype = fm3_flash_type2;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx3.cpu") == 0) {
+		fm3_info->variant = mb9afxx3;
+		fm3_info->flashtype = fm3_flash_type2;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx4.cpu") == 0) {
+		fm3_info->variant = mb9afxx4;
+		fm3_info->flashtype = fm3_flash_type2;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx5.cpu") == 0) {
+		fm3_info->variant = mb9afxx5;
+		fm3_info->flashtype = fm3_flash_type2;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx6.cpu") == 0) {
+		fm3_info->variant = mb9afxx6;
+		fm3_info->flashtype = fm3_flash_type2;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx7.cpu") == 0) {
+		fm3_info->variant = mb9afxx7;
+		fm3_info->flashtype = fm3_flash_type2;
+	} else if (strcmp(CMD_ARGV[5], "mb9afxx8.cpu") == 0) {
+		fm3_info->variant = mb9afxx8;
+		fm3_info->flashtype = fm3_flash_type2;
+	}
+
+	/* unknown Flash type */
+	else {
+		LOG_ERROR("unknown fm3 variant: %s", CMD_ARGV[5]);
+		free(fm3_info);
+		return ERROR_FLASH_BANK_INVALID;
+	}
+
+	fm3_info->probed = 0;
+
+	return ERROR_OK;
+}
+
+/* Data polling algorithm */
+static int fm3_busy_wait(struct target *target, uint32_t offset, int timeout_ms)
+{
+	int retval = ERROR_OK;
+	uint8_t state1, state2;
+	int ms = 0;
+
+	/* While(1) loop exit via "break" and "return" on error */
+	while (1) {
+		/* dummy-read - see flash manual */
+		retval = target_read_u8(target, offset, &state1);
+		if (retval != ERROR_OK)
+			return retval;
+
+		/* Data polling 1 */
+		retval = target_read_u8(target, offset, &state1);
+		if (retval != ERROR_OK)
+			return retval;
+
+		/* Data polling 2 */
+		retval = target_read_u8(target, offset, &state2);
+		if (retval != ERROR_OK)
+			return retval;
+
+		/* Flash command finished via polled data equal? */
+		if ((state1 & FLASH_DQ6) == (state2 & FLASH_DQ6))
+			break;
+		/* Timeout Flag? */
+		else if (state1 & FLASH_DQ5) {
+			/* Retry data polling */
+
+			/* Data polling 1 */
+			retval = target_read_u8(target, offset, &state1);
+			if (retval != ERROR_OK)
+				return retval;
+
+			/* Data polling 2 */
+			retval = target_read_u8(target, offset, &state2);
+			if (retval != ERROR_OK)
+				return retval;
+
+			/* Flash command finished via polled data equal? */
+			if ((state1 & FLASH_DQ6) != (state2 & FLASH_DQ6))
+				return ERROR_FLASH_OPERATION_FAILED;
+
+			/* finish anyway */
+			break;
+		}
+		usleep(1000);
+		++ms;
+
+		/* Polling time exceeded? */
+		if (ms > timeout_ms) {
+			LOG_ERROR("Polling data reading timed out!");
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+	}
+
+	if (retval == ERROR_OK)
+		LOG_DEBUG("fm3_busy_wait(%" PRIx32 ") needs about %d ms", offset, ms);
+
+	return retval;
+}
+
+static int fm3_erase(struct flash_bank *bank, int first, int last)
+{
+	struct fm3_flash_bank *fm3_info = bank->driver_priv;
+	struct target *target = bank->target;
+	int retval = ERROR_OK;
+	uint32_t u32DummyRead;
+	int sector, odd;
+	uint32_t u32FlashType;
+	uint32_t u32FlashSeqAddress1;
+	uint32_t u32FlashSeqAddress2;
+
+	struct working_area *write_algorithm;
+	struct reg_param reg_params[3];
+	struct armv7m_algorithm armv7m_info;
+
+	u32FlashType = (uint32_t) fm3_info->flashtype;
+
+	if (u32FlashType == fm3_flash_type1) {
+		u32FlashSeqAddress1 = 0x00001550;
+		u32FlashSeqAddress2 = 0x00000AA8;
+	} else if (u32FlashType == fm3_flash_type2) {
+		u32FlashSeqAddress1 = 0x00000AA8;
+		u32FlashSeqAddress2 = 0x00000554;
+	} else {
+		LOG_ERROR("Flash/Device type unknown!");
+		return ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	if (target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	/* RAMCODE used for fm3 Flash sector erase:				   */
+	/* R0 keeps Flash Sequence address 1     (u32FlashSeq1)    */
+	/* R1 keeps Flash Sequence address 2     (u32FlashSeq2)    */
+	/* R2 keeps Flash Offset address         (ofs)			   */
+	static const uint8_t fm3_flash_erase_sector_code[] = {
+						/*    *(uint16_t*)u32FlashSeq1 = 0xAA; */
+		0xAA, 0x24,		/*        MOVS  R4, #0xAA              */
+		0x04, 0x80,		/*        STRH  R4, [R0, #0]           */
+						/*    *(uint16_t*)u32FlashSeq2 = 0x55; */
+		0x55, 0x23,		/*        MOVS  R3, #0x55              */
+		0x0B, 0x80,		/*        STRH  R3, [R1, #0]           */
+						/*    *(uint16_t*)u32FlashSeq1 = 0x80; */
+		0x80, 0x25,		/*        MOVS  R5, #0x80              */
+		0x05, 0x80,		/*        STRH  R5, [R0, #0]           */
+						/*    *(uint16_t*)u32FlashSeq1 = 0xAA; */
+		0x04, 0x80,		/*        STRH  R4, [R0, #0]           */
+						/*    *(uint16_t*)u32FlashSeq2 = 0x55; */
+		0x0B, 0x80,		/*        STRH  R3, [R1, #0]           */
+						/* Sector_Erase Command (0x30)         */
+						/*    *(uint16_t*)ofs = 0x30;          */
+		0x30, 0x20,		/*        MOVS  R0, #0x30              */
+		0x10, 0x80,		/*        STRH  R0, [R2, #0]           */
+						/* End Code                            */
+		0x00, 0xBE,		/*        BKPT  #0                     */
+	};
+
+	LOG_INFO("Fujitsu MB9[A/B]FXXX: Sector Erase ... (%d to %d)", first, last);
+
+	/* disable HW watchdog */
+	retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, 0x40011008, 0x00000000);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash acccess) */
+	retval = target_write_u32(target, 0x40000000, 0x0001);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* dummy read of FASZR */
+	retval = target_read_u32(target, 0x40000000, &u32DummyRead);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* allocate working area with flash sector erase code */
+	if (target_alloc_working_area(target, sizeof(fm3_flash_erase_sector_code),
+			&write_algorithm) != ERROR_OK) {
+		LOG_WARNING("no working area available, can't do block memory writes");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+	retval = target_write_buffer(target, write_algorithm->address,
+		sizeof(fm3_flash_erase_sector_code), fm3_flash_erase_sector_code);
+	if (retval != ERROR_OK)
+		return retval;
+
+	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_info.core_mode = ARM_MODE_THREAD;
+
+	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* u32FlashSeqAddress1 */
+	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* u32FlashSeqAddress2 */
+	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* offset				*/
+
+	/* write code buffer and use Flash sector erase code within fm3				*/
+	for (sector = first ; sector <= last ; sector++) {
+		uint32_t offset = bank->sectors[sector].offset;
+
+		for (odd = 0; odd < 2 ; odd++) {
+			if (odd)
+				offset += 4;
+
+			buf_set_u32(reg_params[0].value, 0, 32, u32FlashSeqAddress1);
+			buf_set_u32(reg_params[1].value, 0, 32, u32FlashSeqAddress2);
+			buf_set_u32(reg_params[2].value, 0, 32, offset);
+
+			retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+					write_algorithm->address, 0, 100000, &armv7m_info);
+			if (retval != ERROR_OK) {
+				LOG_ERROR("Error executing flash erase programming algorithm");
+				retval = ERROR_FLASH_OPERATION_FAILED;
+				return retval;
+			}
+
+			retval = fm3_busy_wait(target, offset, 500);
+			if (retval != ERROR_OK)
+				return retval;
+		}
+		bank->sectors[sector].is_erased = 1;
+	}
+
+	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]);
+
+	/* FASZR = 0x02, Enables CPU Run Mode (32-bit Flash acccess) */
+	retval = target_write_u32(target, 0x40000000, 0x0002);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */
+
+	return retval;
+}
+
+static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer,
+		uint32_t offset, uint32_t count)
+{
+	struct fm3_flash_bank *fm3_info = bank->driver_priv;
+	struct target *target = bank->target;
+	uint32_t buffer_size = 2048;		/* Default minimum value */
+	struct working_area *write_algorithm;
+	struct working_area *source;
+	uint32_t address = bank->base + offset;
+	struct reg_param reg_params[6];
+	struct armv7m_algorithm armv7m_info;
+	int retval = ERROR_OK;
+	uint32_t u32FlashType;
+	uint32_t u32FlashSeqAddress1;
+	uint32_t u32FlashSeqAddress2;
+
+	/* Increase buffer_size if needed */
+	if (buffer_size < (target->working_area_size / 2))
+		buffer_size = (target->working_area_size / 2);
+
+	u32FlashType = (uint32_t) fm3_info->flashtype;
+
+	if (u32FlashType == fm3_flash_type1) {
+		u32FlashSeqAddress1 = 0x00001550;
+		u32FlashSeqAddress2 = 0x00000AA8;
+	} else if (u32FlashType == fm3_flash_type2) {
+		u32FlashSeqAddress1 = 0x00000AA8;
+		u32FlashSeqAddress2 = 0x00000554;
+	} else {
+		LOG_ERROR("Flash/Device type unknown!");
+		return ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	/* RAMCODE used for fm3 Flash programming:                 */
+	/* R0 keeps source start address         (u32Source)       */
+	/* R1 keeps target start address         (u32Target)       */
+	/* R2 keeps number of halfwords to write (u32Count)        */
+	/* R3 keeps Flash Sequence address 1     (u32FlashSeq1)    */
+	/* R4 keeps Flash Sequence address 2     (u32FlashSeq2)    */
+	/* R5 returns result value               (u32FlashResult)  */
+
+	static const uint8_t fm3_flash_write_code[] = {
+								/*    fm3_FLASH_IF->FASZ &= 0xFFFD;           */
+	0x5F, 0xF0, 0x80, 0x45,		/*        MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
+	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
+	0x4F, 0xF6, 0xFD, 0x76,		/*        MOVW     R6, #0xFFFD                */
+	0x35, 0x40,					/*        ANDS     R5, R5, R6                 */
+	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
+	0x35, 0x60,					/*        STR      R5, [R6]                   */
+								/*    fm3_FLASH_IF->FASZ |= 1;                */
+	0x5F, 0xF0, 0x80, 0x45,		/*        MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
+	0x2D, 0x68,					/*        LDR      R5, [R3]                   */
+	0x55, 0xF0, 0x01, 0x05,		/*        ORRS.W   R5, R5, #1                 */
+	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
+	0x35, 0x60,					/*        STR      R5, [R6]                   */
+								/*    u32DummyRead = fm3_FLASH_IF->FASZ;      */
+	0x28, 0x4D,					/*        LDR.N    R5, ??u32DummyRead         */
+	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
+	0x36, 0x68,					/*        LDR      R6, [R6]                   */
+	0x2E, 0x60,					/*        STR      R6, [R5]                   */
+								/*    u32FlashResult = FLASH_WRITE_NO_RESULT  */
+	0x26, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
+	0x00, 0x26,					/*        MOVS     R6, #0                     */
+	0x2E, 0x60,					/*        STR      R6, [R5]                   */
+								/*    while ((u32Count > 0 )                  */
+								/*      && (u32FlashResult                    */
+								/*          == FLASH_WRITE_NO_RESULT))        */
+	0x01, 0x2A,					/* L0:    CMP      R2, #1                     */
+	0x2C, 0xDB,					/*        BLT.N    L1                         */
+	0x24, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
+	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
+	0x00, 0x2D,					/*        CMP      R5, #0                     */
+	0x28, 0xD1,					/*        BNE.N    L1                         */
+								/*    *u32FlashSeq1 = FLASH_WRITE_1;          */
+	0xAA, 0x25,					/*        MOVS     R5, #0xAA                  */
+	0x1D, 0x60,					/*        STR      R5, [R3]                   */
+								/*    *u32FlashSeq2 = FLASH_WRITE_2;          */
+	0x55, 0x25,					/*        MOVS     R5, #0x55                  */
+	0x25, 0x60,					/*        STR      R5, [R4]                   */
+								/*    *u32FlashSeq1 = FLASH_WRITE_3;          */
+	0xA0, 0x25,					/*        MOVS     R5, #0xA0                  */
+	0x1D, 0x60,					/*        STRH     R5, [R3]                   */
+								/*    *(volatile uint16_t*)u32Target          */
+								/*      = *(volatile uint16_t*)u32Source;     */
+	0x05, 0x88,					/*        LDRH     R5, [R0]                   */
+	0x0D, 0x80,					/*        STRH     R5, [R1]                   */
+								/*    while (u32FlashResult                   */
+								/*           == FLASH_WRITE_NO_RESTULT)       */
+	0x1E, 0x4D,					/* L2:    LDR.N    R5, ??u32FlashResult       */
+	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
+	0x00, 0x2D,					/*        CMP      R5, #0                     */
+	0x11, 0xD1,					/*        BNE.N    L3                         */
+								/*    if ((*(volatile uint16_t*)u32Target     */
+								/*        & FLASH_DQ5) == FLASH_DQ5)          */
+	0x0D, 0x88,					/*        LDRH     R5, [R1]                   */
+	0xAD, 0x06,					/*        LSLS     R5, R5, #0x1A              */
+	0x02, 0xD5,					/*        BPL.N    L4                         */
+								/*    u32FlashResult = FLASH_WRITE_TIMEOUT    */
+	0x1A, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
+	0x02, 0x26,					/*        MOVS     R6, #2                     */
+	0x2E, 0x60,					/*        STR      R6, [R5]                   */
+								/*    if ((*(volatile uint16_t *)u32Target    */
+								/*         & FLASH_DQ7)                       */
+								/*        == (*(volatile uint16_t*)u32Source  */
+								/*            & FLASH_DQ7))                   */
+	0x0D, 0x88,					/* L4:    LDRH     R5, [R1]                   */
+	0x15, 0xF0, 0x80, 0x05,		/*        ANDS.W   R5, R5, #0x80              */
+	0x06, 0x88,					/*        LDRH     R6, [R0]                   */
+	0x16, 0xF0, 0x80, 0x06,		/*        ANDS.W   R6, R6, #0x80              */
+	0xB5, 0x42,					/*        CMP      R5, R6                     */
+	0xED, 0xD1,					/*        BNE.N    L2                         */
+								/*    u32FlashResult = FLASH_WRITE_OKAY       */
+	0x15, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
+	0x01, 0x26,					/*        MOVS     R6, #1                     */
+	0x2E, 0x60,					/*        STR      R6, [R5]                   */
+	0xE9, 0xE7,					/*        B.N      L2                         */
+								/*    if (u32FlashResult                      */
+								/*        != FLASH_WRITE_TIMEOUT)             */
+	0x13, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
+	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
+	0x02, 0x2D,					/*        CMP      R5, #2                     */
+	0x02, 0xD0,					/*        BEQ.N    L5                         */
+								/*    u32FlashResult = FLASH_WRITE_NO_RESULT  */
+	0x11, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
+	0x00, 0x26,					/*        MOVS     R6, #0                     */
+	0x2E, 0x60,					/*        STR      R6, [R5]                   */
+								/*    u32Count--;                             */
+	0x52, 0x1E,					/* L5:    SUBS     R2, R2, #1                 */
+								/*    u32Source += 2;                         */
+	0x80, 0x1C,					/*        ADDS     R0, R0, #2                 */
+								/*    u32Target += 2;                         */
+	0x89, 0x1C,					/*        ADDS     R1, R1, #2                 */
+	0xD0, 0xE7,					/*        B.N      L0                         */
+								/*    fm3_FLASH_IF->FASZ &= 0xFFFE;           */
+	0x5F, 0xF0, 0x80, 0x45,		/* L1:    MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
+	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
+	0x4F, 0xF6, 0xFE, 0x76,		/*        MOVW     R6, #0xFFFE                */
+	0x35, 0x40,					/*        ANDS     R5, R5, R6                 */
+	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
+	0x35, 0x60,					/*        STR      R5, [R6]                   */
+								/*    fm3_FLASH_IF->FASZ |= 2;                */
+	0x5F, 0xF0, 0x80, 0x45,		/*        MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
+	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
+	0x55, 0xF0, 0x02, 0x05,		/*        ORRS.W   R5, R5, #2                 */
+	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
+	0x35, 0x60,					/*        STR      R5, [R6]                   */
+								/*    u32DummyRead = fm3_FLASH_IF->FASZ;      */
+	0x04, 0x4D,					/*        LDR.N    R5, ??u32DummyRead         */
+	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
+	0x36, 0x68,					/*        LDR      R6, [R6]                   */
+	0x2E, 0x60,					/*        STR      R6, [R5]                   */
+								/*    copy u32FlashResult to R3 for return    */
+								/*      value                                 */
+	0xDF, 0xF8, 0x08, 0x50,		/*        LDR.W    R5, ??u32FlashResult       */
+	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
+								/*    Breakpoint here                         */
+	0x00, 0xBE,					/*        BKPT     #0                         */
+
+	/* The following address pointers assume, that the code is running from   */
+	/* SRAM basic-address + 8.These address pointers will be patched, if a    */
+	/* different start address in RAM is used (e.g. for Flash type 2)!        */
+	/* Default SRAM basic-address is 0x20000000.                              */
+	0x00, 0x00, 0x00, 0x20,     /* u32DummyRead address in RAM (0x20000000)   */
+	0x04, 0x00, 0x00, 0x20      /* u32FlashResult address in RAM (0x20000004) */
+	};
+
+	LOG_INFO("Fujitsu MB9[A/B]FXXX: FLASH Write ...");
+
+	/* disable HW watchdog */
+	retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, 0x40011008, 0x00000000);
+	if (retval != ERROR_OK)
+		return retval;
+
+	count = count / 2;		/* number bytes -> number halfwords */
+
+	/* check code alignment */
+	if (offset & 0x1) {
+		LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
+		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+	}
+
+	/* allocate working area and variables with flash programming code */
+	if (target_alloc_working_area(target, sizeof(fm3_flash_write_code) + 8,
+			&write_algorithm) != ERROR_OK) {
+		LOG_WARNING("no working area available, can't do block memory writes");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+
+	retval = target_write_buffer(target, write_algorithm->address + 8,
+		sizeof(fm3_flash_write_code), fm3_flash_write_code);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* Patching 'local variable address' */
+	/* Algorithm: u32DummyRead: */
+	retval = target_write_u32(target, (write_algorithm->address + 8)
+			+ sizeof(fm3_flash_write_code) - 8, (write_algorithm->address));
+	if (retval != ERROR_OK)
+		return retval;
+	/* Algorithm: u32FlashResult: */
+	retval = target_write_u32(target, (write_algorithm->address + 8)
+			+ sizeof(fm3_flash_write_code) - 4, (write_algorithm->address) + 4);
+	if (retval != ERROR_OK)
+		return retval;
+
+
+
+	/* memory buffer */
+	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
+		buffer_size /= 2;
+		if (buffer_size <= 256) {
+			/* free working area, write algorithm already allocated */
+			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;
+		}
+	}
+
+	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_info.core_mode = ARM_MODE_THREAD;
+
+	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* source start address */
+	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* target start address */
+	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */
+	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */
+	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */
+	init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);  /* result */
+
+	/* write code buffer and use Flash programming code within fm3           */
+	/* Set breakpoint to 0 with time-out of 1000 ms                          */
+	while (count > 0) {
+		uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
+
+		retval = target_write_buffer(target, source->address, thisrun_count * 2, 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, address);
+		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
+		buf_set_u32(reg_params[3].value, 0, 32, u32FlashSeqAddress1);
+		buf_set_u32(reg_params[4].value, 0, 32, u32FlashSeqAddress2);
+
+		retval = target_run_algorithm(target, 0, NULL, 6, reg_params,
+				(write_algorithm->address + 8), 0, 1000, &armv7m_info);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Error executing fm3 Flash programming algorithm");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			break;
+		}
+
+		if (buf_get_u32(reg_params[5].value, 0, 32) != ERROR_OK) {
+			LOG_ERROR("Fujitsu MB9[A/B]FXXX: Flash programming ERROR (Timeout) -> Reg R3: %" PRIx32,
+				buf_get_u32(reg_params[5].value, 0, 32));
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			break;
+		}
+
+		buffer  += thisrun_count * 2;
+		address += thisrun_count * 2;
+		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]);
+	destroy_reg_param(&reg_params[5]);
+
+	return retval;
+}
+
+static int fm3_probe(struct flash_bank *bank)
+{
+	struct fm3_flash_bank *fm3_info = bank->driver_priv;
+	uint16_t num_pages;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+/*
+ -- page-- start -- blocksize - mpu - totalFlash --
+	page0 0x00000	16k
+	page1 0x04000	16k
+	page2 0x08000	96k		___ fxx3  128k Flash
+	page3 0x20000  128k		___ fxx4  256k Flash
+	page4 0x40000  128k		___ fxx5  384k Flash
+	page5 0x60000  128k		___ fxx6  512k Flash
+-----------------------
+	page6 0x80000  128k
+	page7 0xa0000  128k		___ fxx7  256k Flash
+	page8 0xc0000  128k
+	page9 0xe0000  128k		___ fxx8  256k Flash
+ */
+
+	num_pages = 10;				/* max number of Flash pages for malloc */
+	fm3_info->probed = 0;
+
+	bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+	bank->base = 0x00000000;
+	bank->size = 32 * 1024;		/* bytes */
+
+	bank->sectors[0].offset = 0;
+	bank->sectors[0].size = 16 * 1024;
+	bank->sectors[0].is_erased = -1;
+	bank->sectors[0].is_protected = -1;
+
+	bank->sectors[1].offset = 0x4000;
+	bank->sectors[1].size = 16 * 1024;
+	bank->sectors[1].is_erased = -1;
+	bank->sectors[1].is_protected = -1;
+
+	if ((fm3_info->variant == mb9bfxx1)
+	    || (fm3_info->variant == mb9afxx1)) {
+		num_pages = 3;
+		bank->size = 64 * 1024; /* bytes */
+		bank->num_sectors = num_pages;
+
+		bank->sectors[2].offset = 0x8000;
+		bank->sectors[2].size = 32 * 1024;
+		bank->sectors[2].is_erased = -1;
+		bank->sectors[2].is_protected = -1;
+	}
+
+	if ((fm3_info->variant == mb9bfxx2)
+		|| (fm3_info->variant == mb9bfxx4)
+		|| (fm3_info->variant == mb9bfxx5)
+		|| (fm3_info->variant == mb9bfxx6)
+		|| (fm3_info->variant == mb9bfxx7)
+		|| (fm3_info->variant == mb9bfxx8)
+		|| (fm3_info->variant == mb9afxx2)
+		|| (fm3_info->variant == mb9afxx4)
+		|| (fm3_info->variant == mb9afxx5)
+		|| (fm3_info->variant == mb9afxx6)
+		|| (fm3_info->variant == mb9afxx7)
+		|| (fm3_info->variant == mb9afxx8)) {
+		num_pages = 3;
+		bank->size = 128 * 1024; /* bytes */
+		bank->num_sectors = num_pages;
+
+		bank->sectors[2].offset = 0x8000;
+		bank->sectors[2].size = 96 * 1024;
+		bank->sectors[2].is_erased = -1;
+		bank->sectors[2].is_protected = -1;
+	}
+
+	if ((fm3_info->variant == mb9bfxx4)
+		|| (fm3_info->variant == mb9bfxx5)
+		|| (fm3_info->variant == mb9bfxx6)
+		|| (fm3_info->variant == mb9bfxx7)
+		|| (fm3_info->variant == mb9bfxx8)
+		|| (fm3_info->variant == mb9afxx4)
+		|| (fm3_info->variant == mb9afxx5)
+		|| (fm3_info->variant == mb9afxx6)
+		|| (fm3_info->variant == mb9afxx7)
+		|| (fm3_info->variant == mb9afxx8)) {
+		num_pages = 4;
+		bank->size = 256 * 1024; /* bytes */
+		bank->num_sectors = num_pages;
+
+		bank->sectors[3].offset = 0x20000;
+		bank->sectors[3].size = 128 * 1024;
+		bank->sectors[3].is_erased = -1;
+		bank->sectors[3].is_protected = -1;
+	}
+
+	if ((fm3_info->variant == mb9bfxx5)
+		|| (fm3_info->variant == mb9bfxx6)
+		|| (fm3_info->variant == mb9bfxx7)
+		|| (fm3_info->variant == mb9bfxx8)
+		|| (fm3_info->variant == mb9afxx5)
+		|| (fm3_info->variant == mb9afxx6)
+		|| (fm3_info->variant == mb9afxx7)
+		|| (fm3_info->variant == mb9afxx8)) {
+		num_pages = 5;
+		bank->size = 384 * 1024; /* bytes */
+		bank->num_sectors = num_pages;
+
+		bank->sectors[4].offset = 0x40000;
+		bank->sectors[4].size = 128 * 1024;
+		bank->sectors[4].is_erased = -1;
+		bank->sectors[4].is_protected = -1;
+	}
+
+	if ((fm3_info->variant == mb9bfxx6)
+		|| (fm3_info->variant == mb9bfxx7)
+		|| (fm3_info->variant == mb9bfxx8)
+		|| (fm3_info->variant == mb9afxx6)
+		|| (fm3_info->variant == mb9afxx7)
+		|| (fm3_info->variant == mb9afxx8)) {
+		num_pages = 6;
+		bank->size = 512 * 1024; /* bytes */
+		bank->num_sectors = num_pages;
+
+		bank->sectors[5].offset = 0x60000;
+		bank->sectors[5].size = 128 * 1024;
+		bank->sectors[5].is_erased = -1;
+		bank->sectors[5].is_protected = -1;
+	}
+
+	if ((fm3_info->variant == mb9bfxx7)
+		|| (fm3_info->variant == mb9bfxx8)
+		|| (fm3_info->variant == mb9afxx7)
+		|| (fm3_info->variant == mb9afxx8)) {
+		num_pages = 8;
+		bank->size = 768 * 1024; /* bytes */
+		bank->num_sectors = num_pages;
+
+		bank->sectors[6].offset = 0x80000;
+		bank->sectors[6].size = 128 * 1024;
+		bank->sectors[6].is_erased = -1;
+		bank->sectors[6].is_protected = -1;
+
+		bank->sectors[7].offset = 0xa0000;
+		bank->sectors[7].size = 128 * 1024;
+		bank->sectors[7].is_erased = -1;
+		bank->sectors[7].is_protected = -1;
+	}
+
+	if ((fm3_info->variant == mb9bfxx8)
+		|| (fm3_info->variant == mb9afxx8)) {
+		num_pages = 10;
+		bank->size = 1024 * 1024; /* bytes */
+		bank->num_sectors = num_pages;
+
+		bank->sectors[8].offset = 0xc0000;
+		bank->sectors[8].size = 128 * 1024;
+		bank->sectors[8].is_erased = -1;
+		bank->sectors[8].is_protected = -1;
+
+		bank->sectors[9].offset = 0xe0000;
+		bank->sectors[9].size = 128 * 1024;
+		bank->sectors[9].is_erased = -1;
+		bank->sectors[9].is_protected = -1;
+	}
+
+	fm3_info->probed = 1;
+
+	return ERROR_OK;
+}
+
+static int fm3_auto_probe(struct flash_bank *bank)
+{
+	struct fm3_flash_bank *fm3_info = bank->driver_priv;
+	if (fm3_info->probed)
+		return ERROR_OK;
+	return fm3_probe(bank);
+}
+
+/* Chip erase */
+static int fm3_chip_erase(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	struct fm3_flash_bank *fm3_info2 = bank->driver_priv;
+	int retval = ERROR_OK;
+	uint32_t u32DummyRead;
+	uint32_t u32FlashType;
+	uint32_t u32FlashSeqAddress1;
+	uint32_t u32FlashSeqAddress2;
+
+	struct working_area *write_algorithm;
+	struct reg_param reg_params[3];
+	struct armv7m_algorithm armv7m_info;
+
+	u32FlashType = (uint32_t) fm3_info2->flashtype;
+
+	if (u32FlashType == fm3_flash_type1) {
+		LOG_INFO("*** Erasing mb9bfxxx type");
+		u32FlashSeqAddress1 = 0x00001550;
+		u32FlashSeqAddress2 = 0x00000AA8;
+	} else if (u32FlashType == fm3_flash_type2) {
+		LOG_INFO("*** Erasing mb9afxxx type");
+		u32FlashSeqAddress1 = 0x00000AA8;
+		u32FlashSeqAddress2 = 0x00000554;
+	} else {
+		LOG_ERROR("Flash/Device type unknown!");
+		return ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	if (target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	/* RAMCODE used for fm3 Flash chip erase:				   */
+	/* R0 keeps Flash Sequence address 1     (u32FlashSeq1)    */
+	/* R1 keeps Flash Sequence address 2     (u32FlashSeq2)    */
+	static const uint8_t fm3_flash_erase_chip_code[] = {
+						/*    *(uint16_t*)u32FlashSeq1 = 0xAA; */
+		0xAA, 0x22,		/*        MOVS  R2, #0xAA              */
+		0x02, 0x80,		/*        STRH  R2, [R0, #0]           */
+						/*    *(uint16_t*)u32FlashSeq2 = 0x55; */
+		0x55, 0x23,		/*        MOVS  R3, #0x55              */
+		0x0B, 0x80,		/*        STRH  R3, [R1, #0]           */
+						/*    *(uint16_t*)u32FlashSeq1 = 0x80; */
+		0x80, 0x24,		/*        MOVS  R4, #0x80              */
+		0x04, 0x80,		/*        STRH  R4, [R0, #0]           */
+						/*    *(uint16_t*)u32FlashSeq1 = 0xAA; */
+		0x02, 0x80,		/*        STRH  R2, [R0, #0]           */
+						/*    *(uint16_t*)u32FlashSeq2 = 0x55; */
+		0x0B, 0x80,		/*        STRH  R3, [R1, #0]           */
+						/* Chip_Erase Command 0x10             */
+						/*    *(uint16_t*)u32FlashSeq1 = 0x10; */
+		0x10, 0x21,		/*        MOVS  R1, #0x10              */
+		0x01, 0x80,		/*        STRH  R1, [R0, #0]           */
+						/* End Code                            */
+		0x00, 0xBE,		/*        BKPT  #0                      */
+	};
+
+	LOG_INFO("Fujitsu MB9[A/B]xxx: Chip Erase ... (may take several seconds)");
+
+	/* disable HW watchdog */
+	retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, 0x40011008, 0x00000000);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash access) */
+	retval = target_write_u32(target, 0x40000000, 0x0001);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* dummy read of FASZR */
+	retval = target_read_u32(target, 0x40000000, &u32DummyRead);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* allocate working area with flash chip erase code */
+	if (target_alloc_working_area(target, sizeof(fm3_flash_erase_chip_code),
+			&write_algorithm) != ERROR_OK) {
+		LOG_WARNING("no working area available, can't do block memory writes");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+	retval = target_write_buffer(target, write_algorithm->address,
+		sizeof(fm3_flash_erase_chip_code), fm3_flash_erase_chip_code);
+	if (retval != ERROR_OK)
+		return retval;
+
+	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_info.core_mode = ARM_MODE_THREAD;
+
+	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* u32FlashSeqAddress1 */
+	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* u32FlashSeqAddress2 */
+
+	buf_set_u32(reg_params[0].value, 0, 32, u32FlashSeqAddress1);
+	buf_set_u32(reg_params[1].value, 0, 32, u32FlashSeqAddress2);
+
+	retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
+			write_algorithm->address, 0, 100000, &armv7m_info);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("Error executing flash erase programming algorithm");
+		retval = ERROR_FLASH_OPERATION_FAILED;
+		return retval;
+	}
+
+	target_free_working_area(target, write_algorithm);
+
+	destroy_reg_param(&reg_params[0]);
+	destroy_reg_param(&reg_params[1]);
+
+	retval = fm3_busy_wait(target, u32FlashSeqAddress2, 20000);	/* 20s timeout */
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* FASZR = 0x02, Re-enables CPU Run Mode (32-bit Flash access) */
+	retval = target_write_u32(target, 0x40000000, 0x0002);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */
+
+	return retval;
+}
+
+COMMAND_HANDLER(fm3_handle_chip_erase_command)
+{
+	int i;
+
+	if (CMD_ARGC < 1)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	struct flash_bank *bank;
+	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+	if (ERROR_OK != retval)
+		return retval;
+
+	if (fm3_chip_erase(bank) == ERROR_OK) {
+		/* set all sectors as erased */
+		for (i = 0; i < bank->num_sectors; i++)
+			bank->sectors[i].is_erased = 1;
+
+		command_print(CMD_CTX, "fm3 chip erase complete");
+	} else {
+		command_print(CMD_CTX, "fm3 chip erase failed");
+	}
+
+	return ERROR_OK;
+}
+
+static const struct command_registration fm3_exec_command_handlers[] = {
+	{
+		.name = "chip_erase",
+		.usage = "<bank>",
+		.handler = fm3_handle_chip_erase_command,
+		.mode = COMMAND_EXEC,
+		.help = "Erase entire Flash device.",
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration fm3_command_handlers[] = {
+	{
+		.name = "fm3",
+		.mode = COMMAND_ANY,
+		.help = "fm3 Flash command group",
+		.usage = "",
+		.chain = fm3_exec_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver fm3_flash = {
+	.name = "fm3",
+	.commands = fm3_command_handlers,
+	.flash_bank_command = fm3_flash_bank_command,
+	.erase = fm3_erase,
+	.write = fm3_write_block,
+	.probe = fm3_probe,
+	.auto_probe = fm3_auto_probe,
+	.erase_check = default_flash_blank_check,
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/fm4.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/fm4.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/fm4.c
new file mode 100755
index 0000000..c348c1d
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/fm4.c
@@ -0,0 +1,722 @@
+/*
+ * Spansion FM4 flash
+ *
+ * Copyright (c) 2015 Andreas F�rber
+ *
+ * Based on S6E2DH_MN709-00013 for S6E2DH/DF/D5/D3 series
+ * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series
+ * Based on MB9B560R_MN709-00005 for MB9BFx66/x67/x68 series
+ * Based on MB9B560L_MN709-00006 for MB9BFx64/x65/x66 series
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+#define FLASH_BASE 0x40000000
+#define FASZR   (FLASH_BASE + 0x000)
+#define DFCTRLR (FLASH_BASE + 0x030)
+#define DFCTRLR_DFE (1UL << 0)
+
+#define WDG_BASE 0x40011000
+#define WDG_CTL (WDG_BASE + 0x008)
+#define WDG_LCK (WDG_BASE + 0xC00)
+
+enum fm4_variant {
+	mb9bfx64,
+	mb9bfx65,
+	mb9bfx66,
+	mb9bfx67,
+	mb9bfx68,
+
+	s6e2cx8,
+	s6e2cx9,
+	s6e2cxa,
+
+	s6e2dx,
+};
+
+struct fm4_flash_bank {
+	enum fm4_variant variant;
+	int macro_nr;
+	bool probed;
+};
+
+static int fm4_disable_hw_watchdog(struct target *target)
+{
+	int retval;
+
+	retval = target_write_u32(target, WDG_LCK, 0x1ACCE551);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, WDG_LCK, 0xE5331AAE);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_write_u32(target, WDG_CTL, 0);
+	if (retval != ERROR_OK)
+		return retval;
+
+	return ERROR_OK;
+}
+
+static int fm4_enter_flash_cpu_programming_mode(struct target *target)
+{
+	uint32_t u32_value;
+	int retval;
+
+	/* FASZR ASZ = CPU programming mode */
+	retval = target_write_u32(target, FASZR, 0x00000001);
+	if (retval != ERROR_OK)
+		return retval;
+	retval = target_read_u32(target, FASZR, &u32_value);
+	if (retval != ERROR_OK)
+		return retval;
+
+	return ERROR_OK;
+}
+
+static int fm4_enter_flash_cpu_rom_mode(struct target *target)
+{
+	uint32_t u32_value;
+	int retval;
+
+	/* FASZR ASZ = CPU ROM mode */
+	retval = target_write_u32(target, FASZR, 0x00000002);
+	if (retval != ERROR_OK)
+		return retval;
+	retval = target_read_u32(target, FASZR, &u32_value);
+	if (retval != ERROR_OK)
+		return retval;
+
+	return ERROR_OK;
+}
+
+static int fm4_flash_erase(struct flash_bank *bank, int first, int last)
+{
+	struct target *target = bank->target;
+	struct working_area *workarea;
+	struct reg_param reg_params[4];
+	struct armv7m_algorithm armv7m_algo;
+	unsigned i;
+	int retval, sector;
+	const uint8_t erase_sector_code[] = {
+#include "../../../contrib/loaders/flash/fm4/erase.inc"
+	};
+
+	if (target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	LOG_DEBUG("Spansion FM4 erase sectors %d to %d", first, last);
+
+	retval = fm4_disable_hw_watchdog(target);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = fm4_enter_flash_cpu_programming_mode(target);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_alloc_working_area(target, sizeof(erase_sector_code),
+			&workarea);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("No working area available.");
+		retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+		goto err_alloc_code;
+	}
+	retval = target_write_buffer(target, workarea->address,
+			sizeof(erase_sector_code), erase_sector_code);
+	if (retval != ERROR_OK)
+		goto err_write_code;
+
+	armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_algo.core_mode = ARM_MODE_THREAD;
+
+	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);
+
+	for (sector = first; sector <= last; sector++) {
+		uint32_t addr = bank->base + bank->sectors[sector].offset;
+		uint32_t result;
+
+		buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
+		buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
+		buf_set_u32(reg_params[2].value, 0, 32, addr);
+
+		retval = target_run_algorithm(target,
+				0, NULL,
+				ARRAY_SIZE(reg_params), reg_params,
+				workarea->address, 0,
+				1000, &armv7m_algo);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Error executing flash sector erase "
+				"programming algorithm");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run;
+		}
+
+		result = buf_get_u32(reg_params[3].value, 0, 32);
+		if (result == 2) {
+			LOG_ERROR("Timeout error from flash sector erase programming algorithm");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run_ret;
+		} else if (result != 0) {
+			LOG_ERROR("Unexpected error %d from flash sector erase programming algorithm", result);
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run_ret;
+		} else
+			retval = ERROR_OK;
+
+		bank->sectors[sector].is_erased = 1;
+	}
+
+err_run_ret:
+err_run:
+	for (i = 0; i < ARRAY_SIZE(reg_params); i++)
+		destroy_reg_param(&reg_params[i]);
+
+err_write_code:
+	target_free_working_area(target, workarea);
+
+err_alloc_code:
+	if (retval != ERROR_OK)
+		fm4_enter_flash_cpu_rom_mode(target);
+	else
+		retval = fm4_enter_flash_cpu_rom_mode(target);
+
+	return retval;
+}
+
+static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
+		uint32_t offset, uint32_t byte_count)
+{
+	struct target *target = bank->target;
+	struct working_area *code_workarea, *data_workarea;
+	struct reg_param reg_params[6];
+	struct armv7m_algorithm armv7m_algo;
+	uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
+	uint32_t result;
+	unsigned i;
+	int retval;
+	const uint8_t write_block_code[] = {
+#include "../../../contrib/loaders/flash/fm4/write.inc"
+	};
+
+	LOG_DEBUG("Spansion FM4 write at 0x%08" PRIx32 " (%" PRId32 " bytes)",
+		offset, byte_count);
+
+	if (offset & 0x1) {
+		LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment",
+			offset);
+		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+	}
+	if (byte_count & 0x1) {
+		LOG_WARNING("length %" PRId32 " is not 2-byte aligned, rounding up",
+			byte_count);
+	}
+
+	if (target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	retval = fm4_disable_hw_watchdog(target);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_alloc_working_area(target, sizeof(write_block_code),
+			&code_workarea);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("No working area available for write code.");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+	retval = target_write_buffer(target, code_workarea->address,
+			sizeof(write_block_code), write_block_code);
+	if (retval != ERROR_OK)
+		goto err_write_code;
+
+	retval = target_alloc_working_area(target,
+		MIN(halfword_count * 2, target_get_working_area_avail(target)),
+		&data_workarea);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("No working area available for write data.");
+		retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+		goto err_alloc_data;
+	}
+
+	armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_algo.core_mode = ARM_MODE_THREAD;
+
+	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_OUT);
+	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
+	init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);
+
+	retval = fm4_enter_flash_cpu_programming_mode(target);
+	if (retval != ERROR_OK)
+		goto err_flash_mode;
+
+	while (byte_count > 0) {
+		uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2);
+		uint32_t addr = bank->base + offset;
+
+		LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32,
+			MIN(halfwords * 2, byte_count), data_workarea->address);
+
+		retval = target_write_buffer(target, data_workarea->address,
+			MIN(halfwords * 2, byte_count), buffer);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Error writing data buffer");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_write_data;
+		}
+
+		LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRId32 "x)",
+			addr, addr + halfwords * 2 - 1, halfwords);
+
+		buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
+		buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
+		buf_set_u32(reg_params[2].value, 0, 32, addr);
+		buf_set_u32(reg_params[3].value, 0, 32, data_workarea->address);
+		buf_set_u32(reg_params[4].value, 0, 32, halfwords);
+
+		retval = target_run_algorithm(target,
+				0, NULL,
+				ARRAY_SIZE(reg_params), reg_params,
+				code_workarea->address, 0,
+				5 * 60 * 1000, &armv7m_algo);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Error executing flash sector erase "
+				"programming algorithm");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run;
+		}
+
+		result = buf_get_u32(reg_params[5].value, 0, 32);
+		if (result == 2) {
+			LOG_ERROR("Timeout error from flash write "
+				"programming algorithm");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run_ret;
+		} else if (result != 0) {
+			LOG_ERROR("Unexpected error %d from flash write "
+				"programming algorithm", result);
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run_ret;
+		} else
+			retval = ERROR_OK;
+
+		halfword_count -= halfwords;
+		offset += halfwords * 2;
+		buffer += halfwords * 2;
+		byte_count -= MIN(halfwords * 2, byte_count);
+	}
+
+err_run_ret:
+err_run:
+err_write_data:
+	retval = fm4_enter_flash_cpu_rom_mode(target);
+
+err_flash_mode:
+	for (i = 0; i < ARRAY_SIZE(reg_params); i++)
+		destroy_reg_param(&reg_params[i]);
+
+	target_free_working_area(target, data_workarea);
+err_alloc_data:
+err_write_code:
+	target_free_working_area(target, code_workarea);
+
+	return retval;
+}
+
+static int mb9bf_probe(struct flash_bank *bank)
+{
+	struct fm4_flash_bank *fm4_bank = bank->driver_priv;
+	uint32_t flash_addr = bank->base;
+	int i;
+
+	switch (fm4_bank->variant) {
+	case mb9bfx64:
+		bank->num_sectors = 8;
+		break;
+	case mb9bfx65:
+		bank->num_sectors = 10;
+		break;
+	case mb9bfx66:
+		bank->num_sectors = 12;
+		break;
+	case mb9bfx67:
+		bank->num_sectors = 16;
+		break;
+	case mb9bfx68:
+		bank->num_sectors = 20;
+		break;
+	default:
+		return ERROR_FLASH_OPER_UNSUPPORTED;
+	}
+
+	LOG_DEBUG("%d sectors", bank->num_sectors);
+	bank->sectors = calloc(bank->num_sectors,
+				sizeof(struct flash_sector));
+	for (i = 0; i < bank->num_sectors; i++) {
+		if (i < 4)
+			bank->sectors[i].size = 8 * 1024;
+		else if (i == 4)
+			bank->sectors[i].size = 32 * 1024;
+		else
+			bank->sectors[i].size = 64 * 1024;
+		bank->sectors[i].offset = flash_addr - bank->base;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = -1;
+
+		bank->size += bank->sectors[i].size;
+		flash_addr += bank->sectors[i].size;
+	}
+
+	return ERROR_OK;
+}
+
+static void s6e2cc_init_sector(struct flash_sector *sector, int sa)
+{
+	if (sa < 8)
+		sector->size = 8 * 1024;
+	else if (sa == 8)
+		sector->size = 32 * 1024;
+	else
+		sector->size = 64 * 1024;
+
+	sector->is_erased = -1;
+	sector->is_protected = -1;
+}
+
+static int s6e2cc_probe(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	struct fm4_flash_bank *fm4_bank = bank->driver_priv;
+	uint32_t u32_value;
+	uint32_t flash_addr = bank->base;
+	int i, retval, num_sectors, num_extra_sectors;
+
+	retval = target_read_u32(target, DFCTRLR, &u32_value);
+	if (retval != ERROR_OK)
+		return retval;
+	if (u32_value & DFCTRLR_DFE) {
+		LOG_WARNING("Dual Flash mode is not implemented.");
+		return ERROR_FLASH_OPER_UNSUPPORTED;
+	}
+
+	switch (fm4_bank->variant) {
+	case s6e2cx8:
+		num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 0;
+		break;
+	case s6e2cx9:
+		num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 12;
+		break;
+	case s6e2cxa:
+		num_sectors = 20;
+		break;
+	default:
+		return ERROR_FLASH_OPER_UNSUPPORTED;
+	}
+	num_extra_sectors = (fm4_bank->macro_nr == 0) ? 1 : 4;
+	bank->num_sectors = num_sectors + num_extra_sectors;
+
+	LOG_DEBUG("%d sectors", bank->num_sectors);
+	bank->sectors = calloc(bank->num_sectors,
+				sizeof(struct flash_sector));
+	for (i = 0; i < num_sectors; i++) {
+		int sa = 4 + i;
+		bank->sectors[i].offset = flash_addr - bank->base;
+		s6e2cc_init_sector(&bank->sectors[i], sa);
+
+		bank->size += bank->sectors[i].size;
+		flash_addr += bank->sectors[i].size;
+	}
+
+	flash_addr = (fm4_bank->macro_nr == 0) ? 0x00406000 : 0x00408000;
+	for (; i < bank->num_sectors; i++) {
+		int sa = 4 - num_extra_sectors + (i - num_sectors);
+		bank->sectors[i].offset = flash_addr - bank->base;
+		s6e2cc_init_sector(&bank->sectors[i], sa);
+
+		/*
+		 * Don't increase bank->size for these sectors
+		 * to avoid an overlap between Flash Macros #0 and #1.
+		 */
+		flash_addr += bank->sectors[i].size;
+	}
+
+	return ERROR_OK;
+}
+
+static int s6e2dh_probe(struct flash_bank *bank)
+{
+	uint32_t flash_addr = bank->base;
+	int i;
+
+	bank->num_sectors = 10;
+	bank->sectors = calloc(bank->num_sectors,
+				sizeof(struct flash_sector));
+	for (i = 0; i < bank->num_sectors; i++) {
+		if (i < 4)
+			bank->sectors[i].size = 8 * 1024;
+		else if (i == 4)
+			bank->sectors[i].size = 32 * 1024;
+		else
+			bank->sectors[i].size = 64 * 1024;
+		bank->sectors[i].offset = flash_addr - bank->base;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = -1;
+
+		bank->size += bank->sectors[i].size;
+		flash_addr += bank->sectors[i].size;
+	}
+
+	return ERROR_OK;
+}
+
+static int fm4_probe(struct flash_bank *bank)
+{
+	struct fm4_flash_bank *fm4_bank = bank->driver_priv;
+	int retval;
+
+	if (fm4_bank->probed)
+		return ERROR_OK;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	switch (fm4_bank->variant) {
+	case mb9bfx64:
+	case mb9bfx65:
+	case mb9bfx66:
+	case mb9bfx67:
+	case mb9bfx68:
+		retval = mb9bf_probe(bank);
+		break;
+	case s6e2cx8:
+	case s6e2cx9:
+	case s6e2cxa:
+		retval = s6e2cc_probe(bank);
+		break;
+	case s6e2dx:
+		retval = s6e2dh_probe(bank);
+		break;
+	default:
+		return ERROR_FLASH_OPER_UNSUPPORTED;
+	}
+	if (retval != ERROR_OK)
+		return retval;
+
+	fm4_bank->probed = true;
+
+	return ERROR_OK;
+}
+
+static int fm4_auto_probe(struct flash_bank *bank)
+{
+	struct fm4_flash_bank *fm4_bank = bank->driver_priv;
+
+	if (fm4_bank->probed)
+		return ERROR_OK;
+
+	return fm4_probe(bank);
+}
+
+static int fm4_protect_check(struct flash_bank *bank)
+{
+	return ERROR_OK;
+}
+
+static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
+{
+	struct fm4_flash_bank *fm4_bank = bank->driver_priv;
+	const char *name;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	switch (fm4_bank->variant) {
+	case mb9bfx64:
+		name = "MB9BFx64";
+		break;
+	case mb9bfx65:
+		name = "MB9BFx65";
+		break;
+	case mb9bfx66:
+		name = "MB9BFx66";
+		break;
+	case mb9bfx67:
+		name = "MB9BFx67";
+		break;
+	case mb9bfx68:
+		name = "MB9BFx68";
+		break;
+	case s6e2cx8:
+		name = "S6E2Cx8";
+		break;
+	case s6e2cx9:
+		name = "S6E2Cx9";
+		break;
+	case s6e2cxa:
+		name = "S6E2CxA";
+		break;
+	case s6e2dx:
+		name = "S6E2Dx";
+		break;
+	default:
+		name = "unknown";
+		break;
+	}
+
+	switch (fm4_bank->variant) {
+	case s6e2cx8:
+	case s6e2cx9:
+	case s6e2cxa:
+		snprintf(buf, buf_size, "%s MainFlash Macro #%i",
+			name, fm4_bank->macro_nr);
+		break;
+	default:
+		snprintf(buf, buf_size, "%s MainFlash", name);
+		break;
+	}
+
+	return ERROR_OK;
+}
+
+static bool fm4_name_match(const char *s, const char *pattern)
+{
+	int i = 0;
+
+	while (s[i]) {
+		/* If the match string is shorter, ignore excess */
+		if (!pattern[i])
+			return true;
+		/* Use x as wildcard */
+		if (pattern[i] != 'x' && tolower(s[i]) != tolower(pattern[i]))
+			return false;
+		i++;
+	}
+	return true;
+}
+
+static int mb9bf_bank_setup(struct flash_bank *bank, const char *variant)
+{
+	struct fm4_flash_bank *fm4_bank = bank->driver_priv;
+
+	if (fm4_name_match(variant, "MB9BFx64")) {
+		fm4_bank->variant = mb9bfx64;
+	} else if (fm4_name_match(variant, "MB9BFx65")) {
+		fm4_bank->variant = mb9bfx65;
+	} else if (fm4_name_match(variant, "MB9BFx66")) {
+		fm4_bank->variant = mb9bfx66;
+	} else if (fm4_name_match(variant, "MB9BFx67")) {
+		fm4_bank->variant = mb9bfx67;
+	} else if (fm4_name_match(variant, "MB9BFx68")) {
+		fm4_bank->variant = mb9bfx68;
+	} else {
+		LOG_WARNING("MB9BF variant %s not recognized.", variant);
+		return ERROR_FLASH_OPER_UNSUPPORTED;
+	}
+
+	return ERROR_OK;
+}
+
+static int s6e2cc_bank_setup(struct flash_bank *bank, const char *variant)
+{
+	struct fm4_flash_bank *fm4_bank = bank->driver_priv;
+
+	if (fm4_name_match(variant, "S6E2Cx8")) {
+		fm4_bank->variant = s6e2cx8;
+	} else if (fm4_name_match(variant, "S6E2Cx9")) {
+		fm4_bank->variant = s6e2cx9;
+	} else if (fm4_name_match(variant, "S6E2CxA")) {
+		fm4_bank->variant = s6e2cxa;
+	} else {
+		LOG_WARNING("S6E2CC variant %s not recognized.", variant);
+		return ERROR_FLASH_OPER_UNSUPPORTED;
+	}
+
+	return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(fm4_flash_bank_command)
+{
+	struct fm4_flash_bank *fm4_bank;
+	const char *variant;
+	int ret;
+
+	if (CMD_ARGC < 7)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	variant = CMD_ARGV[6];
+
+	fm4_bank = malloc(sizeof(struct fm4_flash_bank));
+	if (!fm4_bank)
+		return ERROR_FLASH_OPERATION_FAILED;
+
+	fm4_bank->probed = false;
+	fm4_bank->macro_nr = (bank->base == 0x00000000) ? 0 : 1;
+
+	bank->driver_priv = fm4_bank;
+
+	if (fm4_name_match(variant, "MB9BF"))
+		ret = mb9bf_bank_setup(bank, variant);
+	else if (fm4_name_match(variant, "S6E2Cx"))
+		ret = s6e2cc_bank_setup(bank, variant);
+	else if (fm4_name_match(variant, "S6E2Dx")) {
+		fm4_bank->variant = s6e2dx;
+		ret = ERROR_OK;
+	} else {
+		LOG_WARNING("Family %s not recognized.", variant);
+		ret = ERROR_FLASH_OPER_UNSUPPORTED;
+	}
+	if (ret != ERROR_OK)
+		free(fm4_bank);
+	return ret;
+}
+
+static const struct command_registration fm4_exec_command_handlers[] = {
+	COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration fm4_command_handlers[] = {
+	{
+		.name = "fm4",
+		.mode = COMMAND_ANY,
+		.help = "fm4 flash command group",
+		.usage = "",
+		.chain = fm4_exec_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver fm4_flash = {
+	.name = "fm4",
+	.commands = fm4_command_handlers,
+	.flash_bank_command = fm4_flash_bank_command,
+	.info = fm4_get_info_command,
+	.probe = fm4_probe,
+	.auto_probe = fm4_auto_probe,
+	.protect_check = fm4_protect_check,
+	.read = default_flash_read,
+	.erase = fm4_flash_erase,
+	.erase_check = default_flash_blank_check,
+	.write = fm4_flash_write,
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/imp.h
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/imp.h b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/imp.h
new file mode 100755
index 0000000..31d0984
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/imp.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *   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.           *
+ ***************************************************************************/
+
+#ifndef FLASH_NOR_IMP_H
+#define FLASH_NOR_IMP_H
+
+/* this is an internal header */
+#include "core.h"
+#include "driver.h"
+/* almost all drivers will need this file */
+#include <target/target.h>
+
+/**
+ * Adds a new NOR bank to the global list of banks.
+ * @param bank The bank that should be added.
+ */
+void flash_bank_add(struct flash_bank *bank);
+
+/**
+ * @return The first bank in the global list.
+ */
+struct flash_bank *flash_bank_list(void);
+
+int flash_driver_erase(struct flash_bank *bank, int first, int last);
+int flash_driver_protect(struct flash_bank *bank, int set, int first, int last);
+int flash_driver_write(struct flash_bank *bank,
+		uint8_t *buffer, uint32_t offset, uint32_t count);
+int flash_driver_read(struct flash_bank *bank,
+		uint8_t *buffer, uint32_t offset, uint32_t count);
+
+/* write (optional verify) an image to flash memory of the given target */
+int flash_write_unlock(struct target *target, struct image *image,
+		uint32_t *written, int erase, bool unlock);
+
+#endif /* FLASH_NOR_IMP_H */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/jtagspi.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/jtagspi.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/jtagspi.c
new file mode 100755
index 0000000..1e623a7
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/jtagspi.c
@@ -0,0 +1,411 @@
+/***************************************************************************
+ *   Copyright (C) 2015 Robert Jordens <jo...@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.                          *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <jtag/jtag.h>
+#include <flash/nor/spi.h>
+#include <helper/time_support.h>
+
+#define JTAGSPI_MAX_TIMEOUT 3000
+
+
+struct jtagspi_flash_bank {
+	struct jtag_tap *tap;
+	const struct flash_device *dev;
+	int probed;
+	uint32_t ir;
+	uint32_t dr_len;
+};
+
+FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
+{
+	struct jtagspi_flash_bank *info;
+
+	if (CMD_ARGC < 8)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	info = malloc(sizeof(struct jtagspi_flash_bank));
+	if (info == NULL) {
+		LOG_ERROR("no memory for flash bank info");
+		return ERROR_FAIL;
+	}
+	bank->driver_priv = info;
+
+	info->tap = NULL;
+	info->probed = 0;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->dr_len);
+
+	return ERROR_OK;
+}
+
+static void jtagspi_set_ir(struct flash_bank *bank)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+	struct scan_field field;
+	uint8_t buf[4];
+
+	if (buf_get_u32(info->tap->cur_instr, 0, info->tap->ir_length) == info->ir)
+		return;
+
+	LOG_DEBUG("loading jtagspi ir");
+	buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
+	field.num_bits = info->tap->ir_length;
+	field.out_value = buf;
+	field.in_value = NULL;
+	jtag_add_ir_scan(info->tap, &field, TAP_IDLE);
+}
+
+static void flip_u8(uint8_t *in, uint8_t *out, int len)
+{
+	for (int i = 0; i < len; i++)
+		out[i] = flip_u32(in[i], 8);
+}
+
+static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
+		uint32_t *addr, uint8_t *data, int len)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+	struct scan_field fields[3];
+	uint8_t cmd_buf[4];
+	uint8_t *data_buf;
+	int is_read, lenb, n;
+
+	/* LOG_DEBUG("cmd=0x%02x len=%i", cmd, len); */
+
+	n = 0;
+	fields[n].num_bits = 8;
+	cmd_buf[0] = cmd;
+	if (addr) {
+		h_u24_to_be(cmd_buf + 1, *addr);
+		fields[n].num_bits += 24;
+	}
+	flip_u8(cmd_buf, cmd_buf, 4);
+	fields[n].out_value = cmd_buf;
+	fields[n].in_value = NULL;
+	n++;
+
+	is_read = (len < 0);
+	if (is_read)
+		len = -len;
+	lenb = DIV_ROUND_UP(len, 8);
+	data_buf = malloc(lenb);
+	if (lenb > 0) {
+		if (data_buf == NULL) {
+			LOG_ERROR("no memory for spi buffer");
+			return ERROR_FAIL;
+		}
+		if (is_read) {
+			fields[n].num_bits = info->dr_len;
+			fields[n].out_value = NULL;
+			fields[n].in_value = NULL;
+			n++;
+			fields[n].out_value = NULL;
+			fields[n].in_value = data_buf;
+		} else {
+			flip_u8(data, data_buf, lenb);
+			fields[n].out_value = data_buf;
+			fields[n].in_value = NULL;
+		}
+		fields[n].num_bits = len;
+		n++;
+	}
+
+	jtagspi_set_ir(bank);
+	jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
+	jtag_execute_queue();
+
+	if (is_read)
+		flip_u8(data_buf, data, lenb);
+	free(data_buf);
+	return ERROR_OK;
+}
+
+static int jtagspi_probe(struct flash_bank *bank)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+	struct flash_sector *sectors;
+	uint8_t in_buf[3];
+	uint32_t id;
+
+	if (info->probed)
+		free(bank->sectors);
+	info->probed = 0;
+
+	if (bank->target->tap == NULL) {
+		LOG_ERROR("Target has no JTAG tap");
+		return ERROR_FAIL;
+	}
+	info->tap = bank->target->tap;
+
+	jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, in_buf, -24);
+	/* the table in spi.c has the manufacturer byte (first) as the lsb */
+	id = le_to_h_u24(in_buf);
+
+	info->dev = NULL;
+	for (const struct flash_device *p = flash_devices; p->name ; p++)
+		if (p->device_id == id) {
+			info->dev = p;
+			break;
+		}
+
+	if (!(info->dev)) {
+		LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
+		return ERROR_FAIL;
+	}
+
+	LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
+		info->dev->name, info->dev->device_id);
+
+	/* Set correct size value */
+	bank->size = info->dev->size_in_bytes;
+
+	/* create and fill sectors array */
+	bank->num_sectors =
+		info->dev->size_in_bytes / info->dev->sectorsize;
+	sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+	if (sectors == NULL) {
+		LOG_ERROR("not enough memory");
+		return ERROR_FAIL;
+	}
+
+	for (int sector = 0; sector < bank->num_sectors; sector++) {
+		sectors[sector].offset = sector * info->dev->sectorsize;
+		sectors[sector].size = info->dev->sectorsize;
+		sectors[sector].is_erased = -1;
+		sectors[sector].is_protected = 0;
+	}
+
+	bank->sectors = sectors;
+	info->probed = 1;
+	return ERROR_OK;
+}
+
+static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
+{
+	uint8_t buf;
+	jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8);
+	*status = buf;
+	/* LOG_DEBUG("status=0x%08" PRIx32, *status); */
+}
+
+static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
+{
+	uint32_t status;
+	long long t0 = timeval_ms();
+	long long dt;
+
+	do {
+		dt = timeval_ms() - t0;
+		jtagspi_read_status(bank, &status);
+		if ((status & SPIFLASH_BSY_BIT) == 0) {
+			LOG_DEBUG("waited %lld ms", dt);
+			return ERROR_OK;
+		}
+		alive_sleep(1);
+	} while (dt <= timeout_ms);
+
+	LOG_ERROR("timeout, device still busy");
+	return ERROR_FAIL;
+}
+
+static int jtagspi_write_enable(struct flash_bank *bank)
+{
+	uint32_t status;
+
+	jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0);
+	jtagspi_read_status(bank, &status);
+	if ((status & SPIFLASH_WE_BIT) == 0) {
+		LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
+		return ERROR_FAIL;
+	}
+	return ERROR_OK;
+}
+
+static int jtagspi_bulk_erase(struct flash_bank *bank)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+	int retval;
+	long long t0 = timeval_ms();
+
+	retval = jtagspi_write_enable(bank);
+	if (retval != ERROR_OK)
+		return retval;
+	jtagspi_cmd(bank, info->dev->chip_erase_cmd, NULL, NULL, 0);
+	retval = jtagspi_wait(bank, bank->num_sectors*JTAGSPI_MAX_TIMEOUT);
+	LOG_INFO("took %lld ms", timeval_ms() - t0);
+	return retval;
+}
+
+static int jtagspi_sector_erase(struct flash_bank *bank, int sector)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+	int retval;
+	long long t0 = timeval_ms();
+
+	retval = jtagspi_write_enable(bank);
+	if (retval != ERROR_OK)
+		return retval;
+	jtagspi_cmd(bank, info->dev->erase_cmd, &bank->sectors[sector].offset, NULL, 0);
+	retval = jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT);
+	LOG_INFO("sector %d took %lld ms", sector, timeval_ms() - t0);
+	return retval;
+}
+
+static int jtagspi_erase(struct flash_bank *bank, int first, int last)
+{
+	int sector;
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+	int retval = ERROR_OK;
+
+	LOG_DEBUG("erase from sector %d to sector %d", first, last);
+
+	if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
+		LOG_ERROR("Flash sector invalid");
+		return ERROR_FLASH_SECTOR_INVALID;
+	}
+
+	if (!(info->probed)) {
+		LOG_ERROR("Flash bank not probed");
+		return ERROR_FLASH_BANK_NOT_PROBED;
+	}
+
+	for (sector = first; sector <= last; sector++) {
+		if (bank->sectors[sector].is_protected) {
+			LOG_ERROR("Flash sector %d protected", sector);
+			return ERROR_FAIL;
+		}
+	}
+
+	if (first == 0 && last == (bank->num_sectors - 1)
+		&& info->dev->chip_erase_cmd != info->dev->erase_cmd) {
+		LOG_DEBUG("Trying bulk erase.");
+		retval = jtagspi_bulk_erase(bank);
+		if (retval == ERROR_OK)
+			return retval;
+		else
+			LOG_WARNING("Bulk flash erase failed. Falling back to sector erase.");
+	}
+
+	for (sector = first; sector <= last; sector++) {
+		retval = jtagspi_sector_erase(bank, sector);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Sector erase failed.");
+			break;
+		}
+	}
+
+	return retval;
+}
+
+static int jtagspi_protect(struct flash_bank *bank, int set, int first, int last)
+{
+	int sector;
+
+	if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
+		LOG_ERROR("Flash sector invalid");
+		return ERROR_FLASH_SECTOR_INVALID;
+	}
+
+	for (sector = first; sector <= last; sector++)
+		bank->sectors[sector].is_protected = set;
+	return ERROR_OK;
+}
+
+static int jtagspi_protect_check(struct flash_bank *bank)
+{
+	return ERROR_OK;
+}
+
+static int jtagspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+
+	if (!(info->probed)) {
+		LOG_ERROR("Flash bank not yet probed.");
+		return ERROR_FLASH_BANK_NOT_PROBED;
+	}
+
+	jtagspi_cmd(bank, SPIFLASH_READ, &offset, buffer, -count*8);
+	return ERROR_OK;
+}
+
+static int jtagspi_page_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+	int retval;
+
+	retval = jtagspi_write_enable(bank);
+	if (retval != ERROR_OK)
+		return retval;
+	jtagspi_cmd(bank, SPIFLASH_PAGE_PROGRAM, &offset, (uint8_t *) buffer, count*8);
+	return jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT);
+}
+
+static int jtagspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+	int retval;
+	uint32_t n;
+
+	if (!(info->probed)) {
+		LOG_ERROR("Flash bank not yet probed.");
+		return ERROR_FLASH_BANK_NOT_PROBED;
+	}
+
+	for (n = 0; n < count; n += info->dev->pagesize) {
+		retval = jtagspi_page_write(bank, buffer + n, offset + n,
+				MIN(count - n, info->dev->pagesize));
+		if (retval != ERROR_OK) {
+			LOG_ERROR("page write error");
+			return retval;
+		}
+		LOG_DEBUG("wrote page at 0x%08" PRIx32, offset + n);
+	}
+	return ERROR_OK;
+}
+
+static int jtagspi_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+	struct jtagspi_flash_bank *info = bank->driver_priv;
+
+	if (!(info->probed)) {
+		snprintf(buf, buf_size, "\nJTAGSPI flash bank not probed yet\n");
+		return ERROR_OK;
+	}
+
+	snprintf(buf, buf_size, "\nSPIFI flash information:\n"
+		"  Device \'%s\' (ID 0x%08" PRIx32 ")\n",
+		info->dev->name, info->dev->device_id);
+
+	return ERROR_OK;
+}
+
+struct flash_driver jtagspi_flash = {
+	.name = "jtagspi",
+	.flash_bank_command = jtagspi_flash_bank_command,
+	.erase = jtagspi_erase,
+	.protect = jtagspi_protect,
+	.write = jtagspi_write,
+	.read = jtagspi_read,
+	.probe = jtagspi_probe,
+	.auto_probe = jtagspi_probe,
+	.erase_check = default_flash_blank_check,
+	.protect_check = jtagspi_protect_check,
+	.info = jtagspi_info
+};