diff options
author | Caleb Szalacinski <contact@skiboy.net> | 2019-08-19 17:45:27 -0500 |
---|---|---|
committer | Tomas Vanek <vanekt@fbl.cz> | 2019-09-08 11:53:12 +0100 |
commit | 5a235226f0db67e85f9c71288dcd015e7081c37b (patch) | |
tree | e000ed89562eb5892e9dad3d21e1ede23142c548 /src | |
parent | 642a9310ca1942e97a6612c2f8cf132d933845de (diff) | |
download | riscv-openocd-5a235226f0db67e85f9c71288dcd015e7081c37b.zip riscv-openocd-5a235226f0db67e85f9c71288dcd015e7081c37b.tar.gz riscv-openocd-5a235226f0db67e85f9c71288dcd015e7081c37b.tar.bz2 |
flash/nor: flash driver for Synwit SWM050 MCUs
SWM050 is a series of MCU product by Foshan Synwit Tech, which is
available in TSSOP-8 or SSOP-16 packages.
Adds flash driver for the internal 8KiB flash of the MCU. The registers
are based on reverse engineering the J-Flash blob provided by the
vendor.
Also adds a pre-made cfg file.
Change-Id: I0b29f0c0d062883542ee743e0750a4c6b6609ebd
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Signed-off-by: Caleb Szalacinski <contact@skiboy.net>
Reviewed-on: http://openocd.zylin.com/4927
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/flash/nor/Makefile.am | 1 | ||||
-rw-r--r-- | src/flash/nor/drivers.c | 2 | ||||
-rw-r--r-- | src/flash/nor/swm050.c | 211 |
3 files changed, 214 insertions, 0 deletions
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 135128e..34f91ce 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -63,6 +63,7 @@ NOR_DRIVERS = \ %D%/str7x.c \ %D%/str9x.c \ %D%/str9xpec.c \ + %D%/swm050.c \ %D%/tms470.c \ %D%/virtual.c \ %D%/w600.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 955d149..551f389 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -77,6 +77,7 @@ extern const struct flash_driver stmsmi_flash; extern const struct flash_driver str7x_flash; extern const struct flash_driver str9x_flash; extern const struct flash_driver str9xpec_flash; +extern const struct flash_driver swm050_flash; extern const struct flash_driver tms470_flash; extern const struct flash_driver virtual_flash; extern const struct flash_driver w600_flash; @@ -146,6 +147,7 @@ static const struct flash_driver * const flash_drivers[] = { &str7x_flash, &str9x_flash, &str9xpec_flash, + &swm050_flash, &tms470_flash, &virtual_flash, &xcf_flash, diff --git a/src/flash/nor/swm050.c b/src/flash/nor/swm050.c new file mode 100644 index 0000000..241207d --- /dev/null +++ b/src/flash/nor/swm050.c @@ -0,0 +1,211 @@ +/*************************************************************************** + * Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io> * + * Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <target/image.h> + +#define SWM050_DELAY 100 + +#define SWM050_FLASH_PAGE_SIZE 0x200 +#define SWM050_FLASH_PAGES 16 + +#define SWM050_CPU_ID 0xE000ED00 +#define SWM050_CPU_ID_VAL 0x410CC200 + +#define SWM050_FLASH_REG1 0x1F000000 +#define SWM050_FLASH_REG2 0x1F000038 +#define SWM050_FLASH_KEY 0xAAAAAAAA + +#define SWM050_SYSCTL_CFG_0 0x400F0000 +#define SWM050_SYSCTL_DBLF 0x400F0008 + +static int swm050_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + int retval, curr_page; + uint32_t curr_addr; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Perform erase */ + retval = target_write_u32(target, SWM050_FLASH_REG1, 0x4); + if (retval != ERROR_OK) + return retval; + + for (curr_page = first; curr_page <= last; curr_page++) { + curr_addr = bank->base + (SWM050_FLASH_PAGE_SIZE * curr_page); + /* Perform write */ + retval = target_write_u32(target, curr_addr, SWM050_FLASH_KEY); + if (retval != ERROR_OK) + return retval; + alive_sleep(SWM050_DELAY); + } + + /* Close flash interface */ + retval = target_write_u32(target, SWM050_FLASH_REG1, 0x0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int swm050_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + int retval; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + retval = ERROR_TARGET_NOT_HALTED; + return retval; + } + + /* Perform write */ + retval = target_write_u32(target, SWM050_FLASH_REG1, 0x1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_memory(target, bank->base + offset, 4, count/4, buffer); + if (retval != ERROR_OK) + return retval; + + /* Close flash interface */ + retval = target_write_u32(target, SWM050_FLASH_REG1, 0x0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int swm050_probe(struct flash_bank *bank) +{ + return ERROR_OK; +} + +static int swm050_mass_erase(struct flash_bank *bank) +{ + struct target *target = bank->target; + int retval; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Perform mass erase */ + retval = target_write_u32(target, SWM050_FLASH_REG1, 0x6); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, SWM050_FLASH_REG2, 0x1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, 0x0, SWM050_FLASH_KEY); + if (retval != ERROR_OK) + return retval; + + alive_sleep(SWM050_DELAY); + + /* Close flash interface */ + retval = target_write_u32(target, SWM050_FLASH_REG1, 0x0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +COMMAND_HANDLER(swm050_handle_mass_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 (ERROR_OK != retval) + return retval; + + retval = swm050_mass_erase(bank); + if (retval == ERROR_OK) + command_print(CMD, "swm050 mass erase complete"); + else + command_print(CMD, "swm050 mass erase failed"); + + return retval; +} + +FLASH_BANK_COMMAND_HANDLER(swm050_flash_bank_command) +{ + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + bank->write_start_alignment = 4; + bank->write_end_alignment = 4; + bank->size = SWM050_FLASH_PAGE_SIZE * SWM050_FLASH_PAGES; + + bank->num_sectors = SWM050_FLASH_PAGES; + bank->sectors = alloc_block_array(0, SWM050_FLASH_PAGE_SIZE, SWM050_FLASH_PAGES); + if (!bank->sectors) + return ERROR_FAIL; + + for (int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = 0; + + return ERROR_OK; +} + +static const struct command_registration swm050_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = swm050_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Erase entire flash device.", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration swm050_command_handlers[] = { + { + .name = "swm050", + .mode = COMMAND_ANY, + .help = "swm050 flash command group", + .usage = "", + .chain = swm050_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver swm050_flash = { + .name = "swm050", + .commands = swm050_command_handlers, + .flash_bank_command = swm050_flash_bank_command, + .erase = swm050_erase, + .write = swm050_write, + .read = default_flash_read, + .probe = swm050_probe, + .auto_probe = swm050_probe, + .erase_check = default_flash_blank_check, + .free_driver_priv = default_flash_free_driver_priv, +}; |