riscv-openocd/contrib/loaders/flash/msp432/main_msp432p411x.c

392 lines
12 KiB
C

/******************************************************************************
*
* Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
#include <stdint.h>
#include <stdbool.h>
#include "driverlib.h"
#include "MSP432P4_FlashLibIf.h"
/* Number of erase repeats until timeout */
#define FLASH_MAX_REPEATS 5
/* 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);
void unlock_flash_sectors(void);
void unlock_all_flash_sectors(void);
void lock_all_flash_sectors(void);
void __cs_set_dco_frequency_range(uint32_t dco_freq);
static bool program_device(void *src, void *dest, uint32_t length);
struct backup_params {
uint32_t BANK0_WAIT_RESTORE;
uint32_t BANK1_WAIT_RESTORE;
uint32_t CS_DC0_FREQ_RESTORE;
uint8_t VCORE_LEVEL_RESTORE;
uint8_t PCM_VCORE_LEVEL_RESTORE;
};
#define BACKUP_PARAMS ((struct backup_params *) 0x20000180)
#define INFO_FLASH_START __INFO_FLASH_A_TECH_START__
#define INFO_FLASH_MIDDLE __INFO_FLASH_A_TECH_MIDDLE__
#define BSL_FLASH_START BSL_API_TABLE_ADDR
/* Main with trampoline */
int main(void)
{
/* Halt watchdog */
MAP_WDT_A_HOLD_TIMER();
/* Disable interrupts */
cpu_cpsid();
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:
FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
msp432_flash_write();
FLASH_LOADER->FLASH_FUNCTION = 0;
break;
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)
{
bool success = false;
/* Point to vector table in RAM */
SCB->VTOR = (uint32_t)0x01000000;
/* backup system parameters */
BACKUP_PARAMS->BANK0_WAIT_RESTORE =
MAP_FLASH_CTL_A_GET_WAIT_STATE(FLASH_A_BANK0);
BACKUP_PARAMS->BANK1_WAIT_RESTORE =
MAP_FLASH_CTL_A_GET_WAIT_STATE(FLASH_A_BANK1);
BACKUP_PARAMS->VCORE_LEVEL_RESTORE = MAP_PCM_GET_CORE_VOLTAGE_LEVEL();
BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE = MAP_PCM_GET_POWER_STATE();
BACKUP_PARAMS->CS_DC0_FREQ_RESTORE = CS->CTL0 & CS_CTL0_DCORSEL_MASK;
/* set parameters for flashing */
success = MAP_PCM_SET_POWER_STATE(PCM_AM_LDO_VCORE0);
/* Set Flash wait states to 2 */
MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK0, 2);
MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK1, 2);
/* Set CPU speed to 24MHz */
__cs_set_dco_frequency_range(CS_DCO_FREQUENCY_24);
if (!success) {
/* Indicate failed power switch */
FLASH_LOADER->RETURN_CODE = FLASH_POWER_ERROR;
} else
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
}
/* Erase entire flash */
void msp432_flash_mass_erase(void)
{
bool success = false;
/* Allow flash writes */
unlock_flash_sectors();
/* Allow some mass erase repeats before timeout with error */
int erase_repeats = FLASH_MAX_REPEATS;
while (!success && (erase_repeats > 0)) {
/* Mass erase with post-verify */
success = ROM_FLASH_CTL_A_PERFORM_MASS_ERASE();
erase_repeats--;
}
if (erase_repeats == 0)
FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR;
else
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
/* Block flash writes */
lock_all_flash_sectors();
}
/* Erase one flash sector */
void msp432_flash_sector_erase(void)
{
bool success = false;
/* Allow flash writes */
unlock_all_flash_sectors();
/* Allow some sector erase repeats before timeout with error */
int erase_repeats = FLASH_MAX_REPEATS;
while (!success && (erase_repeats > 0)) {
/* Sector erase with post-verify */
success = MAP_FLASH_CTL_A_ERASE_SECTOR(FLASH_LOADER->DST_ADDRESS);
erase_repeats--;
}
if (erase_repeats == 0)
FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
else
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
/* Block flash writes */
lock_all_flash_sectors();
}
/* Write data to flash with the help of DriverLib */
void msp432_flash_write(void)
{
bool success = false;
/* Allow flash writes */
unlock_all_flash_sectors();
while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY))
;
FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE;
/* Program memory */
success = program_device((uint32_t *)RAM_LOADER_BUFFER1,
(void *)FLASH_LOADER->DST_ADDRESS, FLASH_LOADER->SRC_LENGTH);
FLASH_LOADER->BUFFER1_STATUS_REGISTER &=
~(BUFFER_ACTIVE | BUFFER_DATA_READY);
/* Block flash writes */
lock_all_flash_sectors();
if (!success)
FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
else
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
}
/* Write data to flash with the help of DriverLib with auto-increment */
void msp432_flash_continous_write(void)
{
bool buffer1_in_use = false;
bool buffer2_in_use = false;
uint32_t *src_address = NULL;
bool success = false;
uint32_t bytes_to_write = FLASH_LOADER->SRC_LENGTH;
uint32_t write_package = 0;
uint32_t start_addr = FLASH_LOADER->DST_ADDRESS;
while (bytes_to_write > 0) {
if (bytes_to_write > SRC_LENGTH_MAX) {
write_package = SRC_LENGTH_MAX;
bytes_to_write -= write_package;
} else {
write_package = bytes_to_write;
bytes_to_write -= write_package;
}
unlock_all_flash_sectors();
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;
}
if (buffer1_in_use || buffer2_in_use) {
success = program_device(src_address, (void *) start_addr, write_package);
start_addr += write_package;
}
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;
}
/* Block flash writes */
lock_all_flash_sectors();
if (!success) {
FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
break;
}
}
if (success)
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
}
/* Unlock Main/Info Flash sectors */
void unlock_flash_sectors(void)
{
if (FLASH_LOADER->ERASE_PARAM & ERASE_MAIN)
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(FLASH_BASE, FLASH_BASE +
MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1);
if (FLASH_LOADER->ERASE_PARAM & ERASE_INFO) {
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_START, TLV_BASE - 1);
if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY)
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(BSL_FLASH_START,
INFO_FLASH_MIDDLE - 1);
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_MIDDLE, INFO_FLASH_MIDDLE +
MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1);
}
}
/* Unlock All Flash sectors */
void unlock_all_flash_sectors(void)
{
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(FLASH_BASE, FLASH_BASE +
MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1);
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_START, TLV_BASE - 1);
if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY)
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(BSL_FLASH_START,
INFO_FLASH_MIDDLE - 1);
MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_MIDDLE, INFO_FLASH_MIDDLE +
MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1);
}
/* Lock all Flash sectors */
void lock_all_flash_sectors(void)
{
MAP_FLASH_CTL_A_PROTECT_MEMORY(FLASH_BASE, FLASH_BASE +
MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1);
MAP_FLASH_CTL_A_PROTECT_MEMORY(INFO_FLASH_START, INFO_FLASH_START +
MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1);
}
/* Force DCO frequency range */
void __cs_set_dco_frequency_range(uint32_t dco_freq)
{
/* Unlocking the CS Module */
CS->KEY = CS_KEY_VAL;
/* Resetting Tuning Parameters and Setting the frequency */
CS->CTL0 = (CS->CTL0 & ~CS_CTL0_DCORSEL_MASK) | dco_freq;
/* Locking the CS Module */
CS->KEY = 0;
}
/* Exit flash programming */
void msp432_flash_exit(void)
{
bool success = false;
/* Restore modified registers, in reverse order */
__cs_set_dco_frequency_range(CS_DCO_FREQUENCY_3);
MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK0,
BACKUP_PARAMS->BANK0_WAIT_RESTORE);
MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK1,
BACKUP_PARAMS->BANK1_WAIT_RESTORE);
success = MAP_PCM_SET_POWER_STATE(BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE);
success &= MAP_PCM_SET_CORE_VOLTAGE_LEVEL(
BACKUP_PARAMS->VCORE_LEVEL_RESTORE);
__cs_set_dco_frequency_range(BACKUP_PARAMS->CS_DC0_FREQ_RESTORE);
/* Point to vector table in Flash */
SCB->VTOR = (uint32_t)0x00000000;
if (!success)
FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
else
FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
}
static bool program_device(void *src, void *dest, uint32_t length)
{
uint32_t dst_address = (uint32_t)dest;
/* Flash main memory first, then information memory */
if ((dst_address < INFO_FLASH_START) && ((dst_address + length) >
INFO_FLASH_START)) {
uint32_t block_length = INFO_FLASH_START - dst_address;
uint32_t src_address = (uint32_t)src;
/* Main memory block */
bool success = MAP_FLASH_CTL_A_PROGRAM_MEMORY(src, dest, block_length);
src_address = src_address + block_length;
block_length = length - block_length;
/* Information memory block */
success &= MAP_FLASH_CTL_A_PROGRAM_MEMORY((void *)src_address,
(void *)INFO_FLASH_START, block_length);
return success;
} else
return MAP_FLASH_CTL_A_PROGRAM_MEMORY(src, dest, length);
}