flash/nor: Add support for TI CC3220SF internal flash 19/4319/9
authorEdward Fewell <efewell@ti.com>
Thu, 28 Dec 2017 23:38:21 +0000 (17:38 -0600)
committerTomas Vanek <vanekt@fbl.cz>
Wed, 6 Jun 2018 14:38:25 +0000 (15:38 +0100)
Added cc3220sf flash driver to support the TI CC3220SF
microcontrollers. Implemented flash driver to support the
internal flash of the CC3220SF. The implementation does not
support the serial flash of the CC32xx family that requires
connection over UART, and not via JTAG/SWD debug. Added config
files for both CC32xx devices (no flash) and CC3220SF (with
flash).

Updated to implement comments from code review.
Additional updates to handle remaining comments from review.
Additional updates per review.

Added code to only request aligned writes and full 32-bit
words down to flash helper algorithm. Updated for recent
changes in OpenOCD flash code.

Removed cc32xx.cfg file made obsolete by this patch.
Change-Id: I58fc1478d07238d39c7ef02339f1097a91668c47
Signed-off-by: Edward Fewell <efewell@ti.com>
Reviewed-on: http://openocd.zylin.com/4319
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
13 files changed:
contrib/loaders/flash/cc3220sf/Makefile [new file with mode: 0644]
contrib/loaders/flash/cc3220sf/cc3220sf.inc [new file with mode: 0644]
contrib/loaders/flash/cc3220sf/cc3220sf.s [new file with mode: 0644]
doc/openocd.texi
src/flash/nor/Makefile.am
src/flash/nor/cc3220sf.c [new file with mode: 0644]
src/flash/nor/cc3220sf.h [new file with mode: 0644]
src/flash/nor/drivers.c
tcl/board/ti_cc3220sf_launchpad.cfg [new file with mode: 0644]
tcl/board/ti_cc32xx_launchpad.cfg [new file with mode: 0644]
tcl/target/cc32xx.cfg [deleted file]
tcl/target/ti_cc3220sf.cfg [new file with mode: 0644]
tcl/target/ti_cc32xx.cfg [new file with mode: 0644]

