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:03:55 UTC

[12/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/xmc1xxx.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/xmc1xxx.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/xmc1xxx.c
new file mode 100755
index 0000000..bb2ec12
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/xmc1xxx.c
@@ -0,0 +1,549 @@
+/*
+ * XMC1000 flash driver
+ *
+ * Copyright (c) 2016 Andreas F�rber
+ *
+ * License: GPL-2.0+
+ */
+
+#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	0x10000000
+#define PAU_BASE	0x40000000
+#define SCU_BASE	0x40010000
+#define NVM_BASE	0x40050000
+
+#define FLASH_CS0	(FLASH_BASE + 0xf00)
+
+#define PAU_FLSIZE	(PAU_BASE + 0x404)
+
+#define SCU_IDCHIP	(SCU_BASE + 0x004)
+
+#define NVMSTATUS	(NVM_BASE + 0x00)
+#define NVMPROG		(NVM_BASE + 0x04)
+#define NVMCONF		(NVM_BASE + 0x08)
+
+#define NVMSTATUS_BUSY		(1 << 0)
+#define NVMSTATUS_VERR_MASK	(0x3 << 2)
+
+#define NVMPROG_ACTION_OPTYPE_IDLE_VERIFY	(0 << 0)
+#define NVMPROG_ACTION_OPTYPE_WRITE		(1 << 0)
+#define NVMPROG_ACTION_OPTYPE_PAGE_ERASE	(2 << 0)
+
+#define NVMPROG_ACTION_ONE_SHOT_ONCE		(1 << 4)
+#define NVMPROG_ACTION_ONE_SHOT_CONTINUOUS	(2 << 4)
+
+#define NVMPROG_ACTION_VERIFY_EACH		(1 << 6)
+#define NVMPROG_ACTION_VERIFY_NO		(2 << 6)
+#define NVMPROG_ACTION_VERIFY_ARRAY		(3 << 6)
+
+#define NVMPROG_ACTION_IDLE	0x00
+#define NVMPROG_ACTION_MASK	0xff
+
+#define NVM_WORD_SIZE 4
+#define NVM_BLOCK_SIZE (4 * NVM_WORD_SIZE)
+#define NVM_PAGE_SIZE (16 * NVM_BLOCK_SIZE)
+
+struct xmc1xxx_flash_bank {
+	bool probed;
+};
+
+static int xmc1xxx_nvm_set_idle(struct target *target)
+{
+	return target_write_u16(target, NVMPROG, NVMPROG_ACTION_IDLE);
+}
+
+static int xmc1xxx_nvm_check_idle(struct target *target)
+{
+	uint16_t val;
+	int retval;
+
+	retval = target_read_u16(target, NVMPROG, &val);
+	if (retval != ERROR_OK)
+		return retval;
+	if ((val & NVMPROG_ACTION_MASK) != NVMPROG_ACTION_IDLE) {
+		LOG_WARNING("NVMPROG.ACTION");
+		retval = xmc1xxx_nvm_set_idle(target);
+	}
+
+	return retval;
+}
+
+static int xmc1xxx_erase(struct flash_bank *bank, int first, int last)
+{
+	struct target *target = bank->target;
+	struct working_area *workarea;
+	struct reg_param reg_params[3];
+	struct armv7m_algorithm armv7m_algo;
+	unsigned i;
+	int retval, sector;
+	const uint8_t erase_code[] = {
+#include "../../../contrib/loaders/flash/xmc1xxx/erase.inc"
+	};
+
+	LOG_DEBUG("Infineon XMC1000 erase sectors %d to %d", first, last);
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	retval = xmc1xxx_nvm_check_idle(target);
+	if (retval != ERROR_OK)
+		return retval;
+
+	retval = target_alloc_working_area(target, sizeof(erase_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_code), erase_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);
+
+	buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
+	buf_set_u32(reg_params[1].value, 0, 32, bank->base +
+		bank->sectors[first].offset);
+	buf_set_u32(reg_params[2].value, 0, 32, bank->base +
+		bank->sectors[last].offset + bank->sectors[last].size);
+
+	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 = xmc1xxx_nvm_set_idle(target);
+		if (retval != ERROR_OK)
+			LOG_WARNING("Couldn't restore NVMPROG.ACTION");
+		retval = ERROR_FLASH_OPERATION_FAILED;
+		goto err_run;
+	}
+
+	for (sector = first; sector <= last; sector++)
+		bank->sectors[sector].is_erased = 1;
+
+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:
+	return retval;
+}
+
+static int xmc1xxx_erase_check(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	struct working_area *workarea;
+	struct reg_param reg_params[3];
+	struct armv7m_algorithm armv7m_algo;
+	uint16_t val;
+	unsigned i;
+	int retval, sector;
+	const uint8_t erase_check_code[] = {
+#include "../../../contrib/loaders/flash/xmc1xxx/erase_check.inc"
+	};
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	retval = target_alloc_working_area(target, sizeof(erase_check_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_check_code), erase_check_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);
+
+	buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
+
+	for (sector = 0; sector < bank->num_sectors; sector++) {
+		uint32_t start = bank->base + bank->sectors[sector].offset;
+		buf_set_u32(reg_params[1].value, 0, 32, start);
+		buf_set_u32(reg_params[2].value, 0, 32, start + bank->sectors[sector].size);
+
+		retval = xmc1xxx_nvm_check_idle(target);
+		if (retval != ERROR_OK)
+			goto err_nvmprog;
+
+		LOG_DEBUG("Erase-checking 0x%08" PRIx32, start);
+		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 check "
+				"programming algorithm");
+			retval = xmc1xxx_nvm_set_idle(target);
+			if (retval != ERROR_OK)
+				LOG_WARNING("Couldn't restore NVMPROG.ACTION");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run;
+		}
+
+		retval = target_read_u16(target, NVMSTATUS, &val);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Couldn't read NVMSTATUS");
+			goto err_nvmstatus;
+		}
+		bank->sectors[sector].is_erased = (val & NVMSTATUS_VERR_MASK) ? 0 : 1;
+	}
+
+err_nvmstatus:
+err_run:
+err_nvmprog:
+	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:
+	return retval;
+}
+
+static int xmc1xxx_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[4];
+	struct armv7m_algorithm armv7m_algo;
+	uint32_t block_count = DIV_ROUND_UP(byte_count, NVM_BLOCK_SIZE);
+	unsigned i;
+	int retval;
+	const uint8_t write_code[] = {
+#include "../../../contrib/loaders/flash/xmc1xxx/write.inc"
+	};
+
+	LOG_DEBUG("Infineon XMC1000 write at 0x%08" PRIx32 " (%" PRId32 " bytes)",
+		offset, byte_count);
+
+	if (offset & (NVM_BLOCK_SIZE - 1)) {
+		LOG_ERROR("offset 0x%" PRIx32 " breaks required block alignment",
+			offset);
+		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+	}
+	if (byte_count & (NVM_BLOCK_SIZE - 1)) {
+		LOG_WARNING("length %" PRId32 " is not block aligned, rounding up",
+			byte_count);
+	}
+
+	if (target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	retval = target_alloc_working_area(target, sizeof(write_code),
+			&code_workarea);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("No working area available for write code.");
+		retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+		goto err_alloc_code;
+	}
+	retval = target_write_buffer(target, code_workarea->address,
+			sizeof(write_code), write_code);
+	if (retval != ERROR_OK)
+		goto err_write_code;
+
+	retval = target_alloc_working_area(target, MAX(NVM_BLOCK_SIZE,
+		MIN(block_count * NVM_BLOCK_SIZE, 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);
+
+	buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
+
+	while (byte_count > 0) {
+		uint32_t blocks = MIN(block_count, data_workarea->size / NVM_BLOCK_SIZE);
+		uint32_t addr = bank->base + offset;
+
+		LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32,
+			MIN(blocks * NVM_BLOCK_SIZE, byte_count),
+			data_workarea->address);
+
+		retval = target_write_buffer(target, data_workarea->address,
+			MIN(blocks * NVM_BLOCK_SIZE, byte_count), buffer);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Error writing data buffer");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_write_data;
+		}
+		if (byte_count < blocks * NVM_BLOCK_SIZE) {
+			retval = target_write_memory(target,
+				data_workarea->address + byte_count, 1,
+				blocks * NVM_BLOCK_SIZE - byte_count,
+				&bank->default_padded_value);
+			if (retval != ERROR_OK) {
+				LOG_ERROR("Error writing data padding");
+				retval = ERROR_FLASH_OPERATION_FAILED;
+				goto err_write_pad;
+			}
+		}
+
+		LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRId32 "x)",
+			addr, addr + blocks * NVM_BLOCK_SIZE - 1, blocks);
+
+		retval = xmc1xxx_nvm_check_idle(target);
+		if (retval != ERROR_OK)
+			goto err_nvmprog;
+
+		buf_set_u32(reg_params[1].value, 0, 32, addr);
+		buf_set_u32(reg_params[2].value, 0, 32, data_workarea->address);
+		buf_set_u32(reg_params[3].value, 0, 32, blocks);
+
+		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 write "
+				"programming algorithm");
+			retval = xmc1xxx_nvm_set_idle(target);
+			if (retval != ERROR_OK)
+				LOG_WARNING("Couldn't restore NVMPROG.ACTION");
+			retval = ERROR_FLASH_OPERATION_FAILED;
+			goto err_run;
+		}
+
+		block_count -= blocks;
+		offset += blocks * NVM_BLOCK_SIZE;
+		buffer += blocks * NVM_BLOCK_SIZE;
+		byte_count -= MIN(blocks * NVM_BLOCK_SIZE, byte_count);
+	}
+
+err_run:
+err_nvmprog:
+err_write_pad:
+err_write_data:
+	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);
+
+err_alloc_code:
+	return retval;
+}
+
+static int xmc1xxx_protect_check(struct flash_bank *bank)
+{
+	uint32_t nvmconf;
+	int i, num_protected, retval;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	retval = target_read_u32(bank->target, NVMCONF, &nvmconf);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("Cannot read NVMCONF register.");
+		return retval;
+	}
+	LOG_DEBUG("NVMCONF = %08" PRIx32, nvmconf);
+
+	num_protected = (nvmconf >> 4) & 0xff;
+
+	for (i = 0; i < bank->num_sectors; i++)
+		bank->sectors[i].is_protected = (i < num_protected) ? 1 : 0;
+
+	return ERROR_OK;
+}
+
+static int xmc1xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
+{
+	uint32_t chipid[8];
+	int i, retval;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	/* Obtain the 8-word Chip Identification Number */
+	for (i = 0; i < 7; i++) {
+		retval = target_read_u32(bank->target, FLASH_CS0 + i * 4, &chipid[i]);
+		if (retval != ERROR_OK) {
+			LOG_ERROR("Cannot read CS0 register %i.", i);
+			return retval;
+		}
+		LOG_DEBUG("ID[%d] = %08" PRIX32, i, chipid[i]);
+	}
+	retval = target_read_u32(bank->target, SCU_BASE + 0x000, &chipid[7]);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("Cannot read DBGROMID register.");
+		return retval;
+	}
+	LOG_DEBUG("ID[7] = %08" PRIX32, chipid[7]);
+
+	snprintf(buf, buf_size, "XMC%" PRIx32 "00 %X flash %uKB ROM %uKB SRAM %uKB",
+			(chipid[0] >> 12) & 0xff,
+			0xAA + (chipid[7] >> 28) - 1,
+			(((chipid[6] >> 12) & 0x3f) - 1) * 4,
+			(((chipid[4] >> 8) & 0x3f) * 256) / 1024,
+			(((chipid[5] >> 8) & 0x1f) * 256 * 4) / 1024);
+
+	return ERROR_OK;
+}
+
+static int xmc1xxx_probe(struct flash_bank *bank)
+{
+	struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
+	uint32_t flash_addr = bank->base;
+	uint32_t idchip, flsize;
+	int i, retval;
+
+	if (xmc_bank->probed)
+		return ERROR_OK;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	retval = target_read_u32(bank->target, SCU_IDCHIP, &idchip);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("Cannot read IDCHIP register.");
+		return retval;
+	}
+
+	if ((idchip & 0xffff0000) != 0x10000) {
+		LOG_ERROR("IDCHIP register does not match XMC1xxx.");
+		return ERROR_FAIL;
+	}
+
+	LOG_DEBUG("IDCHIP = %08" PRIx32, idchip);
+
+	retval = target_read_u32(bank->target, PAU_FLSIZE, &flsize);
+	if (retval != ERROR_OK) {
+		LOG_ERROR("Cannot read FLSIZE register.");
+		return retval;
+	}
+
+	bank->num_sectors = 1 + ((flsize >> 12) & 0x3f) - 1;
+	bank->size = bank->num_sectors * 4 * 1024;
+	bank->sectors = calloc(bank->num_sectors,
+			       sizeof(struct flash_sector));
+	for (i = 0; i < bank->num_sectors; i++) {
+		if (i == 0) {
+			bank->sectors[i].size = 0x200;
+			bank->sectors[i].offset = 0xE00;
+			flash_addr += 0x1000;
+		} else {
+			bank->sectors[i].size = 4 * 1024;
+			bank->sectors[i].offset = flash_addr - bank->base;
+			flash_addr += bank->sectors[i].size;
+		}
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = -1;
+	}
+
+	xmc_bank->probed = true;
+
+	return ERROR_OK;
+}
+
+static int xmc1xxx_auto_probe(struct flash_bank *bank)
+{
+	struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
+
+	if (xmc_bank->probed)
+		return ERROR_OK;
+
+	return xmc1xxx_probe(bank);
+}
+
+FLASH_BANK_COMMAND_HANDLER(xmc1xxx_flash_bank_command)
+{
+	struct xmc1xxx_flash_bank *xmc_bank;
+
+	xmc_bank = malloc(sizeof(struct xmc1xxx_flash_bank));
+	if (!xmc_bank)
+		return ERROR_FLASH_OPERATION_FAILED;
+
+	xmc_bank->probed = false;
+
+	bank->driver_priv = xmc_bank;
+
+	return ERROR_OK;
+}
+
+static const struct command_registration xmc1xxx_exec_command_handlers[] = {
+	COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration xmc1xxx_command_handlers[] = {
+	{
+		.name = "xmc1xxx",
+		.mode = COMMAND_ANY,
+		.help = "xmc1xxx flash command group",
+		.usage = "",
+		.chain = xmc1xxx_exec_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver xmc1xxx_flash = {
+	.name = "xmc1xxx",
+	.commands = xmc1xxx_command_handlers,
+	.flash_bank_command = xmc1xxx_flash_bank_command,
+	.info = xmc1xxx_get_info_command,
+	.probe = xmc1xxx_probe,
+	.auto_probe = xmc1xxx_auto_probe,
+	.protect_check = xmc1xxx_protect_check,
+	.read = default_flash_read,
+	.erase = xmc1xxx_erase,
+	.erase_check = xmc1xxx_erase_check,
+	.write = xmc1xxx_write,
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/xmc4xxx.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/xmc4xxx.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/xmc4xxx.c
new file mode 100755
index 0000000..4fa273b
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/xmc4xxx.c
@@ -0,0 +1,1444 @@
+/**************************************************************************
+*   Copyright (C) 2015 Jeff Ciesielski <je...@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 <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+/* Maximum number of sectors */
+#define MAX_XMC_SECTORS 12
+
+/* System control unit registers */
+#define SCU_REG_BASE 0x50004000
+
+#define SCU_ID_CHIP 0x04
+
+/* Base of the non-cached flash memory */
+#define PFLASH_BASE	0x0C000000
+
+/* User configuration block offsets */
+#define UCB0_BASE       0x00000000
+#define UCB1_BASE       0x00000400
+#define UCB2_BASE       0x00000800
+
+/* Flash register base */
+#define FLASH_REG_BASE 0x58000000
+
+/* PMU ID Registers */
+#define FLASH_REG_PMU_ID	(FLASH_REG_BASE | 0x0508)
+
+/* PMU Fields */
+#define PMU_MOD_REV_MASK	0xFF
+#define PMU_MOD_TYPE_MASK	0xFF00
+#define PMU_MOD_NO_MASK		0xFFFF0000
+
+/* Prefetch Config */
+#define FLASH_REG_PREF_PCON	(FLASH_REG_BASE | 0x4000)
+
+/* Prefetch Fields */
+#define PCON_IBYP	(1 << 0)
+#define PCON_IINV	(1 << 1)
+
+/* Flash ID Register */
+#define FLASH_REG_FLASH0_ID	(FLASH_REG_BASE | 0x2008)
+
+/* Flash Status Register */
+#define FLASH_REG_FLASH0_FSR	(FLASH_REG_BASE | 0x2010)
+
+#define FSR_PBUSY	(0)
+#define FSR_FABUSY	(1)
+#define FSR_PROG	(4)
+#define FSR_ERASE	(5)
+#define FSR_PFPAGE	(6)
+#define FSR_PFOPER	(8)
+#define FSR_SQER	(10)
+#define FSR_PROER	(11)
+#define FSR_PFSBER	(12)
+#define FSR_PFDBER	(14)
+#define FSR_PROIN	(16)
+#define FSR_RPROIN	(18)
+#define FSR_RPRODIS	(19)
+#define FSR_WPROIN0	(21)
+#define FSR_WPROIN1	(22)
+#define FSR_WPROIN2	(23)
+#define FSR_WPRODIS0	(25)
+#define FSR_WPRODIS1	(26)
+#define FSR_SLM		(28)
+#define FSR_VER		(31)
+
+#define FSR_PBUSY_MASK		(0x01 << FSR_PBUSY)
+#define FSR_FABUSY_MASK		(0x01 << FSR_FABUSY)
+#define FSR_PROG_MASK		(0x01 << FSR_PROG)
+#define FSR_ERASE_MASK		(0x01 << FSR_ERASE)
+#define FSR_PFPAGE_MASK		(0x01 << FSR_PFPAGE)
+#define FSR_PFOPER_MASK		(0x01 << FSR_PFOPER)
+#define FSR_SQER_MASK		(0x01 << FSR_SQER)
+#define FSR_PROER_MASK		(0x01 << FSR_PROER)
+#define FSR_PFSBER_MASK		(0x01 << FSR_PFSBER)
+#define FSR_PFDBER_MASK		(0x01 << FSR_PFDBER)
+#define FSR_PROIN_MASK		(0x01 << FSR_PROIN)
+#define FSR_RPROIN_MASK		(0x01 << FSR_RPROIN)
+#define FSR_RPRODIS_MASK	(0x01 << FSR_RPRODIS)
+#define FSR_WPROIN0_MASK	(0x01 << FSR_WPROIN0)
+#define FSR_WPROIN1_MASK	(0x01 << FSR_WPROIN1)
+#define FSR_WPROIN2_MASK	(0x01 << FSR_WPROIN2)
+#define FSR_WPRODIS0_MASK	(0x01 << FSR_WPRODIS0)
+#define FSR_WPRODIS1_MASK	(0x01 << FSR_WPRODIS1)
+#define FSR_SLM_MASK		(0x01 << FSR_SLM)
+#define FSR_VER_MASK		(0x01 << FSR_VER)
+
+/* Flash Config Register */
+#define FLASH_REG_FLASH0_FCON	(FLASH_REG_BASE | 0x2014)
+
+#define FCON_WSPFLASH           (0)
+#define FCON_WSECPF             (4)
+#define FCON_IDLE               (13)
+#define FCON_ESLDIS             (14)
+#define FCON_SLEEP              (15)
+#define FCON_RPA                (16)
+#define FCON_DCF                (17)
+#define FCON_DDF                (18)
+#define FCON_VOPERM             (24)
+#define FCON_SQERM              (25)
+#define FCON_PROERM             (26)
+#define FCON_PFSBERM            (27)
+#define FCON_PFDBERM            (29)
+#define FCON_EOBM               (31)
+
+#define FCON_WSPFLASH_MASK      (0x0f << FCON_WSPFLASH)
+#define FCON_WSECPF_MASK        (0x01 << FCON_WSECPF)
+#define FCON_IDLE_MASK          (0x01 << FCON_IDLE)
+#define FCON_ESLDIS_MASK        (0x01 << FCON_ESLDIS)
+#define FCON_SLEEP_MASK         (0x01 << FCON_SLEEP)
+#define FCON_RPA_MASK           (0x01 << FCON_RPA)
+#define FCON_DCF_MASK           (0x01 << FCON_DCF)
+#define FCON_DDF_MASK           (0x01 << FCON_DDF)
+#define FCON_VOPERM_MASK        (0x01 << FCON_VOPERM)
+#define FCON_SQERM_MASK         (0x01 << FCON_SQERM)
+#define FCON_PROERM_MASK        (0x01 << FCON_PROERM)
+#define FCON_PFSBERM_MASK       (0x01 << FCON_PFSBERM)
+#define FCON_PFDBERM_MASK       (0x01 << FCON_PFDBERM)
+#define FCON_EOBM_MASK          (0x01 << FCON_EOBM)
+
+/* Flash Margin Control Register */
+#define FLASH_REG_FLASH0_MARP	(FLASH_REG_BASE | 0x2018)
+
+#define MARP_MARGIN		(0)
+#define MARP_TRAPDIS		(15)
+
+#define MARP_MARGIN_MASK        (0x0f << MARP_MARGIN)
+#define MARP_TRAPDIS_MASK       (0x01 << MARP_TRAPDIS)
+
+/* Flash Protection Registers */
+#define FLASH_REG_FLASH0_PROCON0	(FLASH_REG_BASE | 0x2020)
+#define FLASH_REG_FLASH0_PROCON1	(FLASH_REG_BASE | 0x2024)
+#define FLASH_REG_FLASH0_PROCON2	(FLASH_REG_BASE | 0x2028)
+
+#define PROCON_S0L             (0)
+#define PROCON_S1L             (1)
+#define PROCON_S2L             (2)
+#define PROCON_S3L             (3)
+#define PROCON_S4L             (4)
+#define PROCON_S5L             (5)
+#define PROCON_S6L             (6)
+#define PROCON_S7L             (7)
+#define PROCON_S8L             (8)
+#define PROCON_S9L             (9)
+#define PROCON_S10_S11L        (10)
+#define PROCON_RPRO            (15)
+
+#define PROCON_S0L_MASK        (0x01 << PROCON_S0L)
+#define PROCON_S1L_MASK        (0x01 << PROCON_S1L)
+#define PROCON_S2L_MASK        (0x01 << PROCON_S2L)
+#define PROCON_S3L_MASK        (0x01 << PROCON_S3L)
+#define PROCON_S4L_MASK        (0x01 << PROCON_S4L)
+#define PROCON_S5L_MASK        (0x01 << PROCON_S5L)
+#define PROCON_S6L_MASK        (0x01 << PROCON_S6L)
+#define PROCON_S7L_MASK        (0x01 << PROCON_S7L)
+#define PROCON_S8L_MASK        (0x01 << PROCON_S8L)
+#define PROCON_S9L_MASK        (0x01 << PROCON_S9L)
+#define PROCON_S10_S11L_MASK   (0x01 << PROCON_S10_S11L)
+#define PROCON_RPRO_MASK       (0x01 << PROCON_RPRO)
+
+#define FLASH_PROTECT_CONFIRMATION_CODE 0x8AFE15C3
+
+/* Flash controller configuration values */
+#define FLASH_ID_XMC4500        0xA2
+#define FLASH_ID_XMC4700_4800   0x92
+#define FLASH_ID_XMC4100_4200   0x9C
+#define FLASH_ID_XMC4400        0x9F
+
+/* Timeouts */
+#define FLASH_OP_TIMEOUT 5000
+
+/* Flash commands (write/erase/protect) are performed using special
+ * command sequences that are written to magic addresses in the flash controller */
+/* Command sequence addresses.  See reference manual, section 8: Flash Command Sequences */
+#define FLASH_CMD_ERASE_1 0x0C005554
+#define FLASH_CMD_ERASE_2 0x0C00AAA8
+#define FLASH_CMD_ERASE_3 FLASH_CMD_ERASE_1
+#define FLASH_CMD_ERASE_4 FLASH_CMD_ERASE_1
+#define FLASH_CMD_ERASE_5 FLASH_CMD_ERASE_2
+/* ERASE_6 is the sector base address */
+
+#define FLASH_CMD_CLEAR_STATUS FLASH_CMD_ERASE_1
+
+#define FLASH_CMD_ENTER_PAGEMODE FLASH_CMD_ERASE_1
+
+#define FLASH_CMD_LOAD_PAGE_1 0x0C0055F0
+#define FLASH_CMD_LOAD_PAGE_2 0x0C0055F4
+
+#define FLASH_CMD_WRITE_PAGE_1 FLASH_CMD_ERASE_1
+#define FLASH_CMD_WRITE_PAGE_2 FLASH_CMD_ERASE_2
+#define FLASH_CMD_WRITE_PAGE_3 FLASH_CMD_ERASE_1
+/* WRITE_PAGE_4 is the page base address */
+
+#define FLASH_CMD_TEMP_UNPROT_1 FLASH_CMD_ERASE_1
+#define FLASH_CMD_TEMP_UNPROT_2 FLASH_CMD_ERASE_2
+#define FLASH_CMD_TEMP_UNPROT_3 0x0C00553C
+#define FLASH_CMD_TEMP_UNPROT_4 FLASH_CMD_ERASE_2
+#define FLASH_CMD_TEMP_UNPROT_5 FLASH_CMD_ERASE_2
+#define FLASH_CMD_TEMP_UNPROT_6 0x0C005558
+
+struct xmc4xxx_flash_bank {
+	bool probed;
+
+	/* We need the flash controller ID to choose the sector layout */
+	uint32_t fcon_id;
+
+	/* Passwords used for protection operations */
+	uint32_t pw1;
+	uint32_t pw2;
+	bool pw_set;
+
+	/* Protection flags */
+	bool read_protected;
+
+	bool write_prot_otp[MAX_XMC_SECTORS];
+};
+
+struct xmc4xxx_command_seq {
+	uint32_t address;
+	uint32_t magic;
+};
+
+/* Sector capacities.  See section 8 of xmc4x00_rm */
+static const unsigned int sector_capacity_8[8] = {
+	16, 16, 16, 16, 16, 16, 16, 128
+};
+
+static const unsigned int sector_capacity_9[9] = {
+	16, 16, 16, 16, 16, 16, 16, 128, 256
+};
+
+static const unsigned int sector_capacity_12[12] = {
+	16, 16, 16, 16, 16, 16, 16, 16, 128, 256, 256, 256
+};
+
+static const unsigned int sector_capacity_16[16] = {
+	16, 16, 16, 16, 16, 16, 16, 16, 128, 256, 256, 256, 256, 256, 256, 256
+};
+
+static int xmc4xxx_write_command_sequence(struct flash_bank *bank,
+					 struct xmc4xxx_command_seq *seq,
+					 int seq_len)
+{
+	int res = ERROR_OK;
+
+	for (int i = 0; i < seq_len; i++) {
+		res = target_write_u32(bank->target, seq[i].address,
+				       seq[i].magic);
+		if (res != ERROR_OK)
+			return res;
+	}
+
+	return ERROR_OK;
+}
+
+static int xmc4xxx_load_bank_layout(struct flash_bank *bank)
+{
+	const unsigned int *capacity = NULL;
+
+	/* At this point, we know which flash controller ID we're
+	 * talking to and simply need to fill out the bank structure accordingly */
+	LOG_DEBUG("%d sectors", bank->num_sectors);
+
+	switch (bank->num_sectors) {
+	case 8:
+		capacity = sector_capacity_8;
+		break;
+	case 9:
+		capacity = sector_capacity_9;
+		break;
+	case 12:
+		capacity = sector_capacity_12;
+		break;
+	case 16:
+		capacity = sector_capacity_16;
+		break;
+	default:
+		LOG_ERROR("Unexpected number of sectors, %d\n",
+			  bank->num_sectors);
+		return ERROR_FAIL;
+	}
+
+	/* This looks like a bank that we understand, now we know the
+	 * corresponding sector capacities and we can add those up into the
+	 * bank size. */
+	uint32_t total_offset = 0;
+	bank->sectors = calloc(bank->num_sectors,
+			       sizeof(struct flash_sector));
+	for (int i = 0; i < bank->num_sectors; i++) {
+		bank->sectors[i].size = capacity[i] * 1024;
+		bank->sectors[i].offset = total_offset;
+		bank->sectors[i].is_erased = -1;
+		bank->sectors[i].is_protected = -1;
+
+		bank->size += bank->sectors[i].size;
+		LOG_DEBUG("\t%d: %uk", i, capacity[i]);
+		total_offset += bank->sectors[i].size;
+	}
+
+	/* This part doesn't follow the typical standard of 0xff
+	 * being the default padding value.*/
+	bank->default_padded_value = 0x00;
+
+	return ERROR_OK;
+}
+
+static int xmc4xxx_probe(struct flash_bank *bank)
+{
+	int res;
+	uint32_t devid, config;
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+	uint8_t flash_id;
+
+	if (fb->probed)
+		return ERROR_OK;
+
+	/* It's not possible for the DAP to access the OTP locations needed for
+	 * probing the part info and Flash geometry so we require that the target
+	 * be halted before proceeding. */
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	/* The SCU registers contain the ID of the chip */
+	res = target_read_u32(bank->target, SCU_REG_BASE + SCU_ID_CHIP, &devid);
+	if (res != ERROR_OK) {
+		LOG_ERROR("Cannot read device identification register.");
+		return res;
+	}
+
+	/* Make sure this is a XMC4000 family device */
+	if ((devid & 0xF0000) != 0x40000 && devid != 0) {
+		LOG_ERROR("Platform ID doesn't match XMC4xxx: 0x%08" PRIx32, devid);
+		return ERROR_FAIL;
+	}
+
+	LOG_DEBUG("Found XMC4xxx with devid: 0x%08" PRIx32, devid);
+
+	/* Now sanity-check the Flash controller itself. */
+	res = target_read_u32(bank->target, FLASH_REG_FLASH0_ID,
+			&config);
+	if (res != ERROR_OK) {
+		LOG_ERROR("Cannot read Flash bank configuration.");
+		return res;
+	}
+	flash_id = (config & 0xff0000) >> 16;
+
+	/* The Flash configuration register is our only means of
+	 * determining the sector layout. We need to make sure that
+	 * we understand the type of controller we're dealing with */
+	switch (flash_id) {
+	case FLASH_ID_XMC4100_4200:
+		bank->num_sectors = 8;
+		LOG_DEBUG("XMC4xxx: XMC4100/4200 detected.");
+		break;
+	case FLASH_ID_XMC4400:
+		bank->num_sectors = 9;
+		LOG_DEBUG("XMC4xxx: XMC4400 detected.");
+		break;
+	case FLASH_ID_XMC4500:
+		bank->num_sectors = 12;
+		LOG_DEBUG("XMC4xxx: XMC4500 detected.");
+		break;
+	case FLASH_ID_XMC4700_4800:
+		bank->num_sectors = 16;
+		LOG_DEBUG("XMC4xxx: XMC4700/4800 detected.");
+		break;
+	default:
+		LOG_ERROR("XMC4xxx: Unexpected flash ID. got %02" PRIx8,
+			  flash_id);
+		return ERROR_FAIL;
+	}
+
+	/* Retrieve information about the particular bank we're probing and fill in
+	 * the bank structure accordingly. */
+	res = xmc4xxx_load_bank_layout(bank);
+	if (res == ERROR_OK) {
+		/* We're done */
+		fb->probed = true;
+	} else {
+		LOG_ERROR("Unable to load bank information.");
+		return ERROR_FAIL;
+	}
+
+	return ERROR_OK;
+}
+
+static int xmc4xxx_get_sector_start_addr(struct flash_bank *bank,
+					 int sector, uint32_t *ret_addr)
+{
+	/* Make sure we understand this sector */
+	if (sector > bank->num_sectors)
+		return ERROR_FAIL;
+
+	*ret_addr = bank->base + bank->sectors[sector].offset;
+
+	return ERROR_OK;
+
+}
+
+static int xmc4xxx_clear_flash_status(struct flash_bank *bank)
+{
+	int res;
+	/* TODO: Do we need to check for sequence error? */
+	LOG_INFO("Clearing flash status");
+	res = target_write_u32(bank->target, FLASH_CMD_CLEAR_STATUS,
+			       0xF5);
+	if (res != ERROR_OK) {
+		LOG_ERROR("Unable to write erase command sequence");
+		return res;
+	}
+
+	return ERROR_OK;
+}
+
+static int xmc4xxx_get_flash_status(struct flash_bank *bank, uint32_t *status)
+{
+	int res;
+
+	res = target_read_u32(bank->target, FLASH_REG_FLASH0_FSR, status);
+
+	if (res != ERROR_OK)
+		LOG_ERROR("Cannot read flash status register.");
+
+	return res;
+}
+
+static int xmc4xxx_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+	int res;
+	uint32_t status;
+
+	res = xmc4xxx_get_flash_status(bank, &status);
+	if (res != ERROR_OK)
+		return res;
+
+	/* While the flash controller is busy, wait */
+	while (status & FSR_PBUSY_MASK) {
+		res = xmc4xxx_get_flash_status(bank, &status);
+		if (res != ERROR_OK)
+			return res;
+
+		if (timeout-- <= 0) {
+			LOG_ERROR("Timed out waiting for flash");
+			return ERROR_FAIL;
+		}
+		alive_sleep(1);
+		keep_alive();
+	}
+
+	if (status & FSR_PROER_MASK) {
+		LOG_ERROR("XMC4xxx flash protected");
+		res = ERROR_FAIL;
+	}
+
+	return res;
+}
+
+static int xmc4xxx_erase_sector(struct flash_bank *bank, uint32_t address,
+				bool user_config)
+{
+	int res;
+	uint32_t status;
+
+	/* See reference manual table 8.4: Command Sequences for Flash Control */
+	struct xmc4xxx_command_seq erase_cmd_seq[6] = {
+		{FLASH_CMD_ERASE_1, 0xAA},
+		{FLASH_CMD_ERASE_2, 0x55},
+		{FLASH_CMD_ERASE_3, 0x80},
+		{FLASH_CMD_ERASE_4, 0xAA},
+		{FLASH_CMD_ERASE_5, 0x55},
+		{0xFF,              0xFF} /* Needs filled in */
+	};
+
+	/* We need to fill in the base address of the sector we'll be
+	 * erasing, as well as the magic code that determines whether
+	 * this is a standard flash sector or a user configuration block */
+
+	erase_cmd_seq[5].address = address;
+	if (user_config) {
+		/* Removing flash protection requires the addition of
+		 * the base address */
+		erase_cmd_seq[5].address += bank->base;
+		erase_cmd_seq[5].magic = 0xC0;
+	} else {
+		erase_cmd_seq[5].magic = 0x30;
+	}
+
+	res = xmc4xxx_write_command_sequence(bank, erase_cmd_seq,
+					     ARRAY_SIZE(erase_cmd_seq));
+	if (res != ERROR_OK)
+		return res;
+
+	/* Read the flash status register */
+	res = target_read_u32(bank->target, FLASH_REG_FLASH0_FSR, &status);
+	if (res != ERROR_OK) {
+		LOG_ERROR("Cannot read flash status register.");
+		return res;
+	}
+
+	/* Check for a sequence error */
+	if (status & FSR_SQER_MASK) {
+		LOG_ERROR("Error with flash erase sequence");
+		return ERROR_FAIL;
+	}
+
+	/* Make sure a flash erase was triggered */
+	if (!(status & FSR_ERASE_MASK)) {
+		LOG_ERROR("Flash failed to erase");
+		return ERROR_FAIL;
+	}
+
+	/* Now we must wait for the erase operation to end */
+	res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT);
+
+	return res;
+}
+
+static int xmc4xxx_erase(struct flash_bank *bank, int first, int last)
+{
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+	int res;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Unable to erase, target is not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	if (!fb->probed) {
+		res = xmc4xxx_probe(bank);
+		if (res != ERROR_OK)
+			return res;
+	}
+
+	uint32_t tmp_addr;
+	/* Loop through the sectors and erase each one */
+	for (int i = first; i <= last; i++) {
+		res = xmc4xxx_get_sector_start_addr(bank, i, &tmp_addr);
+		if (res != ERROR_OK) {
+			LOG_ERROR("Invalid sector %d", i);
+			return res;
+		}
+
+		LOG_DEBUG("Erasing sector %d @ 0x%08"PRIx32, i, tmp_addr);
+
+		res = xmc4xxx_erase_sector(bank, tmp_addr, false);
+		if (res != ERROR_OK) {
+			LOG_ERROR("Unable to write erase command sequence");
+			goto clear_status_and_exit;
+		}
+
+		/* Now we must wait for the erase operation to end */
+		res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT);
+
+		if (res != ERROR_OK)
+			goto clear_status_and_exit;
+
+		bank->sectors[i].is_erased = 1;
+	}
+
+clear_status_and_exit:
+	res = xmc4xxx_clear_flash_status(bank);
+	return res;
+
+}
+
+static int xmc4xxx_enter_page_mode(struct flash_bank *bank)
+{
+	int res;
+	uint32_t status;
+
+	res = target_write_u32(bank->target, FLASH_CMD_ENTER_PAGEMODE, 0x50);
+	if (res != ERROR_OK) {
+		LOG_ERROR("Unable to write enter page mode command");
+		return ERROR_FAIL;
+	}
+
+	res = xmc4xxx_get_flash_status(bank, &status);
+
+	if (res != ERROR_OK)
+		return res;
+
+	/* Make sure we're in page mode */
+	if (!(status & FSR_PFPAGE_MASK)) {
+		LOG_ERROR("Unable to enter page mode");
+		return ERROR_FAIL;
+	}
+
+	/* Make sure we didn't encounter a sequence error */
+	if (status & FSR_SQER_MASK) {
+		LOG_ERROR("Sequence error while entering page mode");
+		return ERROR_FAIL;
+	}
+
+	return res;
+}
+
+/* The logical erase value of an xmc4xxx memory cell is 0x00,
+ * therefore, we cannot use the built in flash blank check and must
+ * implement our own */
+
+/** Checks whether a memory region is zeroed. */
+static int xmc4xxx_blank_check_memory(struct target *target,
+	uint32_t address, uint32_t count, uint32_t *blank)
+{
+	struct working_area *erase_check_algorithm;
+	struct reg_param reg_params[3];
+	struct armv7m_algorithm armv7m_info;
+	int retval;
+
+	static const uint8_t erase_check_code[] = {
+#include "../../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
+	};
+
+	/* make sure we have a working area */
+	if (target_alloc_working_area(target, sizeof(erase_check_code),
+		&erase_check_algorithm) != ERROR_OK)
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+	retval = target_write_buffer(target, erase_check_algorithm->address,
+			sizeof(erase_check_code), (uint8_t *)erase_check_code);
+	if (retval != ERROR_OK)
+		goto cleanup;
+
+	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+	armv7m_info.core_mode = ARM_MODE_THREAD;
+
+	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+	buf_set_u32(reg_params[0].value, 0, 32, address);
+
+	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+	buf_set_u32(reg_params[1].value, 0, 32, count);
+
+	init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
+	buf_set_u32(reg_params[2].value, 0, 32, 0x00);
+
+	retval = target_run_algorithm(target,
+				      0,
+				      NULL,
+				      3,
+				      reg_params,
+				      erase_check_algorithm->address,
+				      erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
+				      10000,
+				      &armv7m_info);
+
+	if (retval == ERROR_OK)
+		*blank = buf_get_u32(reg_params[2].value, 0, 32);
+
+	destroy_reg_param(&reg_params[0]);
+	destroy_reg_param(&reg_params[1]);
+	destroy_reg_param(&reg_params[2]);
+
+cleanup:
+	target_free_working_area(target, erase_check_algorithm);
+
+	return retval;
+}
+
+static int xmc4xxx_flash_blank_check(struct flash_bank *bank)
+{
+	struct target *target = bank->target;
+	int i;
+	int retval = ERROR_OK;
+	uint32_t blank;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Target not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	for (i = 0; i < bank->num_sectors; i++) {
+		uint32_t address = bank->base + bank->sectors[i].offset;
+		uint32_t size = bank->sectors[i].size;
+
+		LOG_DEBUG("Erase checking 0x%08"PRIx32, address);
+		retval = xmc4xxx_blank_check_memory(target, address, size, &blank);
+
+		if (retval != ERROR_OK)
+			break;
+
+		if (blank == 0x00)
+			bank->sectors[i].is_erased = 1;
+		else
+			bank->sectors[i].is_erased = 0;
+	}
+
+	return retval;
+}
+
+static int xmc4xxx_write_page(struct flash_bank *bank, const uint8_t *pg_buf,
+			      uint32_t offset, bool user_config)
+{
+	int res;
+	uint32_t status;
+
+	/* Base of the flash write command */
+	struct xmc4xxx_command_seq write_cmd_seq[4] = {
+		{FLASH_CMD_WRITE_PAGE_1, 0xAA},
+		{FLASH_CMD_WRITE_PAGE_2, 0x55},
+		{FLASH_CMD_WRITE_PAGE_3, 0xFF}, /* Needs filled in */
+		{0xFF,                   0xFF}	/* Needs filled in */
+	};
+
+	/* The command sequence differs depending on whether this is
+	 * being written to standard flash or the user configuration
+	 * area */
+	if (user_config)
+		write_cmd_seq[2].magic = 0xC0;
+	else
+		write_cmd_seq[2].magic = 0xA0;
+
+	/* Finally, we need to add the address that this page will be
+	 * written to */
+	write_cmd_seq[3].address = bank->base + offset;
+	write_cmd_seq[3].magic = 0xAA;
+
+
+	/* Flash pages are written 256 bytes at a time.  For each 256
+	 * byte chunk, we need to:
+	 * 1. Enter page mode. This activates the flash write buffer
+	 * 2. Load the page buffer with data (2x 32 bit words at a time)
+	 * 3. Burn the page buffer into its intended location
+	 * If the starting offset is not on a 256 byte boundary, we
+	 * will need to pad the beginning of the write buffer
+	 * accordingly. Likewise, if the last page does not fill the
+	 * buffer, we should pad it to avoid leftover data from being
+	 * written to flash
+	 */
+	res = xmc4xxx_enter_page_mode(bank);
+	if (res != ERROR_OK)
+		return res;
+
+	/* Copy the data into the page buffer*/
+	for (int i = 0; i < 256; i += 8) {
+		uint32_t w_lo = target_buffer_get_u32(bank->target, &pg_buf[i]);
+		uint32_t w_hi = target_buffer_get_u32(bank->target, &pg_buf[i + 4]);
+		LOG_DEBUG("WLO: %08"PRIx32, w_lo);
+		LOG_DEBUG("WHI: %08"PRIx32, w_hi);
+
+		/* Data is loaded 2x 32 bit words at a time */
+		res = target_write_u32(bank->target, FLASH_CMD_LOAD_PAGE_1, w_lo);
+		if (res != ERROR_OK)
+			return res;
+
+		res = target_write_u32(bank->target, FLASH_CMD_LOAD_PAGE_2, w_hi);
+		if (res != ERROR_OK)
+			return res;
+
+		/* Check for an error */
+		res = xmc4xxx_get_flash_status(bank, &status);
+		if (res != ERROR_OK)
+			return res;
+
+		if (status & FSR_SQER_MASK) {
+			LOG_ERROR("Error loading page buffer");
+			return ERROR_FAIL;
+		}
+	}
+
+	/* The page buffer is now full, time to commit it to flash */
+
+	res = xmc4xxx_write_command_sequence(bank, write_cmd_seq, ARRAY_SIZE(write_cmd_seq));
+	if (res != ERROR_OK) {
+		LOG_ERROR("Unable to enter write command sequence");
+		return res;
+	}
+
+	/* Read the flash status register */
+	res = xmc4xxx_get_flash_status(bank, &status);
+	if (res != ERROR_OK)
+		return res;
+
+	/* Check for a sequence error */
+	if (status & FSR_SQER_MASK) {
+		LOG_ERROR("Error with flash write sequence");
+		return ERROR_FAIL;
+	}
+
+	/* Make sure a flash write was triggered */
+	if (!(status & FSR_PROG_MASK)) {
+		LOG_ERROR("Failed to write flash page");
+		return ERROR_FAIL;
+	}
+
+	/* Wait for the write operation to end */
+	res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT);
+	if (res != ERROR_OK)
+		return res;
+
+	/* TODO: Verify that page was written without error */
+	return res;
+}
+
+static int xmc4xxx_write(struct flash_bank *bank, const uint8_t *buffer,
+			 uint32_t offset, uint32_t count)
+{
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+	int res = ERROR_OK;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_ERROR("Unable to erase, target is not halted");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	if (!fb->probed) {
+		res = xmc4xxx_probe(bank);
+		if (res != ERROR_OK)
+			return res;
+	}
+
+	/* Make sure we won't run off the end of the flash bank */
+	if ((offset + count) > (bank->size)) {
+		LOG_ERROR("Attempting to write past the end of flash");
+		return ERROR_FAIL;
+	}
+
+
+	/* Attempt to write the passed in buffer to flash */
+	/* Pages are written 256 bytes at a time, we need to handle
+	 * scenarios where padding is required at the beginning and
+	 * end of a page */
+	while (count) {
+		/* page working area */
+		uint8_t tmp_buf[256] = {0};
+
+		/* Amount of data we'll be writing to this page */
+		int remaining;
+		int end_pad;
+
+		remaining = MIN(count, sizeof(tmp_buf));
+		end_pad   = sizeof(tmp_buf) - remaining;
+
+		/* Make sure we're starting on a page boundary */
+		int start_pad = offset % 256;
+		if (start_pad) {
+			LOG_INFO("Write does not start on a 256 byte boundary. "
+				 "Padding by %d bytes", start_pad);
+			memset(tmp_buf, 0xff, start_pad);
+			/* Subtract the amount of start offset from
+			 * the amount of data we'll need to write */
+			remaining -= start_pad;
+		}
+
+		/* Remove the amount we'll be writing from the total count */
+		count -= remaining;
+
+		/* Now copy in the remaining data */
+		memcpy(&tmp_buf[start_pad], buffer, remaining);
+
+		if (end_pad) {
+			LOG_INFO("Padding end of page @%08"PRIx32" by %d bytes",
+				 bank->base + offset, end_pad);
+			memset(&tmp_buf[256 - end_pad], 0xff, end_pad);
+		}
+
+		/* Now commit this page to flash, if there was start
+		 * padding, we should subtract that from the target offset */
+		res = xmc4xxx_write_page(bank, tmp_buf, (offset - start_pad), false);
+		if (res != ERROR_OK) {
+			LOG_ERROR("Unable to write flash page");
+			goto abort_write_and_exit;
+		}
+
+		/* Advance the buffer pointer */
+		buffer += remaining;
+
+		/* Advance the offset */
+		offset += remaining;
+	}
+
+abort_write_and_exit:
+	xmc4xxx_clear_flash_status(bank);
+	return res;
+
+}
+
+static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
+{
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+	uint32_t scu_idcode;
+
+	if (bank->target->state != TARGET_HALTED) {
+		LOG_WARNING("Cannot communicate... target not halted.");
+		return ERROR_TARGET_NOT_HALTED;
+	}
+
+	/* The SCU registers contain the ID of the chip */
+	int res = target_read_u32(bank->target, SCU_REG_BASE + SCU_ID_CHIP, &scu_idcode);
+	if (res != ERROR_OK) {
+		LOG_ERROR("Cannot read device identification register.");
+		return res;
+	}
+
+	uint16_t dev_id = (scu_idcode & 0xfff0) >> 4;
+	uint16_t rev_id = scu_idcode & 0xf;
+	const char *dev_str;
+	const char *rev_str = NULL;
+
+	switch (dev_id) {
+	case 0x100:
+		dev_str = "XMC4100";
+
+		switch (rev_id) {
+		case 0x1:
+			rev_str = "AA";
+			break;
+		case 0x2:
+			rev_str = "AB";
+			break;
+		}
+		break;
+	case 0x200:
+		dev_str = "XMC4200";
+
+		switch (rev_id) {
+		case 0x1:
+			rev_str = "AA";
+			break;
+		case 0x2:
+			rev_str = "AB";
+			break;
+		}
+		break;
+	case 0x400:
+		dev_str = "XMC4400";
+
+		switch (rev_id) {
+		case 0x1:
+			rev_str = "AA";
+			break;
+		case 0x2:
+			rev_str = "AB";
+			break;
+		}
+		break;
+	case 0:
+		/* XMC4500 EES AA13 with date codes before GE212
+		 * had zero SCU_IDCHIP
+		 */
+		dev_str = "XMC4500 EES";
+		rev_str = "AA13";
+		break;
+	case 0x500:
+		dev_str = "XMC4500";
+
+		switch (rev_id) {
+		case 0x2:
+			rev_str = "AA";
+			break;
+		case 0x3:
+			rev_str = "AB";
+			break;
+		case 0x4:
+			rev_str = "AC";
+			break;
+		}
+		break;
+	case 0x700:
+		dev_str = "XMC4700";
+
+		switch (rev_id) {
+		case 0x1:
+			rev_str = "EES-AA";
+			break;
+		}
+		break;
+	case 0x800:
+		dev_str = "XMC4800";
+
+		switch (rev_id) {
+		case 0x1:
+			rev_str = "EES-AA";
+			break;
+		}
+		break;
+
+	default:
+		snprintf(buf, buf_size,
+			 "Cannot identify target as an XMC4xxx. SCU_ID: %"PRIx32"\n",
+			 scu_idcode);
+		return ERROR_OK;
+	}
+
+	/* String to declare protection data held in the private driver */
+	char prot_str[512] = {0};
+	if (fb->read_protected)
+		snprintf(prot_str, sizeof(prot_str), "\nFlash is read protected");
+
+	bool otp_enabled = false;
+	for (int i = 0; i < bank->num_sectors; i++)
+		if (fb->write_prot_otp[i])
+			otp_enabled = true;
+
+	/* If OTP Write protection is enabled (User 2), list each
+	 * sector that has it enabled */
+	char otp_str[8];
+	if (otp_enabled) {
+		strcat(prot_str, "\nOTP Protection is enabled for sectors:\n");
+		for (int i = 0; i < bank->num_sectors; i++) {
+			if (fb->write_prot_otp[i]) {
+				snprintf(otp_str, sizeof(otp_str), "- %d\n", i);
+				strncat(prot_str, otp_str, ARRAY_SIZE(otp_str));
+			}
+		}
+	}
+
+	if (rev_str != NULL)
+		snprintf(buf, buf_size, "%s - Rev: %s%s",
+			 dev_str, rev_str, prot_str);
+	else
+		snprintf(buf, buf_size, "%s - Rev: unknown (0x%01x)%s",
+			 dev_str, rev_id, prot_str);
+
+	return ERROR_OK;
+}
+
+static int xmc4xxx_temp_unprotect(struct flash_bank *bank, int user_level)
+{
+	struct xmc4xxx_flash_bank *fb;
+	int res = ERROR_OK;
+	uint32_t status = 0;
+
+	struct xmc4xxx_command_seq temp_unprot_seq[6] = {
+		{FLASH_CMD_TEMP_UNPROT_1, 0xAA},
+		{FLASH_CMD_TEMP_UNPROT_2, 0x55},
+		{FLASH_CMD_TEMP_UNPROT_3, 0xFF}, /* Needs filled in */
+		{FLASH_CMD_TEMP_UNPROT_4, 0xFF}, /* Needs filled in */
+		{FLASH_CMD_TEMP_UNPROT_5, 0xFF}, /* Needs filled in */
+		{FLASH_CMD_TEMP_UNPROT_6, 0x05}
+	};
+
+	if (user_level < 0 || user_level > 2) {
+		LOG_ERROR("Invalid user level, must be 0-2");
+		return ERROR_FAIL;
+	}
+
+	fb = bank->driver_priv;
+
+	/* Fill in the user level and passwords */
+	temp_unprot_seq[2].magic = user_level;
+	temp_unprot_seq[3].magic = fb->pw1;
+	temp_unprot_seq[4].magic = fb->pw2;
+
+	res = xmc4xxx_write_command_sequence(bank, temp_unprot_seq,
+					     ARRAY_SIZE(temp_unprot_seq));
+	if (res != ERROR_OK) {
+		LOG_ERROR("Unable to write temp unprotect sequence");
+		return res;
+	}
+
+	res = xmc4xxx_get_flash_status(bank, &status);
+	if (res != ERROR_OK)
+		return res;
+
+	if (status & FSR_WPRODIS0) {
+		LOG_INFO("Flash is temporarily unprotected");
+	} else {
+		LOG_INFO("Unable to disable flash protection");
+		res = ERROR_FAIL;
+	}
+
+
+	return res;
+}
+
+static int xmc4xxx_flash_unprotect(struct flash_bank *bank, int32_t level)
+{
+	uint32_t addr;
+	int res;
+
+	if ((level < 0) || (level > 1)) {
+		LOG_ERROR("Invalid user level. Must be 0-1");
+		return ERROR_FAIL;
+	}
+
+	switch (level) {
+	case 0:
+		addr = UCB0_BASE;
+		break;
+	case 1:
+		addr = UCB1_BASE;
+		break;
+	}
+
+	res = xmc4xxx_erase_sector(bank, addr, true);
+
+	if (res != ERROR_OK)
+		LOG_ERROR("Error erasing user configuration block");
+
+	return res;
+}
+
+/* Reference: "XMC4500 Flash Protection.pptx" app note */
+static int xmc4xxx_flash_protect(struct flash_bank *bank, int level, bool read_protect,
+				 int first, int last)
+{
+	/* User configuration block buffers */
+	uint8_t ucp0_buf[8 * sizeof(uint32_t)] = {0};
+	uint32_t ucb_base = 0;
+	uint32_t procon = 0;
+	int res = ERROR_OK;
+	uint32_t status = 0;
+	bool proin = false;
+
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+
+	/* Read protect only works for user 0, make sure we don't try
+	 * to do something silly */
+	if (level != 0 && read_protect) {
+		LOG_ERROR("Read protection is for user level 0 only!");
+		return ERROR_FAIL;
+	}
+
+	/* Check to see if protection is already installed for the
+	 * specified user level.  If it is, the user configuration
+	 * block will need to be erased before we can continue */
+
+	/* Grab the flash status register*/
+	res = xmc4xxx_get_flash_status(bank, &status);
+	if (res != ERROR_OK)
+		return res;
+
+	switch (level) {
+	case 0:
+		if ((status & FSR_RPROIN_MASK) || (status & FSR_WPROIN0_MASK))
+			proin = true;
+		break;
+	case 1:
+		if (status & FSR_WPROIN1_MASK)
+			proin = true;
+		break;
+	case 2:
+		if (status & FSR_WPROIN2_MASK)
+			proin = true;
+		break;
+	}
+
+	if (proin) {
+		LOG_ERROR("Flash protection is installed for user %d"
+			  " and must be removed before continuing", level);
+		return ERROR_FAIL;
+	}
+
+	/* If this device has 12 flash sectors, protection for
+	 * sectors 10 & 11 are handled jointly. If we are trying to
+	 * write all sectors, we should decrement
+	 * last to ensure we don't write to a register bit that
+	 * doesn't exist*/
+	if ((bank->num_sectors == 12) && (last == 12))
+		last--;
+
+	/*  We need to fill out the procon register representation
+	 *   that we will be writing to the device */
+	for (int i = first; i <= last; i++)
+		procon |= 1 << i;
+
+	/* If read protection is requested, set the appropriate bit
+	 * (we checked that this is allowed above) */
+	if (read_protect)
+		procon |= PROCON_RPRO_MASK;
+
+	LOG_DEBUG("Setting flash protection with procon:");
+	LOG_DEBUG("PROCON: %"PRIx32, procon);
+
+	/* First we need to copy in the procon register to the buffer
+	 * we're going to attempt to write.  This is written twice */
+	target_buffer_set_u32(bank->target, &ucp0_buf[0 * 4], procon);
+	target_buffer_set_u32(bank->target, &ucp0_buf[2 * 4], procon);
+
+	/* Now we must copy in both flash passwords.  As with the
+	 * procon data, this must be written twice (4 total words
+	 * worth of data) */
+	target_buffer_set_u32(bank->target, &ucp0_buf[4 * 4], fb->pw1);
+	target_buffer_set_u32(bank->target, &ucp0_buf[5 * 4], fb->pw2);
+	target_buffer_set_u32(bank->target, &ucp0_buf[6 * 4], fb->pw1);
+	target_buffer_set_u32(bank->target, &ucp0_buf[7 * 4], fb->pw2);
+
+	/* Finally, (if requested) we copy in the confirmation
+	 * code so that the protection is permanent and will
+	 * require a password to undo. */
+	target_buffer_set_u32(bank->target, &ucp0_buf[0 * 4], FLASH_PROTECT_CONFIRMATION_CODE);
+	target_buffer_set_u32(bank->target, &ucp0_buf[2 * 4], FLASH_PROTECT_CONFIRMATION_CODE);
+
+	/* Now that the data is copied into place, we must write
+	 * these pages into flash */
+
+	/* The user configuration block base depends on what level of
+	 * protection we're trying to install, select the proper one */
+	switch (level) {
+	case 0:
+		ucb_base = UCB0_BASE;
+		break;
+	case 1:
+		ucb_base = UCB1_BASE;
+		break;
+	case 2:
+		ucb_base = UCB2_BASE;
+		break;
+	}
+
+	/* Write the user config pages */
+	res = xmc4xxx_write_page(bank, ucp0_buf, ucb_base, true);
+	if (res != ERROR_OK) {
+		LOG_ERROR("Error writing user configuration block 0");
+		return res;
+	}
+
+	return ERROR_OK;
+}
+
+static int xmc4xxx_protect(struct flash_bank *bank, int set, int first, int last)
+{
+	int ret;
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+
+	/* Check for flash passwords */
+	if (!fb->pw_set) {
+		LOG_ERROR("Flash passwords not set, use xmc4xxx flash_password to set them");
+		return ERROR_FAIL;
+	}
+
+	/* We want to clear flash protection temporarily*/
+	if (set == 0) {
+		LOG_WARNING("Flash protection will be temporarily disabled"
+			    " for all pages (User 0 only)!");
+		ret = xmc4xxx_temp_unprotect(bank, 0);
+		return ret;
+	}
+
+	/* Install write protection for user 0 on the specified pages */
+	ret = xmc4xxx_flash_protect(bank, 0, false, first, last);
+
+	return ret;
+}
+
+static int xmc4xxx_protect_check(struct flash_bank *bank)
+{
+	int ret;
+	uint32_t protection[3] = {0};
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+
+	ret = target_read_u32(bank->target, FLASH_REG_FLASH0_PROCON0, &protection[0]);
+	if (ret != ERROR_OK) {
+		LOG_ERROR("Unable to read flash User0 protection register");
+		return ret;
+	}
+
+	ret = target_read_u32(bank->target, FLASH_REG_FLASH0_PROCON1, &protection[1]);
+	if (ret != ERROR_OK) {
+		LOG_ERROR("Unable to read flash User1 protection register");
+		return ret;
+	}
+
+	ret = target_read_u32(bank->target, FLASH_REG_FLASH0_PROCON2, &protection[2]);
+	if (ret != ERROR_OK) {
+		LOG_ERROR("Unable to read flash User2 protection register");
+		return ret;
+	}
+
+	int sectors = bank->num_sectors;
+
+	/* On devices with 12 sectors, sectors 10 & 11 are ptected
+	 * together instead of individually */
+	if (sectors == 12)
+		sectors--;
+
+	/* Clear the protection status */
+	for (int i = 0; i < bank->num_sectors; i++) {
+		bank->sectors[i].is_protected = 0;
+		fb->write_prot_otp[i] = false;
+	}
+	fb->read_protected = false;
+
+	/* The xmc4xxx series supports 3 levels of user protection
+	 * (User0, User1 (low priority), and User 2(OTP), we need to
+	 * check all 3 */
+	for (unsigned int i = 0; i < ARRAY_SIZE(protection); i++) {
+
+		/* Check for write protection on every available
+		*  sector */
+		for (int j = 0; j < sectors; j++) {
+			int set = (protection[i] & (1 << j)) ? 1 : 0;
+			bank->sectors[j].is_protected |= set;
+
+			/* Handle sector 11 */
+			if (j == 10)
+				bank->sectors[j + 1].is_protected |= set;
+
+			/* User 2 indicates this protection is
+			 * permanent, make note in the private driver structure */
+			if (i == 2 && set) {
+				fb->write_prot_otp[j] = true;
+
+				/* Handle sector 11 */
+				if (j == 10)
+					fb->write_prot_otp[j + 1] = true;
+			}
+
+		}
+	}
+
+	/* XMC4xxx also supports read proptection, make a note
+	 * in the private driver structure */
+	if (protection[0] & PROCON_RPRO_MASK)
+		fb->read_protected = true;
+
+	return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(xmc4xxx_flash_bank_command)
+{
+	bank->driver_priv = malloc(sizeof(struct xmc4xxx_flash_bank));
+
+	if (!bank->driver_priv)
+		return ERROR_FLASH_OPERATION_FAILED;
+
+	(void)memset(bank->driver_priv, 0, sizeof(struct xmc4xxx_flash_bank));
+
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(xmc4xxx_handle_flash_password_command)
+{
+	int res;
+	struct flash_bank *bank;
+
+	if (CMD_ARGC < 3)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	res = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+	if (res != ERROR_OK)
+		return res;
+
+	struct xmc4xxx_flash_bank *fb = bank->driver_priv;
+
+	errno = 0;
+
+	/* We skip over the flash bank */
+	fb->pw1 = strtol(CMD_ARGV[1], NULL, 16);
+
+	if (errno)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	fb->pw2 = strtol(CMD_ARGV[2], NULL, 16);
+
+	if (errno)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	fb->pw_set = true;
+
+	command_print(CMD_CTX, "XMC4xxx flash passwords set to:\n");
+	command_print(CMD_CTX, "-0x%08"PRIx32"\n", fb->pw1);
+	command_print(CMD_CTX, "-0x%08"PRIx32"\n", fb->pw2);
+	return ERROR_OK;
+}
+
+COMMAND_HANDLER(xmc4xxx_handle_flash_unprotect_command)
+{
+	struct flash_bank *bank;
+	int res;
+	int32_t level;
+
+	if (CMD_ARGC < 2)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	res = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+	if (res != ERROR_OK)
+		return res;
+
+	COMMAND_PARSE_NUMBER(s32, CMD_ARGV[1], level);
+
+	res = xmc4xxx_flash_unprotect(bank, level);
+
+	return res;
+}
+
+static const struct command_registration xmc4xxx_exec_command_handlers[] = {
+	{
+		.name = "flash_password",
+		.handler = xmc4xxx_handle_flash_password_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id password1 password2",
+		.help = "Set the flash passwords used for protect operations. "
+		"Passwords should be in standard hex form (0x00000000). "
+		"(You must call this before any other protect commands) "
+		"NOTE: The xmc4xxx's UCB area only allows for FOUR cycles. "
+		"Please use protection carefully!",
+	},
+	{
+		.name = "flash_unprotect",
+		.handler = xmc4xxx_handle_flash_unprotect_command,
+		.mode = COMMAND_EXEC,
+		.usage = "bank_id user_level[0-1]",
+		.help = "Permanently Removes flash protection (read and write) "
+		"for the specified user level",
+	},	COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration xmc4xxx_command_handlers[] = {
+	{
+		.name = "xmc4xxx",
+		.mode = COMMAND_ANY,
+		.help = "xmc4xxx flash command group",
+		.usage = "",
+		.chain = xmc4xxx_exec_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver xmc4xxx_flash = {
+	.name = "xmc4xxx",
+	.commands = xmc4xxx_command_handlers,
+	.flash_bank_command = xmc4xxx_flash_bank_command,
+	.erase = xmc4xxx_erase,
+	.write = xmc4xxx_write,
+	.read = default_flash_read,
+	.probe = xmc4xxx_probe,
+	.auto_probe = xmc4xxx_probe,
+	.erase_check = xmc4xxx_flash_blank_check,
+	.info = xmc4xxx_get_info_command,
+	.protect_check = xmc4xxx_protect_check,
+	.protect = xmc4xxx_protect,
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/startup.tcl
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/startup.tcl b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/startup.tcl
new file mode 100755
index 0000000..fbb8d8e
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/startup.tcl
@@ -0,0 +1,110 @@
+# Defines basic Tcl procs for OpenOCD flash module
+
+#
+# program utility proc
+# usage: program filename
+# optional args: verify, reset, exit and address
+#
+
+proc program_error {description exit} {
+	if {$exit == 1} {
+		echo $description
+		shutdown error
+	}
+
+	error $description
+}
+
+proc program {filename args} {
+	set exit 0
+
+	foreach arg $args {
+		if {[string equal $arg "verify"]} {
+			set verify 1
+		} elseif {[string equal $arg "reset"]} {
+			set reset 1
+		} elseif {[string equal $arg "exit"]} {
+			set exit 1
+		} else {
+			set address $arg
+		}
+	}
+
+	# make sure init is called
+	if {[catch {init}] != 0} {
+		program_error "** OpenOCD init failed **" 1
+	}
+
+	# reset target and call any init scripts
+	if {[catch {reset init}] != 0} {
+		program_error "** Unable to reset target **" $exit
+	}
+
+	# start programming phase
+	echo "** Programming Started **"
+	if {[info exists address]} {
+		set flash_args "$filename $address"
+	} else {
+		set flash_args "$filename"
+	}
+
+	if {[catch {eval flash write_image erase $flash_args}] == 0} {
+		echo "** Programming Finished **"
+		if {[info exists verify]} {
+			# verify phase
+			echo "** Verify Started **"
+			if {[catch {eval verify_image $flash_args}] == 0} {
+				echo "** Verified OK **"
+			} else {
+				program_error "** Verify Failed **" $exit
+			}
+		}
+
+		if {[info exists reset]} {
+			# reset target if requested
+			# also disable target polling, we are shutting down anyway
+			poll off
+			echo "** Resetting Target **"
+			reset run
+		}
+	} else {
+		program_error "** Programming Failed **" $exit
+	}
+
+	if {$exit == 1} {
+		shutdown
+	}
+	return
+}
+
+add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional"
+add_usage_text program "<filename> \[address\] \[verify\] \[reset\] \[exit\]"
+
+# stm32f0x uses the same flash driver as the stm32f1x
+# this alias enables the use of either name.
+proc stm32f0x args {
+	eval stm32f1x $args
+}
+
+# stm32f3x uses the same flash driver as the stm32f1x
+# this alias enables the use of either name.
+proc stm32f3x args {
+	eval stm32f1x $args
+}
+
+# stm32f4x uses the same flash driver as the stm32f2x
+# this alias enables the use of either name.
+proc stm32f4x args {
+	eval stm32f2x $args
+}
+
+# ease migration to updated flash driver
+proc stm32x args {
+	echo "DEPRECATED! use 'stm32f1x $args' not 'stm32x $args'"
+	eval stm32f1x $args
+}
+
+proc stm32f2xxx args {
+	echo "DEPRECATED! use 'stm32f2x $args' not 'stm32f2xxx $args'"
+	eval stm32f2x $args
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.c
new file mode 100755
index 0000000..f103ed2
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.c
@@ -0,0 +1,114 @@
+/***************************************************************************
+ *   Copyright (C) 2009 Zachary T Welch <zw...@superlucidity.net>             *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <helper/log.h>
+
+COMMAND_HANDLER(handle_foo_command)
+{
+	if (CMD_ARGC < 1 || CMD_ARGC > 2)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+
+	uint32_t address;
+	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
+
+	const char *msg = "<unchanged>";
+	if (CMD_ARGC == 2) {
+		bool enable;
+		COMMAND_PARSE_ENABLE(CMD_ARGV[1], enable);
+		msg = enable ? "enable" : "disable";
+	}
+
+	LOG_INFO("%s: address=0x%8.8" PRIx32 " enabled=%s", CMD_NAME, address, msg);
+	return ERROR_OK;
+}
+
+static bool foo_flag;
+
+COMMAND_HANDLER(handle_flag_command)
+{
+	return CALL_COMMAND_HANDLER(handle_command_parse_bool,
+		&foo_flag, "foo flag");
+}
+
+static const struct command_registration foo_command_handlers[] = {
+	{
+		.name = "bar",
+		.handler = &handle_foo_command,
+		.mode = COMMAND_ANY,
+		.usage = "address ['enable'|'disable']",
+		.help = "an example command",
+	},
+	{
+		.name = "baz",
+		.handler = &handle_foo_command,
+		.mode = COMMAND_ANY,
+		.usage = "address ['enable'|'disable']",
+		.help = "a sample command",
+	},
+	{
+		.name = "flag",
+		.handler = &handle_flag_command,
+		.mode = COMMAND_ANY,
+		.usage = "[on|off]",
+		.help = "set a flag",
+	},
+	COMMAND_REGISTRATION_DONE
+};
+
+static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name)
+{
+	if (CMD_ARGC > 1)
+		return ERROR_COMMAND_SYNTAX_ERROR;
+	if (1 == CMD_ARGC) {
+		*sep = " ";
+		*name = CMD_ARGV[0];
+	} else
+		*sep = *name = "";
+
+	return ERROR_OK;
+}
+COMMAND_HANDLER(handle_hello_command)
+{
+	const char *sep, *name;
+	int retval = CALL_COMMAND_HANDLER(handle_hello_args, &sep, &name);
+	if (ERROR_OK == retval)
+		command_print(CMD_CTX, "Greetings%s%s!", sep, name);
+	return retval;
+}
+
+const struct command_registration hello_command_handlers[] = {
+	{
+		.name = "hello",
+		.handler = handle_hello_command,
+		.mode = COMMAND_ANY,
+		.help = "prints a warm welcome",
+		.usage = "[name]",
+	},
+	{
+		.name = "foo",
+		.mode = COMMAND_ANY,
+		.help = "example command handler skeleton",
+
+		.chain = foo_command_handlers,
+	},
+	COMMAND_REGISTRATION_DONE
+};

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.h
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.h b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.h
new file mode 100755
index 0000000..d066951
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/hello.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ *   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 OPENOCD_HELLO_H
+#define OPENOCD_HELLO_H
+
+struct command_registration;
+
+/**
+ * Export the registration for the hello command group, so it can be
+ * embedded in example drivers.
+ */
+extern const struct command_registration hello_command_handlers[];
+
+#endif	/* OPENOCD_HELLO_H */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/Makefile.am
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/Makefile.am b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/Makefile.am
new file mode 100755
index 0000000..64caf98
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/Makefile.am
@@ -0,0 +1,56 @@
+include $(top_srcdir)/common.mk
+
+METASOURCES = AUTO
+noinst_LTLIBRARIES = libhelper.la
+
+CONFIGFILES = options.c time_support_common.c
+
+libhelper_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS)
+
+libhelper_la_SOURCES = \
+	binarybuffer.c \
+	$(CONFIGFILES) \
+	configuration.c \
+	log.c \
+	command.c \
+	time_support.c \
+	replacements.c \
+	fileio.c \
+	util.c \
+	jep106.c \
+	jim-nvp.c
+
+if IOUTIL
+libhelper_la_SOURCES += ioutil.c
+else
+libhelper_la_SOURCES += ioutil_stubs.c
+endif
+
+libhelper_la_CFLAGS =
+if IS_MINGW
+# FD_* macros are sloppy with their signs on MinGW32 platform
+libhelper_la_CFLAGS += -Wno-sign-compare
+endif
+
+noinst_HEADERS = \
+	binarybuffer.h \
+	configuration.h \
+	ioutil.h \
+	list.h \
+	util.h \
+	types.h \
+	log.h \
+	command.h \
+	time_support.h \
+	replacements.h \
+	fileio.h \
+	system.h \
+	bin2char.sh \
+	jep106.h \
+	jep106.inc \
+	update_jep106.pl \
+	jim-nvp.h
+
+EXTRA_DIST = startup.tcl
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/bin2char.sh
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/bin2char.sh b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/bin2char.sh
new file mode 100755
index 0000000..85a0fd6
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/bin2char.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+[ $# != 0 ] && {
+    echo "Usage: $0"
+    echo
+    echo "Read binary data from standard input and write it as a comma separated"
+    echo "list of hexadecimal byte values to standard ouput. The output is usable"
+    echo "as a C array initializer. It is terminated with a comma so it can be"
+    echo "continued e.g. for zero termination."
+    exit 1
+}
+
+echo "/* Autogenerated with $0 */"
+od -v -A n -t x1 | sed 's/ *\(..\) */0x\1,/g'

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/binarybuffer.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/binarybuffer.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/binarybuffer.c
new file mode 100755
index 0000000..3cadabd
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/helper/binarybuffer.c
@@ -0,0 +1,420 @@
+/***************************************************************************
+ *   Copyright (C) 2004, 2005 by Dominic Rath                              *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2007,2008 �yvind Harboe                                 *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "log.h"
+#include "binarybuffer.h"
+
+static const unsigned char bit_reverse_table256[] = {
+	0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+	0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+	0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+	0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+	0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+	0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+	0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+	0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+	0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+	0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+	0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+	0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+	0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+	0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+	0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+	0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+void *buf_cpy(const void *from, void *_to, unsigned size)
+{
+	if (NULL == from || NULL == _to)
+		return NULL;
+
+	/* copy entire buffer */
+	memcpy(_to, from, DIV_ROUND_UP(size, 8));
+
+	/* mask out bits that don't belong to the buffer */
+	unsigned trailing_bits = size % 8;
+	if (trailing_bits) {
+		uint8_t *to = _to;
+		to[size / 8] &= (1 << trailing_bits) - 1;
+	}
+	return _to;
+}
+
+static bool buf_cmp_masked(uint8_t a, uint8_t b, uint8_t m)
+{
+	return (a & m) != (b & m);
+}
+static bool buf_cmp_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing)
+{
+	uint8_t mask = (1 << trailing) - 1;
+	return buf_cmp_masked(a, b, mask & m);
+}
+
+bool buf_cmp(const void *_buf1, const void *_buf2, unsigned size)
+{
+	if (!_buf1 || !_buf2)
+		return _buf1 != _buf2;
+
+	unsigned last = size / 8;
+	if (memcmp(_buf1, _buf2, last) != 0)
+		return false;
+
+	unsigned trailing = size % 8;
+	if (!trailing)
+		return false;
+
+	const uint8_t *buf1 = _buf1, *buf2 = _buf2;
+	return buf_cmp_trailing(buf1[last], buf2[last], 0xff, trailing);
+}
+
+bool buf_cmp_mask(const void *_buf1, const void *_buf2,
+	const void *_mask, unsigned size)
+{
+	if (!_buf1 || !_buf2)
+		return _buf1 != _buf2 || _buf1 != _mask;
+
+	const uint8_t *buf1 = _buf1, *buf2 = _buf2, *mask = _mask;
+	unsigned last = size / 8;
+	for (unsigned i = 0; i < last; i++) {
+		if (buf_cmp_masked(buf1[i], buf2[i], mask[i]))
+			return true;
+	}
+	unsigned trailing = size % 8;
+	if (!trailing)
+		return false;
+	return buf_cmp_trailing(buf1[last], buf2[last], mask[last], trailing);
+}
+
+
+void *buf_set_ones(void *_buf, unsigned size)
+{
+	uint8_t *buf = _buf;
+	if (!buf)
+		return NULL;
+
+	memset(buf, 0xff, size / 8);
+
+	unsigned trailing_bits = size % 8;
+	if (trailing_bits)
+		buf[size / 8] = (1 << trailing_bits) - 1;
+
+	return buf;
+}
+
+void *buf_set_buf(const void *_src, unsigned src_start,
+	void *_dst, unsigned dst_start, unsigned len)
+{
+	const uint8_t *src = _src;
+	uint8_t *dst = _dst;
+	unsigned i, sb, db, sq, dq, lb, lq;
+
+	sb = src_start / 8;
+	db = dst_start / 8;
+	sq = src_start % 8;
+	dq = dst_start % 8;
+	lb = len / 8;
+	lq = len % 8;
+
+	src += sb;
+	dst += db;
+
+	/* check if both buffers are on byte boundary and
+	 * len is a multiple of 8bit so we can simple copy
+	 * the buffer */
+	if ((sq == 0) && (dq == 0) &&  (lq == 0)) {
+		for (i = 0; i < lb; i++)
+			*dst++ = *src++;
+		return _dst;
+	}
+
+	/* fallback to slow bit copy */
+	for (i = 0; i < len; i++) {
+		if (((*src >> (sq&7)) & 1) == 1)
+			*dst |= 1 << (dq&7);
+		else
+			*dst &= ~(1 << (dq&7));
+		if (sq++ == 7) {
+			sq = 0;
+			src++;
+		}
+		if (dq++ == 7) {
+			dq = 0;
+			dst++;
+		}
+	}
+
+	return _dst;
+}
+
+uint32_t flip_u32(uint32_t value, unsigned int num)
+{
+	uint32_t c = (bit_reverse_table256[value & 0xff] << 24) |
+		(bit_reverse_table256[(value >> 8) & 0xff] << 16) |
+		(bit_reverse_table256[(value >> 16) & 0xff] << 8) |
+		(bit_reverse_table256[(value >> 24) & 0xff]);
+
+	if (num < 32)
+		c = c >> (32 - num);
+
+	return c;
+}
+
+static int ceil_f_to_u32(float x)
+{
+	if (x < 0)	/* return zero for negative numbers */
+		return 0;
+
+	uint32_t y = x;	/* cut off fraction */
+
+	if ((x - y) > 0.0)	/* if there was a fractional part, increase by one */
+		y++;
+
+	return y;
+}
+
+char *buf_to_str(const void *_buf, unsigned buf_len, unsigned radix)
+{
+	float factor;
+	switch (radix) {
+		case 16:
+			factor = 2.0;	/* log(256) / log(16) = 2.0 */
+			break;
+		case 10:
+			factor = 2.40824;	/* log(256) / log(10) = 2.40824 */
+			break;
+		case 8:
+			factor = 2.66667;	/* log(256) / log(8) = 2.66667 */
+			break;
+		default:
+			return NULL;
+	}
+
+	unsigned str_len = ceil_f_to_u32(DIV_ROUND_UP(buf_len, 8) * factor);
+	char *str = calloc(str_len + 1, 1);
+
+	const uint8_t *buf = _buf;
+	int b256_len = DIV_ROUND_UP(buf_len, 8);
+	for (int i = b256_len - 1; i >= 0; i--) {
+		uint32_t tmp = buf[i];
+		if (((unsigned)i == (buf_len / 8)) && (buf_len % 8))
+			tmp &= (0xff >> (8 - (buf_len % 8)));
+
+		/* base-256 digits */
+		for (unsigned j = str_len; j > 0; j--) {
+			tmp += (uint32_t)str[j-1] * 256;
+			str[j-1] = (uint8_t)(tmp % radix);
+			tmp /= radix;
+		}
+	}
+
+	const char * const DIGITS = "0123456789ABCDEF";
+	for (unsigned j = 0; j < str_len; j++)
+		str[j] = DIGITS[(int)str[j]];
+
+	return str;
+}
+
+/** identify radix, and skip radix-prefix (0, 0x or 0X) */
+static void str_radix_guess(const char **_str, unsigned *_str_len,
+	unsigned *_radix)
+{
+	unsigned radix = *_radix;
+	if (0 != radix)
+		return;
+	const char *str = *_str;
+	unsigned str_len = *_str_len;
+	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+		radix = 16;
+		str += 2;
+		str_len -= 2;
+	} else if ((str[0] == '0') && (str_len != 1)) {
+		radix = 8;
+		str += 1;
+		str_len -= 1;
+	} else
+		radix = 10;
+	*_str = str;
+	*_str_len = str_len;
+	*_radix = radix;
+}
+
+int str_to_buf(const char *str, unsigned str_len,
+	void *_buf, unsigned buf_len, unsigned radix)
+{
+	str_radix_guess(&str, &str_len, &radix);
+
+	float factor;
+	if (radix == 16)
+		factor = 0.5;	/* log(16) / log(256) = 0.5 */
+	else if (radix == 10)
+		factor = 0.41524;	/* log(10) / log(256) = 0.41524 */
+	else if (radix == 8)
+		factor = 0.375;	/* log(8) / log(256) = 0.375 */
+	else
+		return 0;
+
+	/* copy to zero-terminated buffer */
+	char *charbuf = strndup(str, str_len);
+
+	/* number of digits in base-256 notation */
+	unsigned b256_len = ceil_f_to_u32(str_len * factor);
+	uint8_t *b256_buf = calloc(b256_len, 1);
+
+	/* go through zero terminated buffer
+	 * input digits (ASCII) */
+	unsigned i;
+	for (i = 0; charbuf[i]; i++) {
+		uint32_t tmp = charbuf[i];
+		if ((tmp >= '0') && (tmp <= '9'))
+			tmp = (tmp - '0');
+		else if ((tmp >= 'a') && (tmp <= 'f'))
+			tmp = (tmp - 'a' + 10);
+		else if ((tmp >= 'A') && (tmp <= 'F'))
+			tmp = (tmp - 'A' + 10);
+		else
+			continue;	/* skip characters other than [0-9,a-f,A-F] */
+
+		if (tmp >= radix)
+			continue;	/* skip digits invalid for the current radix */
+
+		/* base-256 digits */
+		for (unsigned j = 0; j < b256_len; j++) {
+			tmp += (uint32_t)b256_buf[j] * radix;
+			b256_buf[j] = (uint8_t)(tmp & 0xFF);
+			tmp >>= 8;
+		}
+
+	}
+
+	uint8_t *buf = _buf;
+	for (unsigned j = 0; j < DIV_ROUND_UP(buf_len, 8); j++) {
+		if (j < b256_len)
+			buf[j] = b256_buf[j];
+		else
+			buf[j] = 0;
+	}
+
+	/* mask out bits that don't belong to the buffer */
+	if (buf_len % 8)
+		buf[(buf_len / 8)] &= 0xff >> (8 - (buf_len % 8));
+
+	free(b256_buf);
+	free(charbuf);
+
+	return i;
+}
+
+void bit_copy_queue_init(struct bit_copy_queue *q)
+{
+	INIT_LIST_HEAD(&q->list);
+}
+
+int bit_copy_queued(struct bit_copy_queue *q, uint8_t *dst, unsigned dst_offset, const uint8_t *src,
+	unsigned src_offset, unsigned bit_count)
+{
+	struct bit_copy_queue_entry *qe = malloc(sizeof(*qe));
+	if (!qe)
+		return ERROR_FAIL;
+
+	qe->dst = dst;
+	qe->dst_offset = dst_offset;
+	qe->src = src;
+	qe->src_offset = src_offset;
+	qe->bit_count = bit_count;
+	list_add_tail(&qe->list, &q->list);
+
+	return ERROR_OK;
+}
+
+void bit_copy_execute(struct bit_copy_queue *q)
+{
+	struct bit_copy_queue_entry *qe;
+	struct bit_copy_queue_entry *tmp;
+	list_for_each_entry_safe(qe, tmp, &q->list, list) {
+		bit_copy(qe->dst, qe->dst_offset, qe->src, qe->src_offset, qe->bit_count);
+		list_del(&qe->list);
+		free(qe);
+	}
+}
+
+void bit_copy_discard(struct bit_copy_queue *q)
+{
+	struct bit_copy_queue_entry *qe;
+	struct bit_copy_queue_entry *tmp;
+	list_for_each_entry_safe(qe, tmp, &q->list, list) {
+		list_del(&qe->list);
+		free(qe);
+	}
+}
+
+int unhexify(char *bin, const char *hex, int count)
+{
+	int i, tmp;
+
+	for (i = 0; i < count; i++) {
+		if (sscanf(hex + (2 * i), "%02x", &tmp) != 1)
+			return i;
+		bin[i] = tmp;
+	}
+
+	return i;
+}
+
+int hexify(char *hex, const char *bin, int count, int out_maxlen)
+{
+	int i, cmd_len = 0;
+
+	/* May use a length, or a null-terminated string as input. */
+	if (count == 0)
+		count = strlen(bin);
+
+	for (i = 0; i < count; i++)
+		cmd_len += snprintf(hex + cmd_len, out_maxlen - cmd_len, "%02x", bin[i] & 0xff);
+
+	return cmd_len;
+}
+
+void buffer_shr(void *_buf, unsigned buf_len, unsigned count)
+{
+	unsigned i;
+	unsigned char *buf = _buf;
+	unsigned bytes_to_remove;
+	unsigned shift;
+
+	bytes_to_remove = count / 8;
+	shift = count - (bytes_to_remove * 8);
+
+	for (i = 0; i < (buf_len - 1); i++)
+		buf[i] = (buf[i] >> shift) | ((buf[i+1] << (8 - shift)) & 0xff);
+
+	buf[(buf_len - 1)] = buf[(buf_len - 1)] >> shift;
+
+	if (bytes_to_remove) {
+		memmove(buf, &buf[bytes_to_remove], buf_len - bytes_to_remove);
+		memset(&buf[buf_len - bytes_to_remove], 0, bytes_to_remove);
+	}
+}