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