# 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