flash/nor: flash driver for Synwit SWM050 MCUs 27/4927/5
authorCaleb Szalacinski <contact@skiboy.net>
Mon, 19 Aug 2019 22:45:27 +0000 (17:45 -0500)
committerTomas Vanek <vanekt@fbl.cz>
Sun, 8 Sep 2019 10:53:12 +0000 (11:53 +0100)
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>
doc/openocd.texi
src/flash/nor/Makefile.am
src/flash/nor/drivers.c
src/flash/nor/swm050.c [new file with mode: 0644]
tcl/target/swm050.cfg [new file with mode: 0644]

index 9490f88fb56ef94ca21e8daae20d3e47cec09adc..c5a926ca86b5e3a8b7d4075f3451fbfe1d58fd5e 100644 (file)
@@ -7002,6 +7002,23 @@ unlock str9 device.
 
 @end deffn
 
 
 @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.
 @deffn {Flash Driver} tms470
 Most members of the TMS470 microcontroller family from Texas Instruments
 include internal flash and use ARM7TDMI cores.
index 135128ee4f1602e7206b18563a0375080130a263..34f91ce1eab3713105a8892a6ceeb3704cdb51c1 100644 (file)
@@ -63,6 +63,7 @@ NOR_DRIVERS = \
        %D%/str7x.c \
        %D%/str9x.c \
        %D%/str9xpec.c \
        %D%/str7x.c \
        %D%/str9x.c \
        %D%/str9xpec.c \
+       %D%/swm050.c \
        %D%/tms470.c \
        %D%/virtual.c \
        %D%/w600.c \
        %D%/tms470.c \
        %D%/virtual.c \
        %D%/w600.c \
index 955d149b5fc9e93b6e8b6b5bd3a4253dff682c2b..551f389de967243fd336c143aed6e3e4dff19d97 100644 (file)
@@ -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 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;
 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,
        &str7x_flash,
        &str9x_flash,
        &str9xpec_flash,
+       &swm050_flash,
        &tms470_flash,
        &virtual_flash,
        &xcf_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 (file)
index 0000000..241207d
--- /dev/null
@@ -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,
+};
diff --git a/tcl/target/swm050.cfg b/tcl/target/swm050.cfg
new file mode 100644 (file)
index 0000000..a819f9c
--- /dev/null
@@ -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
+}

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)