diff --git a/README b/README
index a6b4c5bd01194c879df33d01c00b4b7ed2cd3c25..11ea2db3b2896d21d8f179e84ca34c62c5e0723a 100644
--- a/README
+++ b/README
@@ -130,7 +130,7 @@ ADUC702x, AT91SAM, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis,
 LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI,
 Milandr, NIIET, NuMicro, PIC32mx, PSoC4, SiM3x, Stellaris, STM32, STMSMI,
 STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx,
-i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400, XMC4xxx.
+i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400, XMC1xxx, XMC4xxx.
 
 
 ==================
diff --git a/contrib/loaders/flash/xmc1xxx/Makefile b/contrib/loaders/flash/xmc1xxx/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..066466efdb5656975158bb04cc1e8286c74987f8
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/Makefile
@@ -0,0 +1,30 @@
+BIN2C = ../../../../src/helper/bin2char.sh
+
+CROSS_COMPILE ?= arm-none-eabi-
+
+CC=$(CROSS_COMPILE)gcc
+OBJCOPY=$(CROSS_COMPILE)objcopy
+OBJDUMP=$(CROSS_COMPILE)objdump
+
+all: erase.inc erase_check.inc write.inc
+
+.PHONY: clean
+
+.INTERMEDIATE: erase.elf erase_check.elf write.elf
+
+erase.elf erase_check.elf write.elf: xmc1xxx.S
+
+%.elf: %.S
+	$(CC) -static -nostartfiles $< -o $@
+
+%.lst: %.elf
+	$(OBJDUMP) -S $< > $@
+
+%.bin: %.elf
+	$(OBJCOPY) -Obinary $< $@
+
+%.inc: %.bin
+	$(BIN2C) < $< > $@
+
+clean:
+	-rm -f *.elf *.lst *.bin *.inc
diff --git a/contrib/loaders/flash/xmc1xxx/erase.S b/contrib/loaders/flash/xmc1xxx/erase.S
new file mode 100644
index 0000000000000000000000000000000000000000..e5a4808fccd7f602bc84beca638b249f224a7e0d
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/erase.S
@@ -0,0 +1,53 @@
+/*
+ * Infineon XMC1000 flash sectors erase
+ *
+ * Copyright (c) 2016 Andreas Färber
+ *
+ * Based on XMC1100 AA-Step Reference Manual
+ *
+ * License: GPL-2.0+
+ */
+
+#include "xmc1xxx.S"
+
+#define DUMMY_VALUE 0x42
+
+	.macro erase_page, nvmbase, addr, tmp, tmp2
+
+	movs	\tmp, #DUMMY_VALUE
+	str	\tmp, [\addr]
+
+	busy_wait \nvmbase, \tmp, \tmp2
+
+	.endm
+
+
+	.macro erase, nvmbase, addr, end, tmp, tmp2
+
+	movs	\tmp, #NVMPROG_ACTION_PAGE_ERASE_CONTINUOUS
+	strh	\tmp, [\nvmbase, #NVMPROG]
+2001:
+	erase_page \nvmbase, \addr, \tmp, \tmp2
+
+	movs	\tmp, #(NVM_PAGE_SIZE - 1)
+	adds	\tmp, \tmp, #1
+	add	\addr, \addr, \tmp
+	cmp	\addr, \end
+	blt	2001b
+
+	movs	\tmp, #NVMPROG_ACTION_IDLE
+	strh	\tmp, [\nvmbase, #NVMPROG]
+
+	.endm
+
+
+	/*
+	 * r0 = 0x40050000
+	 * r1 = e.g. 0x10001000
+	 * r2 = e.g. 0x10011000
+	 * NVMPROG.ACTION = 0x00
+	 */
+erase:
+	erase r0, r1, r2, r3, r4
+
+	bkpt	#0
diff --git a/contrib/loaders/flash/xmc1xxx/erase.inc b/contrib/loaders/flash/xmc1xxx/erase.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b33e57d1f54b3e8a643f1731eca32adae2f3d774
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/erase.inc
@@ -0,0 +1,4 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0xa2,0x23,0x83,0x80,0x42,0x23,0x0b,0x60,0x03,0x88,0x01,0x24,0x23,0x40,0xa3,0x42,
+0xfa,0xd0,0xff,0x23,0x01,0x33,0x19,0x44,0x91,0x42,0xf3,0xdb,0x00,0x23,0x83,0x80,
+0x00,0xbe,
diff --git a/contrib/loaders/flash/xmc1xxx/erase_check.S b/contrib/loaders/flash/xmc1xxx/erase_check.S
new file mode 100644
index 0000000000000000000000000000000000000000..6c993443a9d3f30e9d9009ff0f21c9bd42747f0c
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/erase_check.S
@@ -0,0 +1,67 @@
+/*
+ * Infineon XMC1000 flash sector erase check
+ *
+ * Copyright (c) 2016 Andreas Färber
+ *
+ * Based on XMC1100 AA-Step Reference Manual
+ *
+ * License: GPL-2.0+
+ */
+
+#include "xmc1xxx.S"
+
+	.macro verify_block, nvmbase, addr, tmp, tmp2
+
+	movs	\tmp, #0x00
+	mvns	\tmp, \tmp
+	str	\tmp, [\addr, #0x0]
+	str	\tmp, [\addr, #0x4]
+	str	\tmp, [\addr, #0x8]
+	str	\tmp, [\addr, #0xC]
+
+	busy_wait \nvmbase, \tmp, \tmp2
+
+	.endm
+
+
+	.macro erase_check, nvmbase, addr, end, tmp, tmp2
+
+	ldrh	\tmp, [\nvmbase, #NVMCONF]
+	movs	\tmp2, #NVMCONF_HRLEV_MASK
+	mvns	\tmp2, \tmp2
+	ands	\tmp, \tmp, \tmp2
+	movs	\tmp2, #NVMCONF_HRLEV_HRE
+	orrs	\tmp, \tmp, \tmp2
+	strh	\tmp, [\nvmbase, #NVMCONF]
+
+	movs	\tmp, #NVMPROG_ACTION_VERIFY_CONTINUOUS
+	strh	\tmp, [\nvmbase, #NVMPROG]
+2001:
+	verify_block \nvmbase, \addr, \tmp, \tmp2
+
+	ldrh	\tmp, [\nvmbase, #NVMSTATUS]
+	movs	\tmp2, #NVMSTATUS_VERR_MASK
+	ands	\tmp, \tmp, \tmp2
+	cmp	\tmp, #NVMSTATUS_VERR_NOFAIL
+	bne	2010f
+
+	adds	\addr, \addr, #NVM_BLOCK_SIZE
+	cmp	\addr, \end
+	blt	2001b
+2010:
+	movs	\tmp, #NVMPROG_ACTION_IDLE
+	strh	\tmp, [\nvmbase, #NVMPROG]
+
+	.endm
+
+
+	/*
+	 * r0 = 0x40050000
+	 * r1 = e.g. 0x10001000
+	 * r2 = e.g. 0x10002000
+	 * NVMPROG.ACTION = 0x00
+	 */
+erase_check:
+	erase_check r0, r1, r2, r3, r4
+
+	bkpt	#0
diff --git a/contrib/loaders/flash/xmc1xxx/erase_check.inc b/contrib/loaders/flash/xmc1xxx/erase_check.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8fc8e0b5d51661beb4457e04a325725dbfaa4037
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/erase_check.inc
@@ -0,0 +1,5 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x03,0x89,0x06,0x24,0xe4,0x43,0x23,0x40,0x04,0x24,0x23,0x43,0x03,0x81,0xe0,0x23,
+0x83,0x80,0x00,0x23,0xdb,0x43,0x0b,0x60,0x4b,0x60,0x8b,0x60,0xcb,0x60,0x03,0x88,
+0x01,0x24,0x23,0x40,0xa3,0x42,0xfa,0xd0,0x03,0x88,0x0c,0x24,0x23,0x40,0x00,0x2b,
+0x02,0xd1,0x10,0x31,0x91,0x42,0xec,0xdb,0x00,0x23,0x83,0x80,0x00,0xbe,
diff --git a/contrib/loaders/flash/xmc1xxx/write.S b/contrib/loaders/flash/xmc1xxx/write.S
new file mode 100644
index 0000000000000000000000000000000000000000..640f6ca960a822a634f0667013cc6cd8e457dc08
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/write.S
@@ -0,0 +1,58 @@
+/*
+ * Infineon XMC1000 flash write
+ *
+ * Copyright (c) 2016 Andreas Färber
+ *
+ * Based on XMC1100 AA-Step Reference Manual
+ *
+ * License: GPL-2.0+
+ */
+
+#include "xmc1xxx.S"
+
+	.macro write_block, nvmbase, dest, src, tmp, tmp2
+
+	ldr	\tmp, [\src,  #0x0]
+	str	\tmp, [\dest, #0x0]
+	ldr	\tmp, [\src,  #0x4]
+	str	\tmp, [\dest, #0x4]
+	ldr	\tmp, [\src,  #0x8]
+	str	\tmp, [\dest, #0x8]
+	ldr	\tmp, [\src,  #0xc]
+	str	\tmp, [\dest, #0xc]
+
+	busy_wait \nvmbase, \tmp, \tmp2
+
+	.endm
+
+
+	.macro write, nvmbase, dest, src, count, tmp, tmp2
+
+	movs	\tmp, #NVMPROG_ACTION_WRITE_CONTINUOUS
+	strh	\tmp, [\nvmbase, #NVMPROG]
+1001:
+	write_block \nvmbase, \dest, \src, \tmp, \tmp2
+
+	adds	\dest, \dest, #NVM_BLOCK_SIZE
+	adds	\src, \src, #NVM_BLOCK_SIZE
+	subs	\count, \count, #1
+	cmp	\count, #0
+	bgt	1001b
+
+	movs	\tmp, #NVMPROG_ACTION_IDLE
+	strh	\tmp, [\nvmbase, #NVMPROG]
+
+	.endm
+
+
+	/*
+	 * r0 = 0x40050000
+	 * r1 = e.g. 0x10001000
+	 * r2 = e.g. 0x20000000
+	 * r3 = e.g. 1
+	 * NVMPROG.ACTION = 0x00
+	 */
+write:
+	write r0, r1, r2, r3, r4, r5
+
+	bkpt	#0
diff --git a/contrib/loaders/flash/xmc1xxx/write.inc b/contrib/loaders/flash/xmc1xxx/write.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8272bb7e7d4caa09125da6d0f316f8458c637719
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/write.inc
@@ -0,0 +1,4 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0xa1,0x24,0x84,0x80,0x14,0x68,0x0c,0x60,0x54,0x68,0x4c,0x60,0x94,0x68,0x8c,0x60,
+0xd4,0x68,0xcc,0x60,0x04,0x88,0x01,0x25,0x2c,0x40,0xac,0x42,0xfa,0xd0,0x10,0x31,
+0x10,0x32,0x01,0x3b,0x00,0x2b,0xed,0xdc,0x00,0x24,0x84,0x80,0x00,0xbe,
diff --git a/contrib/loaders/flash/xmc1xxx/xmc1xxx.S b/contrib/loaders/flash/xmc1xxx/xmc1xxx.S
new file mode 100644
index 0000000000000000000000000000000000000000..dfe7d3f41ef602d14be8c24ab40ab4602285d5bc
--- /dev/null
+++ b/contrib/loaders/flash/xmc1xxx/xmc1xxx.S
@@ -0,0 +1,46 @@
+/*
+ * Infineon XMC1000 flash
+ *
+ * Copyright (c) 2016 Andreas Färber
+ *
+ * Based on XMC1100 AA-Step Reference Manual
+ *
+ * License: GPL-2.0+
+ */
+
+	.text
+	.syntax unified
+	.cpu cortex-m0
+	.thumb
+	.thumb_func
+
+#define NVMSTATUS	0x00
+#define NVMPROG		0x04
+#define NVMCONF		0x08
+
+#define NVMSTATUS_BUSY		(1 << 0)
+#define NVMSTATUS_VERR_NOFAIL	(0x0 << 2)
+#define NVMSTATUS_VERR_MASK	(0x3 << 2)
+
+#define NVMPROG_ACTION_IDLE			0x00
+#define NVMPROG_ACTION_WRITE_CONTINUOUS		0xA1
+#define NVMPROG_ACTION_PAGE_ERASE_CONTINUOUS	0xA2
+#define NVMPROG_ACTION_VERIFY_CONTINUOUS	0xE0
+
+#define NVMCONF_HRLEV_NR	(0x0 << 1)
+#define NVMCONF_HRLEV_HRE	(0x2 << 1)
+#define NVMCONF_HRLEV_MASK	(0x3 << 1)
+
+#define NVM_WORD_SIZE	4
+#define NVM_BLOCK_SIZE	(4 * NVM_WORD_SIZE)
+#define NVM_PAGE_SIZE	(16 * NVM_BLOCK_SIZE)
+
+	.macro busy_wait, nvmbase, tmp, tmp2
+1:
+	ldrh	\tmp, [\nvmbase, #NVMSTATUS]
+	movs	\tmp2, #NVMSTATUS_BUSY
+	ands	\tmp, \tmp, \tmp2
+	cmp	\tmp, \tmp2
+	beq	1b
+
+	.endm
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 8e7c7f8a70df15eb5c7e23de4a8f1bbe21cc0533..e839191b23ca1b3501077a04e8a074996d6cd167 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -5977,6 +5977,11 @@ the flash clock.
 @end deffn
 @end deffn
 
+@deffn {Flash Driver} xmc1xxx
+All members of the XMC1xxx microcontroller family from Infineon.
+This driver does not require the chip and bus width to be specified.
+@end deffn
+
 @deffn {Flash Driver} xmc4xxx
 All members of the XMC4xxx microcontroller family from Infineon.
 This driver does not require the chip and bus width to be specified.
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index b5fab1f1206984c5a28f82f3d2be2b6827b6ce5b..3386211ee61b382308984663d03a58a3ee1b908d 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -53,6 +53,7 @@ NOR_DRIVERS = \
 	str9xpec.c \
 	tms470.c \
 	virtual.c \
+	xmc1xxx.c \
 	xmc4xxx.c
 
 noinst_HEADERS = \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 51a401840ec7d27b8433d466c09132ca8f9fd780..e39b37e4b654b3fbcc618bdd5bda689299e179e5 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -65,6 +65,7 @@ extern struct flash_driver str9x_flash;
 extern struct flash_driver str9xpec_flash;
 extern struct flash_driver tms470_flash;
 extern struct flash_driver virtual_flash;
+extern struct flash_driver xmc1xxx_flash;
 extern struct flash_driver xmc4xxx_flash;
 
 /**
@@ -115,6 +116,7 @@ static struct flash_driver *flash_drivers[] = {
 	&str9xpec_flash,
 	&tms470_flash,
 	&virtual_flash,
+	&xmc1xxx_flash,
 	&xmc4xxx_flash,
 	NULL,
 };
diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c
new file mode 100644
index 0000000000000000000000000000000000000000..bb2ec1272a34d8e49859ef642801145d7f54534a
--- /dev/null
+++ b/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,
+};
diff --git a/tcl/board/xmc-2go.cfg b/tcl/board/xmc-2go.cfg
index 664426307caca952aabd99304bb40be3056c80e8..90dbf43660c373034fb60a52908260544acc5839 100644
--- a/tcl/board/xmc-2go.cfg
+++ b/tcl/board/xmc-2go.cfg
@@ -9,6 +9,7 @@ source [find interface/jlink.cfg]
 transport select swd
 
 set CHIPNAME xmc1100
+set WORKAREASIZE 0x4000
 source [find target/xmc1xxx.cfg]
 
 reset_config srst_only srst_nogate
diff --git a/tcl/board/xmc1100-boot-kit.cfg b/tcl/board/xmc1100-boot-kit.cfg
index 4c83fd3ace7bb4fb02395e16f6ac5af4f3c53902..5e7c607344766a8618a27a0a4923ecdd727404fd 100644
--- a/tcl/board/xmc1100-boot-kit.cfg
+++ b/tcl/board/xmc1100-boot-kit.cfg
@@ -9,6 +9,7 @@ source [find interface/jlink.cfg]
 transport select swd
 
 set CHIPNAME xmc1100
+set WORKAREASIZE 0x4000
 source [find target/xmc1xxx.cfg]
 
 reset_config srst_only srst_nogate
diff --git a/tcl/target/xmc1xxx.cfg b/tcl/target/xmc1xxx.cfg
index 0a0e47eeac83eefaab82c1290014acb0c072d719..d3123c4376275cdae560ac44a44efbe330c84f38 100644
--- a/tcl/target/xmc1xxx.cfg
+++ b/tcl/target/xmc1xxx.cfg
@@ -24,4 +24,17 @@ swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_SWD_TAPID
 set _TARGETNAME $_CHIPNAME.cpu
 target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME
 
+if { [info exists WORKAREASIZE] } {
+   set _WORKAREASIZE $WORKAREASIZE
+} else {
+   set _WORKAREASIZE 0x4000
+}
+
+$_TARGETNAME configure -work-area-phys 0x20000000 \
+                       -work-area-size $_WORKAREASIZE \
+                       -work-area-backup 0
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME xmc1xxx 0x10000000 0 0 0 $_TARGETNAME
+
 adapter_khz 1000