mirror of
git://git.code.sf.net/p/openocd/code
synced 2025-07-19 08:38:14 +10:00
Replace the BSD-3-Clause boilerplate with the SPDX tag. Add the SPDX tag and the copyright to two makefiles that were added by TI with the other files in their respective folder. The SPDX tag on files *.c is incorrect, as it should use the C99 single line comment using '//'. But current checkpatch doesn't allow C99 comments, so keep using standard C comments, by now. Change-Id: I3ad1b2dbdb6054b74dcc26e394c9223ba0427caf Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/7158 Tested-by: jenkins
326 lines
9.3 KiB
C
326 lines
9.3 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "driverlib.h"
|
|
|
|
#include "MSP432E4_FlashLibIf.h"
|
|
|
|
/* Local prototypes */
|
|
void msp432_flash_init(void);
|
|
void msp432_flash_mass_erase(void);
|
|
void msp432_flash_sector_erase(void);
|
|
void msp432_flash_write(void);
|
|
void msp432_flash_continous_write(void);
|
|
void msp432_flash_exit(void);
|
|
|
|
int main(void)
|
|
{
|
|
/* Disable interrupts */
|
|
__asm(" cpsid i");
|
|
|
|
/* Halt watchdog */
|
|
SYSCTL->RCGCWD &= ~(SYSCTL_RCGCWD_R1 + SYSCTL_RCGCWD_R0);
|
|
|
|
while (1) {
|
|
switch (FLASH_LOADER->FLASH_FUNCTION) {
|
|
case FLASH_INIT:
|
|
FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
|
|
msp432_flash_init();
|
|
FLASH_LOADER->FLASH_FUNCTION = 0;
|
|
break;
|
|
case FLASH_MASS_ERASE:
|
|
FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
|
|
msp432_flash_mass_erase();
|
|
FLASH_LOADER->FLASH_FUNCTION = 0;
|
|
break;
|
|
case FLASH_SECTOR_ERASE:
|
|
FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
|
|
msp432_flash_sector_erase();
|
|
FLASH_LOADER->FLASH_FUNCTION = 0;
|
|
break;
|
|
case FLASH_PROGRAM:
|
|
case FLASH_CONTINUOUS_PROGRAM:
|
|
FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
|
|
msp432_flash_continous_write();
|
|
FLASH_LOADER->FLASH_FUNCTION = 0;
|
|
break;
|
|
case FLASH_EXIT:
|
|
FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
|
|
msp432_flash_exit();
|
|
FLASH_LOADER->FLASH_FUNCTION = 0;
|
|
break;
|
|
case FLASH_NO_COMMAND:
|
|
break;
|
|
default:
|
|
FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Initialize flash */
|
|
void msp432_flash_init(void)
|
|
{
|
|
SCB->VTOR = 0x20000000;
|
|
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
|
|
}
|
|
|
|
/* Erase entire flash */
|
|
void msp432_flash_mass_erase(void)
|
|
{
|
|
bool success = false;
|
|
|
|
/* Clear the flash access and error interrupts. */
|
|
FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
|
|
FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
|
|
|
|
/* Trigger mass erase */
|
|
FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_MERASE;
|
|
while (FLASH_CTRL->FMC & FLASH_FMC_MERASE)
|
|
;
|
|
|
|
/* Return an error if an access violation occurred. */
|
|
success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
|
|
FLASH_FCRIS_ERRIS));
|
|
if (!success)
|
|
FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR;
|
|
else
|
|
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
|
|
}
|
|
|
|
/* Erase one flash sector */
|
|
void msp432_flash_sector_erase(void)
|
|
{
|
|
bool success = false;
|
|
|
|
/* Clear the flash access and error interrupts. */
|
|
FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
|
|
FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
|
|
|
|
/* Set 16kB aligned flash page address to be erased (16kB block) */
|
|
FLASH_CTRL->FMA = FLASH_LOADER->DST_ADDRESS;
|
|
/* Trigger sector erase (erase flash page) */
|
|
FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
|
|
while (FLASH_CTRL->FMC & FLASH_FMC_ERASE)
|
|
;
|
|
|
|
/* Return an error if an access violation occurred. */
|
|
success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
|
|
FLASH_FCRIS_ERRIS));
|
|
|
|
if (!success)
|
|
FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
|
|
else
|
|
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
|
|
}
|
|
|
|
/* Write data to flash */
|
|
void msp432_flash_continous_write(void)
|
|
{
|
|
bool buffer1_in_use = false;
|
|
bool buffer2_in_use = false;
|
|
uint32_t *src_address = NULL;
|
|
bool success = true;
|
|
uint32_t i = 0;
|
|
uint32_t address = FLASH_LOADER->DST_ADDRESS;
|
|
uint32_t data_to_write = FLASH_LOADER->SRC_LENGTH;
|
|
int32_t write_package = 0;
|
|
|
|
/* Clear the flash access and error interrupts. */
|
|
FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
|
|
FLASH_FCMISC_INVDMISC | FLASH_FCMISC_PROGMISC | FLASH_FCMISC_PMISC);
|
|
do {
|
|
if (data_to_write > SRC_LENGTH_MAX) {
|
|
write_package = SRC_LENGTH_MAX;
|
|
data_to_write -= write_package;
|
|
} else {
|
|
write_package = data_to_write;
|
|
data_to_write -= write_package;
|
|
}
|
|
while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) &&
|
|
!(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY))
|
|
;
|
|
|
|
if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) {
|
|
FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE;
|
|
src_address = (uint32_t *) RAM_LOADER_BUFFER1;
|
|
buffer1_in_use = true;
|
|
} else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) {
|
|
FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE;
|
|
src_address = (uint32_t *) RAM_LOADER_BUFFER2;
|
|
buffer2_in_use = true;
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
if (0 != (address & 0x3)) {
|
|
uint32_t head;
|
|
uint8_t *ui8head = (uint8_t *)&head;
|
|
uint8_t *buffer = (uint8_t *)src_address;
|
|
|
|
/* 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 */
|
|
head = *(uint32_t *)head_address;
|
|
|
|
/* Substitute in the new data to write */
|
|
while ((write_package > 0) && (head_offset < 4)) {
|
|
ui8head[head_offset] = *buffer;
|
|
head_offset++;
|
|
address++;
|
|
buffer++;
|
|
write_package--;
|
|
}
|
|
src_address = (uint32_t *)buffer;
|
|
|
|
FLASH_CTRL->FMD = head;
|
|
FLASH_CTRL->FMA = head_address;
|
|
FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
|
|
|
|
/* Wait until the word has been programmed. */
|
|
while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
|
|
;
|
|
|
|
/* Return an error if an access violation occurred. */
|
|
success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
|
|
FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
|
|
}
|
|
|
|
/* Program a word at a time until aligned on 32-word boundary */
|
|
while ((write_package >= 4) && ((address & 0x7f) != 0) && success) {
|
|
FLASH_CTRL->FMD = *src_address++;
|
|
FLASH_CTRL->FMA = address;
|
|
FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
|
|
|
|
/* Wait until the word has been programmed. */
|
|
while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
|
|
;
|
|
|
|
/* Prepare for next word to write */
|
|
write_package -= 4;
|
|
address += 4;
|
|
|
|
/* Return an error if an access violation occurred. */
|
|
success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
|
|
FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
|
|
}
|
|
|
|
/* Program data in 32-word blocks */
|
|
while ((write_package >= 32) && success) {
|
|
/* Loop over the words in this 32-word block. */
|
|
i = 0;
|
|
do {
|
|
FLASH_CTRL->FWBN[i] = *src_address++;
|
|
write_package -= 4;
|
|
i++;
|
|
} while ((write_package > 0) && (i < 32));
|
|
FLASH_CTRL->FMA = address;
|
|
FLASH_CTRL->FMC2 = FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF;
|
|
|
|
/* Wait until the write buffer has been programmed. */
|
|
while (FLASH_CTRL->FMC2 & FLASH_FMC2_WRBUF)
|
|
;
|
|
|
|
/* Increment destination address by words written */
|
|
address += 128;
|
|
|
|
/* Return an error if an access violation occurred. */
|
|
success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
|
|
FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
|
|
}
|
|
|
|
/* Program a word at a time on left over data */
|
|
while ((write_package >= 4) && success) {
|
|
FLASH_CTRL->FMD = *src_address++;
|
|
FLASH_CTRL->FMA = address;
|
|
FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
|
|
|
|
/* Wait until the word has been programmed. */
|
|
while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
|
|
;
|
|
|
|
/* Prepare for next word to write */
|
|
write_package -= 4;
|
|
address += 4;
|
|
|
|
/* Return an error if an access violation occurred. */
|
|
success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
|
|
FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
|
|
}
|
|
|
|
if ((write_package > 0) && success) {
|
|
uint32_t tail;
|
|
uint8_t *ui8tail = (uint8_t *)&tail;
|
|
uint8_t *buffer = (uint8_t *)src_address;
|
|
|
|
/* Set starting offset for data to write */
|
|
uint32_t tail_offset = 0;
|
|
|
|
/* Get the address to write this last word to */
|
|
uint32_t tail_address = address;
|
|
|
|
/* Retrieve what is already in flash at the tail address */
|
|
tail = *(uint32_t *)address;
|
|
|
|
/* Substitute in the new data to write */
|
|
while (write_package > 0) {
|
|
ui8tail[tail_offset] = *buffer;
|
|
tail_offset++;
|
|
address++;
|
|
buffer++;
|
|
write_package--;
|
|
}
|
|
|
|
FLASH_CTRL->FMD = tail;
|
|
FLASH_CTRL->FMA = tail_address;
|
|
FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
|
|
|
|
/* Wait until the word has been programmed. */
|
|
while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
|
|
;
|
|
|
|
/* Return an error if an access violation occurred. */
|
|
success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
|
|
FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
|
|
}
|
|
|
|
if (buffer1_in_use) {
|
|
FLASH_LOADER->BUFFER1_STATUS_REGISTER &=
|
|
~(BUFFER_ACTIVE | BUFFER_DATA_READY);
|
|
buffer1_in_use = false;
|
|
} else if (buffer2_in_use) {
|
|
FLASH_LOADER->BUFFER2_STATUS_REGISTER &=
|
|
~(BUFFER_ACTIVE | BUFFER_DATA_READY);
|
|
buffer2_in_use = false;
|
|
}
|
|
} while (success && data_to_write);
|
|
|
|
if (!success)
|
|
FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
|
|
else
|
|
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
|
|
}
|
|
|
|
/* Exit flash programming */
|
|
void msp432_flash_exit(void)
|
|
{
|
|
SCB->VTOR = 0x00000000;
|
|
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
|
|
}
|