diff --git a/contrib/loaders/flash/cc3220sf/Makefile b/contrib/loaders/flash/cc3220sf/Makefile
new file mode 100644 (file)
index 0000000..d1dcc25
--- /dev/null
@@ -0,0 +1,19 @@
+BIN2C = ../../../../src/helper/bin2char.sh
+
+CROSS_COMPILE ?= arm-none-eabi-
+AS      = $(CROSS_COMPILE)as
+OBJCOPY = $(CROSS_COMPILE)objcopy
+
+all: cc3220sf.inc
+
+%.elf: %.s
+       $(AS) $< -o $@
+
+%.bin: %.elf
+       $(OBJCOPY) -Obinary $< $@
+
+%.inc: %.bin
+       $(BIN2C) < $< > $@
+
+clean:
+       -rm -f *.elf *.bin *.inc
diff --git a/contrib/loaders/flash/cc3220sf/cc3220sf.inc b/contrib/loaders/flash/cc3220sf/cc3220sf.inc
new file mode 100644 (file)
index 0000000..29c54c6
--- /dev/null
@@ -0,0 +1,10 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0xdf,0xf8,0x7c,0xa0,0xdf,0xf8,0x7c,0xb0,0xdf,0xf8,0x7c,0xc0,0x01,0xf0,0x7f,0x03,
+0x00,0x2b,0x1e,0xd1,0x4f,0xf0,0x00,0x04,0xcc,0xf8,0x00,0x10,0x03,0x68,0xcb,0xf8,
+0x00,0x30,0x0b,0xf1,0x04,0x0b,0x00,0xf1,0x04,0x00,0xa2,0xf1,0x01,0x02,0x04,0xf1,
+0x01,0x04,0x01,0xf1,0x04,0x01,0x00,0x2a,0x01,0xd0,0x20,0x2c,0xee,0xd1,0xcc,0xf8,
+0x20,0xa0,0xdc,0xf8,0x20,0x30,0x13,0xf0,0x01,0x0f,0xfa,0xd1,0x00,0x2a,0xd7,0xd1,
+0x13,0xe0,0xcc,0xf8,0x00,0x10,0x03,0x68,0xcc,0xf8,0x04,0x30,0xcc,0xf8,0x08,0xa0,
+0xdc,0xf8,0x08,0x30,0x13,0xf0,0x01,0x0f,0xfa,0xd1,0xa2,0xf1,0x01,0x02,0x00,0xf1,
+0x04,0x00,0x01,0xf1,0x04,0x01,0x00,0x2a,0xc2,0xd1,0x00,0xbe,0x01,0xbe,0xfc,0xe7,
+0x01,0x00,0x42,0xa4,0x00,0xd1,0x0f,0x40,0x00,0xd0,0x0f,0x40,
diff --git a/contrib/loaders/flash/cc3220sf/cc3220sf.s b/contrib/loaders/flash/cc3220sf/cc3220sf.s
new file mode 100644 (file)
index 0000000..cffcfa0
--- /dev/null
@@ -0,0 +1,93 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by Texas Instruments, 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/>. *
+ ***************************************************************************/
+
+       /* Params:
+        * r0 = buffer start address (in)
+        * r1 = flash destination address (in)
+        * r2 = number of words to write (in/out)
+        */
+
+       .text
+       .cpu cortex-m4
+       .code 16
+       .thumb
+       .syntax unified
+
+       .align 2
+
+       /* r3 = scratchpad
+        * r4 = buffer word counter
+        * r10 = flash programming key
+        * r11 = base FWB address
+        * r12 = base flash regs address
+        */
+
+start:
+       ldr     r10, =0xa4420001        /* flash programming key */
+       ldr     r11, =0x400fd100        /* base of FWB */
+       ldr     r12, =0x400fd000        /* base of flash regs */
+       and     r3, r1, #0x7f           /* is the dest address 32 word aligned? */
+       cmp     r3, #0
+       bne     program_word            /* if not aligned do one word at a time */
+
+       /* program using the write buffers */
+program_buffer:
+       mov     r4, #0                          /* start the buffer word counter at 0 */
+       str     r1, [r12]                       /* store the dest addr in FMA */
+fill_buffer:
+       ldr     r3, [r0]                        /* get the word to write to FWB */
+       str     r3, [r11]                       /* store the word in the FWB */
+       add     r11, r11, #4            /* increment the FWB pointer */
+       add     r0, r0, #4                      /* increment the source pointer */
+       sub     r2, r2, #1                      /* decrement the total word counter */
+       add     r4, r4, #1                      /* increment the buffer word counter */
+       add     r1, r1, #4                      /* increment the dest pointer */
+       cmp     r2, #0                          /* is the total word counter now 0? */
+       beq     buffer_ready            /* go to end if total word counter is 0 */
+       cmp     r4, #32                         /* is the buffer word counter now 32? */
+       bne     fill_buffer                     /* go to continue to fill buffer */
+buffer_ready:
+       str     r10, [r12, #0x20]       /* store the key and write bit to FMC2 */
+wait_buffer_done:
+       ldr     r3, [r12, #0x20]        /* read FMC2 */
+       tst     r3, #1                          /* see if the write bit is cleared */
+       bne     wait_buffer_done        /* go to read FMC2 if bit not cleared */
+       cmp     r2, #0                          /* is the total word counter now 0? */
+       bne     start                           /* go if there is more to program */
+       b       exit
+
+       /* program just one word */
+program_word:
+       str     r1, [r12]                       /* store the dest addr in FMA */
+       ldr     r3, [r0]                        /* get the word to write to FMD */
+       str     r3, [r12, #0x4]         /* store the word in FMD */
+       str     r10, [r12, #0x8]        /* store the key and write bit to FMC */
+wait_word_done:
+       ldr     r3, [r12, #0x8]         /* read FMC */
+       tst     r3, #1                          /* see if the write bit is cleared */
+       bne     wait_word_done          /* go to read FMC if bit not cleared */
+       sub     r2, r2, #1                      /* decrement the total word counter */
+       add     r0, r0, #4                      /* increment the source pointer */
+       add     r1, r1, #4                      /* increment the dest pointer */
+       cmp     r2, #0                          /* is the total word counter now 0 */
+       bne     start                           /* go if there is more to program */
+
+       /* end */
+exit:
+       bkpt    #0
+       bkpt    #1
+       b       exit
index 24928f6..5b7d6d5 100644 (file)
@@ -5578,6 +5578,20 @@ Triggering a mass erase is also useful when users want to disable readout protec
 
 @end deffn
 
+@deffn {Flash Driver} cc3220sf
+The CC3220SF version of the SimpleLink CC32xx microcontrollers from Texas
+Instruments includes 1MB of internal flash. The cc3220sf flash driver only
+supports the internal flash. The serial flash on SimpleLink boards is
+programmed via the bootloader over a UART connection. Security features of
+the CC3220SF may erase the internal flash during power on reset. Refer to
+documentation at @url{www.ti.com/cc3220sf} for details on security features
+and programming the serial flash.
+
+@example
+flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME
+@end example
+@end deffn
+
 @deffn {Flash Driver} efm32
 All members of the EFM32 microcontroller family from Energy Micro include
 internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes
index b935364..5335931 100644 (file)
@@ -19,6 +19,7 @@ NOR_DRIVERS = \
        %D%/atsamv.c \
        %D%/avrf.c \
        %D%/bluenrg-x.c \
+       %D%/cc3220sf.c \
        %D%/cfi.c \
        %D%/dsp5680xx_flash.c \
        %D%/efm32.c \
@@ -63,6 +64,7 @@ NOR_DRIVERS = \
 
 NORHEADERS = \
        %D%/core.h \
+       %D%/cc3220sf.h \
        %D%/cfi.h \
        %D%/driver.h \
        %D%/imp.h \
diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c
new file mode 100644 (file)
index 0000000..af45743
--- /dev/null
@@ -0,0 +1,529 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by Texas Instruments, 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 "cc3220sf.h"
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+#define FLASH_TIMEOUT 5000
+
+struct cc3220sf_bank {
+       bool probed;
+       struct armv7m_algorithm armv7m_info;
+};
+
+static int cc3220sf_mass_erase(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       bool done;
+       long long start_ms;
+       long long elapsed_ms;
+       uint32_t value;
+
+       int retval = ERROR_OK;
+
+       if (TARGET_HALTED != target->state) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Set starting address to erase to zero */
+       retval = target_write_u32(target, FMA_REGISTER_ADDR, 0);
+       if (ERROR_OK != retval)
+               return retval;
+
+       /* Write the MERASE bit of the FMC register */
+       retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE);
+       if (ERROR_OK != retval)
+               return retval;
+
+       /* Poll the MERASE bit until the mass erase is complete */
+       done = false;
+       start_ms = timeval_ms();
+       while (!done) {
+               retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
+               if (ERROR_OK != retval)
+                       return retval;
+
+               if ((value & FMC_MERASE_BIT) == 0) {
+                       /* Bit clears when mass erase is finished */
+                       done = true;
+               } else {
+                       elapsed_ms = timeval_ms() - start_ms;
+                       if (elapsed_ms > 500)
+                               keep_alive();
+                       if (elapsed_ms > FLASH_TIMEOUT)
+                               break;
+               }
+       }
+
+       if (!done) {
+               /* Mass erase timed out waiting for confirmation */
+               return ERROR_FAIL;
+       }
+
+       return retval;
+}
+
+FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
+{
+       struct cc3220sf_bank *cc3220sf_bank;
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
+       if (NULL == cc3220sf_bank)
+               return ERROR_FAIL;
+
+       /* Initialize private flash information */
+       cc3220sf_bank->probed = false;
+
+       /* Finish initialization of flash bank */
+       bank->driver_priv = cc3220sf_bank;
+       bank->next = NULL;
+
+       return ERROR_OK;
+}
+
+static int cc3220sf_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       bool done;
+       long long start_ms;
+       long long elapsed_ms;
+       uint32_t address;
+       uint32_t value;
+
+       int retval = ERROR_OK;
+
+       if (TARGET_HALTED != target->state) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Do a mass erase if user requested all sectors of flash */
+       if ((first == 0) && (last == (bank->num_sectors - 1))) {
+               /* Request mass erase of flash */
+               return cc3220sf_mass_erase(bank);
+       }
+
+       /* Erase requested sectors one by one */
+       for (int i = first; i <= last; i++) {
+
+               /* Determine address of sector to erase */
+               address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE;
+
+               /* Set starting address to erase */
+               retval = target_write_u32(target, FMA_REGISTER_ADDR, address);
+               if (ERROR_OK != retval)
+                       return retval;
+
+               /* Write the ERASE bit of the FMC register */
+               retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE);
+               if (ERROR_OK != retval)
+                       return retval;
+
+               /* Poll the ERASE bit until the erase is complete */
+               done = false;
+               start_ms = timeval_ms();
+               while (!done) {
+                       retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
+                       if (ERROR_OK != retval)
+                               return retval;
+
+                       if ((value & FMC_ERASE_BIT) == 0) {
+                               /* Bit clears when mass erase is finished */
+                               done = true;
+                       } else {
+                               elapsed_ms = timeval_ms() - start_ms;
+                               if (elapsed_ms > 500)
+                                       keep_alive();
+                               if (elapsed_ms > FLASH_TIMEOUT)
+                                       break;
+                       }
+               }
+
+               if (!done) {
+                       /* Sector erase timed out waiting for confirmation */
+                       return ERROR_FAIL;
+               }
+       }
+
+       return retval;
+}
+
+static int cc3220sf_protect(struct flash_bank *bank, int set, int first,
+       int last)
+{
+       return ERROR_OK;
+}
+
+static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
+       uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
+       struct working_area *algo_working_area;
+       struct working_area *buffer_working_area;
+       struct reg_param reg_params[3];
+       uint32_t algo_base_address;
+       uint32_t algo_buffer_address;
+       uint32_t algo_buffer_size;
+       uint32_t address;
+       uint32_t remaining;
+       uint32_t words;
+       uint32_t result;
+
+       int retval = ERROR_OK;
+
+       if (TARGET_HALTED != target->state) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Obtain working area to use for flash helper algorithm */
+       retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
+                               &algo_working_area);
+       if (ERROR_OK != retval)
+               return retval;
+
+       /* Obtain working area to use for flash buffer */
+       retval = target_alloc_working_area(target,
+                               target_get_working_area_avail(target), &buffer_working_area);
+       if (ERROR_OK != retval) {
+               target_free_working_area(target, algo_working_area);
+               return retval;
+       }
+
+       algo_base_address = algo_working_area->address;
+       algo_buffer_address = buffer_working_area->address;
+       algo_buffer_size = buffer_working_area->size;
+
+       /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
+       /* (algo runs more efficiently if it operates on 32 words at a time) */
+       if (algo_buffer_size > 0x80)
+               algo_buffer_size &= ~0x7f;
+
+       /* Write flash helper algorithm into target memory */
+       retval = target_write_buffer(target, algo_base_address,
+                               sizeof(cc3220sf_algo), cc3220sf_algo);
+       if (ERROR_OK != retval) {
+               target_free_working_area(target, algo_working_area);
+               target_free_working_area(target, buffer_working_area);
+               return retval;
+       }
+
+       /* Initialize the ARMv7m specific info to run the algorithm */
+       cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
+
+       /* Initialize register params for flash helper algorithm */
+       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_IN_OUT);
+
+       /* Prepare to write to flash */
+       address = FLASH_BASE_ADDR + offset;
+       remaining = count;
+
+       /* The flash hardware can only write complete words to flash. If
+        * an unaligned address is passed in, we must do a read-modify-write
+        * on a word with enough bytes to align the rest of the buffer. And
+        * if less than a whole word remains at the end, we must also do a
+        * read-modify-write on a final word to finish up.
+        */
+
+       /* Do one word write to align address on 32-bit boundary if needed */
+       if (0 != (address & 0x3)) {
+               uint8_t head[4];
+
+               /* Get starting offset for data to write (will be 1 to 3) */
+               uint32_t head_offset = address & 0x03;
+
+               /* Get the aligned address to write this first word to */
+               uint32_t head_address = address & 0xfffffffc;
+
+               /* Retrieve what is already in flash at the head address */
+               retval = target_read_buffer(target, head_address, sizeof(head), head);
+
+               if (ERROR_OK == retval) {
+                       /* Substitute in the new data to write */
+                       while ((remaining > 0) && (head_offset < 4)) {
+                               head[head_offset] = *buffer;
+                               head_offset++;
+                               address++;
+                               buffer++;
+                               remaining--;
+                       }
+               }
+
+               if (ERROR_OK == retval) {
+                       /* Helper parameters are passed in registers R0-R2 */
+                       /* Set start of data buffer, address to write to, and word count */
+                       buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
+                       buf_set_u32(reg_params[1].value, 0, 32, head_address);
+                       buf_set_u32(reg_params[2].value, 0, 32, 1);
+
+                       /* Write head value into buffer to flash */
+                       retval = target_write_buffer(target, algo_buffer_address,
+                                               sizeof(head), head);
+               }
+
+               if (ERROR_OK == retval) {
+                       /* Execute the flash helper algorithm */
+                       retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+                                               algo_base_address, 0, FLASH_TIMEOUT,
+                                               &cc3220sf_bank->armv7m_info);
+                       if (ERROR_OK != retval)
+                               LOG_ERROR("cc3220sf: Flash algorithm failed to run");
+
+                       /* Check that the head value was written to flash */
+                       result = buf_get_u32(reg_params[2].value, 0, 32);
+                       if (0 != result) {
+                               retval = ERROR_FAIL;
+                               LOG_ERROR("cc3220sf: Flash operation failed");
+                       }
+               }
+       }
+
+       /* Check if there's data at end of buffer that isn't a full word */
+       uint32_t tail_count = remaining & 0x03;
+       /* Adjust remaining so it is a multiple of whole words */
+       remaining -= tail_count;
+
+       while ((ERROR_OK == retval) && (remaining > 0)) {
+               /* Set start of data buffer and address to write to */
+               buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+
+               /* Download data to write into memory buffer */
+               if (remaining >= algo_buffer_size) {
+                       /* Fill up buffer with data to flash */
+                       retval = target_write_buffer(target, algo_buffer_address,
+                                               algo_buffer_size, buffer);
+                       if (ERROR_OK != retval)
+                               break;
+
+                       /* Count to write is in 32-bit words */
+                       words = algo_buffer_size / 4;
+
+                       /* Bump variables to next data */
+                       address += algo_buffer_size;
+                       buffer += algo_buffer_size;
+                       remaining -= algo_buffer_size;
+               } else {
+                       /* Fill buffer with what's left of the data */
+                       retval = target_write_buffer(target, algo_buffer_address,
+                                               remaining, buffer);
+                       if (ERROR_OK != retval)
+                               break;
+
+                       /* Calculate the final word count to write */
+                       words = remaining / 4;
+                       if (0 != (remaining % 4))
+                               words++;
+
+                       /* Bump variables to any final data */
+                       address += remaining;
+                       buffer += remaining;
+                       remaining = 0;
+               }
+
+               /* Set number of words to write */
+               buf_set_u32(reg_params[2].value, 0, 32, words);
+
+               /* Execute the flash helper algorithm */
+               retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+                                       algo_base_address, 0, FLASH_TIMEOUT,
+                                       &cc3220sf_bank->armv7m_info);
+               if (ERROR_OK != retval) {
+                       LOG_ERROR("cc3220sf: Flash algorithm failed to run");
+                       break;
+               }
+
+               /* Check that all words were written to flash */
+               result = buf_get_u32(reg_params[2].value, 0, 32);
+               if (0 != result) {
+                       retval = ERROR_FAIL;
+                       LOG_ERROR("cc3220sf: Flash operation failed");
+                       break;
+               }
+       }
+
+       /* Do one word write for any final bytes less than a full word */
+       if ((ERROR_OK == retval) && (0 != tail_count)) {
+               uint8_t tail[4];
+
+               /* Set starting byte offset for data to write */
+               uint32_t tail_offset = 0;
+
+               /* Retrieve what is already in flash at the tail address */
+               retval = target_read_buffer(target, address, sizeof(tail), tail);
+
+               if (ERROR_OK == retval) {
+                       /* Substitute in the new data to write */
+                       while (tail_count > 0) {
+                               tail[tail_offset] = *buffer;
+                               tail_offset++;
+                               buffer++;
+                               tail_count--;
+                       }
+               }
+
+               if (ERROR_OK == retval) {
+                       /* Set start of data buffer, address to write to, and word count */
+                       buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
+                       buf_set_u32(reg_params[1].value, 0, 32, address);
+                       buf_set_u32(reg_params[2].value, 0, 32, 1);
+
+                       /* Write tail value into buffer to flash */
+                       retval = target_write_buffer(target, algo_buffer_address,
+                                               sizeof(tail), tail);
+               }
+
+               if (ERROR_OK == retval) {
+                       /* Execute the flash helper algorithm */
+                       retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+                                               algo_base_address, 0, FLASH_TIMEOUT,
+                                               &cc3220sf_bank->armv7m_info);
+                       if (ERROR_OK != retval)
+                               LOG_ERROR("cc3220sf: Flash algorithm failed to run");
+
+                       /* Check that the tail was written to flash */
+                       result = buf_get_u32(reg_params[2].value, 0, 32);
+                       if (0 != result) {
+                               retval = ERROR_FAIL;
+                               LOG_ERROR("cc3220sf: Flash operation failed");
+                       }
+               }
+       }
+
+       /* Free resources  */
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       target_free_working_area(target, algo_working_area);
+       target_free_working_area(target, buffer_working_area);
+
+       return retval;
+}
+
+static int cc3220sf_probe(struct flash_bank *bank)
+{
+       struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
+
+       uint32_t base;
+       uint32_t size;
+       int num_sectors;
+       int bank_id;
+
+       bank_id = bank->bank_number;
+
+       if (0 == bank_id) {
+               base = FLASH_BASE_ADDR;
+               size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
+               num_sectors = FLASH_NUM_SECTORS;
+       } else {
+               /* Invalid bank number somehow */
+               return ERROR_FAIL;
+       }
+
+       if (NULL != bank->sectors) {
+               free(bank->sectors);
+               bank->sectors = NULL;
+       }
+
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+       if (NULL == bank->sectors)
+               return ERROR_FAIL;
+
+       bank->base = base;
+       bank->size = size;
+       bank->write_start_alignment = 0;
+       bank->write_end_alignment = 0;
+       bank->num_sectors = num_sectors;
+
+       for (int i = 0; i < num_sectors; i++) {
+               bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
+               bank->sectors[i].size = FLASH_SECTOR_SIZE;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 0;
+       }
+
+       /* We've successfully recorded the stats on this flash bank */
+       cc3220sf_bank->probed = true;
+
+       /* If we fall through to here, then all went well */
+
+       return ERROR_OK;
+}
+
+static int cc3220sf_auto_probe(struct flash_bank *bank)
+{
+       struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
+
+       int retval = ERROR_OK;
+
+       if (0 != bank->bank_number) {
+               /* Invalid bank number somehow */
+               return ERROR_FAIL;
+       }
+
+       if (!cc3220sf_bank->probed)
+               retval = cc3220sf_probe(bank);
+
+       return retval;
+}
+
+static int cc3220sf_protect_check(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       int printed;
+
+       printed = snprintf(buf, buf_size, "CC3220SF with 1MB internal flash\n");
+
+       if (printed >= buf_size)
+               return ERROR_BUF_TOO_SMALL;
+
+       return ERROR_OK;
+}
+
+struct flash_driver cc3220sf_flash = {
+       .name = "cc3220sf",
+       .flash_bank_command = cc3220sf_flash_bank_command,
+       .erase = cc3220sf_erase,
+       .protect = cc3220sf_protect,
+       .write = cc3220sf_write,
+       .read = default_flash_read,
+       .probe = cc3220sf_probe,
+       .auto_probe = cc3220sf_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = cc3220sf_protect_check,
+       .info = cc3220sf_info,
+       .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/cc3220sf.h b/src/flash/nor/cc3220sf.h
new file mode 100644 (file)
index 0000000..36c17be
--- /dev/null
@@ -0,0 +1,45 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by Texas Instruments, 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/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_CC3220SF_H
+#define OPENOCD_FLASH_NOR_CC3220SF_H
+
+/* CC3220SF device types */
+#define CC3220_NO_TYPE 0 /* Device type not determined yet */
+#define CC3220_OTHER   1 /* CC3220 variant without flash */
+#define CC3220SF       2 /* CC3220SF variant with flash */
+
+/* Flash parameters */
+#define FLASH_BASE_ADDR   0x01000000
+#define FLASH_SECTOR_SIZE 2048
+#define FLASH_NUM_SECTORS 512
+
+/* CC2200SF flash registers */
+#define FMA_REGISTER_ADDR 0x400FD000
+#define FMC_REGISTER_ADDR 0x400FD008
+#define FMC_DEFAULT_VALUE 0xA4420000
+#define FMC_ERASE_BIT     0x00000002
+#define FMC_MERASE_BIT    0x00000004
+#define FMC_ERASE_VALUE   (FMC_DEFAULT_VALUE | FMC_ERASE_BIT)
+#define FMC_MERASE_VALUE  (FMC_DEFAULT_VALUE | FMC_MERASE_BIT)
+
+/* Flash helper algorithm for CC3220SF */
+const uint8_t cc3220sf_algo[] = {
+#include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc"
+};
+
+#endif /* OPENOCD_FLASH_NOR_CC3220SF_H */
index a4640a5..b09e58f 100644 (file)
@@ -32,6 +32,7 @@ extern struct flash_driver ath79_flash;
 extern struct flash_driver atsamv_flash;
 extern struct flash_driver avr_flash;
 extern struct flash_driver bluenrgx_flash;
+extern struct flash_driver cc3220sf_flash;
 extern struct flash_driver cfi_flash;
 extern struct flash_driver dsp5680xx_flash;
 extern struct flash_driver efm32_flash;
@@ -90,6 +91,7 @@ static struct flash_driver *flash_drivers[] = {
        &atsamv_flash,
        &avr_flash,
        &bluenrgx_flash,
+       &cc3220sf_flash,
        &cfi_flash,
        &dsp5680xx_flash,
        &efm32_flash,
diff --git a/tcl/board/ti_cc3220sf_launchpad.cfg b/tcl/board/ti_cc3220sf_launchpad.cfg
new file mode 100644 (file)
index 0000000..a3dac62
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# TI CC3220SF-LaunchXL LaunchPad Evaluation Kit
+#
+source [find interface/xds110.cfg]
+adapter_khz 2500
+transport select swd
+source [find target/ti_cc3220sf.cfg]
diff --git a/tcl/board/ti_cc32xx_launchpad.cfg b/tcl/board/ti_cc32xx_launchpad.cfg
new file mode 100644 (file)
index 0000000..f657bdf
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# TI CC32xx-LaunchXL LaunchPad Evaluation Kit
+#
+source [find interface/xds110.cfg]
+adapter_khz 2500
+transport select swd
+source [find target/ti_cc32xx.cfg]
diff --git a/tcl/target/cc32xx.cfg b/tcl/target/cc32xx.cfg
deleted file mode 100755 (executable)
index dfc4c17..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# Config for Texas Instruments SoC CC32xx family
-
-source [find target/swj-dp.tcl]
-
-adapter_khz 100
-
-source [find target/icepick.cfg]
-
-if { [info exists CHIPNAME] } {
-   set _CHIPNAME $CHIPNAME
-} else {
-   set _CHIPNAME cc32xx
-}
-
-#
-# Main DAP
-#
-if { [info exists DAP_TAPID] } {
-   set _DAP_TAPID $DAP_TAPID
-} else {
-   if {[using_jtag]} {
-      set _DAP_TAPID 0x4BA00477
-   } else {
-      set _DAP_TAPID 0x2BA01477
-   }
-}
-
-if {[using_jtag]} {
-   jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable
-   jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0"
-} else {
-   swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID
-}
-
-#
-# ICEpick-C (JTAG route controller)
-#
-if { [info exists JRC_TAPID] } {
-   set _JRC_TAPID $JRC_TAPID
-} else {
-   set _JRC_TAPID 0x0B97C02F
-}
-
-if {[using_jtag]} {
-   jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version
-   jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap"
-}
-
-#
-# Cortex-M3 target
-#
-set _TARGETNAME $_CHIPNAME.cpu
-dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
-target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
diff --git a/tcl/target/ti_cc3220sf.cfg b/tcl/target/ti_cc3220sf.cfg
new file mode 100644 (file)
index 0000000..f7d9bfe
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Texas Instruments CC3220SF - ARM Cortex-M4
+#
+# http://www.ti.com/CC3220SF
+#
+
+source [find target/swj-dp.tcl]
+source [find target/icepick.cfg]
+source [find target/ti_cc32xx.cfg]
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME
diff --git a/tcl/target/ti_cc32xx.cfg b/tcl/target/ti_cc32xx.cfg
new file mode 100644 (file)
index 0000000..bc3038d
--- /dev/null
@@ -0,0 +1,64 @@
+#
+# Texas Instruments CC32xx - ARM Cortex-M4
+#
+# http://www.ti.com/product/CC3200
+# http://www.ti.com/product/CC3220
+#
+
+source [find target/swj-dp.tcl]
+source [find target/icepick.cfg]
+
+if { [info exists CHIPNAME] } {
+       set _CHIPNAME $CHIPNAME
+} else {
+       set _CHIPNAME cc32xx
+}
+
+#
+# Main DAP
+#
+if { [info exists DAP_TAPID] } {
+       set _DAP_TAPID $DAP_TAPID
+} else {
+       if {[using_jtag]} {
+               set _DAP_TAPID 0x4BA00477
+       } else {
+               set _DAP_TAPID 0x2BA01477
+       }
+}
+
+if {[using_jtag]} {
+       jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable
+       jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0"
+} else {
+       swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID
+}
+
+#
+# ICEpick-C (JTAG route controller)
+#
+if { [info exists JRC_TAPID] } {
+       set _JRC_TAPID $JRC_TAPID
+} else {
+       set _JRC_TAPID 0x0B97C02F
+}
+
+if {[using_jtag]} {
+       jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version
+       jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu"
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
+
+if { [info exists WORKAREASIZE] } {
+       set _WORKAREASIZE $WORKAREASIZE
+} else {
+       set _WORKAREASIZE 0x2000
+}
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+reset_config srst_only
+adapter_nsrst_delay 1100