This is an automated email from Gerrit.

"Nishanth Menon <n...@ti.com>" just uploaded a new patch set to Gerrit, which 
you can find at https://review.openocd.org/c/openocd/+/8384

-- gerrit

commit b776584c182c9e5ced86186ec57ac7e7de0d5711
Author: Nishanth Menon <n...@ti.com>
Date:   Thu Sep 28 03:37:03 2023 -0500

    flash/nor: Add basic support for TI's MSPM0L/G family
    
    Add basic flashing support for Texas Instruments MSPM0L, C and G family of
    Cortex-M0 based micro-controllers.
    
    This initial basic flashing support allows for controlling protection,
    erase, write and read of non-main flash region.
    
    This has been tested with:
    * valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes 
--verbose
    * Ubuntu clang version 19.0.0 
(++20240627042246+c791d86eab13-1~exp1~20240627042407.1770)
    
    Valgrind-clean, no new Clang analyzer warnings have been introduced.
    
    Change-Id: I29b8055ea6da9c38c5b7b91bea1ec7581c5bc8ff
    Co-developed-by: Henry Nguyen <h-nguy...@ti.com>
    Signed-off-by: Henry Nguyen <h-nguy...@ti.com>
    Signed-off-by: Nishanth Menon <n...@ti.com>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index e46e6004bc..a394092159 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -7238,6 +7238,19 @@ msp432 bsl lock
 @end deffn
 @end deffn
 
+@deffn {Flash Driver} {mspm0}
+All Arm Cortex-M0+ MSPM microcontroller versions from Texas
+Instruments include internal flash. The mspm0 flash driver
+automatically recognizes the specific version's flash parameters and
+autoconfigures itself. The main program flash starts at address 0x0.
+Non-main flash starts at 0x41c00000. If present on the device, the
+optional region called "Data" starts at 0x41d00000.
+
+@example
+flash bank $_FLASHNAME mspm0 0 0 0 0 $_TARGETNAME
+@end example
+@end deffn
+
 @deffn {Flash Driver} {niietcm4}
 This drivers handles the integrated NOR flash on NIIET Cortex-M4
 based controllers. Flash size and sector layout are auto-configured by the 
driver.
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index afa11e7d40..a1c6da332b 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -44,6 +44,7 @@ NOR_DRIVERS = \
        %D%/max32xxx.c \
        %D%/mdr.c \
        %D%/msp432.c \
+       %D%/mspm0.c \
        %D%/mrvlqspi.c \
        %D%/niietcm4.c \
        %D%/non_cfi.c \
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 211661e214..ac945530d5 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -273,6 +273,7 @@ extern const struct flash_driver max32xxx_flash;
 extern const struct flash_driver mdr_flash;
 extern const struct flash_driver mrvlqspi_flash;
 extern const struct flash_driver msp432_flash;
+extern const struct flash_driver mspm0_flash;
 extern const struct flash_driver niietcm4_flash;
 extern const struct flash_driver npcx_flash;
 extern const struct flash_driver nrf51_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 34359889a6..2e8a83cf19 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -50,6 +50,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &mdr_flash,
        &mrvlqspi_flash,
        &msp432_flash,
+       &mspm0_flash,
        &niietcm4_flash,
        &npcx_flash,
        &nrf5_flash,
