This is an automated email from Gerrit. "Jeremy Grosser <jer...@synack.me>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8220
-- gerrit commit e9237c816ffcc8b28378fe76735f5d3555900d67 Author: Jeremy Grosser <jer...@synack.me> Date: Mon Apr 22 15:32:32 2024 -0700 flash/nor/mspm0: Add TI MSPM0xxxx support Tested with LP-MSPM0G3507 development board Change-Id: Ibe71a25a2aa2d213b153fd1c13a5231753e4614c Signed-off-by: Jeremy Grosser <jer...@synack.me> 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 7d6f8c5cc4..27a2fde2bf 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -272,6 +272,7 @@ extern const struct flash_driver lpcspifi_flash; 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 mspm0_flash; extern const struct flash_driver msp432_flash; extern const struct flash_driver niietcm4_flash; extern const struct flash_driver npcx_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 34359889a6..1abfc2257b 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..df8cc6a0d9 --- /dev/null +++ b/src/flash/nor/mspm0.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" + +#define FLASHCTL_BASE (0x400CD000UL) +#define FLASHCTL_CMDEXEC (FLASHCTL_BASE + 0x1100) +#define FLASHCTL_CMDTYPE (FLASHCTL_BASE + 0x1104) +#define FLASHCTL_CMDADDR (FLASHCTL_BASE + 0x1120) +#define FLASHCTL_CMDBYTEN (FLASHCTL_BASE + 0x1124) +#define FLASHCTL_CMDDATA0 (FLASHCTL_BASE + 0x1130) +#define FLASHCTL_CMDDATA1 (FLASHCTL_BASE + 0x1134) +#define FLASHCTL_CMDWEPROTA (FLASHCTL_BASE + 0x11D0) +#define FLASHCTL_CMDWEPROTB (FLASHCTL_BASE + 0x11D4) +#define FLASHCTL_CMDWEPROTC (FLASHCTL_BASE + 0x11D8) +#define FLASHCTL_STATCMD (FLASHCTL_BASE + 0x13D0) + +#define CMDTYPE_SIZE_SECTOR (0x04 << 3) +#define CMDTYPE_SIZE_WORD (0x00 << 3) // one word of flash is 64 bits + +#define CMDTYPE_COMMAND_NOOP 0x00 +#define CMDTYPE_COMMAND_PROGRAM 0x01 +#define CMDTYPE_COMMAND_ERASE 0x02 +#define CMDTYPE_COMMAND_READ_VERIFY 0x03 +#define CMDTYPE_COMMAND_BLANK_VERIFY 0x04 + +#define STATCMD_FAILMISC (1 << 12) +#define STATCMD_FAILMODE (1 << 7) +#define STATCMD_FAILILLADDR (1 << 6) +#define STATCMD_FAILVERIFY (1 << 5) +#define STATCMD_FAILWEPROT (1 << 4) +#define STATCMD_CMDINPROGRESS (1 << 2) +#define STATCMD_CMDPASS (1 << 1) +#define STATCMD_CMDDONE (1 << 0) + +#define CPUSS_BASE (0x40400000) +#define CPUSS_CTL (CPUSS_BASE + 0x1300) +#define SECTOR_SIZE 1024 + +struct mspm0_flash_bank { +}; + +static const struct command_registration mspm0_any_command_handlers[] = { + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration mspm0_command_handlers[] = { + { + .name = "mspm0", + .mode = COMMAND_ANY, + .help = "TI mspm0 flash command group", + .usage = "", + .chain = mspm0_any_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +FLASH_BANK_COMMAND_HANDLER(mspm0_flash_bank_command) +{ + bank->driver_priv = malloc(sizeof(struct mspm0_flash_bank)); + if(!bank->driver_priv) { + return ERROR_FLASH_OPERATION_FAILED; + } + (void)memset(bank->driver_priv, 0, sizeof(struct mspm0_flash_bank)); + bank->sectors = NULL; + return ERROR_OK; +} + +static void mspm0_unprotect_sector(struct flash_bank *bank, uint32_t sector) { + struct target *target = bank->target; + if(sector < 32) { + target_write_u32(target, FLASHCTL_CMDWEPROTA, ~(1 << sector)); + }else if(sector < (32 + 256)) { + target_write_u32(target, FLASHCTL_CMDWEPROTB, ~(1 << ((sector - 32) / 8))); + }else{ + target_write_u32(target, FLASHCTL_CMDWEPROTC, ~(1 << ((sector - 288) / 8))); + } +} + +static void mspm0_protect_main(struct flash_bank *bank) { + struct target *target = bank->target; + target_write_u32(target, FLASHCTL_CMDWEPROTA, 0xffffffff); + target_write_u32(target, FLASHCTL_CMDWEPROTB, 0xffffffff); + target_write_u32(target, FLASHCTL_CMDWEPROTC, 0xffffffff); +} + +static void mspm0_disable_cache(struct flash_bank *bank) { + target_write_u32(bank->target, CPUSS_CTL, 0); +} + +static void mspm0_enable_cache(struct flash_bank *bank) { + target_write_u32(bank->target, CPUSS_CTL, 0x7); +} + +static int mspm0_flash_wait(struct flash_bank *bank) { + struct target *target = bank->target; + uint32_t statcmd; + + do{ + target_read_u32(target, FLASHCTL_STATCMD, &statcmd); + }while((statcmd & STATCMD_CMDDONE) == 0); + + if(statcmd & STATCMD_FAILWEPROT) { + return ERROR_FLASH_PROTECTED; + } + + if(statcmd & (STATCMD_FAILVERIFY | STATCMD_FAILMISC)) { + return ERROR_FLASH_OPERATION_FAILED; + } + + if(statcmd & STATCMD_FAILILLADDR) { + return ERROR_FLASH_SECTOR_INVALID; + } + + if(statcmd & STATCMD_FAILMODE) { + return ERROR_FLASH_BUSY; + } + + if(statcmd != (STATCMD_CMDDONE | STATCMD_CMDPASS)) { + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +int mspm0_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { + struct target *target = bank->target; + uint32_t sector; + int err = ERROR_FLASH_SECTOR_INVALID; + + mspm0_disable_cache(bank); + + for(sector = first; sector <= last; sector++) { + mspm0_unprotect_sector(bank, sector); + target_write_u32(target, FLASHCTL_CMDTYPE, CMDTYPE_SIZE_SECTOR | CMDTYPE_COMMAND_ERASE); + target_write_u32(target, FLASHCTL_CMDADDR, bank->base + bank->sectors[sector].offset); + target_write_u32(target, FLASHCTL_CMDEXEC, 1); + err = mspm0_flash_wait(bank); + } + + mspm0_protect_main(bank); + + return err; +} + +static int mspm0_write_word(struct flash_bank *bank, uint32_t addr, uint32_t *data) { + struct target *target = bank->target; + uint32_t sector = addr / SECTOR_SIZE; + int err; + + mspm0_unprotect_sector(bank, sector); + target_write_u32(target, FLASHCTL_CMDTYPE, CMDTYPE_SIZE_WORD | CMDTYPE_COMMAND_PROGRAM); + target_write_u32(target, FLASHCTL_CMDADDR, addr); + target_write_u32(target, FLASHCTL_CMDBYTEN, 0xFFFFFFFF); + target_write_u32(target, FLASHCTL_CMDDATA0, data[0]); + target_write_u32(target, FLASHCTL_CMDDATA1, data[1]); + target_write_u32(target, FLASHCTL_CMDEXEC, 1); + err = mspm0_flash_wait(bank); + + return err; +} + +int mspm0_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { + uint32_t *ptr = (uint32_t *)buffer; + uint32_t i; + int err; + + err = mspm0_erase(bank, offset / SECTOR_SIZE, (offset + count) / SECTOR_SIZE); + if(err != ERROR_OK) { + return err; + } + + mspm0_disable_cache(bank); + for(i = 0; i < count; i += 8) { + err = mspm0_write_word(bank, offset + i, ptr); + ptr += 2; + if(err != ERROR_OK) { + return err; + } + } + + mspm0_protect_main(bank); + mspm0_enable_cache(bank); + + return ERROR_OK; +} + +int mspm0_probe(struct flash_bank *bank) { + uint32_t sramflash; + + bank->bank_number = 0; + bank->base = 0x00000000; + bank->chip_width = 8; + bank->bus_width = 4; + target_read_u32(bank->target, 0x41C40018, &sramflash); + bank->size = (sramflash & 0xFFF) * 1024; + bank->num_sectors = bank->size / SECTOR_SIZE; + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + for(unsigned int sector = 0; sector < bank->num_sectors; sector++) { + bank->sectors[sector] = (struct flash_sector){ + .offset = bank->base + (SECTOR_SIZE * sector), + .size = SECTOR_SIZE, + .is_erased = false, + .is_protected = false, + }; + } + + bank->num_prot_blocks = 0; + bank->next = NULL; + + return ERROR_OK; +} + +int mspm0_protect_check(struct flash_bank *bank) { + return ERROR_OK; +} + +int mspm0_info(struct flash_bank *bank, struct command_invocation *cmd) { + return ERROR_OK; +} + +int mspm0_auto_probe(struct flash_bank *bank) { + if(bank->sectors != NULL) { + return ERROR_OK; + }else{ + return mspm0_probe(bank); + } +} + +const struct flash_driver mspm0_flash = { + .name = "mspm0", + .commands = mspm0_command_handlers, // done + .flash_bank_command = mspm0_flash_bank_command, // done + .erase = mspm0_erase, // done + .protect = NULL, + .write = mspm0_write, // done + .read = default_flash_read, + .verify = default_flash_verify, + .probe = mspm0_probe, // done + .erase_check = default_flash_blank_check, + .protect_check = mspm0_protect_check, // TODO + .info = mspm0_info, // TODO + .auto_probe = mspm0_auto_probe, // done + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/tcl/target/ti_mspm0.cfg b/tcl/target/ti_mspm0.cfg new file mode 100644 index 0000000000..fb1c6c1d3d --- /dev/null +++ b/tcl/target/ti_mspm0.cfg @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME mspm0 +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x6ba02477 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -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 -work-area-backup 0 + +flash bank $_CHIPNAME.flash mspm0 0 0 0 0 $_TARGETNAME + +adapter speed 2000 + +reset_config srst_open_drain +cortex_m reset_config sysresetreq + +# At power on, if flash 0x00000000 .. 0x00000008 are erased and no secondary +# bootloader is configured, the ROM BSL will wait up to 10 seconds for a +# handshake on UART or I2C. If the timeout expires with no handshake, the +# device goes into STANDBY and the AHB is not accessible from the debug port. +# The only way out of this state is a power on reset. +# +# If you see "Could not find MEM-AP to control the core" and +# "Examination failed" errors, this is likely what has happened. +# +# Telnet to openocd and issue "reset" until "Examination succeed", then you have +# 10 seconds to halt the CPU before it goes into STANDBY again. Once halted, +# you can write to the flash and reset normally. --