This is an automated email from Gerrit. "Name of user not set <toms.sturma...@gmail.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7115
-- gerrit commit d71c7de353d82ad80aeeef13f1fd58890f5036de Author: Toms Stūrmanis <toms.sturma...@gmail.com> Date: Thu Aug 11 20:22:09 2022 +0300 src/flash/nor: flash driver for RSL10 Add new flash driver for internal flash of onsemi RSL10 device. Signed-off-by: Toms Stūrmanis <toms.sturma...@gmail.com> Change-Id: I8030542cb9805e94f56d7a69404cef5d88d6dd5a diff --git a/contrib/loaders/flash/rsl10/Makefile b/contrib/loaders/flash/rsl10/Makefile new file mode 100644 index 0000000000..2580b7e1df --- /dev/null +++ b/contrib/loaders/flash/rsl10/Makefile @@ -0,0 +1,28 @@ +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 erase_sector.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 diff --git a/contrib/loaders/flash/rsl10/rom_launcher.S b/contrib/loaders/flash/rsl10/rom_launcher.S new file mode 100644 index 0000000000..2e8dfe230f --- /dev/null +++ b/contrib/loaders/flash/rsl10/rom_launcher.S @@ -0,0 +1,22 @@ + + .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 diff --git a/contrib/loaders/flash/rsl10/rom_launcher.inc b/contrib/loaders/flash/rsl10/rom_launcher.inc new file mode 100644 index 0000000000..795c8e0d92 --- /dev/null +++ b/contrib/loaders/flash/rsl10/rom_launcher.inc @@ -0,0 +1,2 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x98,0x47,0x00,0xbe, diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index e3afc0ddf1..b80ce18166 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -77,7 +77,8 @@ NOR_DRIVERS = \ %D%/w600.c \ %D%/xcf.c \ %D%/xmc1xxx.c \ - %D%/xmc4xxx.c + %D%/xmc4xxx.c \ + %D%/rsl10.c NORHEADERS = \ %D%/core.h \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index e3fd36ad71..ee54ef2d67 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -78,6 +78,7 @@ extern const struct flash_driver w600_flash; extern const struct flash_driver xcf_flash; extern const struct flash_driver xmc1xxx_flash; extern const struct flash_driver xmc4xxx_flash; +extern const struct flash_driver rsl10_flash; /** * The list of built-in flash drivers. @@ -153,6 +154,7 @@ static const struct flash_driver * const flash_drivers[] = { &xmc1xxx_flash, &xmc4xxx_flash, &w600_flash, + &rsl10_flash, NULL, }; diff --git a/src/flash/nor/rsl10.c b/src/flash/nor/rsl10.c new file mode 100644 index 0000000000..644e2334d9 --- /dev/null +++ b/src/flash/nor/rsl10.c @@ -0,0 +1,577 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Toms Stūrmanis * + * toms.sturma...@gmail.com * + ***************************************************************************/ + +#include <stdint.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/binarybuffer.h> +#include <target/algorithm.h> +#include <target/armv7m.h> + +#include "imp.h" +#include "rsl10.h" + +const struct flash_driver rsl10_flash; + +struct rsl10_info { + uint32_t refcount; + + struct rsl10_bank { + struct rsl10_info *chip; + bool probed; + } bank[5]; + struct target *target; + + unsigned int flash_size_kb; + unsigned int ram_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 = -1; + uint32_t test_bit = -1; + int res = -1; + uint32_t parts = bank->num_sectors / 3; + + READ_U32(RSL10_FLASH_IF_STATUS, status); + LOG_DEBUG("parts: %d, status: %" PRIx32, parts, status); + + if (bank->base == RSL10_FLASH_MAIN_ADDRESS) { + for (unsigned int i = 0; i < bank->num_sectors; i++) { + if (i < parts) + bank->sectors[i].is_protected = + (status & RSL10_MAIN_LOW_W_UNLOCKED) ? false : true; + else if (parts <= i && i < 2 * parts) + bank->sectors[i].is_protected = + (status & RSL10_MAIN_MIDDLE_W_UNLOCKED) ? false : true; + else + bank->sectors[i].is_protected = + (status & RSL10_MAIN_HIGH_W_UNLOCKED) ? false : true; + } + } else { + switch (bank->base) { + case RSL10_FLASH_NVR1_ADDRESS: + test_bit = RSL10_NVR1_W_UNLOCKED; + break; + case RSL10_FLASH_NVR2_ADDRESS: + test_bit = RSL10_NVR2_W_UNLOCKED; + break; + case RSL10_FLASH_NVR3_ADDRESS: + test_bit = RSL10_NVR3_W_UNLOCKED; + break; + default: + break; + } + + bank->sectors[0].is_protected = (status & test_bit) ? false : true; + } + return ERROR_OK; +} + +static int rsl10_protect( + struct flash_bank *bank, int set, unsigned int first, unsigned int last +) +{ + int res; + struct rsl10_info *chip; + OK(rsl10_get_probed_chip_if_halted(bank, &chip)); + + if (bank->base == RSL10_FLASH_MAIN_ADDRESS) { + uint32_t bits = 0; + uint32_t parts = bank->num_sectors / 3; + if (first <= parts) + bits |= RSL10_MAIN_LOW_W_ENABLE; + if (last >= 2 * parts) + bits |= RSL10_MAIN_HIGH_W_ENABLE; + if (parts <= last && first <= 2 * parts) + bits |= RSL10_MAIN_MIDDLE_W_ENABLE; + + uint32_t status = 0; + READ_U32(RSL10_FLASH_MAIN_CTRL, status); + uint32_t value = 0; + if (set) + value = status & ~bits; + else + value = status | bits; + + WRITE_U32(RSL10_FLASH_MAIN_CTRL, value); + WRITE_U32(RSL10_FLASH_MAIN_WRITE_UNLOCK, RSL10_FLASH_MAIN_KEY); + } else { + uint32_t bit = 0; + switch (bank->base) { + case RSL10_FLASH_NVR1_ADDRESS: + bit = RSL10_NVR1_W_ENABLE; + break; + case RSL10_FLASH_NVR2_ADDRESS: + bit = RSL10_NVR2_W_ENABLE; + break; + case RSL10_FLASH_NVR3_ADDRESS: + bit = RSL10_NVR3_W_ENABLE; + break; + default: + break; + } + + uint32_t status = 0; + READ_U32(RSL10_FLASH_NVR_CTRL, status); + uint32_t value = 0; + if (set) + value = status & ~bit; + else + value = status | bit; + WRITE_U32(RSL10_FLASH_NVR_CTRL, value); + WRITE_U32(RSL10_FLASH_NVR_WRITE_UNLOCK, RSL10_FLASH_NVR_KEY); + } + + return ERROR_OK; +} + +static int rsl10_check_device(struct flash_bank *bank) +{ + uint32_t configid; + int res; + READ_U32(RSL10_ID, configid); + if (configid != 0x9010106) { + 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; + + rsl10_check_device(bank); + free(bank->sectors); + + uint32_t bank_id = 0; + switch (bank->base) { + case RSL10_FLASH_MAIN_ADDRESS: + bank_id = 0; + break; + case RSL10_FLASH_NVR1_ADDRESS: + bank_id = 1; + break; + case RSL10_FLASH_NVR2_ADDRESS: + bank_id = 2; + break; + case RSL10_FLASH_NVR3_ADDRESS: + bank_id = 3; + break; + default: + return ERROR_FAIL; + } + + uint32_t flash_page_size = 2048; + + bank->num_sectors = bank->size / flash_page_size; + chip->ram_size_kb = bank->size / 1024; + chip->flash_size_kb = bank->size / 1024; + bank->sectors = alloc_block_array(0, flash_page_size, bank->num_sectors); + if (!bank->sectors) + 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; + int res = ERROR_OK; + + static const uint8_t rsl10_flash_erase_code[] = { +#include "../../../contrib/loaders/flash/rsl10/rom_launcher.inc" + }; + + LOG_DEBUG("erasing buffer flash address=0x%" PRIx32, address); + + if (target_alloc_working_area( + target, sizeof(rsl10_flash_erase_code), &write_algorithm + ) != ERROR_OK) { + LOG_WARNING("no working area available, no fallback, just exit!!!"); + return ERROR_FAIL; + } + + res = target_write_buffer( + target, write_algorithm->address, sizeof(rsl10_flash_erase_code), + rsl10_flash_erase_code + ); + if (res != ERROR_OK) + goto clear_algorithm; + + struct reg_param reg_params[2]; + 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_OUT); + init_reg_param(®_params[1], "r3", 32, PARAM_OUT); + + buf_set_u32(reg_params[0].value, 0, 32, address); + uint32_t cmd = 0; + res = target_read_u32(target, RSL10_ROM_ERASE_SECTOR, &cmd); + if (res != ERROR_OK) + goto clear_algorithm; + buf_set_u32(reg_params[1].value, 0, 32, cmd); + + res = target_run_algorithm( + target, 0, NULL, 2, reg_params, write_algorithm->address, + write_algorithm->address + sizeof(rsl10_flash_erase_code) - 2, 1000, + &armv7m_info + ); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + +clear_algorithm: + target_free_working_area(target, write_algorithm); + return res; +} + +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; + int res = ERROR_OK; + + if (bytes == 4) + LOG_INFO( + "Writing 0x%" PRIx32 " to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, + *(uint32_t *)buffer, address, bytes + ); + else + LOG_INFO( + "Writing buffer to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, + address, bytes + ); + + static const uint8_t rsl10_flash_write_code[] = { +#include "../../../contrib/loaders/flash/rsl10/rom_launcher.inc" + }; + + assert(bytes % 4 == 0); + + /* allocate working area with flash programming code */ + if (target_alloc_working_area( + target, sizeof(rsl10_flash_write_code), &write_algorithm + ) != ERROR_OK) { + LOG_WARNING("no working area available, no fallback, just exit!!!"); + + return ERROR_FAIL; + } + + res = target_write_buffer( + target, write_algorithm->address, sizeof(rsl10_flash_write_code), + rsl10_flash_write_code + ); + if (res != ERROR_OK) + return res; + + struct working_area *source; + +#define MAX_SIZE 0x1800 + /* memory buffer */ + uint32_t buffer_size = MAX_SIZE; + while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { + buffer_size /= 2; + buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ + if (buffer_size <= 256) { + LOG_WARNING("No large enough working area available, can't do " + "block memory writes"); + target_free_working_area(target, write_algorithm); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + struct reg_param reg_params[4]; + struct armv7m_algorithm armv7m_info; + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + uint32_t sent_bytes = 0; + uint32_t write_address = 0; + uint32_t bytes_to_send = 0; + uint32_t remaining_bytes = 0; + bool fix_last = false; + bool fix_address = false; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* start addr */ + 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); /* data */ + + if (address % 8 != 0) { + address -= 4; + bytes += 4; + fix_address = true; + } + + uint32_t cmd = 0; + res = target_read_u32(target, RSL10_ROM_WRITE_BUFFER, &cmd); + if (res != ERROR_OK) + goto free_everything; + + while (sent_bytes < bytes) { + remaining_bytes = bytes - sent_bytes; + bytes_to_send = remaining_bytes >= MAX_SIZE ? MAX_SIZE : remaining_bytes; + + if (bytes_to_send % 8 != 0) { + bytes_to_send += 4; + fix_last = true; + } + + if (fix_address) { + res = target_write_buffer( + target, source->address + 4, bytes_to_send - 4, buffer + ); + uint32_t fix_data = 0; + res = target_read_u32(target, address, &fix_data); + if (res != ERROR_OK) + goto free_everything; + res = + target_write_buffer(target, source->address, 4, (uint8_t *)&fix_data); + if (res != ERROR_OK) + goto free_everything; + fix_address = false; + } else { + res = target_write_buffer( + target, source->address, bytes_to_send, buffer + sent_bytes + ); + if (res != ERROR_OK) + goto free_everything; + } + + write_address = address + sent_bytes; + + if (fix_last) { + uint32_t fix_data = 0; + res = + target_read_u32(target, write_address + bytes_to_send - 4, &fix_data); + if (res != ERROR_OK) + goto free_everything; + res = target_write_buffer( + target, source->address + bytes_to_send - 4, 4, (uint8_t *)&fix_data + ); + if (res != ERROR_OK) + goto free_everything; + } + + 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); + + res = target_run_algorithm( + target, 0, NULL, 4, reg_params, write_algorithm->address, + write_algorithm->address + sizeof(rsl10_flash_write_code) - 2, 1000, + &armv7m_info + ); + + if (res != ERROR_OK) { + LOG_WARNING("failed to write algo"); + goto free_everything; + } + + sent_bytes += bytes_to_send; + LOG_DEBUG("ret: %d, sending: %x, sent: %x", res, sent_bytes, bytes_to_send); + } + +free_everything: + target_free_working_area(target, source); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + + target_free_working_area(target, write_algorithm); + + return res; +} + +static int rsl10_write( + struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, + uint32_t count +) +{ + struct rsl10_info *chip; + + int res = 0; + OK(rsl10_get_probed_chip_if_halted(bank, &chip)); + rsl10_ll_flash_write(chip, bank->base + offset, buffer, count); + return ERROR_OK; +} + +static int +rsl10_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + LOG_INFO("erase bank: %x, %x", first, last); + int res; + struct rsl10_info *chip; + + OK(rsl10_get_probed_chip_if_halted(bank, &chip)); + for (uint32_t i = first; i <= last; i++) + rsl10_ll_flash_erase(chip, bank->base + i * 0x800); + + 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_MAIN_ADDRESS: + case RSL10_FLASH_NVR1_ADDRESS: + case RSL10_FLASH_NVR2_ADDRESS: + case RSL10_FLASH_NVR3_ADDRESS: + case RSL10_FLASH_NVR4_ADDRESS: + 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_MAIN_ADDRESS: + nbank = &chip->bank[0]; + break; + case RSL10_FLASH_NVR1_ADDRESS: + nbank = &chip->bank[1]; + break; + case RSL10_FLASH_NVR2_ADDRESS: + nbank = &chip->bank[2]; + break; + case RSL10_FLASH_NVR3_ADDRESS: + nbank = &chip->bank[3]; + break; + case RSL10_FLASH_NVR4_ADDRESS: + nbank = &chip->bank[4]; + break; + } + assert(nbank); + + chip->refcount++; + nbank->chip = chip; + nbank->probed = false; + bank->driver_priv = nbank; + bank->write_start_alignment = bank->write_end_alignment = 4; + + return ERROR_OK; +} + +const struct flash_driver rsl10_flash = { + .name = "rsl10", + /* .commands = nrf5_command_handlers, */ + .flash_bank_command = rsl10_flash_bank_command, + /* .info = nrf5_info, */ + .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, +}; diff --git a/src/flash/nor/rsl10.h b/src/flash/nor/rsl10.h new file mode 100644 index 0000000000..10432623f6 --- /dev/null +++ b/src/flash/nor/rsl10.h @@ -0,0 +1,76 @@ +#ifndef RSL10_H_ +#define RSL10_H_ + +#define BIT(n) (1UL << (n)) +#define WRITE_U32(reg, value) \ + do { \ + res = target_write_u32(bank->target, reg, value); \ + if (res != ERROR_OK) \ + return res; \ + } while (0) + +#define READ_U32(reg, value) \ + do { \ + res = target_read_u32(bank->target, reg, &value); \ + if (res != ERROR_OK) \ + return res; \ + } while (0) + +#define OK(func) \ + do { \ + res = func; \ + if (res != ERROR_OK) \ + return res; \ + } while (0) + +enum rsl10_flash_addresses { + RSL10_FLASH_MAIN_ADDRESS = 0x00100000, + RSL10_FLASH_NVR1_ADDRESS = 0x00080000, + RSL10_FLASH_NVR2_ADDRESS = 0x00080800, + RSL10_FLASH_NVR3_ADDRESS = 0x00081000, + RSL10_FLASH_NVR4_ADDRESS = 0x00081800, +}; + +enum rsl10_registers { + RSL10_ID = 0x1FFFFFFC, + + RSL10_FLASH_BASE = 0x40000000, +#define RSL10_FLASH_REG(offset) (RSL10_FLASH_BASE + offset) + RSL10_FLASH_MAIN_WRITE_UNLOCK = RSL10_FLASH_REG(0x504), + RSL10_FLASH_MAIN_CTRL = RSL10_FLASH_REG(0x508), + RSL10_FLASH_IF_STATUS = RSL10_FLASH_REG(0x538), + RSL10_FLASH_NVR_WRITE_UNLOCK = RSL10_FLASH_REG(0x548), + RSL10_FLASH_NVR_CTRL = RSL10_FLASH_REG(0x54C), +}; + +enum rsl10_keys { + RSL10_FLASH_MAIN_KEY = 0xDBC8264E, + RSL10_FLASH_NVR_KEY = 0x71B371F5, +}; + +enum rsl10_write_bits { + RSL10_MAIN_LOW_W_ENABLE = BIT(0), + RSL10_MAIN_MIDDLE_W_ENABLE = BIT(1), + RSL10_MAIN_HIGH_W_ENABLE = BIT(2), + + RSL10_MAIN_HIGH_W_UNLOCKED = BIT(2), + RSL10_MAIN_MIDDLE_W_UNLOCKED = BIT(1), + RSL10_MAIN_LOW_W_UNLOCKED = BIT(0), + + RSL10_NVR1_W_ENABLE = BIT(1), + RSL10_NVR2_W_ENABLE = BIT(2), + RSL10_NVR3_W_ENABLE = BIT(3), + + RSL10_NVR1_W_UNLOCKED = BIT(4), + RSL10_NVR2_W_UNLOCKED = BIT(5), + RSL10_NVR3_W_UNLOCKED = BIT(6), +}; + +enum rsl10_rom_commands { + RSL10_ROM_WRITE_WORD_PAIR = 0x3C, + RSL10_ROM_WRITE_BUFFER = 0x40, + RSL10_ROM_ERASE_SECTOR = 0x44, + RSL10_ROM_ERASE_ALL = 0x48, +}; + +#endif /* RSL10_H_ */ diff --git a/tcl/target/rsl10.cfg b/tcl/target/rsl10.cfg new file mode 100644 index 0000000000..8426ee6f6a --- /dev/null +++ b/tcl/target/rsl10.cfg @@ -0,0 +1,111 @@ +# +# RSL10 +# + +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 + +adapter speed 1000 + +$_TARGETNAME configure -work-area-phys 0x20000000 -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_lock_warning {} { + echo "****** WARNING ******" + echo "RSL10 device probably has lock engaged." + echo "Debug access is denied." + echo "Use 'rsl10_unlock key0 key1 key2 key3' to erase and unlock the device." + echo "****** ....... ******" + echo "" + poll off +} + +proc rsl10_unlock {p0 p1 p2 p3} { + set target [target current] + set dap [$target cget -dap] + poll off + + $dap apsel 0 + $dap apcsw 0x23000000 + $dap apreg 0 0 0x23000052 + + # unlock debug + $dap apreg 0 4 0x400000F0 + $dap apreg 0 12 $p0 + $dap apreg 0 12 $p1 + $dap apreg 0 12 $p2 + $dap apreg 0 12 $p3 + + $dap apreg 0 12 + + # restore debug + reset init + flash protect 3 0 0 off + flash fillw 0x00081040 0x00000000 1 + flash protect 3 0 0 on + + echo "****** WARNING ******" + echo "$target device has been successfully erased and unlocked." + echo "****** ....... ******" + echo "" +} + +proc rsl10_lock {p0 p1 p2 p3} { + reset init + flash protect 3 0 0 off + flash erase_sector 3 0 0 + + # save keys in flash + flash fillw 0x00081044 $p0 1 + flash fillw 0x00081048 $p1 1 + flash fillw 0x0008104c $p2 1 + flash fillw 0x00081050 $p3 1 + + # lock debug port + flash fillw 0x00081040 0x4C6F634B 1 + + flash protect 3 0 0 on + + set target [target current] + echo "****** WARNING ******" + echo "$target device has been successfully prepared to lock." + echo "Debug port is locked after restart." + echo "Unlock with 'rsl10_unlock $p0 $p1 $p2 $p3'" + 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 --