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

[18/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/ocl.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/ocl.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/ocl.c
new file mode 100755
index 0000000..c547d9a
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/ocl.c
@@ -0,0 +1,345 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Pavel Chromy                                    *
+ *   chromy@asix.cz                                                        *
+ *                                                                         *
+ *   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 "ocl.h"
+#include <target/embeddedice.h>
+
+struct ocl_priv {
+	struct arm_jtag *jtag_info;
+	unsigned int buflen;
+	unsigned int bufalign;
+};
+
+static int ocl_erase_check(struct flash_bank *bank)
+{
+	return ERROR_OK;
+}
+
+static int ocl_protect_check(struct flash_bank *bank)
+{
+	return ERROR_OK;
+}
+
+/* flash_bank ocl 0 0 0 0 <target#> */
+FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
+{
+	struct arm7_9_common *arm7_9;
+	struct ocl_priv *ocl;
+
+	if (CMD_ARGC < 6)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	arm7_9 = target_to_arm7_9(bank->target);
+	if (!is_arm7_9(arm7_9))
+		return ERROR_TARGET_INVALID;
+
+	ocl = bank->driver_priv = malloc(sizeof(struct ocl_priv));
+	ocl->jtag_info = &arm7_9->jtag_info;
+	ocl->buflen = 0;
+	ocl->bufalign = 1;
+
+	return ERROR_OK;
+}
+
+static int ocl_erase(struct flash_bank *bank, int first, int last)
+{
+	struct ocl_priv *ocl = bank->driver_priv;
+	int retval;
+	uint32_t dcc_buffer[3];
+
+	/* check preconditions */
+	if (bank->num_sectors == 0)
+		return ERROR_FLASH_BANK_NOT_PROBED;
+
+	if (bank->target->state != TARGET_RUNNING) {
+		LOG_ERROR("target has to be running to communicate with the loader");
+		return ERROR_TARGET_NOT_RUNNING;
+	}
+
+	if ((first == 0) && (last == bank->num_sectors - 1)) {
+		dcc_buffer[0] = OCL_ERASE_ALL;
+		retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1);
+		if (retval != ERROR_OK)
+			return retval;
+	} else {
+		dcc_buffer[0] = OCL_ERASE_BLOCK;
+		dcc_buffer[1] = first;
+		dcc_buffer[2] = last;
+		retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3);
+		if (retval != ERROR_OK)
+			return retval;
+	}
+
+	/* wait for response, fixed timeout of 1 s */
+	retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* receive response */
+	retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1);
+	if (retval != ERROR_OK)
+		return retval;
+
+	if (dcc_buffer[1] != OCL_CMD_DONE) {
+		if (dcc_buffer[0] == OCL_ERASE_ALL)
+			LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]);
+		else
+			LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]);
+		return ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	return ERROR_OK;
+}
+
+static int ocl_protect(struct flash_bank *bank, int set, int first, int last)
+{
+	return ERROR_OK;
+}
+
+static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+	struct ocl_priv *ocl = bank->driver_priv;
+	int retval;
+	uint32_t *dcc_buffer;
+	uint32_t *dcc_bufptr;
+	int byteofs;
+	int runlen;
+	uint32_t chksum;
+
+	int i;
+
+	/* check preconditions */
+	if (ocl->buflen == 0 || ocl->bufalign == 0)
+		return ERROR_FLASH_BANK_NOT_PROBED;
+
+	if (bank->target->state != TARGET_RUNNING) {
+		LOG_ERROR("target has to be running to communicate with the loader");
+		return ERROR_TARGET_NOT_RUNNING;
+	}
+
+	/* allocate buffer for max. ocl buffer + overhead */
+	dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3));
+
+	while (count) {
+		if (count + (offset % ocl->bufalign) > ocl->buflen)
+			runlen = ocl->buflen - (offset % ocl->bufalign);
+		else
+			runlen = count;
+
+		dcc_buffer[0] = OCL_FLASH_BLOCK | runlen;
+		dcc_buffer[1] = offset;
+		dcc_bufptr = &dcc_buffer[2];
+
+		*dcc_bufptr = 0xffffffff;
+		byteofs = (offset % ocl->bufalign) % 4;
+		chksum = OCL_CHKS_INIT;
+
+		/* copy data to DCC buffer in proper byte order and properly aligned */
+		for (i = 0; i < runlen; i++) {
+			switch (byteofs++) {
+				case 0:
+					*dcc_bufptr &= *(buffer++) | 0xffffff00;
+					break;
+				case 1:
+					*dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff;
+					break;
+				case 2:
+					*dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff;
+					break;
+				case 3:
+					*dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff;
+					chksum ^= *(dcc_bufptr++);
+					*dcc_bufptr = 0xffffffff;
+					byteofs = 0;
+					break;
+			}
+		}
+
+		/* add the remaining word to checksum */
+		if (byteofs)
+			chksum ^= *(dcc_bufptr++);
+
+		*(dcc_bufptr++) = chksum;
+
+		/* send the data */
+		retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer);
+		if (retval != ERROR_OK) {
+			free(dcc_buffer);
+		  return retval;
+		}
+
+		/* wait for response, fixed timeout of 1 s */
+		retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000);
+		if (retval != ERROR_OK) {
+			free(dcc_buffer);
+			return retval;
+		}
+
+		/* receive response */
+		retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+		if (retval != ERROR_OK) {
+			free(dcc_buffer);
+			return retval;
+		}
+
+		if (dcc_buffer[0] != OCL_CMD_DONE) {
+			LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]);
+			free(dcc_buffer);
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+
+		count -= runlen;
+		offset += runlen;
+	}
+
+	free(dcc_buffer);
+	return ERROR_OK;
+}
+
+static int ocl_probe(struct flash_bank *bank)
+{
+	struct ocl_priv *ocl = bank->driver_priv;
+	int retval;
+	uint32_t dcc_buffer[1];
+	int sectsize;
+	int i;
+
+	/* purge pending data in DCC */
+	embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+
+	dcc_buffer[0] = OCL_PROBE;
+	retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* wait for response, fixed timeout of 1 s */
+	retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000);
+	if (retval != ERROR_OK)
+		return retval;
+
+	/* receive response */
+	retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+	if (retval != ERROR_OK)
+		return retval;
+
+	if (dcc_buffer[0] != OCL_CMD_DONE) {
+		LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]);
+		return ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	/* receive and fill in parameters, detection of loader is important, receive it one by one */
+	retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
+	if (retval != ERROR_OK)
+		return retval;
+	retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+	if (retval != ERROR_OK)
+		return retval;
+	bank->base = dcc_buffer[0];
+
+	retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
+	if (retval != ERROR_OK)
+		return retval;
+	retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+	if (retval != ERROR_OK)
+		return retval;
+	bank->size = dcc_buffer[0];
+
+	retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
+	if (retval != ERROR_OK)
+		return retval;
+	retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+	if (retval != ERROR_OK)
+		return retval;
+	bank->num_sectors = dcc_buffer[0];
+
+	retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
+	if (retval != ERROR_OK)
+		return retval;
+	retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+	if (retval != ERROR_OK)
+		return retval;
+	ocl->buflen = dcc_buffer[0] & 0xffff;
+	ocl->bufalign = dcc_buffer[0] >> 16;
+
+	bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors);
+	if (bank->num_sectors == 0) {
+		LOG_ERROR("number of sectors shall be non zero value");
+		return ERROR_FLASH_BANK_INVALID;
+	}
+	if (bank->size % bank->num_sectors) {
+		LOG_ERROR("bank size not divisible by number of sectors");
+		return ERROR_FLASH_BANK_INVALID;
+	}
+	sectsize = bank->size / bank->num_sectors;
+	for (i = 0; i < bank->num_sectors; i++) {
+		bank->sectors[i].offset = i * sectsize;
+		bank->sectors[i].size = sectsize;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = -1;
+	}
+
+	if (ocl->bufalign == 0)
+		ocl->bufalign = 1;
+
+	if (ocl->buflen == 0) {
+		LOG_ERROR("buflen shall be non zero value");
+		return ERROR_FLASH_BANK_INVALID;
+	}
+
+	if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign)) {
+		LOG_ERROR("buflen is not multiple of bufalign");
+		return ERROR_FLASH_BANK_INVALID;
+	}
+
+	if (ocl->buflen % 4) {
+		LOG_ERROR("buflen shall be divisible by 4");
+		return ERROR_FLASH_BANK_INVALID;
+	}
+
+	return ERROR_OK;
+}
+
+static int ocl_auto_probe(struct flash_bank *bank)
+{
+	struct ocl_priv *ocl = bank->driver_priv;
+
+	if (ocl->buflen == 0 || ocl->bufalign == 0)
+		return ERROR_FLASH_BANK_NOT_PROBED;
+
+	return ERROR_OK;
+}
+
+struct flash_driver ocl_flash = {
+	.name = "ocl",
+	.flash_bank_command = ocl_flash_bank_command,
+	.erase = ocl_erase,
+	.protect = ocl_protect,
+	.write = ocl_write,
+	.read = default_flash_read,
+	.probe = ocl_probe,
+	.erase_check = ocl_erase_check,
+	.protect_check = ocl_protect_check,
+	.auto_probe = ocl_auto_probe,
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/ocl.h
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/ocl.h b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/ocl.h
new file mode 100755
index 0000000..d056b46
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/ocl.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Pavel Chromy                                    *
+ *   chromy@asix.cz                                                        *
+ *                                                                         *
+ *   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 OCL_H
+#define OCL_H
+
+/* command/response mask */
+#define OCL_CMD_MASK 0xFFFF0000L
+
+/* commads */
+#define OCL_FLASH_BLOCK 0x0CFB0000L
+#define OCL_ERASE_BLOCK 0x0CEB0000L
+#define OCL_ERASE_ALL 0x0CEA0000L
+#define OCL_PROBE 0x0CBE0000L
+
+/* responses */
+#define OCL_CMD_DONE 0x0ACD0000L
+#define OCL_CMD_ERR 0x0ACE0000L
+#define OCL_CHKS_FAIL 0x0ACF0000L
+#define OCL_BUFF_OVER 0x0AB00000L
+
+#define OCL_CHKS_INIT 0xC100CD0CL
+
+#endif /* OCL_H */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/pic32mx.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/pic32mx.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/pic32mx.c
new file mode 100755
index 0000000..ce5bffb
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/pic32mx.c
@@ -0,0 +1,936 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   Copyright (C) 2008 by John McCarthy                                   *
+ *   jgmcc@magma.ca                                                        *
+ *                                                                         *
+ *   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 <jtag/jtag.h>
+#include "imp.h"
+#include <target/algorithm.h>
+#include <target/mips32.h>
+#include <target/mips_m4k.h>
+
+#define PIC32MX_MANUF_ID	0x029
+
+/* pic32mx memory locations */
+
+#define PIC32MX_PHYS_RAM			0x00000000
+#define PIC32MX_PHYS_PGM_FLASH		0x1D000000
+#define PIC32MX_PHYS_PERIPHERALS	0x1F800000
+#define PIC32MX_PHYS_BOOT_FLASH		0x1FC00000
+
+/*
+ * Translate Virtual and Physical addresses.
+ * Note: These macros only work for KSEG0/KSEG1 addresses.
+ */
+
+#define Virt2Phys(v)	((v) & 0x1FFFFFFF)
+
+/* pic32mx configuration register locations */
+
+#define PIC32MX_DEVCFG0_1_2	0xBFC00BFC
+#define PIC32MX_DEVCFG0		0xBFC02FFC
+#define PIC32MX_DEVCFG1		0xBFC02FF8
+#define PIC32MX_DEVCFG2		0xBFC02FF4
+#define PIC32MX_DEVCFG3		0xBFC02FF0
+#define PIC32MX_DEVID		0xBF80F220
+
+#define PIC32MX_BMXPFMSZ	0xBF882060
+#define PIC32MX_BMXBOOTSZ	0xBF882070
+#define PIC32MX_BMXDRMSZ	0xBF882040
+
+/* pic32mx flash controller register locations */
+
+#define PIC32MX_NVMCON		0xBF80F400
+#define PIC32MX_NVMCONCLR	0xBF80F404
+#define PIC32MX_NVMCONSET	0xBF80F408
+#define PIC32MX_NVMCONINV	0xBF80F40C
+#define NVMCON_NVMWR		(1 << 15)
+#define NVMCON_NVMWREN		(1 << 14)
+#define NVMCON_NVMERR		(1 << 13)
+#define NVMCON_LVDERR		(1 << 12)
+#define NVMCON_LVDSTAT		(1 << 11)
+#define NVMCON_OP_PFM_ERASE		0x5
+#define NVMCON_OP_PAGE_ERASE	0x4
+#define NVMCON_OP_ROW_PROG		0x3
+#define NVMCON_OP_WORD_PROG		0x1
+#define NVMCON_OP_NOP			0x0
+
+#define PIC32MX_NVMKEY		0xBF80F410
+#define PIC32MX_NVMADDR		0xBF80F420
+#define PIC32MX_NVMADDRCLR	0xBF80F424
+#define PIC32MX_NVMADDRSET	0xBF80F428
+#define PIC32MX_NVMADDRINV	0xBF80F42C
+#define PIC32MX_NVMDATA		0xBF80F430
+#define PIC32MX_NVMSRCADDR	0xBF80F440
+
+/* flash unlock keys */
+
+#define NVMKEY1			0xAA996655
+#define NVMKEY2			0x556699AA
+
+#define MX_1_2			1	/* PIC32mx1xx/2xx */
+
+struct pic32mx_flash_bank {
+	int probed;
+	int dev_type;		/* Default 0. 1 for Pic32MX1XX/2XX variant */
+};
+
+/*
+ * DEVID values as per PIC32MX Flash Programming Specification Rev J
+ */
+
+static const struct pic32mx_devs_s {
+	uint32_t devid;
+	const char *name;
+} pic32mx_devs[] = {
+	{0x04A07053, "110F016B"},
+	{0x04A09053, "110F016C"},
+	{0x04A0B053, "110F016D"},
+	{0x04A06053, "120F032B"},
+	{0x04A08053, "120F032C"},
+	{0x04A0A053, "120F032D"},
+	{0x04D07053, "130F064B"},
+	{0x04D09053, "130F064C"},
+	{0x04D0B053, "130F064D"},
+	{0x04D06053, "150F128B"},
+	{0x04D08053, "150F128C"},
+	{0x04D0A053, "150F128D"},
+	{0x04A01053, "210F016B"},
+	{0x04A03053, "210F016C"},
+	{0x04A05053, "210F016D"},
+	{0x04A00053, "220F032B"},
+	{0x04A02053, "220F032C"},
+	{0x04A04053, "220F032D"},
+	{0x04D01053, "230F064B"},
+	{0x04D03053, "230F064C"},
+	{0x04D05053, "230F064D"},
+	{0x04D00053, "250F128B"},
+	{0x04D02053, "250F128C"},
+	{0x04D04053, "250F128D"},
+	{0x00938053, "360F512L"},
+	{0x00934053, "360F256L"},
+	{0x0092D053, "340F128L"},
+	{0x0092A053, "320F128L"},
+	{0x00916053, "340F512H"},
+	{0x00912053, "340F256H"},
+	{0x0090D053, "340F128H"},
+	{0x0090A053, "320F128H"},
+	{0x00906053, "320F064H"},
+	{0x00902053, "320F032H"},
+	{0x00978053, "460F512L"},
+	{0x00974053, "460F256L"},
+	{0x0096D053, "440F128L"},
+	{0x00952053, "440F256H"},
+	{0x00956053, "440F512H"},
+	{0x0094D053, "440F128H"},
+	{0x00942053, "420F032H"},
+	{0x04307053, "795F512L"},
+	{0x0430E053, "795F512H"},
+	{0x04306053, "775F512L"},
+	{0x0430D053, "775F512H"},
+	{0x04312053, "775F256L"},
+	{0x04303053, "775F256H"},
+	{0x04417053, "764F128L"},
+	{0x0440B053, "764F128H"},
+	{0x04341053, "695F512L"},
+	{0x04325053, "695F512H"},
+	{0x04311053, "675F512L"},
+	{0x0430C053, "675F512H"},
+	{0x04305053, "675F256L"},
+	{0x0430B053, "675F256H"},
+	{0x04413053, "664F128L"},
+	{0x04407053, "664F128H"},
+	{0x04411053, "664F064L"},
+	{0x04405053, "664F064H"},
+	{0x0430F053, "575F512L"},
+	{0x04309053, "575F512H"},
+	{0x04333053, "575F256L"},
+	{0x04317053, "575F256H"},
+	{0x0440F053, "564F128L"},
+	{0x04403053, "564F128H"},
+	{0x0440D053, "564F064L"},
+	{0x04401053, "564F064H"},
+	{0x04400053, "534F064H"},
+	{0x0440C053, "534F064L"},
+	{0x00000000, NULL}
+};
+
+/* flash bank pic32mx <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command)
+{
+	struct pic32mx_flash_bank *pic32mx_info;
+
+	if (CMD_ARGC < 6)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank));
+	bank->driver_priv = pic32mx_info;
+
+	pic32mx_info->probed = 0;
+	pic32mx_info->dev_type = 0;
+
+	return ERROR_OK;
+}
+
+static uint32_t pic32mx_get_flash_status(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	uint32_t status;
+
+	target_read_u32(target, PIC32MX_NVMCON, &status);
+
+	return status;
+}
+
+static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+	uint32_t status;
+
+	/* wait for busy to clear */
+	while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0)) {
+		LOG_DEBUG("status: 0x%" PRIx32, status);
+		alive_sleep(1);
+	}
+	if (timeout <= 0)
+		LOG_DEBUG("timeout: status: 0x%" PRIx32, status);
+
+	return status;
+}
+
+static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout)
+{
+	struct target *target = bank->target;
+	uint32_t status;
+
+	target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op);
+
+	/* unlock flash registers */
+	target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1);
+	target_write_u32(target, PIC32MX_NVMKEY, NVMKEY2);
+
+	/* start operation */
+	target_write_u32(target, PIC32MX_NVMCONSET, NVMCON_NVMWR);
+
+	status = pic32mx_wait_status_busy(bank, timeout);
+
+	/* lock flash registers */
+	target_write_u32(target, PIC32MX_NVMCONCLR, NVMCON_NVMWREN);
+
+	return status;
+}
+
+static int pic32mx_protect_check(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
+
+	uint32_t config0_address;
+	uint32_t devcfg0;
+	int s;
+	int num_pages;
+
+	if (target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	if (pic32mx_info->dev_type == MX_1_2)
+		config0_address = PIC32MX_DEVCFG0_1_2;
+	else
+		config0_address = PIC32MX_DEVCFG0;
+
+	target_read_u32(target, config0_address, &devcfg0);
+
+	if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */
+		num_pages = 0xffff;			/* All pages protected */
+	else if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) {
+		if (devcfg0 & (1 << 24))
+			num_pages = 0;			/* All pages unprotected */
+		else
+			num_pages = 0xffff;		/* All pages protected */
+	} else {
+		/* pgm flash */
+		if (pic32mx_info->dev_type == MX_1_2)
+			num_pages = (~devcfg0 >> 10) & 0x3f;
+		else
+			num_pages = (~devcfg0 >> 12) & 0xff;
+	}
+
+	for (s = 0; s < bank->num_sectors && s < num_pages; s++)
+		bank->sectors[s].is_protected = 1;
+	for (; s < bank->num_sectors; s++)
+		bank->sectors[s].is_protected = 0;
+
+	return ERROR_OK;
+}
+
+static int pic32mx_erase(struct flash_bank *bank, int first, int last)
+{
+	struct target *target = bank->target;
+	int i;
+	uint32_t status;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	if ((first == 0) && (last == (bank->num_sectors - 1))
+		&& (Virt2Phys(bank->base) == PIC32MX_PHYS_PGM_FLASH)) {
+		/* this will only erase the Program Flash (PFM), not the Boot Flash (BFM)
+		 * we need to use the MTAP to perform a full erase */
+		LOG_DEBUG("Erasing entire program flash");
+		status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50);
+		if (status & NVMCON_NVMERR)
+			return ERROR_FLASH_OPERATION_FAILED;
+		if (status & NVMCON_LVDERR)
+			return ERROR_FLASH_OPERATION_FAILED;
+		return ERROR_OK;
+	}
+
+	for (i = first; i <= last; i++) {
+		target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(bank->base + bank->sectors[i].offset));
+
+		status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);
+
+		if (status & NVMCON_NVMERR)
+			return ERROR_FLASH_OPERATION_FAILED;
+		if (status & NVMCON_LVDERR)
+			return ERROR_FLASH_OPERATION_FAILED;
+		bank->sectors[i].is_erased = 1;
+	}
+
+	return ERROR_OK;
+}
+
+static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last)
+{
+	struct target *target = bank->target;
+
+	if (target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	return ERROR_OK;
+}
+
+/* see contib/loaders/flash/pic32mx.s for src */
+
+static uint32_t pic32mx_flash_write_code[] = {
+					/* write: */
+	0x3C08AA99,		/* lui $t0, 0xaa99 */
+	0x35086655,		/* ori $t0, 0x6655 */
+	0x3C095566,		/* lui $t1, 0x5566 */
+	0x352999AA,		/* ori $t1, 0x99aa */
+	0x3C0ABF80,		/* lui $t2, 0xbf80 */
+	0x354AF400,		/* ori $t2, 0xf400 */
+	0x340B4003,		/* ori $t3, $zero, 0x4003 */
+	0x340C8000,		/* ori $t4, $zero, 0x8000 */
+					/* write_row: */
+	0x2CD30080,		/* sltiu $s3, $a2, 128 */
+	0x16600008,		/* bne $s3, $zero, write_word */
+	0x340D4000,		/* ori $t5, $zero, 0x4000 */
+	0xAD450020,		/* sw $a1, 32($t2) */
+	0xAD440040,		/* sw $a0, 64($t2) */
+	0x04110016,		/* bal progflash */
+	0x24840200,		/* addiu $a0, $a0, 512 */
+	0x24A50200,		/* addiu $a1, $a1, 512 */
+	0x1000FFF7,		/* beq $zero, $zero, write_row */
+	0x24C6FF80,		/* addiu $a2, $a2, -128 */
+					/* write_word: */
+	0x3C15A000,		/* lui $s5, 0xa000 */
+	0x36B50000,		/* ori $s5, $s5, 0x0 */
+	0x00952025,		/* or $a0, $a0, $s5 */
+	0x10000008,		/* beq $zero, $zero, next_word */
+	0x340B4001,		/* ori $t3, $zero, 0x4001 */
+					/* prog_word: */
+	0x8C940000,		/* lw $s4, 0($a0) */
+	0xAD540030,		/* sw $s4, 48($t2) */
+	0xAD450020,		/* sw $a1, 32($t2) */
+	0x04110009,		/* bal progflash */
+	0x24840004,		/* addiu $a0, $a0, 4 */
+	0x24A50004,		/* addiu $a1, $a1, 4 */
+	0x24C6FFFF,		/* addiu $a2, $a2, -1 */
+					/* next_word: */
+	0x14C0FFF8,		/* bne $a2, $zero, prog_word */
+	0x00000000,		/* nop */
+					/* done: */
+	0x10000002,		/* beq $zero, $zero, exit */
+	0x24040000,		/* addiu $a0, $zero, 0 */
+					/* error: */
+	0x26240000,		/* addiu $a0, $s1, 0 */
+					/* exit: */
+	0x7000003F,		/* sdbbp */
+					/* progflash: */
+	0xAD4B0000,		/* sw $t3, 0($t2) */
+	0xAD480010,		/* sw $t0, 16($t2) */
+	0xAD490010,		/* sw $t1, 16($t2) */
+	0xAD4C0008,		/* sw $t4, 8($t2) */
+					/* waitflash: */
+	0x8D500000,		/* lw $s0, 0($t2) */
+	0x020C8024,		/* and $s0, $s0, $t4 */
+	0x1600FFFD,		/* bne $s0, $zero, waitflash */
+	0x00000000,		/* nop */
+	0x00000000,		/* nop */
+	0x00000000,		/* nop */
+	0x00000000,		/* nop */
+	0x00000000,		/* nop */
+	0x8D510000,		/* lw $s1, 0($t2) */
+	0x30113000,		/* andi $s1, $zero, 0x3000 */
+	0x1620FFEF,		/* bne $s1, $zero, error */
+	0xAD4D0004,		/* sw $t5, 4($t2) */
+	0x03E00008,		/* jr $ra */
+	0x00000000		/* nop */
+};
+
+static int pic32mx_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 = 16384;
+	struct working_area *write_algorithm;
+	struct working_area *source;
+	uint32_t address = bank->base + offset;
+	struct reg_param reg_params[3];
+	uint32_t row_size;
+	int retval = ERROR_OK;
+
+	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
+	struct mips32_algorithm mips32_info;
+
+	/* flash write code */
+	if (target_alloc_working_area(target, sizeof(pic32mx_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;
+	}
+
+	/* Change values for counters and row size, depending on variant */
+	if (pic32mx_info->dev_type == MX_1_2) {
+		/* 128 byte row */
+		pic32mx_flash_write_code[8] = 0x2CD30020;
+		pic32mx_flash_write_code[14] = 0x24840080;
+		pic32mx_flash_write_code[15] = 0x24A50080;
+		pic32mx_flash_write_code[17] = 0x24C6FFE0;
+		row_size = 128;
+	} else {
+		/* 512 byte row */
+		pic32mx_flash_write_code[8] = 0x2CD30080;
+		pic32mx_flash_write_code[14] = 0x24840200;
+		pic32mx_flash_write_code[15] = 0x24A50200;
+		pic32mx_flash_write_code[17] = 0x24C6FF80;
+		row_size = 512;
+	}
+
+	uint8_t code[sizeof(pic32mx_flash_write_code)];
+	target_buffer_set_u32_array(target, code, ARRAY_SIZE(pic32mx_flash_write_code),
+			pic32mx_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;
+		}
+	}
+
+	mips32_info.common_magic = MIPS32_COMMON_MAGIC;
+	mips32_info.isa_mode = MIPS32_ISA_MIPS32;
+
+	init_reg_param(&reg_params[0], "r4", 32, PARAM_IN_OUT);
+	init_reg_param(&reg_params[1], "r5", 32, PARAM_OUT);
+	init_reg_param(&reg_params[2], "r6", 32, PARAM_OUT);
+
+	int row_offset = offset % row_size;
+	uint8_t *new_buffer = NULL;
+	if (row_offset && (count >= (row_size / 4))) {
+		new_buffer = malloc(buffer_size);
+		if (new_buffer == NULL) {
+			LOG_ERROR("Out of memory");
+			return ERROR_FAIL;
+		}
+		memset(new_buffer,  0xff, row_offset);
+		address -= row_offset;
+	} else
+		row_offset = 0;
+
+	while (count > 0) {
+		uint32_t status;
+		uint32_t thisrun_count;
+
+		if (row_offset) {
+			thisrun_count = (count > ((buffer_size - row_offset) / 4)) ?
+				((buffer_size - row_offset) / 4) : count;
+
+			memcpy(new_buffer + row_offset, buffer, thisrun_count * 4);
+
+			retval = target_write_buffer(target, source->address,
+				row_offset + thisrun_count * 4, new_buffer);
+			if (retval != ERROR_OK)
+				break;
+		} else {
+			thisrun_count = (count > (buffer_size / 4)) ?
+					(buffer_size / 4) : count;
+
+			retval = target_write_buffer(target, source->address,
+					thisrun_count * 4, buffer);
+			if (retval != ERROR_OK)
+				break;
+		}
+
+		buf_set_u32(reg_params[0].value, 0, 32, Virt2Phys(source->address));
+		buf_set_u32(reg_params[1].value, 0, 32, Virt2Phys(address));
+		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count + row_offset / 4);
+
+		retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+				write_algorithm->address,
+				0, 10000, &mips32_info);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("error executing pic32mx flash write algorithm");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			break;
+		}
+
+		status = buf_get_u32(reg_params[0].value, 0, 32);
+
+		if (status & NVMCON_NVMERR) {
+			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			break;
+		}
+
+		if (status & NVMCON_LVDERR) {
+			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			break;
+		}
+
+		buffer += thisrun_count * 4;
+		address += thisrun_count * 4;
+		count -= thisrun_count;
+		if (row_offset) {
+			address += row_offset;
+			row_offset = 0;
+		}
+	}
+
+	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]);
+
+	if (new_buffer != NULL)
+		free(new_buffer);
+	return retval;
+}
+
+static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word)
+{
+	struct target *target = bank->target;
+
+	target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(address));
+	target_write_u32(target, PIC32MX_NVMDATA, word);
+
+	return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5);
+}
+
+static int pic32mx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+	uint32_t words_remaining = (count / 4);
+	uint32_t bytes_remaining = (count & 0x00000003);
+	uint32_t address = bank->base + offset;
+	uint32_t bytes_written = 0;
+	uint32_t status;
+	int retval;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	LOG_DEBUG("writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32
+			" count: 0x%8.8" PRIx32 "", bank->base, offset, count);
+
+	if (offset & 0x3) {
+		LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset);
+		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+	}
+
+	/* multiple words (4-byte) to be programmed? */
+	if (words_remaining > 0) {
+		/* try using a block write */
+		retval = pic32mx_write_block(bank, buffer, offset, words_remaining);
+		if (retval != ERROR_OK) {
+			if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+				/* if block write failed (no sufficient working area),
+				 * we use normal (slow) single dword accesses */
+				LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+			} else if (retval == ERROR_FLASH_OPERATION_FAILED) {
+				LOG_ERROR("flash writing failed");
+				return retval;
+			}
+		} else {
+			buffer += words_remaining * 4;
+			address += words_remaining * 4;
+			words_remaining = 0;
+		}
+	}
+
+	while (words_remaining > 0) {
+		uint32_t value;
+		memcpy(&value, buffer + bytes_written, sizeof(uint32_t));
+
+		status = pic32mx_write_word(bank, address, value);
+
+		if (status & NVMCON_NVMERR) {
+			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+
+		if (status & NVMCON_LVDERR) {
+			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+
+		bytes_written += 4;
+		words_remaining--;
+		address += 4;
+	}
+
+	if (bytes_remaining) {
+		uint32_t value = 0xffffffff;
+		memcpy(&value, buffer + bytes_written, bytes_remaining);
+
+		status = pic32mx_write_word(bank, address, value);
+
+		if (status & NVMCON_NVMERR) {
+			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+
+		if (status & NVMCON_LVDERR) {
+			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
+			return ERROR_FLASH_OPERATION_FAILED;
+		}
+	}
+
+	return ERROR_OK;
+}
+
+static int pic32mx_probe(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
+	struct mips32_common *mips32 = target->arch_info;
+	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+	int i;
+	uint32_t num_pages = 0;
+	uint32_t device_id;
+	int page_size;
+
+	pic32mx_info->probed = 0;
+
+	device_id = ejtag_info->idcode;
+	LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%04x, ver 0x%02x)",
+			  device_id,
+			  (unsigned)((device_id >> 1) & 0x7ff),
+			  (unsigned)((device_id >> 12) & 0xffff),
+			  (unsigned)((device_id >> 28) & 0xf));
+
+	if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) {
+		LOG_WARNING("Cannot identify target as a PIC32MX family.");
+		return ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	/* Check for PIC32mx1xx/2xx */
+	for (i = 0; pic32mx_devs[i].name != NULL; i++) {
+		if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) {
+			if ((*(pic32mx_devs[i].name) == '1') || (*(pic32mx_devs[i].name) == '2'))
+				pic32mx_info->dev_type = MX_1_2;
+			break;
+		}
+	}
+
+	if (pic32mx_info->dev_type == MX_1_2)
+		page_size = 1024;
+	else
+		page_size = 4096;
+
+
+	if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) {
+		/* 0x1FC00000: Boot flash size */
+#if 0
+		/* for some reason this register returns 8k for the boot bank size
+		 * this does not match the docs, so for now set the boot bank at a
+		 * fixed 12k */
+		if (target_read_u32(target, PIC32MX_BMXBOOTSZ, &num_pages) != ERROR_OK) {
+			LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 12k flash");
+			num_pages = (12 * 1024);
+		}
+#else
+		/* fixed 12k boot bank - see comments above */
+		if (pic32mx_info->dev_type == MX_1_2)
+			num_pages = (3 * 1024);
+		else
+			num_pages = (12 * 1024);
+#endif
+	} else {
+		/* read the flash size from the device */
+		if (target_read_u32(target, PIC32MX_BMXPFMSZ, &num_pages) != ERROR_OK) {
+			if (pic32mx_info->dev_type == MX_1_2) {
+				LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 32k flash");
+				num_pages = (32 * 1024);
+			} else {
+				LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 512k flash");
+				num_pages = (512 * 1024);
+			}
+		}
+	}
+
+	LOG_INFO("flash size = %" PRId32 "kbytes", num_pages / 1024);
+
+	if (bank->sectors) {
+		free(bank->sectors);
+		bank->sectors = NULL;
+	}
+
+	/* calculate numbers of pages */
+	num_pages /= page_size;
+	bank->size = (num_pages * page_size);
+	bank->num_sectors = num_pages;
+	bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+
+	for (i = 0; i < (int)num_pages; i++) {
+		bank->sectors[i].offset = i * page_size;
+		bank->sectors[i].size = page_size;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = 1;
+	}
+
+	pic32mx_info->probed = 1;
+
+	return ERROR_OK;
+}
+
+static int pic32mx_auto_probe(struct flash_bank *bank)
+{
+	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
+	if (pic32mx_info->probed)
+		return ERROR_OK;
+	return pic32mx_probe(bank);
+}
+
+static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+	struct target *target = bank->target;
+	struct mips32_common *mips32 = target->arch_info;
+	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+	uint32_t device_id;
+	int printed = 0, i;
+
+	device_id = ejtag_info->idcode;
+
+	if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) {
+		snprintf(buf, buf_size,
+				 "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n",
+				 (unsigned)((device_id >> 1) & 0x7ff),
+				 PIC32MX_MANUF_ID);
+		return ERROR_FLASH_OPERATION_FAILED;
+	}
+
+	for (i = 0; pic32mx_devs[i].name != NULL; i++) {
+		if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) {
+			printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);
+			break;
+		}
+	}
+
+	if (pic32mx_devs[i].name == NULL)
+		printed = snprintf(buf, buf_size, "Unknown");
+
+	buf += printed;
+	buf_size -= printed;
+	snprintf(buf, buf_size, " Ver: 0x%02x",
+			(unsigned)((device_id >> 28) & 0xf));
+
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
+{
+	uint32_t address, value;
+	int status, res;
+
+	if (CMD_ARGC != 3)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+
+	struct flash_bank *bank;
+	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank);
+	if (ERROR_OK != retval)
+		return retval;
+
+	if (address < bank->base || address >= (bank->base + bank->size)) {
+		command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]);
+		return ERROR_OK;
+	}
+
+	res = ERROR_OK;
+	status = pic32mx_write_word(bank, address, value);
+	if (status & NVMCON_NVMERR)
+		res = ERROR_FLASH_OPERATION_FAILED;
+	if (status & NVMCON_LVDERR)
+		res = ERROR_FLASH_OPERATION_FAILED;
+
+	if (res == ERROR_OK)
+		command_print(CMD_CTX, "pic32mx pgm word complete");
+	else
+		command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status);
+
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(pic32mx_handle_unlock_command)
+{
+	uint32_t mchip_cmd;
+	struct target *target = NULL;
+	struct mips_m4k_common *mips_m4k;
+	struct mips_ejtag *ejtag_info;
+	int timeout = 10;
+
+	if (CMD_ARGC < 1) {
+		command_print(CMD_CTX, "pic32mx unlock <bank>");
+		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;
+
+	target = bank->target;
+	mips_m4k = target_to_m4k(target);
+	ejtag_info = &mips_m4k->mips32.ejtag_info;
+
+	/* we have to use the MTAP to perform a full erase */
+	mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP);
+	mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND);
+
+	/* first check status of device */
+	mchip_cmd = MCHP_STATUS;
+	mips_ejtag_drscan_8(ejtag_info, &mchip_cmd);
+	if (mchip_cmd & (1 << 7)) {
+		/* device is not locked */
+		command_print(CMD_CTX, "pic32mx is already unlocked, erasing anyway");
+	}
+
+	/* unlock/erase device */
+	mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST);
+	jtag_add_sleep(200);
+
+	mips_ejtag_drscan_8_out(ejtag_info, MCHP_ERASE);
+
+	do {
+		mchip_cmd = MCHP_STATUS;
+		mips_ejtag_drscan_8(ejtag_info, &mchip_cmd);
+		if (timeout-- == 0) {
+			LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx32 "", mchip_cmd);
+			break;
+		}
+		alive_sleep(1);
+	} while ((mchip_cmd & (1 << 2)) || (!(mchip_cmd & (1 << 3))));
+
+	mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST);
+
+	/* select ejtag tap */
+	mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP);
+
+	command_print(CMD_CTX, "pic32mx unlocked.\n"
+			"INFO: a reset or power cycle is required "
+			"for the new settings to take effect.");
+
+	return ERROR_OK;
+}
+
+static const struct command_registration pic32mx_exec_command_handlers[] = {
+	{
+		.name = "pgm_word",
+		.usage = "<addr> <value> <bank>",
+		.handler = pic32mx_handle_pgm_word_command,
+		.mode = COMMAND_EXEC,
+		.help = "program a word",
+	},
+	{
+		.name = "unlock",
+		.handler = pic32mx_handle_unlock_command,
+		.mode = COMMAND_EXEC,
+		.usage = "[bank_id]",
+		.help = "Unlock/Erase entire device.",
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration pic32mx_command_handlers[] = {
+	{
+		.name = "pic32mx",
+		.mode = COMMAND_ANY,
+		.help = "pic32mx flash command group",
+		.usage = "",
+		.chain = pic32mx_exec_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver pic32mx_flash = {
+	.name = "pic32mx",
+	.commands = pic32mx_command_handlers,
+	.flash_bank_command = pic32mx_flash_bank_command,
+	.erase = pic32mx_erase,
+	.protect = pic32mx_protect,
+	.write = pic32mx_write,
+	.read = default_flash_read,
+	.probe = pic32mx_probe,
+	.auto_probe = pic32mx_auto_probe,
+	.erase_check = default_flash_blank_check,
+	.protect_check = pic32mx_protect_check,
+	.info = pic32mx_info,
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/psoc4.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/psoc4.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/psoc4.c
new file mode 100755
index 0000000..1827450
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/psoc4.c
@@ -0,0 +1,809 @@
+/***************************************************************************
+ *   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                                          *
+ *                                                                         *
+ *   Copyright (C) 2014 by Tomas Vanek (PSoC 4 support derived from STM32) *
+ *   vanekt@fbl.cz                                                         *
+ *                                                                         *
+ *   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 <helper/binarybuffer.h>
+#include <jtag/jtag.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+/* device documets:
+
+ PSoC(R) 4: PSoC 4200 Family Datasheet
+	Document Number: 001-87197 Rev. *B  Revised August 29, 2013
+
+ PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM
+	Document No. 001-85634 Rev. *C March 25, 2014
+
+ PSoC(R) 4 Registers TRM Spec.
+	Document No. 001-85847 Rev. *A June 25, 2013
+
+ CY8C41xx, CY8C42xx Programming Specifications
+	Document No. 001-81799 Rev. *C March 4, 2014
+*/
+
+/* register locations */
+#define PSOC4_CPUSS_SYSREQ	0x40000004
+#define PSOC4_CPUSS_SYSARG	0x40000008
+#define PSOC4_TEST_MODE		0x40030014
+#define PSOC4_SPCIF_GEOMETRY	0x400E0000
+
+#define PSOC4_SFLASH_MACRO	0x0ffff000
+
+/* constants */
+#define PSOC4_SROM_KEY1			0xb6
+#define PSOC4_SROM_KEY2			0xd3
+#define PSOC4_SROM_SYSREQ_BIT		(1<<31)
+#define PSOC4_SROM_HMASTER_BIT		(1<<30)
+#define PSOC4_SROM_PRIVILEGED_BIT	(1<<28)
+#define PSOC4_SROM_STATUS_SUCCEEDED	0xa0000000
+#define PSOC4_SROM_STATUS_FAILED	0xf0000000
+
+#define PSOC4_CMD_GET_SILICON_ID	0
+#define PSOC4_CMD_LOAD_LATCH		4
+#define PSOC4_CMD_WRITE_ROW		5
+#define PSOC4_CMD_PROGRAM_ROW		6
+#define PSOC4_CMD_ERASE_ALL		0xa
+#define PSOC4_CMD_CHECKSUM		0xb
+#define PSOC4_CMD_WRITE_PROTECTION	0xd
+
+#define PSOC4_CHIP_PROT_VIRGIN		0x0
+#define PSOC4_CHIP_PROT_OPEN		0x1
+#define PSOC4_CHIP_PROT_PROTECTED	0x2
+#define PSOC4_CHIP_PROT_KILL		0x4
+
+
+struct psoc4_chip_details {
+	uint16_t id;
+	const char *type;
+	const char *package;
+	uint32_t flash_size_in_kb;
+};
+
+/* list of PSoC 4 chips
+ * flash_size_in_kb is not necessary as it can be decoded from SPCIF_GEOMETRY
+ */
+const struct psoc4_chip_details psoc4_devices[] = {
+	/* 4200 series */
+	{ 0x04A6, "CY8C4245PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
+	{ 0x04B6, "CY8C4245LQI-483", "QFN-40",  .flash_size_in_kb = 32 },
+	{ 0x04C8, "CY8C4245AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
+	{ 0x04FB, "CY8C4245AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
+	{ 0x04F0, "CY8C4244PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
+	{ 0x04F1, "CY8C4244PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
+	{ 0x04F6, "CY8C4244LQI-443", "QFN-40",  .flash_size_in_kb = 16 },
+	{ 0x04FA, "CY8C4244AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
+
+	/* 4100 series */
+	{ 0x0410, "CY8C4124PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
+	{ 0x0411, "CY8C4124PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
+	{ 0x0416, "CY8C4124LQI-443", "QFN-40",  .flash_size_in_kb = 16 },
+	{ 0x041A, "CY8C4124AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
+	{ 0x041B, "CY8C4125AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
+	{ 0x0412, "CY8C4125PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
+	{ 0x0417, "CY8C4125LQI-483", "QFN-40",  .flash_size_in_kb = 32 },
+	{ 0x041C, "CY8C4125AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
+
+	/* CCG1 series */
+	{ 0x0490, "CYPD1103-35FNXI", "CSP-35",  .flash_size_in_kb = 32 },
+	{ 0x0489, "CYPD1121-40LQXI", "QFN-40",  .flash_size_in_kb = 32 },
+	{ 0x048A, "CYPD1122-40LQXI", "QFN-40",  .flash_size_in_kb = 32 },
+	{ 0x0491, "CYPD1131-35FNXI", "CSP-35",  .flash_size_in_kb = 32 },
+	{ 0x0498, "CYPD1132-16SXI",  "SOIC-16", .flash_size_in_kb = 32 },
+	{ 0x0481, "CYPD1134-28PVXI", "SSOP-28", .flash_size_in_kb = 32 },
+	{ 0x048B, "CYPD1134-40LQXI", "QFN-40",  .flash_size_in_kb = 32 },
+};
+
+
+struct psoc4_flash_bank {
+	uint32_t row_size;
+	uint32_t user_bank_size;
+	int probed;
+	uint32_t silicon_id;
+	uint8_t chip_protection;
+	uint8_t cmd_program_row;
+};
+
+
+static const struct psoc4_chip_details *psoc4_details_by_id(uint32_t silicon_id)
+{
+	const struct psoc4_chip_details *p = psoc4_devices;
+	unsigned int i;
+	uint16_t id = silicon_id >> 16; /* ignore die revision */
+	for (i = 0; i < sizeof(psoc4_devices)/sizeof(psoc4_devices[0]); i++, p++) {
+		if (p->id == id)
+			return p;
+	}
+	LOG_DEBUG("Unknown PSoC 4 device silicon id 0x%08" PRIx32 ".", silicon_id);
+	return NULL;
+}
+
+static const char *psoc4_decode_chip_protection(uint8_t protection)
+{
+	switch (protection) {
+	case PSOC4_CHIP_PROT_VIRGIN:
+		return "protection VIRGIN";
+	case PSOC4_CHIP_PROT_OPEN:
+		return "protection open";
+	case PSOC4_CHIP_PROT_PROTECTED:
+		return "PROTECTED";
+	case PSOC4_CHIP_PROT_KILL:
+		return "protection KILL";
+	default:
+		LOG_WARNING("Unknown protection state 0x%02" PRIx8 "", protection);
+		return "";
+	}
+}
+
+
+/* flash bank <name> psoc <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
+{
+	struct psoc4_flash_bank *psoc4_info;
+
+	if (CMD_ARGC < 6)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank));
+
+	bank->driver_priv = psoc4_info;
+	psoc4_info->user_bank_size = bank->size;
+
+	return ERROR_OK;
+}
+
+
+/* PSoC 4 system ROM request
+ *  Setting SROM_SYSREQ_BIT in CPUSS_SYSREQ register runs NMI service
+ *  in sysrem ROM. Algorithm just waits for NMI to finish.
+ *  When sysreq_params_size == 0 only one parameter is passed in CPUSS_SYSARG register.
+ *  Otherwise address of memory parameter block is set in CPUSS_SYSARG
+ *  and the first parameter is written to the first word of parameter block
+ */
+static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
+		uint32_t *sysreq_params, uint32_t sysreq_params_size)
+{
+	struct working_area *sysreq_wait_algorithm;
+	struct working_area *sysreq_mem;
+
+	struct reg_param reg_params[1];
+	struct armv7m_algorithm armv7m_info;
+
+	int retval = ERROR_OK;
+
+	uint32_t param1 = PSOC4_SROM_KEY1
+			 | ((PSOC4_SROM_KEY2 + cmd) << 8)
+			 | (cmd_param << 16);
+
+	static uint8_t psoc4_sysreq_wait_code[] = {
+		/* system request NMI is served immediately after algo run
+       now we are done: break */
+		0x00, 0xbe,		/* bkpt 0 */
+	};
+
+	const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4;
+					/* stack must be aligned */
+	const int stack_size = 196;
+	/* tested stack sizes on PSoC 4:
+		ERASE_ALL	144
+		PROGRAM_ROW	112
+		other sysreq	 68
+	*/
+
+	/* allocate area for sysreq wait code and stack */
+	if (target_alloc_working_area(target, code_words * 4 + stack_size,
+			&sysreq_wait_algorithm) != ERROR_OK) {
+		LOG_DEBUG("no working area for sysreq code");
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+	}
+
+	/* Write the code */
+	retval = target_write_buffer(target,
+			sysreq_wait_algorithm->address,
+			sizeof(psoc4_sysreq_wait_code),
+			psoc4_sysreq_wait_code);
+	if (retval != ERROR_OK) {
+		/* we already allocated the writing code, but failed to get a
+		 * buffer, free the algorithm */
+		goto cleanup_algo;
+	}
+
+	if (sysreq_params_size) {
+		/* Allocate memory for sysreq_params */
+		retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem);
+		if (retval != ERROR_OK) {
+			LOG_WARNING("no working area for sysreq parameters");
+
+			/* we already allocated the writing code, but failed to get a
+			 * buffer, free the algorithm */
+			retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+			goto cleanup_algo;
+		}
+
+		/* Write sysreq_params */
+		sysreq_params[0] = param1;
+		retval = target_write_buffer(target, sysreq_mem->address,
+				sysreq_params_size, (uint8_t *)sysreq_params);
+		if (retval != ERROR_OK)
+			goto cleanup_mem;
+
+		/* Set address of sysreq parameters block */
+		retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, sysreq_mem->address);
+		if (retval != ERROR_OK)
+			goto cleanup_mem;
+
+	} else {
+		/* Sysreq without memory block of parameters */
+		/* Set register parameter */
+		retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, param1);
+		if (retval != ERROR_OK)
+			goto cleanup_mem;
+	}
+
+	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_info.core_mode = ARM_MODE_THREAD;
+
+	/* sysreq stack */
+	init_reg_param(&reg_params[0], "sp", 32, PARAM_OUT);
+	buf_set_u32(reg_params[0].value, 0, 32,
+		    sysreq_wait_algorithm->address + sysreq_wait_algorithm->size);
+
+	struct armv7m_common *armv7m = target_to_armv7m(target);
+	if (armv7m == NULL) {
+
+		/* something is very wrong if armv7m is NULL */
+		LOG_ERROR("unable to get armv7m target");
+		goto cleanup;
+	}
+
+	/* Set SROM request */
+	retval = target_write_u32(target, PSOC4_CPUSS_SYSREQ,
+				  PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd);
+	if (retval != ERROR_OK)
+		goto cleanup;
+
+	/* Execute wait code */
+	retval = target_run_algorithm(target, 0, NULL,
+				sizeof(reg_params) / sizeof(*reg_params), reg_params,
+				sysreq_wait_algorithm->address, 0, 1000, &armv7m_info);
+	if (retval != ERROR_OK)
+		LOG_ERROR("sysreq wait code execution failed");
+
+cleanup:
+	destroy_reg_param(&reg_params[0]);
+
+cleanup_mem:
+	if (sysreq_params_size)
+		target_free_working_area(target, sysreq_mem);
+
+cleanup_algo:
+	target_free_working_area(target, sysreq_wait_algorithm);
+
+	return retval;
+}
+
+
+/* helper routine to get silicon ID from a PSoC 4 chip */
+static int psoc4_get_silicon_id(struct target *target, uint32_t *silicon_id, uint8_t *protection)
+{
+	uint32_t params = PSOC4_SROM_KEY1
+			 | ((PSOC4_SROM_KEY2 + PSOC4_CMD_GET_SILICON_ID) << 8);
+	uint32_t part0, part1;
+
+	int retval = psoc4_sysreq(target, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_read_u32(target, PSOC4_CPUSS_SYSARG, &part0);
+	if (retval != ERROR_OK)
+		return retval;
+
+	if (part0 == params) {
+		LOG_ERROR("sysreq silicon id request not served");
+		return ERROR_FAIL;
+	}
+
+	retval = target_read_u32(target, PSOC4_CPUSS_SYSREQ, &part1);
+	if (retval != ERROR_OK)
+		return retval;
+
+	uint32_t silicon = ((part0 & 0xffff) << 16)
+			| (((part0 >> 16) & 0xff) << 8)
+			| (part1 & 0xff);
+	uint8_t prot = (part1 >> 12) & 0xff;
+
+	if (silicon_id)
+			*silicon_id = silicon;
+	if (protection)
+			*protection = prot;
+
+	LOG_DEBUG("silicon id: 0x%08" PRIx32 "", silicon);
+	LOG_DEBUG("protection: 0x%02" PRIx8 "", prot);
+	return retval;
+}
+
+
+static int psoc4_protect_check(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+
+	uint32_t prot_addr = PSOC4_SFLASH_MACRO;
+	uint32_t protection;
+	int i, s;
+	int num_bits;
+	int retval = ERROR_OK;
+
+	num_bits = bank->num_sectors;
+
+	for (i = 0; i < num_bits; i += 32) {
+		retval = target_read_u32(target, prot_addr, &protection);
+		if (retval != ERROR_OK)
+			return retval;
+
+		prot_addr += 4;
+
+		for (s = 0; s < 32; s++) {
+			if (i + s >= num_bits)
+				break;
+			bank->sectors[i + s].is_protected = (protection & (1 << s)) ? 1 : 0;
+		}
+	}
+
+	retval = psoc4_get_silicon_id(target, NULL, &(psoc4_info->chip_protection));
+	return retval;
+}
+
+
+static int psoc4_mass_erase(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	int i;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	/* Call "Erase All" system ROM API */
+	uint32_t param;
+	int retval = psoc4_sysreq(target, PSOC4_CMD_ERASE_ALL,
+			0,
+			&param, sizeof(param));
+
+	if (retval == ERROR_OK)
+		/* set all sectors as erased */
+		for (i = 0; i < bank->num_sectors; i++)
+			bank->sectors[i].is_erased = 1;
+
+	return retval;
+}
+
+
+static int psoc4_erase(struct flash_bank *bank, int first, int last)
+{
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+	if (psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW) {
+		LOG_INFO("Autoerase enabled, erase command ignored");
+		return ERROR_OK;
+	}
+
+	if ((first == 0) && (last == (bank->num_sectors - 1)))
+		return psoc4_mass_erase(bank);
+
+	LOG_ERROR("Only mass erase available");
+
+	return ERROR_FAIL;
+}
+
+
+static int psoc4_protect(struct flash_bank *bank, int set, int first, int last)
+{
+	struct target *target = bank->target;
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+
+	if (psoc4_info->probed == 0)
+		return ERROR_FAIL;
+
+	if (target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	uint32_t *sysrq_buffer = NULL;
+	int retval;
+	int num_bits = bank->num_sectors;
+	const int param_sz = 8;
+	int prot_sz = num_bits / 8;
+	int chip_prot = PSOC4_CHIP_PROT_OPEN;
+	int flash_macro = 0; /* PSoC 42xx has only macro 0 */
+	int i;
+
+	sysrq_buffer = calloc(1, param_sz + prot_sz);
+	if (sysrq_buffer == NULL) {
+		LOG_ERROR("no memory for row buffer");
+		return ERROR_FAIL;
+	}
+
+	for (i = first; i < num_bits && i <= last; i++)
+		bank->sectors[i].is_protected = set;
+
+	uint32_t *p = sysrq_buffer + 2;
+	for (i = 0; i < num_bits; i++) {
+		if (bank->sectors[i].is_protected)
+			p[i / 32] |= 1 << (i % 32);
+	}
+
+	/* Call "Load Latch" system ROM API */
+	sysrq_buffer[1] = prot_sz - 1;
+	retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
+			0,	/* Byte number in latch from what to write */
+			sysrq_buffer, param_sz + psoc4_info->row_size);
+	if (retval != ERROR_OK)
+		goto cleanup;
+
+	/* Call "Write Protection" system ROM API */
+	retval = psoc4_sysreq(target, PSOC4_CMD_WRITE_PROTECTION,
+			chip_prot | (flash_macro << 8), NULL, 0);
+cleanup:
+	if (retval != ERROR_OK)
+		psoc4_protect_check(bank);
+
+	if (sysrq_buffer)
+		free(sysrq_buffer);
+
+	return retval;
+}
+
+
+COMMAND_HANDLER(psoc4_handle_flash_autoerase_command)
+{
+	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;
+
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+	bool enable = psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW;
+
+	if (CMD_ARGC >= 2)
+		COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
+
+	if (enable) {
+		psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW;
+		LOG_INFO("Flash auto-erase enabled, non mass erase commands will be ignored.");
+	} else {
+		psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW;
+		LOG_INFO("Flash auto-erase disabled. Use psoc mass_erase before flash programming.");
+	}
+
+	return retval;
+}
+
+
+static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
+		uint32_t offset, uint32_t count)
+{
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+	struct target *target = bank->target;
+	uint32_t *sysrq_buffer = NULL;
+	int retval = ERROR_OK;
+	const int param_sz = 8;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	if (offset & 0x1) {
+		LOG_ERROR("offset 0x%08" PRIx32 " breaks required 2-byte alignment", offset);
+		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+	}
+
+	sysrq_buffer = malloc(param_sz + psoc4_info->row_size);
+	if (sysrq_buffer == NULL) {
+		LOG_ERROR("no memory for row buffer");
+		return ERROR_FAIL;
+	}
+
+	uint8_t *row_buffer = (uint8_t *)sysrq_buffer + param_sz;
+	uint32_t row_num = offset / psoc4_info->row_size;
+	uint32_t row_offset = offset - row_num * psoc4_info->row_size;
+	if (row_offset)
+		memset(row_buffer, 0, row_offset);
+
+	bool save_poll = jtag_poll_get_enabled();
+	jtag_poll_set_enabled(false);
+
+	while (count) {
+		uint32_t chunk_size = psoc4_info->row_size - row_offset;
+		if (chunk_size > count) {
+			chunk_size = count;
+			memset(row_buffer + chunk_size, 0, psoc4_info->row_size - chunk_size);
+		}
+		memcpy(row_buffer + row_offset, buffer, chunk_size);
+		LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "",
+				offset, row_offset, chunk_size);
+
+		/* Call "Load Latch" system ROM API */
+		sysrq_buffer[1] = psoc4_info->row_size - 1;
+		retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
+				0,	/* Byte number in latch from what to write */
+				sysrq_buffer, param_sz + psoc4_info->row_size);
+		if (retval != ERROR_OK)
+			goto cleanup;
+
+		/* Call "Program Row" or "Write Row" system ROM API */
+		uint32_t sysrq_param;
+		retval = psoc4_sysreq(target, psoc4_info->cmd_program_row,
+				row_num & 0xffff,
+				&sysrq_param, sizeof(sysrq_param));
+		if (retval != ERROR_OK)
+			goto cleanup;
+
+		buffer += chunk_size;
+		row_num++;
+		row_offset = 0;
+		count -= chunk_size;
+	}
+
+cleanup:
+	jtag_poll_set_enabled(save_poll);
+
+	if (sysrq_buffer)
+		free(sysrq_buffer);
+
+	return retval;
+}
+
+
+static int psoc4_probe(struct flash_bank *bank)
+{
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+	struct target *target = bank->target;
+	uint32_t flash_size_in_kb = 0;
+	uint32_t max_flash_size_in_kb;
+	uint32_t cpu_id;
+	uint32_t silicon_id;
+	uint32_t row_size;
+	uint32_t base_address = 0x00000000;
+	uint8_t protection;
+
+	if (target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	psoc4_info->probed = 0;
+	psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW;
+
+	/* Get the CPUID from the ARM Core
+	 * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */
+	int retval = target_read_u32(target, 0xE000ED00, &cpu_id);
+	if (retval != ERROR_OK)
+		return retval;
+
+	LOG_DEBUG("cpu id = 0x%08" PRIx32 "", cpu_id);
+
+	/* set page size, protection granularity and max flash size depending on family */
+	switch ((cpu_id >> 4) & 0xFFF) {
+	case 0xc20: /* M0 -> PSoC4 */
+		row_size = 128;
+		max_flash_size_in_kb = 32;
+		break;
+	default:
+		LOG_WARNING("Cannot identify target as a PSoC 4 family.");
+		return ERROR_FAIL;
+	}
+
+	uint32_t spcif_geometry;
+	retval = target_read_u32(target, PSOC4_SPCIF_GEOMETRY, &spcif_geometry);
+	if (retval == ERROR_OK) {
+		row_size = 128 * ((spcif_geometry >> 22) & 3);
+		flash_size_in_kb = (spcif_geometry & 0xffff) * 256 / 1024;
+		LOG_INFO("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.",
+			 flash_size_in_kb, row_size);
+	}
+
+	/* Early revisions of ST-Link v2 have some problem reading PSOC4_SPCIF_GEOMETRY
+		and an error is reported late. Dummy read gets this error. */
+	uint32_t dummy;
+	target_read_u32(target, PSOC4_CPUSS_SYSREQ, &dummy);
+
+	/* get silicon ID from target. */
+	retval = psoc4_get_silicon_id(target, &silicon_id, &protection);
+	if (retval != ERROR_OK)
+		return retval;
+
+	const struct psoc4_chip_details *details = psoc4_details_by_id(silicon_id);
+	if (details) {
+		LOG_INFO("%s device detected.", details->type);
+		if (flash_size_in_kb == 0)
+			flash_size_in_kb = details->flash_size_in_kb;
+		else if (flash_size_in_kb != details->flash_size_in_kb)
+			LOG_ERROR("Flash size mismatch");
+	}
+
+	psoc4_info->row_size = row_size;
+	psoc4_info->silicon_id = silicon_id;
+	psoc4_info->chip_protection = protection;
+
+	/* failed reading flash size or flash size invalid (early silicon),
+	 * default to max target family */
+	if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
+		LOG_WARNING("PSoC 4 flash size failed, probe inaccurate - assuming %" PRIu32 " k flash",
+			max_flash_size_in_kb);
+		flash_size_in_kb = max_flash_size_in_kb;
+	}
+
+	/* if the user sets the size manually then ignore the probed value
+	 * this allows us to work around devices that have a invalid flash size register value */
+	if (psoc4_info->user_bank_size) {
+		LOG_INFO("ignoring flash probed value, using configured bank size");
+		flash_size_in_kb = psoc4_info->user_bank_size / 1024;
+	}
+
+	LOG_INFO("flash size = %" PRIu32 " kbytes", flash_size_in_kb);
+
+	/* did we assign flash size? */
+	assert(flash_size_in_kb != 0xffff);
+
+	/* calculate numbers of pages */
+	uint32_t num_rows = flash_size_in_kb * 1024 / row_size;
+
+	/* check that calculation result makes sense */
+	assert(num_rows > 0);
+
+	if (bank->sectors) {
+		free(bank->sectors);
+		bank->sectors = NULL;
+	}
+
+	bank->base = base_address;
+	bank->size = num_rows * row_size;
+	bank->num_sectors = num_rows;
+	bank->sectors = malloc(sizeof(struct flash_sector) * num_rows);
+
+	uint32_t i;
+	for (i = 0; i < num_rows; i++) {
+		bank->sectors[i].offset = i * row_size;
+		bank->sectors[i].size = row_size;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = 1;
+	}
+
+	LOG_INFO("flash bank set %" PRIu32 " rows", num_rows);
+	psoc4_info->probed = 1;
+
+	return ERROR_OK;
+}
+
+static int psoc4_auto_probe(struct flash_bank *bank)
+{
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+	if (psoc4_info->probed)
+		return ERROR_OK;
+	return psoc4_probe(bank);
+}
+
+
+static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+	struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+	int printed = 0;
+
+	if (psoc4_info->probed == 0)
+		return ERROR_FAIL;
+
+	const struct psoc4_chip_details *details = psoc4_details_by_id(psoc4_info->silicon_id);
+
+	if (details) {
+		uint32_t chip_revision = psoc4_info->silicon_id & 0xffff;
+		printed = snprintf(buf, buf_size, "PSoC 4 %s rev 0x%04" PRIx32 " package %s",
+				details->type, chip_revision, details->package);
+	} else
+		printed = snprintf(buf, buf_size, "PSoC 4 silicon id 0x%08" PRIx32 "",
+				psoc4_info->silicon_id);
+
+	buf += printed;
+	buf_size -= printed;
+
+	const char *prot_txt = psoc4_decode_chip_protection(psoc4_info->chip_protection);
+	uint32_t size_in_kb = bank->size / 1024;
+	snprintf(buf, buf_size, " flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
+	return ERROR_OK;
+}
+
+
+COMMAND_HANDLER(psoc4_handle_mass_erase_command)
+{
+	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;
+
+	retval = psoc4_mass_erase(bank);
+	if (retval == ERROR_OK)
+		command_print(CMD_CTX, "psoc mass erase complete");
+	else
+		command_print(CMD_CTX, "psoc mass erase failed");
+
+	return retval;
+}
+
+
+static const struct command_registration psoc4_exec_command_handlers[] = {
+	{
+		.name = "mass_erase",
+		.handler = psoc4_handle_mass_erase_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id",
+		.help = "Erase entire flash device.",
+	},
+	{
+		.name = "flash_autoerase",
+		.handler = psoc4_handle_flash_autoerase_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id on|off",
+		.help = "Set autoerase mode for flash bank.",
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration psoc4_command_handlers[] = {
+	{
+		.name = "psoc4",
+		.mode = COMMAND_ANY,
+		.help = "PSoC 4 flash command group",
+		.usage = "",
+		.chain = psoc4_exec_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver psoc4_flash = {
+	.name = "psoc4",
+	.commands = psoc4_command_handlers,
+	.flash_bank_command = psoc4_flash_bank_command,
+	.erase = psoc4_erase,
+	.protect = psoc4_protect,
+	.write = psoc4_write,
+	.read = default_flash_read,
+	.probe = psoc4_probe,
+	.auto_probe = psoc4_auto_probe,
+	.erase_check = default_flash_blank_check,
+	.protect_check = psoc4_protect_check,
+	.info = get_psoc4_info,
+};