--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2023-2025 Texas Instruments Incorporated - https://www.ti.com/
+#
+# Texas Instruments MSPM0L/G - ARM Cortex-M0 @ 32MHz
+# https://www.ti.com/microcontrollers-mcus-processors/arm-based-microcontrollers/arm-cortex-m0-mcus/overview.html
+#
+
+source [find bitsbytes.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ # Meant to work with MSPM0L and MSPM0G class of devices.
+ set _CHIPNAME mspm0x
+}
+
+if { [info exists CPUTAPID] } {
+ set _DAP_TAPID $CPUTAPID
+} else {
+ set _DAP_TAPID 0x4ba00477
+}
+
+if { [info exists DAP_SWD_ID] } {
+ set _DAP_SWD_ID $DAP_SWD_ID
+} else {
+ set _DAP_SWD_ID 0x2ba01477
+}
+
+source [find target/swj-dp.tcl]
+
+# MSPM0 only supports swd, so set it here and save a line for custom boards
+transport select swd
+
+set _DAP_ID $_DAP_SWD_ID
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_ID
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
+
+if { [info exists WORKAREABASE] } {
+ set _WORKAREABASE $WORKAREABASE
+} else {
+ set _WORKAREABASE 0x20000000
+}
+if { [info exists WORKAREASIZE] } {
+ set _WORKAREASIZE $WORKAREASIZE
+} else {
+ # Smallest SRAM size is 1K SRAM.
+ set _WORKAREASIZE 0x400
+}
+
+#
+# MSPM0 Debug SubSystem Mailbox (DSSM) Communication helpers
+#
+
+proc _mspm0_wait_for_dssm_response {command} {
+ # Wait for SECAP::RCR rx_valid to be set
+ set timeout 1000
+ while { [expr { [$::_CHIPNAME.dap apreg 2 0xc] & 0x1}] != 0x1 } {
+ sleep 1
+ set timeout [expr {$timeout - 1}]
+ if { $timeout == 0 } {
+ set rcr [$::_CHIPNAME.dap apreg 2 0xc]
+ return -code error [format "MSPM0 SECAP RCR=0x%08x timeout rx_valid" $rcr]
+ }
+ }
+
+ # Read SECAP::RXD to clear the RX_VALID bit
+ set rxd [$::_CHIPNAME.dap apreg 2 0x8]
+ # Read SECAP::RCR
+ set rcr [$::_CHIPNAME.dap apreg 2 0xc]
+
+ # Check if we got successful response. This is denoted as:
+ # 8 LSBits of $command should matchup with SECAP::RCR
+ # and
+ # SECAP::RXD should be 0x10003
+ if { ([expr { $command & 0xff}] == $rcr) && ($rxd == 0x10003) } {
+ return 0
+ }
+
+ # Provide some debug log for users to report back if CMD fails.
+ return -code error [format "MSPM0 SECAP CMD FAIL! RXD: 0x%08X RCR: 0x%08X" $rxd $rcr]
+}
+
+proc _mspm0_dssm_command {command} {
+ # SECAP::TCR = command
+ $::_CHIPNAME.dap apreg 2 0x4 $command
+ # SECAP::TDR = 0x0
+ $::_CHIPNAME.dap apreg 2 0x0 0x0
+ # Read SECAP::RCR and RXD to clear up any prev pending reads
+ set rxd [$::_CHIPNAME.dap apreg 2 0x8]
+ set rcr [$::_CHIPNAME.dap apreg 2 0xc]
+ # Make sure everything is synced
+ sleep 1000
+ # Trigger nRST
+ mspm0_board_reset
+
+ # Wait for ROM to do it's magic and respond back
+ set res [_mspm0_wait_for_dssm_response $command]
+ if { $res } {
+ return $res
+ }
+ # Paranoid.. make sure ROM does what it is meant to do
+ # RX valid should have been cleared after the operation is
+ # complete
+ sleep 1000
+
+ # Trigger nRST to get back to sane system
+ mspm0_board_reset
+ sleep 1000
+
+ return 0
+}
+
+# NOTE: Password authentication scheme is NOT supported atm.
+# mspm0_factory_reset: Factory reset the board
+proc mspm0_factory_reset {} {
+ set res [_mspm0_dssm_command 0x020a]
+ if { $res } {
+ echo "Factory Reset failed!"
+ } else {
+ echo "Factory reset success! Halting processor"
+ # We need to halt the processor else the WDT fires!
+ halt
+ }
+ return $res
+}
+
+add_help_text mspm0_factory_reset "Force Factory reset to recover 'bricked' board"
+
+# NOTE: Password authentication scheme is NOT supported atm.
+# mspm0_mass_erase: Mass erase flash
+proc mspm0_mass_erase {} {
+ set res [_mspm0_dssm_command 0x020c]
+ if { $res } {
+ echo "Mass Erase failed!"
+ } else {
+ echo "Mass Erase success! Halting Processor"
+ # We need to halt the processor else the WDT fires!
+ halt
+ }
+ return $res
+}
+
+add_help_text mspm0_mass_erase "Mass erase flash"
+
+# mspm0_start_bootloader: Ask explicitly for bootloader startup
+proc mspm0_start_bootloader {} {
+ set res [_mspm0_dssm_command 0x0108]
+ if { $res } {
+ echo "Start BL failed!"
+ }
+ return $res
+}
+
+add_help_text mspm0_start_bootloader "Ask explicitly for bootloader startup"
+
+# MSPM0 requires board level NRST reset to be toggled for
+# Factory reset operations to function.
+# However this cannot be the default configuration as this
+# prevents reset init reset halt to function properly
+# since the Debug Subsystem (debugss) logic or coresight
+# seems impacted by nRST.
+# This can be overridden in board file as required.
+#
+# mspm0_board_reset: Board level reset
+proc mspm0_board_reset {} {
+ set user_reset_config [reset_config]
+ reset_config srst_only
+ set errno [catch {reset}]
+ eval reset_config $user_reset_config
+ if {$errno} {error}
+}
+
+add_help_text mspm0_board_reset "Request a board level reset"
+
+# If the flash is empty or the device is already in low-power state, then
+# debug access is not available. to handle this, explicitly control power ap
+# to provide access. Refer to Technical Reference Manual for further info.
+proc _mspm0_enable_low_power_mode { } {
+ # PWR_AP::DPREC <= FRCACT(3)=1, RST_CTL(14:16)=1, IHIB_SLP(20)=1
+ $::_CHIPNAME.dap apreg 4 0x00 0x104008
+ # PWR_AP::SPREC <= SYSRST=1
+ $::_CHIPNAME.dap apreg 4 0xF0 0x01
+ # PWR_AP::DPREC <= FRCACT(3)=1, IHIB_SLP(20)=1
+ $::_CHIPNAME.dap apreg 4 0x00 0x100008
+}
+
+$_TARGETNAME configure -event examine-start { _mspm0_enable_low_power_mode }
+$_TARGETNAME configure -work-area-phys $_WORKAREABASE -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME.main mspm0 0 0 0 0 $_TARGETNAME
+flash bank $_FLASHNAME.nonmain mspm0 0x41c00000 0 0 0 $_TARGETNAME
+flash bank $_FLASHNAME.data mspm0 0x41d00000 0 0 0 $_TARGETNAME
+
+cortex_m reset_config sysresetreq