diff --git a/src/flash/nor/mspm0.c b/src/flash/nor/mspm0.c
new file mode 100644
index 0000000000..9774cc94de
--- /dev/null
+++ b/src/flash/nor/mspm0.c
@@ -0,0 +1,1083 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * NOR flash driver for MSPM0L and MSPM0G class of uC from Texas Instruments.
+ *
+ * See:
+ * 
https://www.ti.com/microcontrollers-mcus-processors/arm-based-microcontrollers/arm-cortex-m0-mcus/overview.html
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/bits.h>
+#include <helper/time_support.h>
+
+/* MPM0 Region memory map */
+#define MSPM0_FLASH_BASE_NONMAIN               (0x41c00000)
+#define MSPM0_FLASH_END_NONMAIN                        (0x41c00400)
+#define MSPM0_FLASH_BASE_MAIN                  (0x0)
+#define MSPM0_FLASH_BASE_DATA                  (0x41d00000)
+
+/* MPM0 FACTORYREGION registers */
+#define MSPM0_FACTORYREGION                            (0x41c40000)
+#define MSPM0_TRACEID                                  (MSPM0_FACTORYREGION + 
0x000)
+#define MSPM0_DID                                              
(MSPM0_FACTORYREGION + 0x004)
+#define MSPM0_USERID                                   (MSPM0_FACTORYREGION + 
0x008)
+#define MSPM0_SRAMFLASH                                        
(MSPM0_FACTORYREGION + 0x018)
+
+/* MPM0 FCTL registers */
+#define FLASH_CONTROL_BASE                             (0x400cd000)
+#define FCTL_REG_CMDEXEC                               (FLASH_CONTROL_BASE + 
0x1100)
+#define FCTL_REG_CMDTYPE                               (FLASH_CONTROL_BASE + 
0x1104)
+#define FCTL_REG_CMDADDR                               (FLASH_CONTROL_BASE + 
0x1120)
+#define FCTL_REG_CMDBYTEN                              (FLASH_CONTROL_BASE + 
0x1124)
+#define FCTL_REG_CMDDATA0                              (FLASH_CONTROL_BASE + 
0x1130)
+#define FCTL_REG_CMDWEPROTA                            (FLASH_CONTROL_BASE + 
0x11D0)
+#define FCTL_REG_CMDWEPROTB                            (FLASH_CONTROL_BASE + 
0x11D4)
+#define FCTL_REG_CMDWEPROTNM                   (FLASH_CONTROL_BASE + 0x1210)
+#define FCTL_REG_STATCMD                               (FLASH_CONTROL_BASE + 
0x13D0)
+
+/* FCTL_STATCMD[CMDDONE] Bits */
+#define FCTL_STATCMD_CMDDONE_MASK              (0x00000001U)
+#define FCTL_STATCMD_CMDDONE_STATDONE  (0x00000001U)
+
+/* FCTL_STATCMD[CMDPASS] Bits */
+#define FCTL_STATCMD_CMDPASS_MASK              (0x00000002U)
+#define FCTL_STATCMD_CMDPASS_STATPASS  (0x00000002U)
+
+/* FCTL_CMDEXEC Bits */
+/* FCTL_CMDEXEC[VAL] Bits */
+#define FCTL_CMDEXEC_VAL_EXECUTE               (0x00000001U)
+
+/* FCTL_CMDTYPE[COMMAND] Bits */
+#define FCTL_CMDTYPE_COMMAND_PROGRAM   (0x00000001U)
+#define FCTL_CMDTYPE_COMMAND_ERASE             (0x00000002U)
+
+/* FCTL_CMDTYPE[SIZE] Bits */
+#define FCTL_CMDTYPE_SIZE_ONEWORD              (0x00000000U)
+#define FCTL_CMDTYPE_SIZE_SECTOR               (0x00000040U)
+
+#define MSPM0_MAX_PROTREGS                             (3)
+
+#define MSPM0_FLASH_TIMEOUT_MS                 (8000)
+#define ERR_STRING_MAX                                 (255)
+
+/* SYSCTL BASE*/
+#define SYSCTL_BASE                                            (0x400AF000U)
+#define SYSCTL_SECCFG_SECSTATUS                        (SYSCTL_BASE + 
0x00003048U)
+
+struct mspm0_flash_bank {
+       /* chip id register */
+       uint32_t did;
+       /* Device Unique ID register */
+       uint32_t traceid;
+       uint8_t version;
+
+       /* Pointer to name */
+       const char *name;
+
+       /* Decoded flash information */
+       uint32_t data_flash_size_kb;
+       uint32_t main_flash_size_kb;
+       uint32_t main_flash_num_banks;
+       uint32_t sector_size;
+       /* Decoded SRAM information */
+       uint32_t sram_size_kb;
+
+       /* Flash word size: 64 bit = 8, 128bit = 16 bytes */
+       uint8_t flash_word_size_bytes;
+
+       /* Protection register stuff */
+       uint32_t protect_reg_base;
+       uint32_t protect_reg_count;
+};
+
+struct mspm0_part_info {
+       const char *part_name;
+       uint16_t part;
+       uint8_t variant;
+};
+
+struct mspm0_family_info {
+       const char *family_name;
+       uint16_t part_num;
+       uint8_t part_count;
+       const struct mspm0_part_info *part_info;
+};
+
+/* https://www.ti.com/lit/ds/symlink/mspm0l1346.pdf Table 8-13 and so on */
+static const struct mspm0_part_info mspm0l_parts[] = {
+       { "MSPM0L1105TDGS20R", 0x51DB, 0x16 },
+       { "MSPM0L1105TDGS28R", 0x51DB, 0x83 },
+       { "MSPM0L1105TDYYR", 0x51DB, 0x54 },
+       { "MSPM0L1105TRGER", 0x51DB, 0x86 },
+       { "MSPM0L1105TRHBR", 0x51DB, 0x68 },
+       { "MSPM0L1106TDGS20R", 0x5552, 0x4B },
+       { "MSPM0L1106TDGS28R", 0x5552, 0x98 },
+       { "MSPM0L1106TDYYR", 0x5552, 0x9D },
+       { "MSPM0L1106TRGER", 0x5552, 0x90 },
+       { "MSPM0L1106TRHBR", 0x5552, 0x53 },
+       { "MSPM0L1303SRGER", 0xef0, 0x17 },
+       { "MSPM0L1303TRGER", 0xef0, 0xe2 },
+       { "MSPM0L1304QDGS20R", 0xd717, 0x91 },
+       { "MSPM0L1304QDGS28R", 0xd717, 0xb6 },
+       { "MSPM0L1304QDYYR", 0xd717, 0xa0 },
+       { "MSPM0L1304QRHBR", 0xd717, 0xa9 },
+       { "MSPM0L1304SDGS20R", 0xd717, 0xfa },
+       { "MSPM0L1304SDGS28R", 0xd717, 0x73 },
+       { "MSPM0L1304SDYYR", 0xd717, 0xb7 },
+       { "MSPM0L1304SRGER", 0xd717, 0x26 },
+       { "MSPM0L1304SRHBR", 0xd717, 0xe4 },
+       { "MSPM0L1304TDGS20R", 0xd717, 0x33 },
+       { "MSPM0L1304TDGS28R", 0xd717, 0xa8 },
+       { "MSPM0L1304TDYYR", 0xd717, 0xf9 },
+       { "MSPM0L1304TRGER", 0xd717, 0xb7 },
+       { "MSPM0L1304TRHBR", 0xd717, 0x5a },
+       { "MSPM0L1305QDGS20R", 0x4d03, 0xb7 },
+       { "MSPM0L1305QDGS28R", 0x4d03, 0x74 },
+       { "MSPM0L1305QDYYR", 0x4d03, 0xec },
+       { "MSPM0L1305QRHBR", 0x4d03, 0x78 },
+       { "MSPM0L1305SDGS20R", 0x4d03, 0xc7 },
+       { "MSPM0L1305SDGS28R", 0x4d03, 0x64 },
+       { "MSPM0L1305SDYYR", 0x4d03, 0x91 },
+       { "MSPM0L1305SRGER", 0x4d03, 0x73 },
+       { "MSPM0L1305SRHBR", 0x4d03, 0x2d },
+       { "MSPM0L1305TDGS20R", 0x4d03, 0xa0 },
+       { "MSPM0L1305TDGS28R", 0x4d03, 0xfb },
+       { "MSPM0L1305TDYYR", 0x4d03, 0xde },
+       { "MSPM0L1305TRGER", 0x4d03, 0xea },
+       { "MSPM0L1305TRHBR", 0x4d03, 0x85 },
+       { "MSPM0L1306QDGS20R", 0xbb70, 0x59 },
+       { "MSPM0L1306QDGS28R", 0xbb70, 0xf7 },
+       { "MSPM0L1306QDYYR", 0xbb70, 0x9f },
+       { "MSPM0L1306QRHBR", 0xbb70, 0xc2 },
+       { "MSPM0L1306SDGS20R", 0xbb70, 0xf4 },
+       { "MSPM0L1306SDGS28R", 0xbb70, 0x5 },
+       { "MSPM0L1306SDYYR", 0xbb70, 0xe },
+       { "MSPM0L1306SRGER", 0xbb70, 0x7f },
+       { "MSPM0L1306SRHBR", 0xbb70, 0x3c },
+       { "MSPM0L1306TDGS20R", 0xbb70, 0xa },
+       { "MSPM0L1306TDGS28R", 0xbb70, 0x63 },
+       { "MSPM0L1306TDYYR", 0xbb70, 0x35 },
+       { "MSPM0L1306TRGER", 0xbb70, 0xaa },
+       { "MSPM0L1306TRHBR", 0xbb70, 0x52 },
+       { "MSPM0L1343TDGS20R", 0xb231, 0x2e },
+       { "MSPM0L1344TDGS20R", 0x40b0, 0xd0 },
+       { "MSPM0L1345TDGS28R", 0x98b4, 0x74 },
+       { "MSPM0L1346TDGS28R", 0xf2b5, 0xef },
+};
+
+/* https://www.ti.com/lit/ds/symlink/mspm0g3506.pdf Table 8-20 */
+static const struct mspm0_part_info mspm0g_parts[] = {
+       { "MSPM0G1105TPTR", 0x8934, 0xD },
+       { "MSPM0G1105TRGZR", 0x8934, 0xFE },
+       { "MSPM0G1106TPMR", 0x477B, 0xD4 },
+       { "MSPM0G1106TPTR", 0x477B, 0x71 },
+       { "MSPM0G1106TRGZR", 0x477B, 0xBB },
+       { "MSPM0G1106TRHBR", 0x477B, 0x0 },
+       { "MSPM0G1107TDGS28R", 0x807B, 0x82 },
+       { "MSPM0G1107TPMR", 0x807B, 0xB3 },
+       { "MSPM0G1107TPTR", 0x807B, 0x32 },
+       { "MSPM0G1107TRGER", 0x807B, 0x79 },
+       { "MSPM0G1107TRGZR", 0x807B, 0x20 },
+       { "MSPM0G1107TRHBR", 0x807B, 0xBC },
+       { "MSPM0G1505SDGS28R", 0x13C4, 0x73 },
+       { "MSPM0G1505SPMR", 0x13C4, 0x53 },
+       { "MSPM0G1505SPTR", 0x13C4, 0x3E },
+       { "MSPM0G1505SRGER", 0x13C4, 0x47 },
+       { "MSPM0G1505SRGZR", 0x13C4, 0x34 },
+       { "MSPM0G1505SRHBR", 0x13C4, 0x30 },
+       { "MSPM0G1506SDGS28R", 0x5AE0, 0x3A },
+       { "MSPM0G1506SPMR", 0x5AE0, 0xF6 },
+       { "MSPM0G1506SRGER", 0x5AE0, 0x67 },
+       { "MSPM0G1506SRGZR", 0x5AE0, 0x75 },
+       { "MSPM0G1506SRHBR", 0x5AE0, 0x57 },
+       { "MSPM0G1507SDGS28R", 0x2655, 0x6D },
+       { "MSPM0G1507SPMR", 0x2655, 0x97 },
+       { "MSPM0G1507SRGER", 0x2655, 0x83 },
+       { "MSPM0G1507SRGZR", 0x2655, 0xD3 },
+       { "MSPM0G1507SRHBR", 0x2655, 0x4D },
+       { "MSPM0G3105SDGS20R", 0x4749, 0x21 },
+       { "MSPM0G3105SDGS28R", 0x4749, 0xDD },
+       { "MSPM0G3105SRHBR", 0x4749, 0xBE },
+       { "MSPM0G3106SDGS20R", 0x54C7, 0xD2 },
+       { "MSPM0G3106SDGS28R", 0x54C7, 0xB9 },
+       { "MSPM0G3106SRHBR", 0x54C7, 0x67 },
+       { "MSPM0G3107SDGS20R", 0xAB39, 0x5C },
+       { "MSPM0G3107SDGS28R", 0xAB39, 0xCC },
+       { "MSPM0G3107SRHBR", 0xAB39, 0xB7 },
+       { "MSPM0G3505SDGS28R", 0xc504, 0x8e },
+       { "MSPM0G3505SPMR", 0xc504, 0x1d },
+       { "MSPM0G3505SPTR", 0xc504, 0x93 },
+       { "MSPM0G3505SRGZR", 0xc504, 0xc7 },
+       { "MSPM0G3505SRHBR", 0xc504, 0xe7 },
+       { "MSPM0G3505TDGS28R", 0xc504, 0xdf },
+       { "MSPM0G3506SDGS28R", 0x151f, 0x8 },
+       { "MSPM0G3506SPMR", 0x151f, 0xd4 },
+       { "MSPM0G3506SPTR", 0x151f, 0x39 },
+       { "MSPM0G3506SRGZR", 0x151f, 0xfe },
+       { "MSPM0G3506SRHBR", 0x151f, 0xb5 },
+       { "MSPM0G3507SDGS28R", 0xae2d, 0xca },
+       { "MSPM0G3507SPMR", 0xae2d, 0xc7 },
+       { "MSPM0G3507SPTR", 0xae2d, 0x3f },
+       { "MSPM0G3507SRGZR", 0xae2d, 0xf7 },
+       { "MSPM0G3507SRHBR", 0xae2d, 0x4c },
+       { "M0G3107QPMRQ1", 0x4e2f, 0x51 },
+       { "M0G3107QPTRQ1", 0x4e2f, 0xc7},
+       { "M0G3107QRGZRQ1", 0x4e2f, 0x8a },
+       { "M0G3107QRHBRQ1", 0x4e2f, 0x9a},
+       { "M0G3107QDGS28RQ1", 0x4e2f, 0xd5},
+       { "M0G3107QDGS28RQ1", 0x4e2f, 0x67},
+       { "M0G3107QDGS20RQ1", 0x4e2f, 0xfd},
+       { "M0G3106QPMRQ1", 0x54C7, 0x08},
+       { "M0G3105QDGS32RQ1", 0x1349, 0x08},
+       { "M0G3106QPTRQ1", 0x54C7, 0x3F},
+       { "M0G3105QDGS28RQ1", 0x1349, 0x1B},
+       { "M0G3106QRGZRQ1", 0x94AD, 0xE6},
+       { "M0G3105QDGS20RQ1", 0x1349, 0xFB},
+       { "M0G3106QRHBRQ1", 0x94AD, 0x20},
+       { "M0G3106QDGS32RQ1", 0x94AD, 0x8D},
+       { "M0G3106QDGS28RQ1", 0x94AD, 0x03},
+       { "M0G3106QDGS20RQ1", 0x94AD, 0x6F},
+       { "M0G3105QPMRQ1", 0x1349, 0xD0},
+       { "M0G3105QPTRQ1", 0x1349, 0xEF},
+       { "M0G3105QRGZRQ1", 0x1349, 0x70},
+       { "M0G3105QRHBRQ1", 0x1349, 0x01},
+};
+
+/* https://www.ti.com/lit/gpn/mspm0c1104 Table 8-12 and so on */
+static const struct mspm0_part_info mspm0c_parts[] = {
+       { "MSPS003F4SPW20R", 0x57b3, 0x70},
+       { "MSPM0C1104SDGS20R", 0x57b3, 0x71},
+       { "MSPM0C1104SRUKR", 0x57b3, 0x73},
+       { "MSPM0C1104SDYYR", 0x57b3, 0x75},
+       { "MSPM0C1104SDDFR", 0x57b3, 0x77},
+       { "MSPM0C1104SDSGR", 0x57b3, 0x79},
+};
+
+/* https://www.ti.com/lit/gpn/MSPM0L2228 Table 8-16 and so on */
+static const struct mspm0_part_info mspm0lx22x_parts[] = {
+       { "MSPM0L1227SRGER", 0x7C32, 0xF1},
+       { "MSPM0L1227SPTR", 0x7C32, 0xC9},
+       { "MSPM0L1227SPMR", 0x7C32, 0x1C},
+       { "MSPM0L1227SPNAR", 0x7C32, 0x91},
+       { "MSPM0L1227SPNR", 0x7C32, 0x39},
+       { "MSPM0L1228SRGER", 0x33F7, 0x13},
+       { "MSPM0L1228SRHBR", 0x33F7, 0x3A},
+       { "MSPM0L1228SRGZR", 0x33F7, 0xBC},
+       { "MSPM0L1228SPTR", 0x33F7, 0xF8},
+       { "MSPM0L1228SPMR", 0x33F7, 0xCE},
+       { "MSPM0L1228SPNAR", 0x33F7, 0x59},
+       { "MSPM0L1228SPNR", 0x33F7, 0x7},
+       { "MSPM0L2227SRGZR", 0x5E8F, 0x90},
+       { "MSPM0L2227SPTR", 0x5E8F, 0xA},
+       { "MSPM0L2227SPMR", 0x5E8F, 0x6D},
+       { "MSPM0L2227SPNAR", 0x5E8F, 0x24},
+       { "MSPM0L2227SPNR", 0x5E8F, 0x68},
+       { "MSPM0L2228SRGZR", 0x2C38, 0xB8},
+       { "MSPM0L2228SPTR", 0x2C38, 0x25},
+       { "MSPM0L2228SPMR", 0x2C38, 0x6E},
+       { "MSPM0L2228SPNAR", 0x2C38, 0x63},
+       { "MSPM0L2228SPNR", 0x2C38, 0x3C},
+};
+
+static const struct mspm0_family_info mspm0_finf[] = {
+       { "MSPM0L", 0xbb82, ARRAY_SIZE(mspm0l_parts), mspm0l_parts },
+       { "MPSM0Lx22x", 0xbb9f, ARRAY_SIZE(mspm0lx22x_parts), mspm0lx22x_parts 
},
+       { "MSPM0G", 0xbb88, ARRAY_SIZE(mspm0g_parts), mspm0g_parts },
+       { "MSPM0C", 0xbba1, ARRAY_SIZE(mspm0c_parts), mspm0c_parts },
+};
+
+/*
+ *     OpenOCD command interface
+ */
+
+/*
+ * flash_bank mspm0 <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(mspm0_flash_bank_command)
+{
+       struct mspm0_flash_bank *mspm0_info;
+
+       switch (bank->base) {
+       case MSPM0_FLASH_BASE_NONMAIN:
+       case MSPM0_FLASH_BASE_MAIN:
+       case MSPM0_FLASH_BASE_DATA:
+               break;
+       default:
+               LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
+               return ERROR_FAIL;
+       }
+
+       mspm0_info = calloc(sizeof(struct mspm0_flash_bank), 1);
+       if (!mspm0_info) {
+               LOG_ERROR("%s: Out of memory for mspm0_info!", __func__);
+               return ERROR_FAIL;
+       }
+
+       bank->driver_priv = mspm0_info;
+
+       mspm0_info->sector_size = 0x400;
+
+       return ERROR_OK;
+}
+
+/*
+ * Chip identification and status
+ */
+static int get_mspm0_info(struct flash_bank *bank, struct command_invocation 
*cmd)
+{
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+
+       if (mspm0_info->did == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       command_print_sameline(cmd,
+                              "\nTI MSPM0 information: Chip is "
+                              "%s rev %d Device Unique ID: %d\n",
+                              mspm0_info->name, mspm0_info->version,
+                              mspm0_info->traceid);
+       command_print_sameline(cmd,
+                              "main flash: %dKiB in %d bank(s), sram: %dKiB, 
data flash: %dKiB",
+                              mspm0_info->main_flash_size_kb,
+                              mspm0_info->main_flash_num_banks, 
mspm0_info->sram_size_kb,
+                              mspm0_info->data_flash_size_kb);
+
+       return ERROR_OK;
+}
+
+/* Extract a bitfield helper */
+static uint32_t mspm0_extract_val(uint32_t var, uint8_t hi, uint8_t lo)
+{
+       return (var & GENMASK(hi, lo)) >> lo;
+}
+
+static int mspm0_read_part_info(struct flash_bank *bank)
+{
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t did, userid, flashram;
+       uint8_t minfo_idx = 0xff;
+       uint8_t pinfo_idx = 0xff;
+       uint16_t pnum, part;
+       uint8_t variant, version;
+       const struct mspm0_family_info *minfo = NULL;
+
+       /* Read and parse chip identification register */
+       target_read_u32(target, MSPM0_DID, &did);
+       target_read_u32(target, MSPM0_TRACEID, &mspm0_info->traceid);
+       target_read_u32(target, MSPM0_USERID, &userid);
+       target_read_u32(target, MSPM0_SRAMFLASH, &flashram);
+
+       version = mspm0_extract_val(did, 31, 28);
+       pnum = mspm0_extract_val(did, 27, 12);
+       variant = mspm0_extract_val(userid, 23, 16);
+       part = mspm0_extract_val(userid, 15, 0);
+
+       /* Valid DIEID? - check the ALWAYS_1 bit to be 1 */
+       if (!(did & BIT(0))) {
+               LOG_WARNING("Unknown Device ID[0x%" PRIx32 "], cannot identify 
target",
+                           did);
+               LOG_DEBUG("did 0x%" PRIx32 ", traceid 0x%" PRIx32 ", userid 
0x%" PRIx32
+                         ", flashram 0x%" PRIx32 "", did, mspm0_info->traceid, 
userid,
+                         flashram);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Check if we at least know the family of devices */
+       for (int i = 0; i < (int)ARRAY_SIZE(mspm0_finf); i++) {
+               if (mspm0_finf[i].part_num == pnum) {
+                       minfo_idx = i;
+                       minfo = &mspm0_finf[i];
+                       break;
+               }
+       }
+
+       if (minfo_idx == 0xff) {
+               LOG_WARNING("Unsupported DeviceID[0x%" PRIx32 "], cannot 
identify target",
+                           pnum);
+               LOG_DEBUG("did 0x%" PRIx32 ", traceid 0x%" PRIx32 ", userid 
0x%" PRIx32
+                         ", flashram 0x%" PRIx32 "", did, mspm0_info->traceid, 
userid,
+                         flashram);
+               LOG_DEBUG("Part 0x%" PRIx32 ", Part Num 0x%" PRIx32 ", Variant 
0x%" PRIx32
+                         ", version 0x%" PRIx32, part, pnum, variant, version);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Can we specifically identify the chip */
+       for (int i = 0; i < minfo->part_count; i++) {
+               if (minfo->part_info[i].part == part
+                   && minfo->part_info[i].variant == variant) {
+                       pinfo_idx = i;
+                       break;
+               }
+       }
+       if (minfo_idx == 0xff) {
+               mspm0_info->name = mspm0_finf[minfo_idx].family_name;
+               LOG_WARNING("Unidentified PART[0x%" PRIx32 "]/variant[0x%" 
PRIx32
+                           "], known DeviceID[0x%" PRIx32
+                           "]. Attempting to proceed as %s.", part, variant, 
pnum,
+                           mspm0_info->name);
+       } else {
+               mspm0_info->name = 
mspm0_finf[minfo_idx].part_info[pinfo_idx].part_name;
+               LOG_DEBUG("Part: %s detected", mspm0_info->name);
+       }
+
+       mspm0_info->did = did;
+       mspm0_info->version = version;
+       mspm0_info->data_flash_size_kb = mspm0_extract_val(flashram, 31, 26);
+       mspm0_info->main_flash_size_kb = mspm0_extract_val(flashram, 11, 0);
+       mspm0_info->main_flash_num_banks = mspm0_extract_val(flashram, 13, 12) 
+ 1;
+       mspm0_info->sram_size_kb = mspm0_extract_val(flashram, 25, 16);
+
+       /*
+        * Hardcode flash_word_size unless we find some other pattern
+        * See section 7.7 (Foot note mentions the flash word size).
+        * almost all values seem to be 8 bytes, but if there are variance,
+        * then we should update mspm0_part_info structure with this info.
+        */
+       mspm0_info->flash_word_size_bytes = 8;
+
+       LOG_DEBUG("Detected: main flash: %dKb in %d banks, sram: %dKb, data 
flash: %dKb",
+                 mspm0_info->main_flash_size_kb, 
mspm0_info->main_flash_num_banks,
+                 mspm0_info->sram_size_kb, mspm0_info->data_flash_size_kb);
+
+       return ERROR_OK;
+}
+
+/*
+ * Decode error values
+ */
+const struct {
+       const uint8_t bit_offset;
+       const char *fail_string;
+} mspm0_fctl_fail_decode_strings[] = {
+       { 2, "CMDINPROGRESS" },
+       { 4, "FAILWEPROT" },
+       { 5, "FAILVERIFY" },
+       { 6, "FAILILLADDR" },
+       { 7, "FAILMODE" },
+       { 12, "FAILMISC" },
+};
+
+static void msmp0_fctl_translate_ret_err(uint32_t return_code, char *ret_str)
+{
+       for (unsigned long i = 0; i < 
ARRAY_SIZE(mspm0_fctl_fail_decode_strings); i++) {
+               if (return_code & 
BIT(mspm0_fctl_fail_decode_strings[i].bit_offset)) {
+                       strncat(ret_str, 
mspm0_fctl_fail_decode_strings[i].fail_string,
+                               ERR_STRING_MAX);
+                       strncat(ret_str, " ", ERR_STRING_MAX);
+               }
+       }
+}
+
+static int mspm0_fctl_get_sector_reg(struct flash_bank *bank, uint32_t addr,
+                                                                        
uint32_t *reg, uint32_t *sector_mask)
+{
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t sector_num = (addr >> 10);
+       uint32_t sector_in_bank = sector_num;
+       uint32_t phys_sector_num = sector_num;
+       uint32_t sysctl_sec_status;
+       uint32_t exec_upper_bank;
+
+       /*
+        * If the device has dual banks we will need to check if it is 
configured
+        * to execute from the upper bank. In the scenario that we are executing
+        * from upper bank then we will need to protect it using CMDWEPROTA 
rather
+        * than CMDWEPROTB. We also need to take into account what sector
+        * we're using when going between banks.
+        */
+       if (mspm0_info->main_flash_num_banks > 1) {
+               target_read_u32(target, SYSCTL_SECCFG_SECSTATUS, 
&sysctl_sec_status);
+               exec_upper_bank = mspm0_extract_val(sysctl_sec_status, 12, 12);
+               if (exec_upper_bank) {
+                       if (sector_num > (mspm0_info->main_flash_size_kb / 2)) {
+                               phys_sector_num =
+                                   sector_num - 
(mspm0_info->main_flash_size_kb / 2);
+                       } else {
+                               phys_sector_num =
+                                   sector_num + 
(mspm0_info->main_flash_size_kb / 2);
+                       }
+               }
+               sector_in_bank =
+                   sector_num % (mspm0_info->main_flash_size_kb /
+                                   mspm0_info->main_flash_num_banks);
+       }
+
+       /*
+        * NOTE: All MSPM0 devices will use CMDWEPROTA and CMDWEPROTB for MAIN
+        * flash. CMDWEPROTC is included in the TRM/DATASHEET but for all
+        * practical purposes, it is considered reserved.
+        */
+
+       if (sector_num < mspm0_info->main_flash_size_kb) {
+               /* Use CMDWEPROTA */
+               if (phys_sector_num < (uint32_t)32) {
+                       *sector_mask = (uint32_t)1 << phys_sector_num;
+                       *reg = FCTL_REG_CMDWEPROTA;
+                       return ERROR_OK;
+               }
+
+               /* Use CMDWEPROTB */
+               if (sector_in_bank < (uint32_t)256) {
+                       /* Dual bank system */
+                       if (mspm0_info->main_flash_num_banks > 1) {
+                               *sector_mask = (uint32_t)1 << (sector_in_bank / 
8);
+                       } else {        /* Single bank system */
+                               *sector_mask = (uint32_t)1 << ((sector_in_bank 
- 32) / 8);
+                       }
+                       *reg = FCTL_REG_CMDWEPROTB;
+                       return ERROR_OK;
+               }
+       } else {
+               /*
+                * Due to the consequences of NONMAIN memory we will perform an
+                * additional check to confirm that the address being passed 
through
+                * is NONMAIN flash. If the address passed through is not 
proper we
+                * will return an error.
+                */
+               if (addr >= MSPM0_FLASH_BASE_NONMAIN && addr <= 
MSPM0_FLASH_END_NONMAIN) {
+                       *sector_mask = 1 << (sector_num % 32);
+                       *reg = FCTL_REG_CMDWEPROTNM;
+                       return ERROR_OK;
+               }
+       }
+
+       LOG_ERROR("%s: Unable to map sector protect reg for address 0x%08" 
PRIx32,
+                         mspm0_info->name, addr);
+       return ERROR_FLASH_DST_OUT_OF_BANK;
+}
+
+static int mspm0_fctl_unprotect_sector(struct flash_bank *bank, uint32_t addr)
+{
+       struct target *target = bank->target;
+       uint32_t reg = 0x0;
+       uint32_t sector_mask = 0x0;
+       int ret;
+
+       ret = mspm0_fctl_get_sector_reg(bank, addr, &reg, &sector_mask);
+       if (ret == ERROR_OK)
+               target_write_u32(target, reg, ~sector_mask);
+
+       return ret;
+}
+
+static int msmp0_fctl_wait_cmd_ok(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       uint32_t return_code = 0;
+       long long start_ms;
+       long long elapsed_ms;
+
+       int retval = ERROR_OK;
+
+       start_ms = timeval_ms();
+       while ((return_code & FCTL_STATCMD_CMDDONE_MASK) != 
FCTL_STATCMD_CMDDONE_STATDONE) {
+               retval = target_read_u32(target, FCTL_REG_STATCMD, 
&return_code);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               elapsed_ms = timeval_ms() - start_ms;
+               if (elapsed_ms > 500)
+                       keep_alive();
+               if (elapsed_ms > MSPM0_FLASH_TIMEOUT_MS)
+                       break;
+       }
+
+       if ((return_code & FCTL_STATCMD_CMDPASS_MASK) != 
FCTL_STATCMD_CMDPASS_STATPASS) {
+               char *error_string = calloc(sizeof(char), ERR_STRING_MAX + 1);
+               if (error_string) {
+                       msmp0_fctl_translate_ret_err(return_code, error_string);
+                       LOG_ERROR("%s: Flash command failed: %s", 
mspm0_info->name,
+                                 error_string);
+                       free(error_string);
+               } else {
+                       LOG_ERROR("%s: Flash command failed: 0x%" PRIx32,
+                                 mspm0_info->name, return_code);
+               }
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int mspm0_protect_reg_mainmap(struct flash_bank *bank, uint32_t sector,
+                                    uint32_t *protect_reg_offset,
+                                    uint32_t *protect_reg_bit)
+{
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       uint32_t bank_size, sector_in_bank;
+
+       if (sector < 32) {
+               *protect_reg_offset = 0;
+               *protect_reg_bit = sector % 32;
+               return ERROR_OK;
+       }
+
+       bank_size = mspm0_info->main_flash_size_kb / 
mspm0_info->main_flash_num_banks;
+       sector_in_bank = sector & (bank_size - 1);
+
+       if (sector_in_bank < 256) {
+               *protect_reg_offset = 1;
+               if (mspm0_info->main_flash_num_banks == 1)
+                       *protect_reg_bit = ((sector_in_bank - 32) / 8);
+               else
+                       *protect_reg_bit = (sector_in_bank) / 8;
+               return ERROR_OK;
+       }
+
+       if (sector_in_bank >= 512) {
+               LOG_ERROR("%s: Invalid sector_in_bank %d at bank " 
TARGET_ADDR_FMT,
+                         mspm0_info->name, sector_in_bank, bank->base);
+               return ERROR_FAIL;
+       }
+       *protect_reg_offset = 2;
+       *protect_reg_bit = (sector_in_bank - 256) / 8;
+       return ERROR_OK;
+}
+
+static int mspm0_protect_reg_map(struct flash_bank *bank, uint32_t sector,
+                                uint32_t *protect_reg_offset,
+                                uint32_t *protect_reg_bit)
+{
+       int retval;
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+
+       switch (bank->base) {
+       case MSPM0_FLASH_BASE_NONMAIN:
+               *protect_reg_offset = sector / 32;
+               *protect_reg_bit = sector % 32;
+               break;
+       case MSPM0_FLASH_BASE_MAIN:
+               retval =
+                   mspm0_protect_reg_mainmap(bank, sector, protect_reg_offset,
+                                             protect_reg_bit);
+               if (retval)
+                       return retval;
+               break;
+       case MSPM0_FLASH_BASE_DATA:
+               LOG_ERROR("%s: Bank protection not available " TARGET_ADDR_FMT,
+                         mspm0_info->name, bank->base);
+               return ERROR_FAIL;
+       default:
+               LOG_ERROR("%s: Invalid bank address " TARGET_ADDR_FMT, 
mspm0_info->name,
+                         bank->base);
+               return ERROR_FAIL;
+       }
+
+       /* Basic sanity checks */
+       if (*protect_reg_offset >= mspm0_info->protect_reg_count) {
+               LOG_ERROR("%s: sector %d address overflows protection regs: "
+                         TARGET_ADDR_FMT, mspm0_info->name, sector, 
bank->base);
+               return ERROR_FAIL;
+       }
+       if (*protect_reg_bit >= 32) {
+               LOG_ERROR
+                   ("%s: sector %d address causes DRIVER BUG for reg bit %d on 
bank: "
+                    TARGET_ADDR_FMT, mspm0_info->name, sector, 
*protect_reg_bit,
+                    bank->base);
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int mspm0_protect_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS];
+       uint32_t protect_reg_offset, protect_reg_bit;
+       unsigned int i;
+
+       if (mspm0_info->did == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       for (i = 0; i < bank->num_sectors; i++)
+               bank->sectors[i].is_protected = -1;
+
+       if (!mspm0_info->protect_reg_count)
+               return ERROR_OK;
+
+       /* Do a single scan read of regs before we set the status */
+       for (i = 0; i < mspm0_info->protect_reg_count; i++) {
+               target_read_u32(target,
+                               mspm0_info->protect_reg_base + (i * 4),
+                               &protect_reg_cache[i]);
+       }
+
+       for (i = 0; i < bank->num_sectors; i++) {
+               int retval = mspm0_protect_reg_map(bank, i, &protect_reg_offset,
+                                                  &protect_reg_bit);
+               if (retval) {
+                       LOG_ERROR("%s: sector %d: protect reg decode err: %d",
+                                 mspm0_info->name, i, retval);
+                       bank->sectors[i].is_protected = -1;
+                       continue;
+               }
+               bank->sectors[i].is_protected =
+                   protect_reg_cache[protect_reg_offset] & 
BIT(protect_reg_bit) ? 1 : 0;
+       }
+
+       return ERROR_OK;
+}
+
+static int mspm0_protect(struct flash_bank *bank, int set,
+                        unsigned int first, unsigned int last)
+{
+       struct target *target = bank->target;
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS];
+       uint32_t protect_reg_offset, protect_reg_bit;
+       unsigned int i;
+       int retval;
+
+       if (mspm0_info->did == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       if (!mspm0_info->protect_reg_count)
+               return ERROR_OK;
+
+       /*
+        * Don't trust the protection status set in 
bank->sectors[i].is_protected
+        * Driver might have changed the flash protection scheme.
+        * So, just rescan and update
+        */
+
+       /* Do a single scan read of regs before we set the status */
+       for (i = 0; i < mspm0_info->protect_reg_count; i++) {
+               target_read_u32(target,
+                               mspm0_info->protect_reg_base + (i * 4),
+                               &protect_reg_cache[i]);
+       }
+       /* Flip to binary value */
+       set = !!set;
+       /* Now set the bits that we need to set with */
+       for (i = first; i <= last; i++) {
+               retval =
+                   mspm0_protect_reg_map(bank, i, &protect_reg_offset, 
&protect_reg_bit);
+
+               /* Don't proceed unless all OK */
+               if (retval) {
+                       LOG_ERROR("%s: Sector %d protect regmap fail: %d",
+                                 mspm0_info->name, i, retval);
+                       return retval;
+               }
+               if (set)
+                       protect_reg_cache[protect_reg_offset] |= 
BIT(protect_reg_bit);
+               else
+                       protect_reg_cache[protect_reg_offset] &= 
~BIT(protect_reg_bit);
+       }
+
+       for (i = 0; i < mspm0_info->protect_reg_count; i++) {
+               target_write_u32(target,
+                                mspm0_info->protect_reg_base + (i * 4),
+                                protect_reg_cache[i]);
+       }
+
+       /*
+        * Update our local state data base, since single bit can protect up to
+        * 8 sectors in some banks
+        */
+       for (i = 0; i < bank->num_sectors; i++) {
+               retval =
+                   mspm0_protect_reg_map(bank, i, &protect_reg_offset, 
&protect_reg_bit);
+               if (retval) {
+                       bank->sectors[i].is_protected = -1;
+                       /* Ideally we should never be here as this was checked 
above. */
+                       LOG_DEBUG("%s: Sector %d protect regmap fail: %d",
+                                 mspm0_info->name, i, retval);
+                       continue;
+               }
+               bank->sectors[i].is_protected =
+                   protect_reg_cache[protect_reg_offset] & 
BIT(protect_reg_bit);
+       }
+
+       return ERROR_OK;
+}
+
+static int mspm0_erase(struct flash_bank *bank, unsigned int first, unsigned 
int last)
+{
+       struct target *target = bank->target;
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       unsigned int i;
+       uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS];
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("%s: Please halt target for erasing flash", 
mspm0_info->name);
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (mspm0_info->did == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       /* Pick a copy of the current protection config for later restoration */
+       for (i = 0; i < mspm0_info->protect_reg_count; i++) {
+               target_read_u32(target,
+                               mspm0_info->protect_reg_base + (i * 4),
+                               &protect_reg_cache[i]);
+       }
+
+       for (uint32_t csa = first; csa < last; csa++) {
+               int retval;
+               uint32_t addr = csa * mspm0_info->sector_size;
+
+               retval = mspm0_fctl_unprotect_sector(bank, addr);
+               if (retval) {
+                       LOG_ERROR("%s: Illegal access at address 0x%08" PRIx32
+                                 "(sector: %d)", mspm0_info->name, addr, csa);
+                       return retval;
+               }
+               target_write_u32(target, FCTL_REG_CMDTYPE,
+                                (FCTL_CMDTYPE_COMMAND_ERASE | 
FCTL_CMDTYPE_SIZE_SECTOR));
+               target_write_u32(target, FCTL_REG_CMDADDR, addr);
+               target_write_u32(target, FCTL_REG_CMDEXEC, 
FCTL_CMDEXEC_VAL_EXECUTE);
+               retval = msmp0_fctl_wait_cmd_ok(bank);
+               if (retval) {
+                       LOG_ERROR("%s: Failed Erasing at address 0x%08" PRIx32
+                                 "(sector: %d)", mspm0_info->name, addr, csa);
+                       return retval;
+               }
+               /*
+                * TRM Says:
+                * Note that the CMDWEPROTx registers are reset to a protected 
state
+                * at the end of all program and erase operations.  These 
registers
+                * must be re-configured by software before a new operation is
+                * initiated
+                * Let us just Dump the protection registers back to the system.
+                * That way we retain the protection status as requested by the 
user
+                */
+               for (i = 0; i < mspm0_info->protect_reg_count; i++) {
+                       target_write_u32(target, mspm0_info->protect_reg_base + 
(i * 4),
+                                        protect_reg_cache[i]);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int mspm0_write(struct flash_bank *bank, const uint8_t *buffer,
+                      uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       unsigned int i;
+       uint32_t protect_reg_cache[MSPM0_MAX_PROTREGS];
+
+       /*
+        * XXX: TRM Says:
+        * The number of program operations applied to a given word line must be
+        * monitored to ensure that the maximum word line program limit before
+        * erase is not violated.
+        *
+        * There is no reasonable way we can maintain that state in OpenOCD. So,
+        * Let the manufacturing path figure this out.
+        */
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("%s: Please halt target for programming flash",
+                         mspm0_info->name);
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (mspm0_info->did == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       if (offset % mspm0_info->flash_word_size_bytes) {
+               LOG_ERROR("%s: Offset 0x%0" PRIx32 " Must be aligned to %d 
bytes",
+                         mspm0_info->name, offset, 
mspm0_info->flash_word_size_bytes);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       /*
+        * Pick a copy of the current protection config for later restoration
+        * We need to restore these regs after every write, so instead of trying
+        * to figure things out on the fly, we just context save and restore
+        */
+       for (i = 0; i < mspm0_info->protect_reg_count; i++) {
+               target_read_u32(target,
+                               mspm0_info->protect_reg_base + (i * 4),
+                               &protect_reg_cache[i]);
+       }
+
+       while (count) {
+               uint32_t num_bytes_to_write;
+               uint32_t data_reg = FCTL_REG_CMDDATA0;
+               uint32_t bytes_en;
+               int retval;
+
+               /*
+                * If count is not 64 bit aligned, we will do byte wise op to 
keep things simple
+                * Usually this might mean we need to additional write ops 
towards
+                * trailing edge, but that is a tiny penalty for image 
downloads.
+                * NOTE: we are going to assume the device does not support 
multi-word
+                * programming - there does not seem to be discoverability!
+                */
+               if (count < mspm0_info->flash_word_size_bytes)
+                       num_bytes_to_write = count % 
mspm0_info->flash_word_size_bytes;
+               else
+                       num_bytes_to_write = mspm0_info->flash_word_size_bytes;
+
+               /* Data bytes to write */
+               bytes_en = (1 << num_bytes_to_write) - 1;
+               /* ECC chunks to write */
+               switch (mspm0_info->flash_word_size_bytes) {
+               case 8:
+                       bytes_en |= BIT(8);
+                       break;
+               case 16:
+                       bytes_en |= BIT(16);
+                       bytes_en |= (num_bytes_to_write > 8) ? BIT(17) : 0;
+                       break;
+               default:
+                       LOG_ERROR("%s: Invalid flash_word_size_bytes %d",
+                                 mspm0_info->name, 
mspm0_info->flash_word_size_bytes);
+                       return ERROR_FAIL;
+               }
+
+               target_write_u32(target, FCTL_REG_CMDTYPE,
+                                (FCTL_CMDTYPE_COMMAND_PROGRAM |
+                                 FCTL_CMDTYPE_SIZE_ONEWORD));
+
+               /* When writing to part of flash_word - set the bit fields */
+               target_write_u32(target, FCTL_REG_CMDBYTEN, bytes_en);
+
+               target_write_u32(target, FCTL_REG_CMDADDR, offset);
+
+               retval = mspm0_fctl_unprotect_sector(bank, offset);
+               if (retval)
+                       return retval;
+
+               while (num_bytes_to_write) {
+                       uint32_t sub_count;
+                       uint32_t write_value;
+
+                       /* Make sure alignments are handled correctly */
+                       (void)memcpy(&write_value, buffer, sizeof(uint32_t));
+
+                       target_write_u32(target, data_reg, write_value);
+                       sub_count =
+                           (num_bytes_to_write <
+                            sizeof(uint32_t)) ? num_bytes_to_write : 4;
+                       buffer += sub_count;
+                       data_reg += sub_count;
+                       num_bytes_to_write -= sub_count;
+                       offset += sub_count;
+                       count -= sub_count;
+               }
+
+               target_write_u32(target, FCTL_REG_CMDEXEC, 
FCTL_CMDEXEC_VAL_EXECUTE);
+
+               retval = msmp0_fctl_wait_cmd_ok(bank);
+               if (retval)
+                       return retval;
+               /*
+                * TRM Says:
+                * Note that the CMDWEPROTx registers are reset to a protected 
state
+                * at the end of all program and erase operations.  These 
registers
+                * must be re-configured by software before a new operation is
+                * initiated
+                * Let us just Dump the protection registers back to the system.
+                * That way we retain the protection status as requested by the 
user
+                */
+               for (i = 0; i < mspm0_info->protect_reg_count; i++) {
+                       target_write_u32(target,
+                                        mspm0_info->protect_reg_base + (i * 4),
+                                        protect_reg_cache[i]);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int mspm0_probe(struct flash_bank *bank)
+{
+       struct mspm0_flash_bank *mspm0_info = bank->driver_priv;
+       int retval;
+
+       /*
+        * If this is a mspm0 chip, it has flash; probe() is just
+        * to figure out how much is present.  Only do it once.
+        */
+       if (mspm0_info->did != 0)
+               return ERROR_OK;
+
+       /*
+        * mspm0_read_part_info() already handled error checking and
+        * reporting.  Note that it doesn't write, so we don't care about
+        * whether the target is halted or not.
+        */
+       retval = mspm0_read_part_info(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (bank->sectors) {
+               free(bank->sectors);
+               bank->sectors = NULL;
+       }
+
+       switch (bank->base) {
+       case MSPM0_FLASH_BASE_NONMAIN:
+               bank->size = 512;
+               bank->num_sectors = 0x1;
+               mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTNM;
+               mspm0_info->protect_reg_count = 1;
+               break;
+       case MSPM0_FLASH_BASE_MAIN:
+               bank->size = (mspm0_info->main_flash_size_kb * 1024);
+               bank->num_sectors = bank->size / mspm0_info->sector_size;
+               mspm0_info->protect_reg_base = FCTL_REG_CMDWEPROTA;
+               mspm0_info->protect_reg_count = 3;
+               break;
+       case MSPM0_FLASH_BASE_DATA:
+               if (!mspm0_info->data_flash_size_kb) {
+                       LOG_INFO("%s: Data region NOT available!", 
mspm0_info->name);
+                       bank->size = 0x0;
+                       bank->num_sectors = 0x0;
+                       return ERROR_OK;
+               }
+               bank->size = (mspm0_info->main_flash_size_kb * 1024);
+               bank->num_sectors = bank->size / mspm0_info->sector_size;
+               bank->num_prot_blocks = 0;      /* There is no protection here 
*/
+               break;
+       default:
+               LOG_ERROR("%s: Invalid bank address " TARGET_ADDR_FMT, 
mspm0_info->name,
+                         bank->base);
+               return ERROR_FAIL;
+       }
+       bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector));
+       if (!bank->sectors) {
+               LOG_ERROR("%s: Out of memory for sectors!", mspm0_info->name);
+               return ERROR_FAIL;
+       }
+       for (unsigned int i = 0; i < bank->num_sectors; i++) {
+               bank->sectors[i].offset = i * mspm0_info->sector_size;
+               bank->sectors[i].size = mspm0_info->sector_size;
+               bank->sectors[i].is_erased = -1;
+       }
+
+       return ERROR_OK;
+}
+
+const struct flash_driver mspm0_flash = {
+       .name = "mspm0",
+       .flash_bank_command = mspm0_flash_bank_command,
+       .erase = mspm0_erase,
+       .protect = mspm0_protect,
+       .write = mspm0_write,
+       .read = default_flash_read,
+       .probe = mspm0_probe,
+       .auto_probe = mspm0_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = mspm0_protect_check,
+       .info = get_mspm0_info,
+       .free_driver_priv = default_flash_free_driver_priv,
+};

-- 

Reply via email to