This is an automated email from Gerrit.

Jie Zhang ([email protected]) just uploaded a new patch set to Gerrit, which 
you can find at http://openocd.zylin.com/4643

-- gerrit

commit 3d0b0b11eaf4d12ca221ffded14d8fd027bc4837
Author: Jie Zhang <[email protected]>
Date:   Mon Aug 6 15:41:41 2018 -0400

    flash/nor: add flash drivers for ADuCM3027/9 and ADuCM4050
    
    Change-Id: I27750b118ea98c8ef8297a18109ddc13bb7b5c6e
    Signed-off-by: Jie Zhang <[email protected]>

diff --git a/contrib/loaders/flash/aducm302x.s 
b/contrib/loaders/flash/aducm302x.s
new file mode 100644
index 0000000..2ca5002
--- /dev/null
+++ b/contrib/loaders/flash/aducm302x.s
@@ -0,0 +1,76 @@
+/***************************************************************************
+ *   Modifed from stellaris.s                                              *
+ *   Copyright (C) 2016 - 2018 Analog Devices, Inc.                        *
+ *                                                                         *
+ *   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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+       .text
+       .syntax unified
+       .cpu cortex-m3
+       .thumb
+       .thumb_func
+
+/*
+ * Params :
+ * r0 = workarea start
+ * r1 = workarea end
+ * r2 = target address
+ * r3 = count (64bit double words)
+ *
+ * Clobbered:
+ * r4 = pFLASH_CTRL_BASE
+ * r5 = FLASHWRITECMD
+ * r6 - tmp
+ * r7 - rp
+ * r8 - wp, tmp
+ */
+
+write:
+       ldr     r4, pFLASH_CTRL_BASE
+       ldr     r5, FLASHWRITECMD
+
+wait_fifo:
+       ldr     r8, [r0, #0]    /* read wp */
+       cmp     r8, #0                  /* abort if wp == 0 */
+       beq     exit
+       ldr     r7, [r0, #4]    /* read rp */
+       cmp     r7, r8                  /* wait until rp != wp */
+       beq     wait_fifo
+
+mainloop:
+       str             r2, [r4, #0xc]  /* KH_ADDR - write address */
+       add             r2, r2, #8              /* increment target address */
+       ldr             r6, [r7], #4
+       ldr             r8, [r7], #4
+       str             r6, [r4, #0x10] /* KH_DATA0 - write data */
+       str             r8, [r4, #0x14] /* KH_DATA1 - write data */
+       str             r5, [r4, #8]    /* CMD - enable write */
+busy:
+       ldr             r8, [r4, #0]
+       tst             r8, #4
+       beq             busy
+
+       cmp     r7, r1                  /* wrap rp at end of buffer */
+       it      cs
+       addcs   r7, r0, #8              /* skip loader args */
+       str     r7, [r0, #4]    /* store rp */
+       subs    r3, r3, #1              /* decrement word count */
+       cbz     r3, exit                /* loop if not done */
+       b               wait_fifo
+exit:
+       bkpt    #0
+
+pFLASH_CTRL_BASE: .word 0x40018000
+FLASHWRITECMD: .word 0x4
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 1a89a53..6633ac3 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -5292,6 +5292,35 @@ flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME
 @end example
 @end deffn
 
+@deffn {Flash Driver} aducm302x
+The ADuCM3027/9 microcontrollers from Analog Devices include internal
+flash and use ARM Cortex-M3 cores.
+The flash size on ADuCM3027 is 128KB.
+The flash size on ADuCM3029 is 256KB.
+The flash start address is 0 on both.
+
+@example
+# ADuCM3027
+flash bank $_FLASHNAME aducm302x 0 0x20000 0 0 $_TARGETNAME
+
+# ADuCM3029
+flash bank $_FLASHNAME aducm302x 0 0x40000 0 0 $_TARGETNAME
+@end example
+@end deffn
+
+@deffn {Flash Driver} aducm4x50
+The ADuCM4050 microcontrollers from Analog Devices include internal
+flash and use ARM Cortex-M4F cores.
+The flash size on ADuCM4050 is 512KB.
+But the top two pages (4KB) are reserved as a Protected Key Storage region.
+The flash start address is 0.
+
+@example
+# ADuCM4050
+flash bank $_FLASHNAME aducm4x50 0 0x7f000 0 0 $_TARGETNAME
+@end example
+@end deffn
+
 @deffn {Flash Driver} ambiqmicro
 @cindex ambiqmicro
 @cindex apollo
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 13e589c..eca1dec 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -8,6 +8,7 @@ noinst_LTLIBRARIES += %D%/libocdflashnor.la
 
 NOR_DRIVERS = \
        %D%/aduc702x.c \
+       %D%/aducm302x.c \
        %D%/aducm360.c \
        %D%/ambiqmicro.c \
        %D%/at91sam4.c \
diff --git a/src/flash/nor/aducm302x.c b/src/flash/nor/aducm302x.c
new file mode 100644
index 0000000..63bcba5
--- /dev/null
+++ b/src/flash/nor/aducm302x.c
@@ -0,0 +1,722 @@
+/***************************************************************************
+ *   Flash drivers for Analog Devices ADuCM302x and ADuCM4x50              *
+ *   Modified from stellaris.c                                             *
+ *   Copyright (C) 2014 - 2018 Analog Devices, Inc.                        *
+ *                                                                         *
+ *   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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+
+/* ADuCM302x ID registers */
+#define SYS_ADIID              0x40002020
+#define SYS_CHIPID             0x40002024
+
+#define ADUCM302X_CHIPID 0x280
+#define ADUCM4X50_CHIPID 0x2a0
+
+/* ADuCM302x cache flash control registers */
+#define STAT                   0x40018000
+#define IEN                            0x40018004
+#define CMD                            0x40018008
+#define KH_ADDR                        0x4001800c
+#define KH_DATA0               0x40018010
+#define KH_DATA1               0x40018014
+#define PAGE_ADDR0             0x40018018
+#define PAGE_ADDR1             0x4001801c
+#define KEY                            0x40018020
+#define WR_ABORT_ADDR  0x40018024
+#define WRPROT                 0x40018028
+#define SIGNATURE              0x4001802c
+#define UCFG                   0x40018030
+#define TIME_PARAM0            0x40018034
+#define TIME_PARAM1            0x40018038
+#define ABORT_EN_LO            0x4001803c
+#define ABORT_EN_HI            0x40018040
+#define ECC_CFG                        0x40018044
+#define ECC_ADDR               0x40018048
+
+#define USER_KEY               0x676c7565
+
+#define STAT_CMDBUSY                           (1 << 0)
+#define STAT_WRCLOSE                           (1 << 1)
+#define STAT_CMDCOMP                           (1 << 2)
+#define STAT_WRALCOMP                          (1 << 3)
+#define STAT_CMDFAIL_MASK                      (3 << 4)
+#define STAT_CMDFAIL_SUCCESS           (0 << 4)
+#define STAT_CMDFAIL_IGNORED           (1 << 4)
+#define STAT_CMDFAIL_VERIFY_ERR                (2 << 4)
+#define STAT_CMDFAIL_ABORT                     (3 << 4)
+#define STAT_SLEEPING                          (1 << 6)
+#define STAT_ECCERRCMD_MASK                    (3 << 7)
+#define STAT_ECCERRCMD_SUCCESS         (0 << 7)
+#define STAT_ECCERRCMD_ERR_2BIT                (1 << 7)
+#define STAT_ECCERRCMD_ERR_1BIT                (2 << 7)
+#define STAT_ECCERRCMD_ERR_1OR2                (3 << 7)
+#define STAT_ECCRDERR_MASK                     (3 << 9)
+#define STAT_ECCRDERR_SUCCESS          (0 << 9)
+#define STAT_ECCRDERR_ERR_2BIT         (1 << 9)
+#define STAT_ECCRDERR_ERR_1BIT         (2 << 9)
+#define STAT_ECCRDERR_ERR_1OR2         (3 << 9)
+#define STAT_OVERLAP                           (1 << 11)
+#define STAT_SIGNERR                           (1 << 13)
+#define STAT_INIT                                      (1 << 14)
+#define STAT_ECCINFOSIGN_MASK          (2 << 15)
+#define STAT_ECCINFOSIGN_SUCCESS       (0 << 15)
+#define STAT_ECCINFOSIGN_ERR_2BIT      (1 << 15)
+#define STAT_ECCINFOSIGN_ERR_1BIT      (2 << 15)
+#define STAT_ECCINFOSIGN_ERR_1OR2      (3 << 15)
+#define STAT_ECCERRCNT_MASK                    (7 << 17)
+#define STAT_ECCICODE_MASK                     (3 << 25)
+#define STAT_ECCICODE_SUCCESS          (0 << 25)
+#define STAT_ECCICODE_ERR_2BIT         (1 << 25)
+#define STAT_ECCICODE_ERR_1BIT         (2 << 25)
+#define STAT_ECCDCODE_MASK                     (3 << 27)
+#define STAT_ECCDCODE_SUCCESS          (0 << 27)
+#define STAT_ECCDCODE_ERR_2BIT         (1 << 27)
+#define STAT_ECCDCODE_ERR_1BIT         (2 << 27)
+#define STAT_CACHESRAMPERR                     (1 << 29)
+
+#define ECC_CFG_EN                                     (1 << 0)
+#define ECC_CFG_INFOEN                         (1 << 1)
+
+#define TIME_PARAM0_TERASE_POS         24
+#define TIME_PARAM0_TERASE_MASK                (0xf << TIME_PARAM0_TERASE_POS)
+
+#define CMD_IDLE               0
+#define CMD_ABORT              1
+#define CMD_SLEEP              2
+#define CMD_SIGN               3
+#define CMD_WRITE              4
+#define CMD_CHECK              5
+#define CMD_ERASEPAGE  6
+#define CMD_MASSERASE  7
+
+extern struct command_context *global_cmd_ctx;
+
+struct aducm302x_flash_bank {
+       /* ADuCM302x or ADuCM4x50 */
+       bool is_aducm302x;
+       bool probed;
+
+       /* flash geometry */
+       uint32_t pagesize;
+       /* how many pages in one protect block */
+       int pages_per_block;
+};
+
+static int aducm302x_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct Jim_Obj *objPtr;
+       struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+       const char *chipname;
+       uint16_t chipid_expected, adiid, chipid;
+       long value;
+       int retval, i;
+
+       LOG_DEBUG("bank=%p", bank);
+
+       if (aducm302x_info->probed)
+               return ERROR_OK;
+
+       objPtr = Jim_GetGlobalVariableStr(global_cmd_ctx->interp, "_CHIPNAME", 
JIM_NONE);
+       if (!objPtr)
+       {
+               LOG_ERROR("%s: _CHIPNAME is not defined", target_name(target));
+               return ERROR_FAIL;
+       }
+       chipname = Jim_GetString(objPtr, NULL);
+
+       objPtr = Jim_GetGlobalVariableStr(global_cmd_ctx->interp, "_CHIPID", 
JIM_NONE);
+       if (!objPtr)
+       {
+               LOG_ERROR("%s: _CHIPID is not defined", target_name(target));
+               return ERROR_FAIL;
+       }
+       retval = Jim_GetLong(global_cmd_ctx->interp, objPtr, &value);
+       if (retval == JIM_OK)
+               chipid_expected = value;
+       else
+               return ERROR_FAIL;
+
+       LOG_DEBUG("_CHIPNAME '%s', _CHIPID 0x%" PRIx16 "", chipname, 
chipid_expected);
+
+       /* Read ID register to make sure this is the expected part */
+       target_read_u16(target, SYS_ADIID, &adiid);
+       target_read_u16(target, SYS_CHIPID, &chipid);
+       LOG_DEBUG("ADIID 0x%" PRIx16 ", CHIPID 0x%" PRIx16 "", adiid, chipid);
+
+       if (adiid != 0x4144) {
+               LOG_ERROR("not an Analog Devices Cortex-M based part");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if ((chipid & 0xfff0) != chipid_expected) {
+               LOG_ERROR("not %s part", chipname);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Clear the remap bit */
+       target_write_u32(target, 0x40018054, 0x1);
+
+       aducm302x_info->pagesize = 2048;
+       bank->num_sectors = bank->size / aducm302x_info->pagesize;
+       bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));
+       if (bank->sectors == NULL) {
+               LOG_ERROR("malloc failed");
+               return ERROR_FAIL;
+       }
+       for (i = 0; i < bank->num_sectors; i++) {
+               bank->sectors[i].offset = i * aducm302x_info->pagesize;
+               bank->sectors[i].size = aducm302x_info->pagesize;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = -1;
+       }
+
+       /* The recommended TERASE value in TIME_PARAM0 is now 0x9 for ADuCM4x50 
*/
+       if ((chipid & 0xfff0) == ADUCM4X50_CHIPID) {
+               uint32_t time_param0;
+
+               target_read_u32(target, TIME_PARAM0, &time_param0);
+
+               time_param0 &= ~TIME_PARAM0_TERASE_MASK;
+               time_param0 |= 0x9 << TIME_PARAM0_TERASE_POS;
+
+               target_write_u32(target, KEY, USER_KEY);
+               target_write_u32(target, TIME_PARAM0, time_param0);
+               /* Invalidate User Key */
+               target_write_u32(target, KEY, 0);
+       }
+
+       aducm302x_info->probed = true;
+
+       return ERROR_OK;
+}
+
+static int aducm302x_check_cmdfail(uint32_t flash_stat)
+{
+       if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_SUCCESS)
+               return ERROR_OK;
+
+       if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_IGNORED)
+               LOG_ERROR("command ignored for attempted access of a protected 
or out of memory location)");
+       else if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_VERIFY_ERR)
+               LOG_ERROR("verify error occurred for failed erase or failed 
signature check");
+       else if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_ABORT)
+               LOG_ERROR("command aborted by either user code or a system 
interrupt");
+
+       return ERROR_FLASH_OPERATION_FAILED;
+}
+
+static int aducm302x_mass_erase(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t flash_stat;
+       int retval, i;
+
+       /* Write user key */
+       target_write_u32(target, KEY, USER_KEY);
+       /* Write massive erase command */
+       target_write_u32(target, CMD, CMD_MASSERASE);
+       /* Wait until erase complete */
+       do {
+               target_read_u32(target, STAT, &flash_stat);
+       } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+       retval = aducm302x_check_cmdfail(flash_stat);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (i = 0; i < bank->num_sectors; i++)
+               bank->sectors[i].is_erased = 1;
+
+       return ERROR_OK;
+}
+
+static int aducm302x_erase(struct flash_bank *bank, int first, int last)
+{
+       struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t flash_stat;
+       int retval, i;
+
+       LOG_DEBUG("bank=%p first=%d last = %d", bank, first, last);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!aducm302x_info->probed)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       if (first < 0 || last < first || last >= bank->num_sectors)
+               return ERROR_FLASH_SECTOR_INVALID;
+
+       if (first == 0 && last == bank->num_sectors - 1) {
+               retval = aducm302x_mass_erase(bank);
+               return retval;
+       }
+
+       for (i = first; i <= last; i++) {
+               /* Address is first word in page */
+               target_write_u32(target, PAGE_ADDR0, i * 
aducm302x_info->pagesize);
+               /* Write user key */
+               target_write_u32(target, KEY, USER_KEY);
+               /* Write page erase command */
+               target_write_u32(target, CMD, CMD_ERASEPAGE);
+               /* Wait until erase complete */
+               do {
+                       target_read_u32(target, STAT, &flash_stat);
+               } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+               retval = aducm302x_check_cmdfail(flash_stat);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               bank->sectors[i].is_erased = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int aducm302x_protect(struct flash_bank *bank, int set, int first, int 
last)
+{
+       struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t wrprot;
+       int n = aducm302x_info->pages_per_block;
+       int i;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!set) {
+               LOG_ERROR("Hardware doesn't support page-level unprotect");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (!aducm302x_info->probed)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       /* One protect block has N pages. So the first should be 0, N, 2 * N, 
...
+          The last should be N - 1, 2 * N - 1, 3 * N - 1, ... */
+       if (first < 0 || (first & (n - 1)) || last <= first || (last & (n - 1)) 
!= n - 1
+               || last >= n * 32) {
+               LOG_ERROR("Can't protect unaligned or out-of-range pages.");
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* Convert from pages to protect blocks */
+       first /= n;
+       last /= n;
+
+       target_read_u32(target, WRPROT, &wrprot);
+
+       for (i = first; i <= last; i++)
+               wrprot &= ~(1 << i);
+
+       LOG_DEBUG("WRPROT 0x%"PRIx32, wrprot);
+
+       target_write_u32(target, WRPROT, wrprot);
+
+       return ERROR_OK;
+}
+
+static int aducm302x_protect_check(struct flash_bank *bank)
+{
+       struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t wrprot;
+       int n = aducm302x_info->pages_per_block;
+       int i, j;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!aducm302x_info->probed)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       for (i = 0; i < bank->num_sectors; i++)
+               bank->sectors[i].is_protected = -1;
+
+       target_read_u32(target, WRPROT, &wrprot);
+
+       for (i = 0; i < 32; i++)
+               for (j = 0; j < n; j++)
+                       bank->sectors[i * n + j].is_protected = !(wrprot & (1 
<< i));
+
+       return ERROR_OK;
+}
+
+/* see contrib/loaders/flash/aducm302x.s for source code */
+static const uint8_t aducm302x_write_code[] = {
+                                                               /* write: */
+       0xdf, 0xf8, 0x4c, 0x40,
+       0x13, 0x4d,
+                                                               /* wait_fifo: */
+       0xd0, 0xf8, 0x00, 0x80,
+       0xb8, 0xf1, 0x00, 0x0f,
+       0x00, 0xf0, 0x1e, 0x80,
+       0x47, 0x68,
+       0x47, 0x45,
+       0x3f, 0xf4, 0xf6, 0xaf,
+                                                               /* mainloop: */
+       0xe2, 0x60,
+       0x02, 0xf1, 0x08, 0x02,
+       0x57, 0xf8, 0x04, 0x6b,
+       0x57, 0xf8, 0x04, 0x8b,
+       0x26, 0x61,
+       0xc4, 0xf8, 0x14, 0x80,
+       0xa5, 0x60,
+                                                               /* busy: */
+       0xd4, 0xf8, 0x00, 0x80,
+       0x18, 0xf0, 0x04, 0x0f,
+       0x3f, 0xf4, 0xfa, 0xaf,
+       0x8f, 0x42,
+       0x28, 0xbf,
+       0x00, 0xf1, 0x08, 0x07,
+       0x47, 0x60,
+       0x01, 0x3b,
+       0x0b, 0xb1,
+       0xff, 0xf7, 0xdc, 0xbf,
+                                                               /* exit: */
+       0x00, 0xbe,
+       /* pFLASH_CTRL_BASE: */
+       0x00, 0x80, 0x01, 0x40,
+       /* FLASHWRITECMD: */
+       0x04, 0x00, 0x00, 0x00
+};
+
+static int aducm302x_write_block(struct flash_bank *bank, const uint8_t 
*buffer,
+                                                                uint32_t 
offset, uint32_t dwcount)
+{
+       struct target *target = bank->target;
+       uint32_t buffer_size = 16384 + 8; /* 8 bytes for wp and rp */
+       struct working_area *source;
+       struct working_area *write_algorithm;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[4];
+       struct armv7m_algorithm armv7m_info;
+       int retval;
+
+       /* power of two, and multiple of 8 bytes */
+       static const unsigned buf_min = 128;
+
+       LOG_DEBUG("bank=%p buffer=%p offset=%08"PRIx32" dwcount=%"PRIx32,
+                         bank, buffer, offset, dwcount);
+
+       /* For small buffers it's faster not to download the algorithm */
+       if (dwcount * 8 < buf_min)
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+       /* flash write code */
+       if (target_alloc_working_area(target, sizeof(aducm302x_write_code),
+                                                                 
&write_algorithm) != ERROR_OK) {
+               LOG_DEBUG("no working area for block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       /* plus a buffer big enough for this data */
+       if (dwcount * 8 < buffer_size)
+               buffer_size = dwcount * 8 + 8;
+
+       /* memory buffer */
+       while (target_alloc_working_area_try(target, buffer_size, &source) != 
ERROR_OK) {
+               buffer_size = (buffer_size - 8) / 2;
+               /* make sure it's multiple of 8 bytes */
+               buffer_size = buffer_size / 8 * 8;
+               if (buffer_size <= buf_min) {
+                       target_free_working_area(target, write_algorithm);
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+               /* 8 bytes for wp and rp */
+               buffer_size += 8;
+               LOG_DEBUG("retry target_alloc_working_area(%s, size=%"PRIu32")",
+                                 target_name(target), buffer_size);
+       }
+
+       target_write_buffer(target, write_algorithm->address,
+                                               sizeof(aducm302x_write_code), 
aducm302x_write_code);
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.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, source->address);
+       buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
+       buf_set_u32(reg_params[2].value, 0, 32, address);
+       buf_set_u32(reg_params[3].value, 0, 32, dwcount);
+
+       retval = target_run_flash_async_algorithm(target,
+                                                                               
          buffer, dwcount, 8,
+                                                                               
          0, NULL,
+                                                                               
          4, reg_params,
+                                                                               
          source->address, source->size,
+                                                                               
          write_algorithm->address, 0,
+                                                                               
          &armv7m_info);
+
+       if (retval == ERROR_FLASH_OPERATION_FAILED)
+               LOG_ERROR("error %d executing ADuCM302x flash write algorithm", 
retval);
+
+       target_free_working_area(target, write_algorithm);
+       target_free_working_area(target, source);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[0]);
+
+       return retval;
+}
+
+static int aducm302x_write(struct flash_bank *bank, const uint8_t *buffer,
+                                                  uint32_t offset, uint32_t 
count)
+{
+       struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t address = offset;
+       uint32_t dwords_remaining, bytes_remaining;
+       uint32_t flash_stat;
+       uint32_t ecc_cfg;
+       bool ecc_cfg_modified;
+       int retval = ERROR_OK;
+
+       LOG_DEBUG("bank=%p buffer=%p offset=%08"PRIx32" count=%"PRIx32,
+                         bank, buffer, offset, count);
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!aducm302x_info->probed)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       /* We need to enable it before programming the flash such that when ECC
+          is enabled later, it will not cause an ECC error. ECC_CFG_PTR is also
+          forced to be 0.
+
+          Note that according to the ADuCM302x Hardware Reference Manual, "If
+          ECC is enabled, multiple writes to a single DWORD (64-bit) location
+          cannot be performed without erasing the affected page between writes
+          else ECC errors are reported". The following code assumes for all the
+          DWORDs it writes to this is the first write since they were erased. 
*/
+
+       target_read_u32(target, ECC_CFG, &ecc_cfg);
+       if (ecc_cfg == (ECC_CFG_INFOEN | ECC_CFG_EN)) {
+               ecc_cfg_modified = false;
+       } else {
+               target_write_u32(target, ECC_CFG, ECC_CFG_INFOEN | ECC_CFG_EN);
+               ecc_cfg_modified = true;
+       }
+
+       if (offset & 0x7) {
+               uint8_t first_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff};
+
+               bytes_remaining = 8 - (offset & 0x7);
+               if (bytes_remaining > count)
+                       bytes_remaining = count;
+               memcpy(first_dword + (offset & 0x7), buffer, bytes_remaining);
+
+               /* write one double word */
+               target_write_u32(target, KH_ADDR, address & (~ 0x7));
+               target_write_buffer(target, KH_DATA0, 4, first_dword);
+               target_write_buffer(target, KH_DATA1, 4, first_dword + 4);
+               target_write_u32(target, CMD, CMD_WRITE);
+
+               do {
+                       target_read_u32(target, STAT, &flash_stat);
+               } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+               retval = aducm302x_check_cmdfail(flash_stat);
+               if (retval != ERROR_OK)
+                       goto finish;
+
+               count -= bytes_remaining;
+               address &= ~ 0x7;
+       }
+
+       dwords_remaining = count / 8;
+       bytes_remaining = count % 8;
+
+       if (dwords_remaining > 0) {
+               retval = aducm302x_write_block(bank, buffer, offset, 
dwords_remaining);
+               if (retval != ERROR_OK) {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                               LOG_DEBUG("writing flash word-at-a-time");
+                       else if (retval == ERROR_FLASH_OPERATION_FAILED) {
+                               LOG_ERROR("flash writing failed");
+                               retval = ERROR_FLASH_OPERATION_FAILED;
+                               goto finish;
+                       }
+               } else {
+                       buffer += dwords_remaining * 8;
+                       address += dwords_remaining * 8;
+                       dwords_remaining = 0;
+               }
+       }
+
+       while (dwords_remaining > 0) {
+               target_write_u32(target, KH_ADDR, address);
+               target_write_buffer(target, KH_DATA0, 4, buffer);
+               target_write_buffer(target, KH_DATA1, 4, buffer + 4);
+               target_write_u32(target, CMD, CMD_WRITE);
+
+               do {
+                       target_read_u32(target, STAT, &flash_stat);
+               } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+               retval = aducm302x_check_cmdfail(flash_stat);
+               if (retval != ERROR_OK)
+                       goto finish;
+
+               buffer += 8;
+               address += 8;
+               dwords_remaining--;
+       }
+
+       if (bytes_remaining) {
+               uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff};
+
+               /* copy the last remaining bytes into the write buffer */
+               memcpy(last_dword, buffer, bytes_remaining);
+
+               /* write one double word */
+               target_write_u32(target, KH_ADDR, address);
+               target_write_buffer(target, KH_DATA0, 4, last_dword);
+               target_write_buffer(target, KH_DATA1, 4, last_dword + 4);
+               target_write_u32(target, CMD, CMD_WRITE);
+
+               do {
+                       target_read_u32(target, STAT, &flash_stat);
+               } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+               retval = aducm302x_check_cmdfail(flash_stat);
+               if (retval != ERROR_OK)
+                       goto finish;
+       }
+
+finish:
+
+       /* restore ECC_CFG if it was modified */
+       if (ecc_cfg_modified)
+               target_write_u32(target, ECC_CFG, ecc_cfg);
+
+       return retval;
+}
+
+FLASH_BANK_COMMAND_HANDLER(aducm302x_flash_bank_command)
+{
+       struct aducm302x_flash_bank *aducm302x_info;
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       aducm302x_info = calloc(sizeof(struct aducm302x_flash_bank), 1);
+       if (aducm302x_info == NULL) {
+               LOG_ERROR("calloc failed");
+               return ERROR_FAIL;
+       }
+
+       bank->base = 0x0;
+       bank->driver_priv = aducm302x_info;
+
+       aducm302x_info->is_aducm302x = true;
+
+       /* part wasn't probed for info yet */
+       aducm302x_info->probed = false;
+
+       /* ADuCM302x flash has 4 pages in one protect block */
+       aducm302x_info->pages_per_block = 4;
+
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(aducm4x50_flash_bank_command)
+{
+       struct aducm302x_flash_bank *aducm302x_info;
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       aducm302x_info = calloc(sizeof(struct aducm302x_flash_bank), 1);
+       if (aducm302x_info == NULL) {
+               LOG_ERROR("calloc failed");
+               return ERROR_FAIL;
+       }
+
+       bank->base = 0x0;
+       bank->driver_priv = aducm302x_info;
+
+       aducm302x_info->is_aducm302x = false;
+
+       /* part wasn't probed for info yet */
+       aducm302x_info->probed = false;
+
+       /* ADuCM4x50 flash has 8 pages in one protect block */
+       aducm302x_info->pages_per_block = 8;
+
+       return ERROR_OK;
+}
+
+struct flash_driver aducm302x_flash = {
+       .name = "aducm302x",
+       .usage = NULL,
+       .commands = NULL,
+       .flash_bank_command = aducm302x_flash_bank_command,
+       .erase = aducm302x_erase,
+       .protect = aducm302x_protect,
+       .write = aducm302x_write,
+       .read = default_flash_read,
+       .probe = aducm302x_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = aducm302x_protect_check,
+       .info = NULL,
+       .auto_probe = aducm302x_probe,
+       .free_driver_priv = default_flash_free_driver_priv,
+};
+
+struct flash_driver aducm4x50_flash = {
+       .name = "aducm4x50",
+       .usage = NULL,
+       .commands = NULL,
+       .flash_bank_command = aducm4x50_flash_bank_command,
+       .erase = aducm302x_erase,
+       .protect = aducm302x_protect,
+       .write = aducm302x_write,
+       .read = default_flash_read,
+       .probe = aducm302x_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = aducm302x_protect_check,
+       .info = NULL,
+       .auto_probe = aducm302x_probe,
+       .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 196717f..e1cc356 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -21,7 +21,9 @@
 #include "imp.h"
 
 extern struct flash_driver aduc702x_flash;
+extern struct flash_driver aducm302x_flash;
 extern struct flash_driver aducm360_flash;
+extern struct flash_driver aducm4x50_flash;
 extern struct flash_driver ambiqmicro_flash;
 extern struct flash_driver at91sam3_flash;
 extern struct flash_driver at91sam4_flash;
@@ -85,7 +87,9 @@ extern struct flash_driver xmc4xxx_flash;
  */
 static struct flash_driver *flash_drivers[] = {
        &aduc702x_flash,
+       &aducm302x_flash,
        &aducm360_flash,
+       &aducm4x50_flash,
        &ambiqmicro_flash,
        &at91sam3_flash,
        &at91sam4_flash,
diff --git a/tcl/target/aducm3027.cfg b/tcl/target/aducm3027.cfg
new file mode 100644
index 0000000..efd527a
--- /dev/null
+++ b/tcl/target/aducm3027.cfg
@@ -0,0 +1,6 @@
+# Analog Devices ADuCM3027
+
+set CHIPNAME aducm3027
+set CHIPID 0x0280
+set FLASHSIZE 0x20000
+source [find target/aducm302x.tcl]
diff --git a/tcl/target/aducm3029.cfg b/tcl/target/aducm3029.cfg
new file mode 100644
index 0000000..d1354c6
--- /dev/null
+++ b/tcl/target/aducm3029.cfg
@@ -0,0 +1,6 @@
+# Analog Devices ADuCM3029
+
+set CHIPNAME aducm3029
+set CHIPID 0x0280
+set FLASHSIZE 0x40000
+source [find target/aducm302x.tcl]
diff --git a/tcl/target/aducm302x.tcl b/tcl/target/aducm302x.tcl
new file mode 100644
index 0000000..58c529c
--- /dev/null
+++ b/tcl/target/aducm302x.tcl
@@ -0,0 +1,137 @@
+# Common file for Analog Devices ADuCM302x
+
+# minimal dap memaccess values for adapter frequencies
+#   1 MHz:  6
+#   2 MHz:  8
+#   5 MHz: 18
+#   9 MHz: 27
+#  15 MHz: 43
+#  23 MHz: 74
+
+# hardware has 2 breakpoints, 1 watchpoints
+
+#
+# ADuCM302x devices support only SWD transport.
+#
+transport select swd
+
+source [find target/swj-dp.tcl]
+
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+source [find bitsbytes.tcl]
+source [find memory.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME aducm302x
+}
+
+if { [info exists CHIPID] } {
+   set _CHIPID $CHIPID
+} else {
+   puts stderr "Error: CHIPID is not defined"
+   shutdown error
+}
+
+if { [info exists ENDIAN] } {
+   set _ENDIAN $ENDIAN
+} else {
+   set _ENDIAN little
+}
+
+adapter_khz 1000
+
+if { [info exists CPUTAPID] } {
+   set _CPUTAPID $CPUTAPID
+} else {
+   set _CPUTAPID 0x2ba01477
+}
+
+swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+target create $_CHIPNAME.cpu cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap
+
+if { [info exists WORKAREASIZE] } {
+   set _WORKAREASIZE $WORKAREASIZE
+} else {
+   # default to 8K working area
+   set _WORKAREASIZE 0x2000
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE
+
+$_TARGETNAME configure -event reset-init {
+   # disable watchdog, which will fire in about 32 second after reset.
+   mwh 0x40002c08 0x0
+   # After reset LR is 0xffffffff. There will be an error when GDB tries to
+   # read from that address.
+   reg lr 0
+}
+
+$_TARGETNAME configure -event examine-end {
+   global _CHIPNAME
+   global _CHIPID
+
+   # read ADIID
+   set sys_adiid 0x40002020
+   set adiid [memread16 $sys_adiid]
+
+   # read CHIPID
+   set sys_chipid 0x40002024
+   set chipid [memread16 $sys_chipid]
+
+   if { $adiid != 0x4144 } {
+      puts stderr "Error: not an Analog Devices Cortex-M based part"
+      shutdown error
+   }
+
+   puts [format "Info : CHIPID 0x%04x" $chipid]
+
+   if { [expr { $chipid & 0xfff0 } ] != $_CHIPID } {
+      puts stderr "Error: not $_CHIPNAME part"
+      shutdown error
+   }
+}
+ 
+$_TARGETNAME configure -event gdb-attach {
+   reset init 
+
+   arm semihosting enable
+}
+
+$_TARGETNAME configure -event gdb-flash-erase-start {
+   reset init
+   mww 0x40018054 0x1
+}
+
+$_TARGETNAME configure -event gdb-flash-write-end {
+   # get the reset handler address from application's vector table
+   set reset_handler [memread32 4]
+
+   reset init
+
+   # run kernel and stop at the first instruction of application reset handler
+   bp $reset_handler 2 hw
+   resume
+   wait_halt
+   rbp $reset_handler
+}
+
+set _FLASHNAME $_CHIPNAME.flash
+if { [info exists FLASHSIZE] } {
+   set _FLASHSIZE $FLASHSIZE
+} else {
+   set _FLASHSIZE 0x40000
+}
+flash bank $_FLASHNAME aducm302x 0 $_FLASHSIZE 0 0 $_TARGETNAME
+
+if {![using_hla]} {
+   # if srst is not fitted use SYSRESETREQ to
+   # perform a soft reset
+   cortex_m reset_config sysresetreq
+}
diff --git a/tcl/target/aducm4050.cfg b/tcl/target/aducm4050.cfg
new file mode 100644
index 0000000..7609aef
--- /dev/null
+++ b/tcl/target/aducm4050.cfg
@@ -0,0 +1,8 @@
+# Analog Devices ADuCM4050
+
+set CHIPNAME aducm4050
+set CHIPID 0x02a0
+# ADuCM4050 has 512KB flash, but the top two pages (4KB) are reserved
+# for use as a Protected Key Storage region
+set FLASHSIZE 0x7f000
+source [find target/aducm4x50.tcl]
diff --git a/tcl/target/aducm4x50.tcl b/tcl/target/aducm4x50.tcl
new file mode 100644
index 0000000..466febb
--- /dev/null
+++ b/tcl/target/aducm4x50.tcl
@@ -0,0 +1,166 @@
+# Common file for Analog Devices ADuCM4x50
+
+# minimal dap memaccess values for adapter frequencies
+#   1 MHz:  6
+#   2 MHz:  8
+#   5 MHz: 18
+#   9 MHz: 27
+#  15 MHz: 43
+#  23 MHz: 74
+
+# hardware has 6 breakpoints, 1 watchpoints
+
+#
+# ADuCM4x50 devices support only SWD transport.
+#
+transport select swd
+
+source [find target/swj-dp.tcl]
+
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+source [find bitsbytes.tcl]
+source [find memory.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME aducm4x50
+}
+
+if { [info exists CHIPID] } {
+   set _CHIPID $CHIPID
+} else {
+   puts stderr "Error: CHIPID is not defined"
+   shutdown error
+}
+
+if { [info exists ENDIAN] } {
+   set _ENDIAN $ENDIAN
+} else {
+   set _ENDIAN little
+}
+
+adapter_khz 1000
+
+if { [info exists CPUTAPID] } {
+   set _CPUTAPID $CPUTAPID
+} else {
+   set _CPUTAPID 0x6ba02477
+}
+
+swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+target create $_CHIPNAME.cpu cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap
+
+if { [info exists WORKAREASIZE] } {
+   set _WORKAREASIZE $WORKAREASIZE
+} else {
+   # default to 8K working area
+   set _WORKAREASIZE 0x2000
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE
+
+$_TARGETNAME configure -event reset-init {
+   # disable watchdog, which will fire in about 32 second after reset.
+   mwh 0x40002c08 0x0
+
+   # A previously executed program might have increased processor frequency.
+   # It would have also increased WAITSTATES in FLCC_TIME_PARAM1 for the
+   # increased processor frequency. After reset, processor frequency comes back
+   # to the reset value, but WAITSTATES in FLCC_TIME_PARAM1 does not, which
+   # will cause flash programming error. So we need to set it to the reset
+   # value 0 manually.
+   set time_param1 0x40018038
+   set key         0x40018020
+   set user_key    0x676c7565
+
+   set data [memread32 $time_param1]
+   mww $key $user_key
+   mww $time_param1 [expr {$data & 0xf}]
+   mww $key 0
+   set data [memread32 $time_param1]
+   set retry 0
+   while { [expr {$data & 0x700}] != 0 } {
+      set data [memread32 $time_param1]
+      set retry [expr {$retry + 1}]
+      if { $retry > 10 } break;
+   }
+   if { $retry > 10 } {
+      set msg [format 0x%08x $data]
+      puts stderr "Error: failed to reset WAITSTATES in flash controller 
TIME_PARAM1 register"
+   }
+
+   # After reset LR is 0xffffffff. There will be an error when GDB tries to
+   # read from that address.
+   reg lr 0
+}
+
+$_TARGETNAME configure -event examine-end {
+   global _CHIPNAME
+   global _CHIPID
+
+   # read ADIID
+   set sys_adiid 0x40002020
+   set adiid [memread16 $sys_adiid]
+
+   # read CHIPID
+   set sys_chipid 0x40002024
+   set chipid [memread16 $sys_chipid]
+
+   if { $adiid != 0x4144 } {
+      puts stderr "Error: not an Analog Devices Cortex-M based part"
+      shutdown error
+   }
+
+   puts [format "Info : CHIPID 0x%04x" $chipid]
+
+   if { [expr { $chipid & 0xfff0 } ] != $_CHIPID } {
+      puts stderr "Error: not $_CHIPNAME part"
+      shutdown error
+   }
+}
+ 
+$_TARGETNAME configure -event gdb-attach {
+   reset init 
+
+   arm semihosting enable
+}
+
+$_TARGETNAME configure -event gdb-flash-erase-start {
+   reset init
+   mww 0x40018054 0x1
+}
+
+$_TARGETNAME configure -event gdb-flash-write-end {
+   # get the reset handler address from application's vector table
+   set reset_handler [memread32 4]
+
+   reset init
+
+   # run kernel and stop at the first instruction of application reset handler
+   bp $reset_handler 2 hw
+   resume
+   wait_halt
+   rbp $reset_handler
+}
+
+set _FLASHNAME $_CHIPNAME.flash
+if { [info exists FLASHSIZE] } {
+   set _FLASHSIZE $FLASHSIZE
+} else {
+   # ADuCM4x50 has 512KB flash, but the top two pages (4KB) are reserved
+   # for use as a Protected Key Storage region
+   set _FLASHSIZE 0x7f000
+}
+flash bank $_FLASHNAME aducm4x50 0 $_FLASHSIZE 0 0 $_TARGETNAME
+
+if {![using_hla]} {
+   # if srst is not fitted use SYSRESETREQ to
+   # perform a soft reset
+   cortex_m reset_config sysresetreq
+}

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to