diff --git a/contrib/loaders/flash/cc3220sf/Makefile b/contrib/loaders/flash/cc3220sf/Makefile
new file mode 100644
index 000000000..d1dcc25fd
--- /dev/null
+++ b/contrib/loaders/flash/cc3220sf/Makefile
@@ -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
index 000000000..29c54c684
--- /dev/null
+++ b/contrib/loaders/flash/cc3220sf/cc3220sf.inc
@@ -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
index 000000000..cffcfa053
--- /dev/null
+++ b/contrib/loaders/flash/cc3220sf/cc3220sf.s
@@ -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 . *
+ ***************************************************************************/
+
+ /* 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
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 24928f6be..5b7d6d595 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -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
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index b9353642f..5335931b2 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -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
index 000000000..af45743b9
--- /dev/null
+++ b/src/flash/nor/cc3220sf.c
@@ -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 . *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "cc3220sf.h"
+#include
+#include
+#include
+
+#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(®_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(®_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(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_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
index 000000000..36c17be90
--- /dev/null
+++ b/src/flash/nor/cc3220sf.h
@@ -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 . *
+ ***************************************************************************/
+
+#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 */
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index a4640a5e7..b09e58f61 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -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
index 000000000..a3dac620d
--- /dev/null
+++ b/tcl/board/ti_cc3220sf_launchpad.cfg
@@ -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
index 000000000..f657bdfdb
--- /dev/null
+++ b/tcl/board/ti_cc32xx_launchpad.cfg
@@ -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
index dfc4c17a8..000000000
--- a/tcl/target/cc32xx.cfg
+++ /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
index 000000000..f7d9bfe17
--- /dev/null
+++ b/tcl/target/ti_cc3220sf.cfg
@@ -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
index 000000000..bc3038d8e
--- /dev/null
+++ b/tcl/target/ti_cc32xx.cfg
@@ -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