src/flash/nor: flash driver for RSL10
Add new flash driver for internal flash of onsemi RSL10 device. Valgrind-clean. Clang AddressSanitizer shows no errors. Signed-off-by: Toms Stūrmanis <toms.sturmanis@gmail.com> Change-Id: I8030542cb9805e94f56d7a69404cef5d88d6dd5a Reviewed-on: https://review.openocd.org/c/openocd/+/7115 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
parent
7dff68f65d
commit
ca52cfb2b3
|
@ -0,0 +1,30 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
BIN2C = ../../../../src/helper/bin2char.sh
|
||||||
|
|
||||||
|
CROSS_COMPILE ?= arm-none-eabi-
|
||||||
|
|
||||||
|
CC=$(CROSS_COMPILE)gcc
|
||||||
|
OBJCOPY=$(CROSS_COMPILE)objcopy
|
||||||
|
OBJDUMP=$(CROSS_COMPILE)objdump
|
||||||
|
|
||||||
|
CFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL
|
||||||
|
|
||||||
|
all: rom_launcher.inc
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
|
%.elf: %.S
|
||||||
|
$(CC) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.lst: %.elf
|
||||||
|
$(OBJDUMP) -S $< > $@
|
||||||
|
|
||||||
|
%.bin: %.elf
|
||||||
|
$(OBJCOPY) -Obinary $< $@
|
||||||
|
|
||||||
|
%.inc: %.bin
|
||||||
|
$(BIN2C) < $< > $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f *.elf *.lst *.bin *.inc
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2022 by Toms Stūrmanis *
|
||||||
|
* toms.sturmanis@gmail.com *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m4
|
||||||
|
.thumb
|
||||||
|
.align 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Params :
|
||||||
|
* r0-r2 = arguments
|
||||||
|
* r3 = target address in rom
|
||||||
|
*/
|
||||||
|
|
||||||
|
.thumb_func
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
launch_program_in_rom:
|
||||||
|
// variables are already set, addres to jump is in r3
|
||||||
|
blx r3
|
||||||
|
exit:
|
||||||
|
// Wait for OpenOCD
|
||||||
|
bkpt #0x00
|
|
@ -0,0 +1,2 @@
|
||||||
|
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||||
|
0x98,0x47,0x00,0xbe,
|
|
@ -7396,6 +7396,31 @@ flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME
|
||||||
@end example
|
@end example
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Flash Driver} {rsl10}
|
||||||
|
Supports Onsemi RSL10 microcontroller flash memory. Uses functions
|
||||||
|
stored in ROM to control flash memory interface.
|
||||||
|
|
||||||
|
@example
|
||||||
|
flash bank $_FLASHNAME rsl10 $_FLASHBASE $_FLASHSIZE 0 0 $_TARGETNAME
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@deffn {Command} {rsl10 lock} key1 key2 key3 key4
|
||||||
|
Writes @var{key1 key2 key3 key4} words to @var{0x81044 0x81048 0x8104c
|
||||||
|
0x8050}. Locks debug port by writing @var{0x4C6F634B} to @var{0x81040}.
|
||||||
|
|
||||||
|
To unlock use the @command{rsl10 unlock key1 key2 key3 key4} command.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {rsl10 unlock} key1 key2 key3 key4
|
||||||
|
Unlocks debug port, by writing @var{key1 key2 key3 key4} words to
|
||||||
|
registers through DAP, and clears @var{0x81040} address in flash to 0x1.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {rsl10 mass_erase}
|
||||||
|
Erases all unprotected flash sectors.
|
||||||
|
@end deffn
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} {sim3x}
|
@deffn {Flash Driver} {sim3x}
|
||||||
All members of the SiM3 microcontroller family from Silicon Laboratories
|
All members of the SiM3 microcontroller family from Silicon Laboratories
|
||||||
include internal flash and use ARM Cortex-M3 cores. It supports both JTAG
|
include internal flash and use ARM Cortex-M3 cores. It supports both JTAG
|
||||||
|
|
|
@ -56,6 +56,7 @@ NOR_DRIVERS = \
|
||||||
%D%/psoc6.c \
|
%D%/psoc6.c \
|
||||||
%D%/renesas_rpchf.c \
|
%D%/renesas_rpchf.c \
|
||||||
%D%/rp2040.c \
|
%D%/rp2040.c \
|
||||||
|
%D%/rsl10.c \
|
||||||
%D%/sfdp.c \
|
%D%/sfdp.c \
|
||||||
%D%/sh_qspi.c \
|
%D%/sh_qspi.c \
|
||||||
%D%/sim3x.c \
|
%D%/sim3x.c \
|
||||||
|
|
|
@ -78,6 +78,7 @@ extern const struct flash_driver w600_flash;
|
||||||
extern const struct flash_driver xcf_flash;
|
extern const struct flash_driver xcf_flash;
|
||||||
extern const struct flash_driver xmc1xxx_flash;
|
extern const struct flash_driver xmc1xxx_flash;
|
||||||
extern const struct flash_driver xmc4xxx_flash;
|
extern const struct flash_driver xmc4xxx_flash;
|
||||||
|
extern const struct flash_driver rsl10_flash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of built-in flash drivers.
|
* The list of built-in flash drivers.
|
||||||
|
@ -153,6 +154,7 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||||
&xmc1xxx_flash,
|
&xmc1xxx_flash,
|
||||||
&xmc4xxx_flash,
|
&xmc4xxx_flash,
|
||||||
&w600_flash,
|
&w600_flash,
|
||||||
|
&rsl10_flash,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,841 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2022 by Toms Stūrmanis *
|
||||||
|
* toms.sturmanis@gmail.com *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <helper/binarybuffer.h>
|
||||||
|
#include <helper/bits.h>
|
||||||
|
|
||||||
|
#include <target/algorithm.h>
|
||||||
|
#include <target/arm_adi_v5.h>
|
||||||
|
#include <target/armv7m.h>
|
||||||
|
#include <target/cortex_m.h>
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
|
||||||
|
#define RSL10_FLASH_ADDRESS_MAIN 0x00100000
|
||||||
|
#define RSL10_FLASH_ADDRESS_NVR1 0x00080000
|
||||||
|
#define RSL10_FLASH_ADDRESS_NVR2 0x00080800
|
||||||
|
#define RSL10_FLASH_ADDRESS_NVR3 0x00081000
|
||||||
|
#define RSL10_FLASH_ADDRESS_NVR4 0x00081800
|
||||||
|
#define RSL10_FLASH_ADDRESS_LOCK_INFO_SETTING 0x00081040
|
||||||
|
|
||||||
|
#define RSL10_REG_ID 0x1FFFFFFC
|
||||||
|
|
||||||
|
#define RSL10_FLASH_REG_MAIN_WRITE_UNLOCK 0x40000504
|
||||||
|
#define RSL10_FLASH_REG_MAIN_CTRL 0x40000508
|
||||||
|
#define RSL10_FLASH_REG_IF_STATUS 0x40000538
|
||||||
|
#define RSL10_FLASH_REG_NVR_WRITE_UNLOCK 0x40000548
|
||||||
|
#define RSL10_FLASH_REG_NVR_CTRL 0x4000054C
|
||||||
|
|
||||||
|
#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY1 0x400000F0
|
||||||
|
#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY2 0x400000F4
|
||||||
|
#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY3 0x400000F8
|
||||||
|
#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY4 0x400000FC
|
||||||
|
|
||||||
|
#define RSL10_NVR3_USER_KEY_OFFSET 0x40
|
||||||
|
|
||||||
|
#define RSL10_ID 0x09010106
|
||||||
|
#define RSL10_FLASH_KEY_MAIN 0xDBC8264E
|
||||||
|
#define RSL10_FLASH_KEY_NVR 0x71B371F5
|
||||||
|
#define RSL10_KEY_DEBUG_LOCK 0x4C6F634B
|
||||||
|
|
||||||
|
#define RSL10_FLASH_REG_MAIN_CTRL_LOW_W_ENABLE BIT(0)
|
||||||
|
#define RSL10_FLASH_REG_MAIN_CTRL_MIDDLE_W_ENABLE BIT(1)
|
||||||
|
#define RSL10_FLASH_REG_MAIN_CTRL_HIGH_W_ENABLE BIT(2)
|
||||||
|
|
||||||
|
#define RSL10_FLASH_REG_NVR_CTRL_NVR1_W_ENABLE BIT(1)
|
||||||
|
#define RSL10_FLASH_REG_NVR_CTRL_NVR2_W_ENABLE BIT(2)
|
||||||
|
#define RSL10_FLASH_REG_NVR_CTRL_NVR3_W_ENABLE BIT(3)
|
||||||
|
|
||||||
|
#define RSL10_FLASH_REG_STATUS_LOW_W_UNLOCKED BIT(0)
|
||||||
|
#define RSL10_FLASH_REG_STATUS_MIDDLE_W_UNLOCKED BIT(1)
|
||||||
|
#define RSL10_FLASH_REG_STATUS_HIGH_W_UNLOCKED BIT(2)
|
||||||
|
#define RSL10_FLASH_REG_STATUS_NVR1_W_UNLOCKED BIT(4)
|
||||||
|
#define RSL10_FLASH_REG_STATUS_NVR2_W_UNLOCKED BIT(5)
|
||||||
|
#define RSL10_FLASH_REG_STATUS_NVR3_W_UNLOCKED BIT(6)
|
||||||
|
|
||||||
|
#define RSL10_ROM_CMD_WRITE_WORD_PAIR 0x3C
|
||||||
|
#define RSL10_ROM_CMD_WRITE_BUFFER 0x40
|
||||||
|
#define RSL10_ROM_CMD_ERASE_SECTOR 0x44
|
||||||
|
#define RSL10_ROM_CMD_ERASE_ALL 0x48
|
||||||
|
|
||||||
|
#define FLASH_SECTOR_SIZE 0x2000
|
||||||
|
|
||||||
|
#define RSL10_ROM_CMD_WRITE_BUFFER_MAX_SIZE FLASH_SECTOR_SIZE
|
||||||
|
|
||||||
|
#define ALGO_STACK_POINTER_ADDR 0x20002000
|
||||||
|
|
||||||
|
/* Used to launch flash related functions from ROM
|
||||||
|
* Params :
|
||||||
|
* r0-r2 = arguments
|
||||||
|
* r3 = target address in rom
|
||||||
|
*/
|
||||||
|
static const uint8_t rsl10_rom_launcher_code[] = {
|
||||||
|
#include "../../../contrib/loaders/flash/rsl10/rom_launcher.inc"
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rsl10_flash_status {
|
||||||
|
RSL10_FLASH_ERR_NONE = 0x0,
|
||||||
|
RSL10_FLASH_ERR_GENERAL_FAILURE = 0x1,
|
||||||
|
RSL10_FLASH_ERR_WRITE_NOT_ENABLED = 0x2,
|
||||||
|
RSL10_FLASH_ERR_BAD_ADDRESS = 0x3,
|
||||||
|
RSL10_FLASH_ERR_ERASE_FAILED = 0x4,
|
||||||
|
RSL10_FLASH_ERR_BAD_LENGTH = 0x5,
|
||||||
|
RSL10_FLASH_ERR_INACCESSIBLE = 0x6,
|
||||||
|
RSL10_FLASH_ERR_COPIER_BUSY = 0x7,
|
||||||
|
RSL10_FLASH_ERR_PROG_FAILED = 0x8,
|
||||||
|
RSL10_FLASH_MAX_ERR_CODES /* must be the last one */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rsl10_error_list[] = {
|
||||||
|
[RSL10_FLASH_ERR_GENERAL_FAILURE] = "general failure",
|
||||||
|
[RSL10_FLASH_ERR_WRITE_NOT_ENABLED] = "write not enabled, protected",
|
||||||
|
[RSL10_FLASH_ERR_BAD_ADDRESS] = "bad address",
|
||||||
|
[RSL10_FLASH_ERR_ERASE_FAILED] = "erase failed",
|
||||||
|
[RSL10_FLASH_ERR_BAD_LENGTH] = "bad length",
|
||||||
|
[RSL10_FLASH_ERR_INACCESSIBLE] = "inaccessible: not powered up, or isolated",
|
||||||
|
[RSL10_FLASH_ERR_COPIER_BUSY] = "copier busy",
|
||||||
|
[RSL10_FLASH_ERR_PROG_FAILED] = "prog failed",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *rsl10_error(enum rsl10_flash_status x)
|
||||||
|
{
|
||||||
|
if (x >= RSL10_FLASH_MAX_ERR_CODES || !rsl10_error_list[x])
|
||||||
|
return "unknown";
|
||||||
|
return rsl10_error_list[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct flash_driver rsl10_flash;
|
||||||
|
|
||||||
|
struct rsl10_info {
|
||||||
|
unsigned int refcount;
|
||||||
|
|
||||||
|
struct rsl10_bank {
|
||||||
|
struct rsl10_info *chip;
|
||||||
|
bool probed;
|
||||||
|
} bank[5];
|
||||||
|
struct target *target;
|
||||||
|
|
||||||
|
unsigned int flash_size_kb;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool rsl10_bank_is_probed(const struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct rsl10_bank *nbank = bank->driver_priv;
|
||||||
|
assert(nbank);
|
||||||
|
return nbank->probed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_probe(struct flash_bank *bank);
|
||||||
|
|
||||||
|
static int rsl10_get_probed_chip_if_halted(struct flash_bank *bank, struct rsl10_info **chip)
|
||||||
|
{
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rsl10_bank *nbank = bank->driver_priv;
|
||||||
|
*chip = nbank->chip;
|
||||||
|
|
||||||
|
if (rsl10_bank_is_probed(bank))
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
return rsl10_probe(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_protect_check(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct rsl10_bank *nbank = bank->driver_priv;
|
||||||
|
struct rsl10_info *chip = nbank->chip;
|
||||||
|
|
||||||
|
assert(chip);
|
||||||
|
|
||||||
|
uint32_t status;
|
||||||
|
|
||||||
|
int retval = target_read_u32(bank->target, RSL10_FLASH_REG_IF_STATUS, &status);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (bank->base == RSL10_FLASH_ADDRESS_MAIN) {
|
||||||
|
for (unsigned int i = 0; i < bank->num_prot_blocks; i++)
|
||||||
|
bank->prot_blocks[i].is_protected = (status & (1 << i)) ? 0 : 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
uint32_t test_bit = 0;
|
||||||
|
switch (bank->base) {
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR1:
|
||||||
|
test_bit = RSL10_FLASH_REG_STATUS_NVR1_W_UNLOCKED;
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR2:
|
||||||
|
test_bit = RSL10_FLASH_REG_STATUS_NVR2_W_UNLOCKED;
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR3:
|
||||||
|
test_bit = RSL10_FLASH_REG_STATUS_NVR3_W_UNLOCKED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->sectors[0].is_protected = (status & test_bit) ? 0 : 1;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct rsl10_info *chip;
|
||||||
|
int retval = rsl10_get_probed_chip_if_halted(bank, &chip);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (bank->base == RSL10_FLASH_ADDRESS_MAIN) {
|
||||||
|
uint32_t status;
|
||||||
|
retval = target_read_u32(bank->target, RSL10_FLASH_REG_MAIN_CTRL, &status);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
for (unsigned int i = first; i <= last; i++) {
|
||||||
|
if (set)
|
||||||
|
status &= ~(1 << i);
|
||||||
|
else
|
||||||
|
status |= (1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = target_write_u32(bank->target, RSL10_FLASH_REG_MAIN_CTRL, status);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u32(bank->target, RSL10_FLASH_REG_MAIN_WRITE_UNLOCK, RSL10_FLASH_KEY_MAIN);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
} else {
|
||||||
|
uint32_t bit = 0;
|
||||||
|
switch (bank->base) {
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR1:
|
||||||
|
bit = RSL10_FLASH_REG_NVR_CTRL_NVR1_W_ENABLE;
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR2:
|
||||||
|
bit = RSL10_FLASH_REG_NVR_CTRL_NVR2_W_ENABLE;
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR3:
|
||||||
|
bit = RSL10_FLASH_REG_NVR_CTRL_NVR3_W_ENABLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t status;
|
||||||
|
retval = target_read_u32(bank->target, RSL10_FLASH_REG_NVR_CTRL, &status);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (set)
|
||||||
|
status &= ~bit;
|
||||||
|
else
|
||||||
|
status |= bit;
|
||||||
|
|
||||||
|
retval = target_write_u32(bank->target, RSL10_FLASH_REG_NVR_CTRL, status);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u32(bank->target, RSL10_FLASH_REG_NVR_WRITE_UNLOCK, RSL10_FLASH_KEY_NVR);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_check_device(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
uint32_t configid;
|
||||||
|
int retval = target_read_u32(bank->target, RSL10_REG_ID, &configid);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (configid != RSL10_ID) {
|
||||||
|
LOG_ERROR("This is not supported (RSL10) device, use other flash driver!!!");
|
||||||
|
return ERROR_TARGET_INVALID;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct rsl10_bank *nbank = bank->driver_priv;
|
||||||
|
struct rsl10_info *chip = nbank->chip;
|
||||||
|
|
||||||
|
int retval = rsl10_check_device(bank);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
unsigned int bank_id;
|
||||||
|
unsigned int num_prot_blocks = 0;
|
||||||
|
switch (bank->base) {
|
||||||
|
case RSL10_FLASH_ADDRESS_MAIN:
|
||||||
|
bank_id = 0;
|
||||||
|
num_prot_blocks = 3;
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR1:
|
||||||
|
bank_id = 1;
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR2:
|
||||||
|
bank_id = 2;
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR3:
|
||||||
|
bank_id = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flash_page_size = 2048;
|
||||||
|
|
||||||
|
bank->write_start_alignment = 8;
|
||||||
|
bank->write_end_alignment = 8;
|
||||||
|
|
||||||
|
bank->num_sectors = bank->size / flash_page_size;
|
||||||
|
chip->flash_size_kb = bank->size / 1024;
|
||||||
|
|
||||||
|
free(bank->sectors);
|
||||||
|
bank->sectors = NULL;
|
||||||
|
|
||||||
|
bank->sectors = alloc_block_array(0, flash_page_size, bank->num_sectors);
|
||||||
|
if (!bank->sectors)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
free(bank->prot_blocks);
|
||||||
|
bank->prot_blocks = NULL;
|
||||||
|
|
||||||
|
if (num_prot_blocks > 0) {
|
||||||
|
bank->num_prot_blocks = num_prot_blocks;
|
||||||
|
bank->prot_blocks = alloc_block_array(0, bank->num_sectors / 3 * flash_page_size, bank->num_prot_blocks);
|
||||||
|
if (!bank->prot_blocks)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->bank[bank_id].probed = true;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_auto_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
if (rsl10_bank_is_probed(bank))
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
return rsl10_probe(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_ll_flash_erase(struct rsl10_info *chip, uint32_t address)
|
||||||
|
{
|
||||||
|
struct target *target = chip->target;
|
||||||
|
struct working_area *write_algorithm;
|
||||||
|
|
||||||
|
LOG_DEBUG("erasing buffer flash address=0x%" PRIx32, address);
|
||||||
|
|
||||||
|
int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval =
|
||||||
|
target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_algorithm;
|
||||||
|
|
||||||
|
struct reg_param reg_params[3];
|
||||||
|
struct armv7m_algorithm armv7m_info;
|
||||||
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||||
|
|
||||||
|
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* address */
|
||||||
|
init_reg_param(®_params[1], "r3", 32, PARAM_OUT); /* cmd */
|
||||||
|
init_reg_param(®_params[2], "sp", 32, PARAM_OUT); /* stack pointer */
|
||||||
|
|
||||||
|
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||||
|
uint32_t cmd;
|
||||||
|
retval = target_read_u32(target, RSL10_ROM_CMD_ERASE_SECTOR, &cmd);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_reg_params;
|
||||||
|
buf_set_u32(reg_params[1].value, 0, 32, cmd);
|
||||||
|
buf_set_u32(reg_params[2].value, 0, 32, ALGO_STACK_POINTER_ADDR);
|
||||||
|
|
||||||
|
retval = target_run_algorithm(
|
||||||
|
target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address,
|
||||||
|
write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info
|
||||||
|
);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_reg_params;
|
||||||
|
|
||||||
|
int algo_ret = buf_get_u32(reg_params[0].value, 0, 32);
|
||||||
|
if (algo_ret != RSL10_FLASH_ERR_NONE) {
|
||||||
|
LOG_ERROR("RSL10 ERASE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret);
|
||||||
|
retval = ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_reg_params:
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++)
|
||||||
|
destroy_reg_param(®_params[i]);
|
||||||
|
|
||||||
|
free_algorithm:
|
||||||
|
target_free_working_area(target, write_algorithm);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_ll_flash_write(struct rsl10_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes)
|
||||||
|
{
|
||||||
|
struct target *target = chip->target;
|
||||||
|
struct working_area *write_algorithm;
|
||||||
|
|
||||||
|
if (bytes == 8) {
|
||||||
|
uint32_t data;
|
||||||
|
data = buf_get_u32(buffer, 0, 32);
|
||||||
|
LOG_DEBUG("Writing 0x%" PRIx32 " to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, data, address, bytes);
|
||||||
|
} else
|
||||||
|
LOG_DEBUG("Writing buffer to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, address, bytes);
|
||||||
|
|
||||||
|
/* allocate working area with flash programming code */
|
||||||
|
int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval =
|
||||||
|
target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_algorithm;
|
||||||
|
|
||||||
|
/* memory buffer, rounded down, to be multiple of 8 */
|
||||||
|
uint32_t buffer_avail = target_get_working_area_avail(target) & ~7;
|
||||||
|
uint32_t buffer_size = MIN(RSL10_ROM_CMD_WRITE_BUFFER_MAX_SIZE, buffer_avail);
|
||||||
|
struct working_area *source;
|
||||||
|
retval = target_alloc_working_area(target, buffer_size, &source);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size);
|
||||||
|
goto free_algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reg_param reg_params[5];
|
||||||
|
struct armv7m_algorithm armv7m_info;
|
||||||
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||||
|
|
||||||
|
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* start addr, return value */
|
||||||
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* length */
|
||||||
|
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* data */
|
||||||
|
init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* cmd */
|
||||||
|
init_reg_param(®_params[4], "sp", 32, PARAM_OUT); /* stack pointer */
|
||||||
|
buf_set_u32(reg_params[4].value, 0, 32, ALGO_STACK_POINTER_ADDR);
|
||||||
|
|
||||||
|
uint32_t cmd = 0;
|
||||||
|
uint32_t sent_bytes = 0;
|
||||||
|
uint32_t write_address = 0;
|
||||||
|
uint32_t bytes_to_send = 0;
|
||||||
|
uint32_t remaining_bytes = 0;
|
||||||
|
|
||||||
|
retval = target_read_u32(target, RSL10_ROM_CMD_WRITE_BUFFER, &cmd);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_everything;
|
||||||
|
|
||||||
|
while (sent_bytes < bytes) {
|
||||||
|
remaining_bytes = bytes - sent_bytes;
|
||||||
|
bytes_to_send = remaining_bytes >= buffer_size ? buffer_size : remaining_bytes;
|
||||||
|
|
||||||
|
retval = target_write_buffer(target, source->address, bytes_to_send, buffer + sent_bytes);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_everything;
|
||||||
|
|
||||||
|
write_address = address + sent_bytes;
|
||||||
|
|
||||||
|
LOG_DEBUG(
|
||||||
|
"write_address: 0x%" PRIx32 ", words: 0x%" PRIx32 ", source: 0x%" PRIx64 ", cmd: 0x%" PRIx32, write_address,
|
||||||
|
bytes_to_send / 4, source->address, cmd
|
||||||
|
);
|
||||||
|
buf_set_u32(reg_params[0].value, 0, 32, write_address);
|
||||||
|
buf_set_u32(reg_params[1].value, 0, 32, bytes_to_send / 4);
|
||||||
|
buf_set_u32(reg_params[2].value, 0, 32, source->address);
|
||||||
|
buf_set_u32(reg_params[3].value, 0, 32, cmd);
|
||||||
|
|
||||||
|
retval = target_run_algorithm(
|
||||||
|
target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address,
|
||||||
|
write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info
|
||||||
|
);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_everything;
|
||||||
|
|
||||||
|
int algo_ret = buf_get_u32(reg_params[0].value, 0, 32);
|
||||||
|
if (algo_ret != RSL10_FLASH_ERR_NONE) {
|
||||||
|
LOG_ERROR("RSL10 WRITE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret);
|
||||||
|
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
goto free_everything;
|
||||||
|
}
|
||||||
|
|
||||||
|
sent_bytes += bytes_to_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_everything:
|
||||||
|
target_free_working_area(target, source);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++)
|
||||||
|
destroy_reg_param(®_params[i]);
|
||||||
|
|
||||||
|
free_algorithm:
|
||||||
|
target_free_working_area(target, write_algorithm);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_mass_erase(struct target *target)
|
||||||
|
{
|
||||||
|
struct working_area *write_algorithm;
|
||||||
|
|
||||||
|
int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval =
|
||||||
|
target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_algorithm;
|
||||||
|
|
||||||
|
struct reg_param reg_params[3];
|
||||||
|
struct armv7m_algorithm armv7m_info;
|
||||||
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||||
|
|
||||||
|
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* return value */
|
||||||
|
init_reg_param(®_params[1], "r3", 32, PARAM_OUT); /* cmd */
|
||||||
|
init_reg_param(®_params[2], "sp", 32, PARAM_OUT); /* stack pointer */
|
||||||
|
|
||||||
|
uint32_t cmd;
|
||||||
|
retval = target_read_u32(target, RSL10_ROM_CMD_ERASE_ALL, &cmd);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_reg_params;
|
||||||
|
buf_set_u32(reg_params[1].value, 0, 32, cmd);
|
||||||
|
buf_set_u32(reg_params[2].value, 0, 32, ALGO_STACK_POINTER_ADDR);
|
||||||
|
|
||||||
|
retval = target_run_algorithm(
|
||||||
|
target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address,
|
||||||
|
write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info
|
||||||
|
);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto free_reg_params;
|
||||||
|
|
||||||
|
int algo_ret = buf_get_u32(reg_params[0].value, 0, 32);
|
||||||
|
if (algo_ret != RSL10_FLASH_ERR_NONE) {
|
||||||
|
LOG_ERROR("RSL10 MASS ERASE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret);
|
||||||
|
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_reg_params:
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++)
|
||||||
|
destroy_reg_param(®_params[i]);
|
||||||
|
|
||||||
|
free_algorithm:
|
||||||
|
target_free_working_area(target, write_algorithm);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
struct rsl10_info *chip;
|
||||||
|
|
||||||
|
int retval = rsl10_get_probed_chip_if_halted(bank, &chip);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return rsl10_ll_flash_write(chip, bank->base + offset, buffer, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsl10_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
|
||||||
|
{
|
||||||
|
LOG_INFO("erase bank: %x, %x", first, last);
|
||||||
|
int retval;
|
||||||
|
struct rsl10_info *chip;
|
||||||
|
|
||||||
|
retval = rsl10_get_probed_chip_if_halted(bank, &chip);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
for (unsigned int i = first; i <= last; i++) {
|
||||||
|
retval = rsl10_ll_flash_erase(chip, bank->base + i * 0x800);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rsl10_free_driver_priv(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct rsl10_bank *nbank = bank->driver_priv;
|
||||||
|
struct rsl10_info *chip = nbank->chip;
|
||||||
|
if (!chip)
|
||||||
|
return;
|
||||||
|
|
||||||
|
chip->refcount--;
|
||||||
|
if (chip->refcount == 0) {
|
||||||
|
free(chip);
|
||||||
|
bank->driver_priv = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rsl10_info *rsl10_get_chip(struct target *target)
|
||||||
|
{
|
||||||
|
struct flash_bank *bank_iter;
|
||||||
|
|
||||||
|
/* iterate over rsl10 banks of same target */
|
||||||
|
for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) {
|
||||||
|
if (bank_iter->driver != &rsl10_flash)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bank_iter->target != target)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct rsl10_bank *nbank = bank_iter->driver_priv;
|
||||||
|
if (!nbank)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nbank->chip)
|
||||||
|
return nbank->chip;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH_BANK_COMMAND_HANDLER(rsl10_flash_bank_command)
|
||||||
|
{
|
||||||
|
struct rsl10_info *chip = NULL;
|
||||||
|
struct rsl10_bank *nbank = NULL;
|
||||||
|
LOG_INFO("Creating flash @ " TARGET_ADDR_FMT, bank->base);
|
||||||
|
|
||||||
|
switch (bank->base) {
|
||||||
|
case RSL10_FLASH_ADDRESS_MAIN:
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR1:
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR2:
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR3:
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR4:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip = rsl10_get_chip(bank->target);
|
||||||
|
if (!chip) {
|
||||||
|
chip = calloc(1, sizeof(*chip));
|
||||||
|
if (!chip)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
chip->target = bank->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bank->base) {
|
||||||
|
case RSL10_FLASH_ADDRESS_MAIN:
|
||||||
|
nbank = &chip->bank[0];
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR1:
|
||||||
|
nbank = &chip->bank[1];
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR2:
|
||||||
|
nbank = &chip->bank[2];
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR3:
|
||||||
|
nbank = &chip->bank[3];
|
||||||
|
break;
|
||||||
|
case RSL10_FLASH_ADDRESS_NVR4:
|
||||||
|
nbank = &chip->bank[4];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(nbank);
|
||||||
|
|
||||||
|
chip->refcount++;
|
||||||
|
nbank->chip = chip;
|
||||||
|
nbank->probed = false;
|
||||||
|
bank->driver_priv = nbank;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(rsl10_lock_command)
|
||||||
|
{
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
|
||||||
|
if (CMD_ARGC != 4)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
struct flash_bank *bank;
|
||||||
|
int retval = get_flash_bank_by_addr(target, RSL10_FLASH_ADDRESS_NVR3, true, &bank);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
LOG_INFO("Keys used: %s %s %s %s", CMD_ARGV[0], CMD_ARGV[1], CMD_ARGV[2], CMD_ARGV[3]);
|
||||||
|
|
||||||
|
uint32_t user_key[4];
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], user_key[0]);
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], user_key[1]);
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], user_key[2]);
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], user_key[3]);
|
||||||
|
|
||||||
|
uint8_t write_buffer[6 * 4];
|
||||||
|
target_buffer_set_u32(target, write_buffer, RSL10_KEY_DEBUG_LOCK);
|
||||||
|
target_buffer_set_u32_array(target, &write_buffer[4], 4, user_key);
|
||||||
|
/* pad the end to 64-bit word boundary */
|
||||||
|
memset(&write_buffer[5 * 4], bank->default_padded_value, 4);
|
||||||
|
|
||||||
|
retval = rsl10_erase(bank, 0, 0);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = rsl10_write(bank, write_buffer, RSL10_NVR3_USER_KEY_OFFSET, sizeof(write_buffer));
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
/* erase sector, if write fails, otherwise it can lock debug with wrong keys */
|
||||||
|
return rsl10_erase(bank, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(
|
||||||
|
CMD, "****** WARNING ******\n"
|
||||||
|
"rsl10 device has been successfully prepared to lock.\n"
|
||||||
|
"Debug port is locked after restart.\n"
|
||||||
|
"Unlock with 'rsl10_unlock key0 key1 key2 key3'\n"
|
||||||
|
"****** ....... ******\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
return rsl10_protect(bank, true, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(rsl10_unlock_command)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC != 4)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||||
|
|
||||||
|
struct adiv5_dap *dap = cortex_m->armv7m.arm.dap;
|
||||||
|
struct adiv5_ap *ap = dap_get_ap(dap, 0);
|
||||||
|
|
||||||
|
uint32_t user_key[4];
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], user_key[0]);
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], user_key[1]);
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], user_key[2]);
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], user_key[3]);
|
||||||
|
|
||||||
|
uint8_t write_buffer1[4 * 4];
|
||||||
|
target_buffer_set_u32_array(target, write_buffer1, 4, user_key);
|
||||||
|
int retval = mem_ap_write_buf(ap, write_buffer1, 4, 4, RSL10_FLASH_REG_DEBUG_UNLOCK_KEY1);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
dap_put_ap(ap);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
dap_put_ap(ap);
|
||||||
|
|
||||||
|
uint32_t key;
|
||||||
|
retval = mem_ap_read_atomic_u32(ap, RSL10_FLASH_ADDRESS_LOCK_INFO_SETTING, &key);
|
||||||
|
LOG_INFO("mem read: 0x%08" PRIx32, key);
|
||||||
|
|
||||||
|
if (key == RSL10_KEY_DEBUG_LOCK) {
|
||||||
|
retval = command_run_line(CMD_CTX, "reset init");
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
struct flash_bank *bank;
|
||||||
|
retval = get_flash_bank_by_addr(target, RSL10_FLASH_ADDRESS_NVR3, true, &bank);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = rsl10_protect(bank, false, 0, 0);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
uint8_t write_buffer2[4 * 2];
|
||||||
|
target_buffer_set_u32(target, write_buffer2, 0x1);
|
||||||
|
/* pad the end to 64-bit word boundary */
|
||||||
|
memset(&write_buffer2[4], bank->default_padded_value, 4);
|
||||||
|
|
||||||
|
/* let it fail, because sector is not erased, maybe just erase all? */
|
||||||
|
(void)rsl10_write(bank, write_buffer2, RSL10_NVR3_USER_KEY_OFFSET, sizeof(write_buffer2));
|
||||||
|
command_print(CMD, "Debug port is unlocked!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(rsl10_mass_erase_command)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
|
||||||
|
int retval = rsl10_mass_erase(target);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
command_print(CMD, "Mass erase was succesfull!");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct command_registration rsl10_exec_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "lock",
|
||||||
|
.handler = rsl10_lock_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "Lock rsl10 debug, with passed keys",
|
||||||
|
.usage = "key1 key2 key3 key4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "unlock",
|
||||||
|
.handler = rsl10_unlock_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "Unlock rsl10 debug, with passed keys",
|
||||||
|
.usage = "key1 key2 key3 key4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "mass_erase",
|
||||||
|
.handler = rsl10_mass_erase_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "Mass erase all unprotected flash areas",
|
||||||
|
.usage = "",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE};
|
||||||
|
|
||||||
|
static const struct command_registration rsl10_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "rsl10",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "rsl10 flash command group",
|
||||||
|
.usage = "",
|
||||||
|
.chain = rsl10_exec_command_handlers,
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE};
|
||||||
|
|
||||||
|
const struct flash_driver rsl10_flash = {
|
||||||
|
.name = "rsl10",
|
||||||
|
.commands = rsl10_command_handlers,
|
||||||
|
.flash_bank_command = rsl10_flash_bank_command,
|
||||||
|
.erase = rsl10_erase,
|
||||||
|
.protect = rsl10_protect,
|
||||||
|
.write = rsl10_write,
|
||||||
|
.read = default_flash_read,
|
||||||
|
.probe = rsl10_probe,
|
||||||
|
.auto_probe = rsl10_auto_probe,
|
||||||
|
.erase_check = default_flash_blank_check,
|
||||||
|
.protect_check = rsl10_protect_check,
|
||||||
|
.free_driver_priv = rsl10_free_driver_priv,
|
||||||
|
};
|
|
@ -0,0 +1,70 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#
|
||||||
|
# RSL10: ARM Cortex-M3
|
||||||
|
#
|
||||||
|
|
||||||
|
source [find target/swj-dp.tcl]
|
||||||
|
|
||||||
|
if { [info exists CHIPNAME] } {
|
||||||
|
set _CHIPNAME $CHIPNAME
|
||||||
|
} else {
|
||||||
|
set _CHIPNAME rsl10
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [info exists WORKAREASIZE] } {
|
||||||
|
set _WORKAREASIZE $WORKAREASIZE
|
||||||
|
} else {
|
||||||
|
set _WORKAREASIZE 0x8000
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [info exists CPUTAPID] } {
|
||||||
|
set _CPUTAPID $CPUTAPID
|
||||||
|
} else {
|
||||||
|
set _CPUTAPID 0x2ba01477
|
||||||
|
}
|
||||||
|
|
||||||
|
swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
|
||||||
|
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||||
|
|
||||||
|
set _TARGETNAME $_CHIPNAME.cpu
|
||||||
|
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
|
||||||
|
|
||||||
|
$_TARGETNAME configure -work-area-phys 0x200000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||||
|
|
||||||
|
# TODO: configure reset
|
||||||
|
# reset_config srst_only srst_nogate connect_assert_srst
|
||||||
|
|
||||||
|
$_TARGETNAME configure -event examine-fail rsl10_lock_warning
|
||||||
|
|
||||||
|
proc rsl10_check_connection {} {
|
||||||
|
set target [target current]
|
||||||
|
set dap [$target cget -dap]
|
||||||
|
|
||||||
|
set IDR [$dap apreg 0 0xfc]
|
||||||
|
if {$IDR != 0x24770011} {
|
||||||
|
echo "Error: Cannot access RSL10 AP, maybe connection problem!"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
proc rsl10_lock_warning {} {
|
||||||
|
if {[rsl10_check_connection]} {return}
|
||||||
|
|
||||||
|
poll off
|
||||||
|
echo "****** WARNING ******"
|
||||||
|
echo "RSL10 device probably has lock engaged."
|
||||||
|
echo "Debug access is denied."
|
||||||
|
echo "Use 'rsl10 unlock key1 key2 key3 key4' to erase and unlock the device."
|
||||||
|
echo "****** ....... ******"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
flash bank $_CHIPNAME.main rsl10 0x00100000 0x60000 0 0 $_TARGETNAME
|
||||||
|
flash bank $_CHIPNAME.nvr1 rsl10 0x00080000 0x800 0 0 $_TARGETNAME
|
||||||
|
flash bank $_CHIPNAME.nvr2 rsl10 0x00080800 0x800 0 0 $_TARGETNAME
|
||||||
|
flash bank $_CHIPNAME.nvr3 rsl10 0x00081000 0x800 0 0 $_TARGETNAME
|
||||||
|
|
||||||
|
# TODO: implement flashing for nvr4
|
||||||
|
# flash bank $_CHIPNAME.nvr4 rsl10 0x00081800 0x400 0 0 $_TARGETNAME
|
Loading…
Reference in New Issue