From: Caleb Szalacinski Date: Mon, 19 Aug 2019 22:45:27 +0000 (-0500) Subject: flash/nor: flash driver for Synwit SWM050 MCUs X-Git-Tag: v0.11.0-rc1~601 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=5a235226f0db67e85f9c71288dcd015e7081c37b 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 Signed-off-by: Caleb Szalacinski Reviewed-on: http://openocd.zylin.com/4927 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Andreas Fritiofson --- diff --git a/doc/openocd.texi b/doc/openocd.texi index 9490f88fb5..c5a926ca86 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7002,6 +7002,23 @@ unlock str9 device. @end deffn +@deffn {Flash Driver} swm050 +@cindex swm050 +All members of the swm050 microcontroller family from Foshan Synwit Tech. + +@example +flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME +@end example + +One swm050-specific command is defined: + +@deffn Command {swm050 mass_erase} bank_id +Erases the entire flash bank. +@end deffn + +@end deffn + + @deffn {Flash Driver} tms470 Most members of the TMS470 microcontroller family from Texas Instruments include internal flash and use ARM7TDMI cores. diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 135128ee4f..34f91ce1ea 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 955d149b5f..551f389de9 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 0000000000..241207d879 --- /dev/null +++ b/src/flash/nor/swm050.c @@ -0,0 +1,211 @@ +/*************************************************************************** + * Copyright (C) 2019 Icenowy Zheng * + * Copyright (C) 2019 Caleb Szalacinski * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include + +#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, +}; diff --git a/tcl/target/swm050.cfg b/tcl/target/swm050.cfg new file mode 100644 index 0000000000..a819f9c426 --- /dev/null +++ b/tcl/target/swm050.cfg @@ -0,0 +1,45 @@ +# Synwit SWM050 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME swm050 +} +set _CHIPSERIES swm050 + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x400 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x410CC200 +} + +swd 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 0x20000000 -work-area-size $_WORKAREASIZE +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME + + +$_TARGETNAME configure -event reset-init { + # Stop the watchdog, just to be safe + mww 0x40019000 0x00 + # Set clock divider value to 1 + mww 0x400F0000 0x01 + # Set system clock to 18Mhz + mww 0x400F0008 0x00 +} + +# SWM050 (Cortex-M0 core) supports SYSRESETREQ +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +}