flash/nor: Add Infineon XMC1000 flash driver 18/3418/8
authorAndreas Färber <afaerber@suse.de>
Sun, 17 Apr 2016 17:26:30 +0000 (19:26 +0200)
committerFreddie Chopin <freddie.chopin@gmail.com>
Thu, 5 May 2016 06:50:59 +0000 (07:50 +0100)
The XMC1000 family uses a very different flash interface from XMC4000.

Tested on XMC 2Go and XMC1100 Boot Kit.

Change-Id: I3edaed420ef1c0fb89fdf221022c8b04163d41b3
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/3418
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
Tested-by: jenkins
16 files changed:
README
contrib/loaders/flash/xmc1xxx/Makefile [new file with mode: 0644]
contrib/loaders/flash/xmc1xxx/erase.S [new file with mode: 0644]
contrib/loaders/flash/xmc1xxx/erase.inc [new file with mode: 0644]
contrib/loaders/flash/xmc1xxx/erase_check.S [new file with mode: 0644]
contrib/loaders/flash/xmc1xxx/erase_check.inc [new file with mode: 0644]
contrib/loaders/flash/xmc1xxx/write.S [new file with mode: 0644]
contrib/loaders/flash/xmc1xxx/write.inc [new file with mode: 0644]
contrib/loaders/flash/xmc1xxx/xmc1xxx.S [new file with mode: 0644]
doc/openocd.texi
src/flash/nor/Makefile.am
src/flash/nor/drivers.c
src/flash/nor/xmc1xxx.c [new file with mode: 0644]
tcl/board/xmc-2go.cfg
tcl/board/xmc1100-boot-kit.cfg
tcl/target/xmc1xxx.cfg

diff --git a/README b/README
index a6b4c5bd01194c879df33d01c00b4b7ed2cd3c25..11ea2db3b2896d21d8f179e84ca34c62c5e0723a 100644 (file)
--- 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 (file)
index 0000000..066466e
--- /dev/null
@@ -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 (file)
index 0000000..e5a4808
--- /dev/null
@@ -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 (file)
index 0000000..b33e57d
--- /dev/null
@@ -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 (file)
index 0000000..6c99344
--- /dev/null
@@ -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 (file)
index 0000000..8fc8e0b
--- /dev/null
@@ -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 (file)
index 0000000..640f6ca
--- /dev/null
@@ -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 (file)
index 0000000..8272bb7
--- /dev/null
@@ -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 (file)
index 0000000..dfe7d3f
--- /dev/null
@@ -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
index 8e7c7f8a70df15eb5c7e23de4a8f1bbe21cc0533..e839191b23ca1b3501077a04e8a074996d6cd167 100644 (file)
@@ -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.
index b5fab1f1206984c5a28f82f3d2be2b6827b6ce5b..3386211ee61b382308984663d03a58a3ee1b908d 100644 (file)
@@ -53,6 +53,7 @@ NOR_DRIVERS = \
        str9xpec.c \
        tms470.c \
        virtual.c \
+       xmc1xxx.c \
        xmc4xxx.c
 
 noinst_HEADERS = \
index 51a401840ec7d27b8433d466c09132ca8f9fd780..e39b37e4b654b3fbcc618bdd5bda689299e179e5 100644 (file)
@@ -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 (file)
index 0000000..bb2ec12
--- /dev/null
@@ -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,
+};
index 664426307caca952aabd99304bb40be3056c80e8..90dbf43660c373034fb60a52908260544acc5839 100644 (file)
@@ -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
index 4c83fd3ace7bb4fb02395e16f6ac5af4f3c53902..5e7c607344766a8618a27a0a4923ecdd727404fd 100644 (file)
@@ -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
index 0a0e47eeac83eefaab82c1290014acb0c072d719..d3123c4376275cdae560ac44a44efbe330c84f38 100644 (file)
@@ -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

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)