Files
openocd/src/flash/nor/fm3.c
Antonio Borneo 382148e4dd openocd: fix SPDX tag format for files .c
With the old checkpatch we cannot use the correct format for the
SPDX tags in the file .c, in fact the C99 comments are not allowed
and we had to use the block comment.

With the new checkpatch, let's switch to the correct SPDX format.

Change created automatically through the command:
	sed -i \
	's,^/\* *\(SPDX-License-Identifier: .*[^ ]\) *\*/$,// \1,' \
	$(find src/ contrib/ -name \*.c)

Change-Id: I6da16506baa7af718947562505dd49606d124171
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/7153
Tested-by: jenkins
2022-09-18 08:22:01 +00:00

985 lines
34 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
* Copyright (C) 2011 by Marc Willam, Holger Wech *
* openOCD.fseu(AT)de.fujitsu.com *
* Copyright (C) 2011 Ronny Strutz *
* *
* Copyright (C) 2013 Nemui Trinomius *
* nemuisan_kawausogasuki@live.jp *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#define FLASH_DQ6 0x40 /* Data toggle flag bit (TOGG) position */
#define FLASH_DQ5 0x20 /* Time limit exceeding flag bit (TLOV) position */
enum fm3_variant {
MB9BFXX1, /* Flash Type '1' */
MB9BFXX2,
MB9BFXX3,
MB9BFXX4,
MB9BFXX5,
MB9BFXX6,
MB9BFXX7,
MB9BFXX8,
MB9AFXX1, /* Flash Type '2' */
MB9AFXX2,
MB9AFXX3,
MB9AFXX4,
MB9AFXX5,
MB9AFXX6,
MB9AFXX7,
MB9AFXX8,
};
enum fm3_flash_type {
FM3_NO_FLASH_TYPE = 0,
FM3_FLASH_TYPE1 = 1,
FM3_FLASH_TYPE2 = 2
};
struct fm3_flash_bank {
enum fm3_variant variant;
enum fm3_flash_type flashtype;
bool probed;
};
FLASH_BANK_COMMAND_HANDLER(fm3_flash_bank_command)
{
struct fm3_flash_bank *fm3_info;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
fm3_info = malloc(sizeof(struct fm3_flash_bank));
bank->driver_priv = fm3_info;
/* Flash type '1' */
if (strcmp(CMD_ARGV[5], "mb9bfxx1.cpu") == 0) {
fm3_info->variant = MB9BFXX1;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9bfxx2.cpu") == 0) {
fm3_info->variant = MB9BFXX2;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9bfxx3.cpu") == 0) {
fm3_info->variant = MB9BFXX3;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9bfxx4.cpu") == 0) {
fm3_info->variant = MB9BFXX4;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9bfxx5.cpu") == 0) {
fm3_info->variant = MB9BFXX5;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9bfxx6.cpu") == 0) {
fm3_info->variant = MB9BFXX6;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9bfxx7.cpu") == 0) {
fm3_info->variant = MB9BFXX7;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9bfxx8.cpu") == 0) {
fm3_info->variant = MB9BFXX8;
fm3_info->flashtype = FM3_FLASH_TYPE1;
} else if (strcmp(CMD_ARGV[5], "mb9afxx1.cpu") == 0) { /* Flash type '2' */
fm3_info->variant = MB9AFXX1;
fm3_info->flashtype = FM3_FLASH_TYPE2;
} else if (strcmp(CMD_ARGV[5], "mb9afxx2.cpu") == 0) {
fm3_info->variant = MB9AFXX2;
fm3_info->flashtype = FM3_FLASH_TYPE2;
} else if (strcmp(CMD_ARGV[5], "mb9afxx3.cpu") == 0) {
fm3_info->variant = MB9AFXX3;
fm3_info->flashtype = FM3_FLASH_TYPE2;
} else if (strcmp(CMD_ARGV[5], "mb9afxx4.cpu") == 0) {
fm3_info->variant = MB9AFXX4;
fm3_info->flashtype = FM3_FLASH_TYPE2;
} else if (strcmp(CMD_ARGV[5], "mb9afxx5.cpu") == 0) {
fm3_info->variant = MB9AFXX5;
fm3_info->flashtype = FM3_FLASH_TYPE2;
} else if (strcmp(CMD_ARGV[5], "mb9afxx6.cpu") == 0) {
fm3_info->variant = MB9AFXX6;
fm3_info->flashtype = FM3_FLASH_TYPE2;
} else if (strcmp(CMD_ARGV[5], "mb9afxx7.cpu") == 0) {
fm3_info->variant = MB9AFXX7;
fm3_info->flashtype = FM3_FLASH_TYPE2;
} else if (strcmp(CMD_ARGV[5], "mb9afxx8.cpu") == 0) {
fm3_info->variant = MB9AFXX8;
fm3_info->flashtype = FM3_FLASH_TYPE2;
}
/* unknown Flash type */
else {
LOG_ERROR("unknown fm3 variant: %s", CMD_ARGV[5]);
free(fm3_info);
return ERROR_FLASH_BANK_INVALID;
}
fm3_info->probed = false;
return ERROR_OK;
}
/* Data polling algorithm */
static int fm3_busy_wait(struct target *target, uint32_t offset, int timeout_ms)
{
int retval = ERROR_OK;
uint8_t state1, state2;
int ms = 0;
/* While(1) loop exit via "break" and "return" on error */
while (1) {
/* dummy-read - see flash manual */
retval = target_read_u8(target, offset, &state1);
if (retval != ERROR_OK)
return retval;
/* Data polling 1 */
retval = target_read_u8(target, offset, &state1);
if (retval != ERROR_OK)
return retval;
/* Data polling 2 */
retval = target_read_u8(target, offset, &state2);
if (retval != ERROR_OK)
return retval;
/* Flash command finished via polled data equal? */
if ((state1 & FLASH_DQ6) == (state2 & FLASH_DQ6))
break;
/* Timeout Flag? */
else if (state1 & FLASH_DQ5) {
/* Retry data polling */
/* Data polling 1 */
retval = target_read_u8(target, offset, &state1);
if (retval != ERROR_OK)
return retval;
/* Data polling 2 */
retval = target_read_u8(target, offset, &state2);
if (retval != ERROR_OK)
return retval;
/* Flash command finished via polled data equal? */
if ((state1 & FLASH_DQ6) != (state2 & FLASH_DQ6))
return ERROR_FLASH_OPERATION_FAILED;
/* finish anyway */
break;
}
usleep(1000);
++ms;
/* Polling time exceeded? */
if (ms > timeout_ms) {
LOG_ERROR("Polling data reading timed out!");
return ERROR_FLASH_OPERATION_FAILED;
}
}
if (retval == ERROR_OK)
LOG_DEBUG("fm3_busy_wait(%" PRIx32 ") needs about %d ms", offset, ms);
return retval;
}
static int fm3_erase(struct flash_bank *bank, unsigned int first,
unsigned int last)
{
struct fm3_flash_bank *fm3_info = bank->driver_priv;
struct target *target = bank->target;
int retval = ERROR_OK;
uint32_t u32_dummy_read;
int odd;
uint32_t u32_flash_type;
uint32_t u32_flash_seq_address1;
uint32_t u32_flash_seq_address2;
struct working_area *write_algorithm;
struct reg_param reg_params[3];
struct armv7m_algorithm armv7m_info;
u32_flash_type = (uint32_t) fm3_info->flashtype;
if (u32_flash_type == FM3_FLASH_TYPE1) {
u32_flash_seq_address1 = 0x00001550;
u32_flash_seq_address2 = 0x00000AA8;
} else if (u32_flash_type == FM3_FLASH_TYPE2) {
u32_flash_seq_address1 = 0x00000AA8;
u32_flash_seq_address2 = 0x00000554;
} else {
LOG_ERROR("Flash/Device type unknown!");
return ERROR_FLASH_OPERATION_FAILED;
}
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* RAMCODE used for fm3 Flash sector erase: */
/* R0 keeps Flash Sequence address 1 (u32FlashSeq1) */
/* R1 keeps Flash Sequence address 2 (u32FlashSeq2) */
/* R2 keeps Flash Offset address (ofs) */
static const uint8_t fm3_flash_erase_sector_code[] = {
/* *(uint16_t*)u32FlashSeq1 = 0xAA; */
0xAA, 0x24, /* MOVS R4, #0xAA */
0x04, 0x80, /* STRH R4, [R0, #0] */
/* *(uint16_t*)u32FlashSeq2 = 0x55; */
0x55, 0x23, /* MOVS R3, #0x55 */
0x0B, 0x80, /* STRH R3, [R1, #0] */
/* *(uint16_t*)u32FlashSeq1 = 0x80; */
0x80, 0x25, /* MOVS R5, #0x80 */
0x05, 0x80, /* STRH R5, [R0, #0] */
/* *(uint16_t*)u32FlashSeq1 = 0xAA; */
0x04, 0x80, /* STRH R4, [R0, #0] */
/* *(uint16_t*)u32FlashSeq2 = 0x55; */
0x0B, 0x80, /* STRH R3, [R1, #0] */
/* Sector_Erase Command (0x30) */
/* *(uint16_t*)ofs = 0x30; */
0x30, 0x20, /* MOVS R0, #0x30 */
0x10, 0x80, /* STRH R0, [R2, #0] */
/* End Code */
0x00, 0xBE, /* BKPT #0 */
};
LOG_INFO("Fujitsu MB9[A/B]FXXX: Sector Erase ... (%u to %u)", first, last);
/* disable HW watchdog */
retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, 0x40011008, 0x00000000);
if (retval != ERROR_OK)
return retval;
/* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash access) */
retval = target_write_u32(target, 0x40000000, 0x0001);
if (retval != ERROR_OK)
return retval;
/* dummy read of FASZR */
retval = target_read_u32(target, 0x40000000, &u32_dummy_read);
if (retval != ERROR_OK)
return retval;
/* allocate working area with flash sector erase code */
if (target_alloc_working_area(target, sizeof(fm3_flash_erase_sector_code),
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
retval = target_write_buffer(target, write_algorithm->address,
sizeof(fm3_flash_erase_sector_code), fm3_flash_erase_sector_code);
if (retval != ERROR_OK)
return retval;
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* u32_flash_seq_address1 */
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* u32_flash_seq_address2 */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* offset */
/* write code buffer and use Flash sector erase code within fm3 */
for (unsigned int sector = first ; sector <= last ; sector++) {
uint32_t offset = bank->sectors[sector].offset;
for (odd = 0; odd < 2 ; odd++) {
if (odd)
offset += 4;
buf_set_u32(reg_params[0].value, 0, 32, u32_flash_seq_address1);
buf_set_u32(reg_params[1].value, 0, 32, u32_flash_seq_address2);
buf_set_u32(reg_params[2].value, 0, 32, offset);
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
write_algorithm->address, 0, 100000, &armv7m_info);
if (retval != ERROR_OK) {
LOG_ERROR("Error executing flash erase programming algorithm");
retval = ERROR_FLASH_OPERATION_FAILED;
return retval;
}
retval = fm3_busy_wait(target, offset, 500);
if (retval != ERROR_OK)
return retval;
}
}
target_free_working_area(target, write_algorithm);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
/* FASZR = 0x02, Enables CPU Run Mode (32-bit Flash access) */
retval = target_write_u32(target, 0x40000000, 0x0002);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */
return retval;
}
static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct fm3_flash_bank *fm3_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t buffer_size = 2048; /* Default minimum value */
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
uint32_t u32_flash_type;
uint32_t u32_flash_seq_address1;
uint32_t u32_flash_seq_address2;
/* Increase buffer_size if needed */
if (buffer_size < (target->working_area_size / 2))
buffer_size = (target->working_area_size / 2);
u32_flash_type = (uint32_t) fm3_info->flashtype;
if (u32_flash_type == FM3_FLASH_TYPE1) {
u32_flash_seq_address1 = 0x00001550;
u32_flash_seq_address2 = 0x00000AA8;
} else if (u32_flash_type == FM3_FLASH_TYPE2) {
u32_flash_seq_address1 = 0x00000AA8;
u32_flash_seq_address2 = 0x00000554;
} else {
LOG_ERROR("Flash/Device type unknown!");
return ERROR_FLASH_OPERATION_FAILED;
}
/* RAMCODE used for fm3 Flash programming: */
/* R0 keeps source start address (u32Source) */
/* R1 keeps target start address (u32Target) */
/* R2 keeps number of halfwords to write (u32Count) */
/* R3 keeps Flash Sequence address 1 (u32FlashSeq1) */
/* R4 keeps Flash Sequence address 2 (u32FlashSeq2) */
/* R5 returns result value (u32FlashResult) */
static const uint8_t fm3_flash_write_code[] = {
/* fm3_FLASH_IF->FASZ &= 0xFFFD; */
0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
0x2D, 0x68, /* LDR R5, [R5] */
0x4F, 0xF6, 0xFD, 0x76, /* MOVW R6, #0xFFFD */
0x35, 0x40, /* ANDS R5, R5, R6 */
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
0x35, 0x60, /* STR R5, [R6] */
/* fm3_FLASH_IF->FASZ |= 1; */
0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
0x2D, 0x68, /* LDR R5, [R3] */
0x55, 0xF0, 0x01, 0x05, /* ORRS.W R5, R5, #1 */
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
0x35, 0x60, /* STR R5, [R6] */
/* u32_dummy_read = fm3_FLASH_IF->FASZ; */
0x28, 0x4D, /* LDR.N R5, ??u32_dummy_read */
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
0x36, 0x68, /* LDR R6, [R6] */
0x2E, 0x60, /* STR R6, [R5] */
/* u32FlashResult = FLASH_WRITE_NO_RESULT */
0x26, 0x4D, /* LDR.N R5, ??u32FlashResult */
0x00, 0x26, /* MOVS R6, #0 */
0x2E, 0x60, /* STR R6, [R5] */
/* while ((u32Count > 0 ) */
/* && (u32FlashResult */
/* == FLASH_WRITE_NO_RESULT)) */
0x01, 0x2A, /* L0: CMP R2, #1 */
0x2C, 0xDB, /* BLT.N L1 */
0x24, 0x4D, /* LDR.N R5, ??u32FlashResult */
0x2D, 0x68, /* LDR R5, [R5] */
0x00, 0x2D, /* CMP R5, #0 */
0x28, 0xD1, /* BNE.N L1 */
/* *u32FlashSeq1 = FLASH_WRITE_1; */
0xAA, 0x25, /* MOVS R5, #0xAA */
0x1D, 0x60, /* STR R5, [R3] */
/* *u32FlashSeq2 = FLASH_WRITE_2; */
0x55, 0x25, /* MOVS R5, #0x55 */
0x25, 0x60, /* STR R5, [R4] */
/* *u32FlashSeq1 = FLASH_WRITE_3; */
0xA0, 0x25, /* MOVS R5, #0xA0 */
0x1D, 0x60, /* STRH R5, [R3] */
/* *(volatile uint16_t*)u32Target */
/* = *(volatile uint16_t*)u32Source; */
0x05, 0x88, /* LDRH R5, [R0] */
0x0D, 0x80, /* STRH R5, [R1] */
/* while (u32FlashResult */
/* == FLASH_WRITE_NO_RESTULT) */
0x1E, 0x4D, /* L2: LDR.N R5, ??u32FlashResult */
0x2D, 0x68, /* LDR R5, [R5] */
0x00, 0x2D, /* CMP R5, #0 */
0x11, 0xD1, /* BNE.N L3 */
/* if ((*(volatile uint16_t*)u32Target */
/* & FLASH_DQ5) == FLASH_DQ5) */
0x0D, 0x88, /* LDRH R5, [R1] */
0xAD, 0x06, /* LSLS R5, R5, #0x1A */
0x02, 0xD5, /* BPL.N L4 */
/* u32FlashResult = FLASH_WRITE_TIMEOUT */
0x1A, 0x4D, /* LDR.N R5, ??u32FlashResult */
0x02, 0x26, /* MOVS R6, #2 */
0x2E, 0x60, /* STR R6, [R5] */
/* if ((*(volatile uint16_t *)u32Target */
/* & FLASH_DQ7) */
/* == (*(volatile uint16_t*)u32Source */
/* & FLASH_DQ7)) */
0x0D, 0x88, /* L4: LDRH R5, [R1] */
0x15, 0xF0, 0x80, 0x05, /* ANDS.W R5, R5, #0x80 */
0x06, 0x88, /* LDRH R6, [R0] */
0x16, 0xF0, 0x80, 0x06, /* ANDS.W R6, R6, #0x80 */
0xB5, 0x42, /* CMP R5, R6 */
0xED, 0xD1, /* BNE.N L2 */
/* u32FlashResult = FLASH_WRITE_OKAY */
0x15, 0x4D, /* LDR.N R5, ??u32FlashResult */
0x01, 0x26, /* MOVS R6, #1 */
0x2E, 0x60, /* STR R6, [R5] */
0xE9, 0xE7, /* B.N L2 */
/* if (u32FlashResult */
/* != FLASH_WRITE_TIMEOUT) */
0x13, 0x4D, /* LDR.N R5, ??u32FlashResult */
0x2D, 0x68, /* LDR R5, [R5] */
0x02, 0x2D, /* CMP R5, #2 */
0x02, 0xD0, /* BEQ.N L5 */
/* u32FlashResult = FLASH_WRITE_NO_RESULT */
0x11, 0x4D, /* LDR.N R5, ??u32FlashResult */
0x00, 0x26, /* MOVS R6, #0 */
0x2E, 0x60, /* STR R6, [R5] */
/* u32Count--; */
0x52, 0x1E, /* L5: SUBS R2, R2, #1 */
/* u32Source += 2; */
0x80, 0x1C, /* ADDS R0, R0, #2 */
/* u32Target += 2; */
0x89, 0x1C, /* ADDS R1, R1, #2 */
0xD0, 0xE7, /* B.N L0 */
/* fm3_FLASH_IF->FASZ &= 0xFFFE; */
0x5F, 0xF0, 0x80, 0x45, /* L1: MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
0x2D, 0x68, /* LDR R5, [R5] */
0x4F, 0xF6, 0xFE, 0x76, /* MOVW R6, #0xFFFE */
0x35, 0x40, /* ANDS R5, R5, R6 */
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
0x35, 0x60, /* STR R5, [R6] */
/* fm3_FLASH_IF->FASZ |= 2; */
0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
0x2D, 0x68, /* LDR R5, [R5] */
0x55, 0xF0, 0x02, 0x05, /* ORRS.W R5, R5, #2 */
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
0x35, 0x60, /* STR R5, [R6] */
/* u32_dummy_read = fm3_FLASH_IF->FASZ; */
0x04, 0x4D, /* LDR.N R5, ??u32_dummy_read */
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
0x36, 0x68, /* LDR R6, [R6] */
0x2E, 0x60, /* STR R6, [R5] */
/* copy u32FlashResult to R3 for return */
/* value */
0xDF, 0xF8, 0x08, 0x50, /* LDR.W R5, ??u32FlashResult */
0x2D, 0x68, /* LDR R5, [R5] */
/* Breakpoint here */
0x00, 0xBE, /* BKPT #0 */
/* The following address pointers assume, that the code is running from */
/* SRAM basic-address + 8.These address pointers will be patched, if a */
/* different start address in RAM is used (e.g. for Flash type 2)! */
/* Default SRAM basic-address is 0x20000000. */
0x00, 0x00, 0x00, 0x20, /* u32_dummy_read address in RAM (0x20000000) */
0x04, 0x00, 0x00, 0x20 /* u32FlashResult address in RAM (0x20000004) */
};
LOG_INFO("Fujitsu MB9[A/B]FXXX: FLASH Write ...");
/* disable HW watchdog */
retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, 0x40011008, 0x00000000);
if (retval != ERROR_OK)
return retval;
count = count / 2; /* number bytes -> number halfwords */
/* check code alignment */
if (offset & 0x1) {
LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
/* allocate working area and variables with flash programming code */
if (target_alloc_working_area(target, sizeof(fm3_flash_write_code) + 8,
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
retval = target_write_buffer(target, write_algorithm->address + 8,
sizeof(fm3_flash_write_code), fm3_flash_write_code);
if (retval != ERROR_OK)
return retval;
/* Patching 'local variable address' */
/* Algorithm: u32_dummy_read: */
retval = target_write_u32(target, (write_algorithm->address + 8)
+ sizeof(fm3_flash_write_code) - 8, (write_algorithm->address));
if (retval != ERROR_OK)
return retval;
/* Algorithm: u32FlashResult: */
retval = target_write_u32(target, (write_algorithm->address + 8)
+ sizeof(fm3_flash_write_code) - 4, (write_algorithm->address) + 4);
if (retval != ERROR_OK)
return retval;
/* memory buffer */
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
buffer_size /= 2;
if (buffer_size <= 256) {
/* free working area, write algorithm already allocated */
target_free_working_area(target, write_algorithm);
LOG_WARNING("No large enough working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
}
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* source start address */
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* target start address */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */
init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */
init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */
init_reg_param(&reg_params[5], "r5", 32, PARAM_IN); /* result */
/* write code buffer and use Flash programming code within fm3 */
/* Set breakpoint to 0 with time-out of 1000 ms */
while (count > 0) {
uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer);
if (retval != ERROR_OK)
break;
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, address);
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
buf_set_u32(reg_params[3].value, 0, 32, u32_flash_seq_address1);
buf_set_u32(reg_params[4].value, 0, 32, u32_flash_seq_address2);
retval = target_run_algorithm(target, 0, NULL, 6, reg_params,
(write_algorithm->address + 8), 0, 1000, &armv7m_info);
if (retval != ERROR_OK) {
LOG_ERROR("Error executing fm3 Flash programming algorithm");
retval = ERROR_FLASH_OPERATION_FAILED;
break;
}
if (buf_get_u32(reg_params[5].value, 0, 32) != ERROR_OK) {
LOG_ERROR("Fujitsu MB9[A/B]FXXX: Flash programming ERROR (Timeout) -> Reg R3: %" PRIx32,
buf_get_u32(reg_params[5].value, 0, 32));
retval = ERROR_FLASH_OPERATION_FAILED;
break;
}
buffer += thisrun_count * 2;
address += thisrun_count * 2;
count -= thisrun_count;
}
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
destroy_reg_param(&reg_params[4]);
destroy_reg_param(&reg_params[5]);
return retval;
}
static int fm3_probe(struct flash_bank *bank)
{
struct fm3_flash_bank *fm3_info = bank->driver_priv;
uint16_t num_pages;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/*
-- page-- start -- blocksize - mpu - totalFlash --
page0 0x00000 16k
page1 0x04000 16k
page2 0x08000 96k ___ fxx3 128k Flash
page3 0x20000 128k ___ fxx4 256k Flash
page4 0x40000 128k ___ fxx5 384k Flash
page5 0x60000 128k ___ fxx6 512k Flash
-----------------------
page6 0x80000 128k
page7 0xa0000 128k ___ fxx7 256k Flash
page8 0xc0000 128k
page9 0xe0000 128k ___ fxx8 256k Flash
*/
num_pages = 10; /* max number of Flash pages for malloc */
fm3_info->probed = false;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
bank->base = 0x00000000;
bank->size = 32 * 1024; /* bytes */
bank->sectors[0].offset = 0;
bank->sectors[0].size = 16 * 1024;
bank->sectors[0].is_erased = -1;
bank->sectors[0].is_protected = -1;
bank->sectors[1].offset = 0x4000;
bank->sectors[1].size = 16 * 1024;
bank->sectors[1].is_erased = -1;
bank->sectors[1].is_protected = -1;
if ((fm3_info->variant == MB9BFXX1)
|| (fm3_info->variant == MB9AFXX1)) {
num_pages = 3;
bank->size = 64 * 1024; /* bytes */
bank->num_sectors = num_pages;
bank->sectors[2].offset = 0x8000;
bank->sectors[2].size = 32 * 1024;
bank->sectors[2].is_erased = -1;
bank->sectors[2].is_protected = -1;
}
if ((fm3_info->variant == MB9BFXX2)
|| (fm3_info->variant == MB9BFXX4)
|| (fm3_info->variant == MB9BFXX5)
|| (fm3_info->variant == MB9BFXX6)
|| (fm3_info->variant == MB9BFXX7)
|| (fm3_info->variant == MB9BFXX8)
|| (fm3_info->variant == MB9AFXX2)
|| (fm3_info->variant == MB9AFXX4)
|| (fm3_info->variant == MB9AFXX5)
|| (fm3_info->variant == MB9AFXX6)
|| (fm3_info->variant == MB9AFXX7)
|| (fm3_info->variant == MB9AFXX8)) {
num_pages = 3;
bank->size = 128 * 1024; /* bytes */
bank->num_sectors = num_pages;
bank->sectors[2].offset = 0x8000;
bank->sectors[2].size = 96 * 1024;
bank->sectors[2].is_erased = -1;
bank->sectors[2].is_protected = -1;
}
if ((fm3_info->variant == MB9BFXX4)
|| (fm3_info->variant == MB9BFXX5)
|| (fm3_info->variant == MB9BFXX6)
|| (fm3_info->variant == MB9BFXX7)
|| (fm3_info->variant == MB9BFXX8)
|| (fm3_info->variant == MB9AFXX4)
|| (fm3_info->variant == MB9AFXX5)
|| (fm3_info->variant == MB9AFXX6)
|| (fm3_info->variant == MB9AFXX7)
|| (fm3_info->variant == MB9AFXX8)) {
num_pages = 4;
bank->size = 256 * 1024; /* bytes */
bank->num_sectors = num_pages;
bank->sectors[3].offset = 0x20000;
bank->sectors[3].size = 128 * 1024;
bank->sectors[3].is_erased = -1;
bank->sectors[3].is_protected = -1;
}
if ((fm3_info->variant == MB9BFXX5)
|| (fm3_info->variant == MB9BFXX6)
|| (fm3_info->variant == MB9BFXX7)
|| (fm3_info->variant == MB9BFXX8)
|| (fm3_info->variant == MB9AFXX5)
|| (fm3_info->variant == MB9AFXX6)
|| (fm3_info->variant == MB9AFXX7)
|| (fm3_info->variant == MB9AFXX8)) {
num_pages = 5;
bank->size = 384 * 1024; /* bytes */
bank->num_sectors = num_pages;
bank->sectors[4].offset = 0x40000;
bank->sectors[4].size = 128 * 1024;
bank->sectors[4].is_erased = -1;
bank->sectors[4].is_protected = -1;
}
if ((fm3_info->variant == MB9BFXX6)
|| (fm3_info->variant == MB9BFXX7)
|| (fm3_info->variant == MB9BFXX8)
|| (fm3_info->variant == MB9AFXX6)
|| (fm3_info->variant == MB9AFXX7)
|| (fm3_info->variant == MB9AFXX8)) {
num_pages = 6;
bank->size = 512 * 1024; /* bytes */
bank->num_sectors = num_pages;
bank->sectors[5].offset = 0x60000;
bank->sectors[5].size = 128 * 1024;
bank->sectors[5].is_erased = -1;
bank->sectors[5].is_protected = -1;
}
if ((fm3_info->variant == MB9BFXX7)
|| (fm3_info->variant == MB9BFXX8)
|| (fm3_info->variant == MB9AFXX7)
|| (fm3_info->variant == MB9AFXX8)) {
num_pages = 8;
bank->size = 768 * 1024; /* bytes */
bank->num_sectors = num_pages;
bank->sectors[6].offset = 0x80000;
bank->sectors[6].size = 128 * 1024;
bank->sectors[6].is_erased = -1;
bank->sectors[6].is_protected = -1;
bank->sectors[7].offset = 0xa0000;
bank->sectors[7].size = 128 * 1024;
bank->sectors[7].is_erased = -1;
bank->sectors[7].is_protected = -1;
}
if ((fm3_info->variant == MB9BFXX8)
|| (fm3_info->variant == MB9AFXX8)) {
num_pages = 10;
bank->size = 1024 * 1024; /* bytes */
bank->num_sectors = num_pages;
bank->sectors[8].offset = 0xc0000;
bank->sectors[8].size = 128 * 1024;
bank->sectors[8].is_erased = -1;
bank->sectors[8].is_protected = -1;
bank->sectors[9].offset = 0xe0000;
bank->sectors[9].size = 128 * 1024;
bank->sectors[9].is_erased = -1;
bank->sectors[9].is_protected = -1;
}
fm3_info->probed = true;
return ERROR_OK;
}
static int fm3_auto_probe(struct flash_bank *bank)
{
struct fm3_flash_bank *fm3_info = bank->driver_priv;
if (fm3_info->probed)
return ERROR_OK;
return fm3_probe(bank);
}
/* Chip erase */
static int fm3_chip_erase(struct flash_bank *bank)
{
struct target *target = bank->target;
struct fm3_flash_bank *fm3_info2 = bank->driver_priv;
int retval = ERROR_OK;
uint32_t u32_dummy_read;
uint32_t u32_flash_type;
uint32_t u32_flash_seq_address1;
uint32_t u32_flash_seq_address2;
struct working_area *write_algorithm;
struct reg_param reg_params[3];
struct armv7m_algorithm armv7m_info;
u32_flash_type = (uint32_t) fm3_info2->flashtype;
if (u32_flash_type == FM3_FLASH_TYPE1) {
LOG_INFO("*** Erasing mb9bfxxx type");
u32_flash_seq_address1 = 0x00001550;
u32_flash_seq_address2 = 0x00000AA8;
} else if (u32_flash_type == FM3_FLASH_TYPE2) {
LOG_INFO("*** Erasing mb9afxxx type");
u32_flash_seq_address1 = 0x00000AA8;
u32_flash_seq_address2 = 0x00000554;
} else {
LOG_ERROR("Flash/Device type unknown!");
return ERROR_FLASH_OPERATION_FAILED;
}
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* RAMCODE used for fm3 Flash chip erase: */
/* R0 keeps Flash Sequence address 1 (u32FlashSeq1) */
/* R1 keeps Flash Sequence address 2 (u32FlashSeq2) */
static const uint8_t fm3_flash_erase_chip_code[] = {
/* *(uint16_t*)u32FlashSeq1 = 0xAA; */
0xAA, 0x22, /* MOVS R2, #0xAA */
0x02, 0x80, /* STRH R2, [R0, #0] */
/* *(uint16_t*)u32FlashSeq2 = 0x55; */
0x55, 0x23, /* MOVS R3, #0x55 */
0x0B, 0x80, /* STRH R3, [R1, #0] */
/* *(uint16_t*)u32FlashSeq1 = 0x80; */
0x80, 0x24, /* MOVS R4, #0x80 */
0x04, 0x80, /* STRH R4, [R0, #0] */
/* *(uint16_t*)u32FlashSeq1 = 0xAA; */
0x02, 0x80, /* STRH R2, [R0, #0] */
/* *(uint16_t*)u32FlashSeq2 = 0x55; */
0x0B, 0x80, /* STRH R3, [R1, #0] */
/* Chip_Erase Command 0x10 */
/* *(uint16_t*)u32FlashSeq1 = 0x10; */
0x10, 0x21, /* MOVS R1, #0x10 */
0x01, 0x80, /* STRH R1, [R0, #0] */
/* End Code */
0x00, 0xBE, /* BKPT #0 */
};
LOG_INFO("Fujitsu MB9[A/B]xxx: Chip Erase ... (may take several seconds)");
/* disable HW watchdog */
retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, 0x40011008, 0x00000000);
if (retval != ERROR_OK)
return retval;
/* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash access) */
retval = target_write_u32(target, 0x40000000, 0x0001);
if (retval != ERROR_OK)
return retval;
/* dummy read of FASZR */
retval = target_read_u32(target, 0x40000000, &u32_dummy_read);
if (retval != ERROR_OK)
return retval;
/* allocate working area with flash chip erase code */
if (target_alloc_working_area(target, sizeof(fm3_flash_erase_chip_code),
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
retval = target_write_buffer(target, write_algorithm->address,
sizeof(fm3_flash_erase_chip_code), fm3_flash_erase_chip_code);
if (retval != ERROR_OK)
return retval;
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* u32_flash_seq_address1 */
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* u32_flash_seq_address2 */
buf_set_u32(reg_params[0].value, 0, 32, u32_flash_seq_address1);
buf_set_u32(reg_params[1].value, 0, 32, u32_flash_seq_address2);
retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
write_algorithm->address, 0, 100000, &armv7m_info);
if (retval != ERROR_OK) {
LOG_ERROR("Error executing flash erase programming algorithm");
retval = ERROR_FLASH_OPERATION_FAILED;
return retval;
}
target_free_working_area(target, write_algorithm);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
retval = fm3_busy_wait(target, u32_flash_seq_address2, 20000); /* 20s timeout */
if (retval != ERROR_OK)
return retval;
/* FASZR = 0x02, Re-enables CPU Run Mode (32-bit Flash access) */
retval = target_write_u32(target, 0x40000000, 0x0002);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */
return retval;
}
COMMAND_HANDLER(fm3_handle_chip_erase_command)
{
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (retval != ERROR_OK)
return retval;
if (fm3_chip_erase(bank) == ERROR_OK) {
command_print(CMD, "fm3 chip erase complete");
} else {
command_print(CMD, "fm3 chip erase failed");
}
return ERROR_OK;
}
static const struct command_registration fm3_exec_command_handlers[] = {
{
.name = "chip_erase",
.usage = "<bank>",
.handler = fm3_handle_chip_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase entire Flash device.",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration fm3_command_handlers[] = {
{
.name = "fm3",
.mode = COMMAND_ANY,
.help = "fm3 Flash command group",
.usage = "",
.chain = fm3_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
const struct flash_driver fm3_flash = {
.name = "fm3",
.commands = fm3_command_handlers,
.flash_bank_command = fm3_flash_bank_command,
.erase = fm3_erase,
.write = fm3_write_block,
.probe = fm3_probe,
.auto_probe = fm3_auto_probe,
.erase_check = default_flash_blank_check,
.free_driver_priv = default_flash_free_driver_priv,
};