This is an automated email from Gerrit. "Nishanth Menon <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9726
-- gerrit commit 60c63f7191f0a0e6be938c1a53ebc86b7d137c5b Author: Nishanth Menon <[email protected]> Date: Thu May 28 23:38:44 2026 -0500 flash/nor/mspm0: workaround FLASH_ERR_01 in mspm0_read_part_info MSPM0G devices have errata FLASH_ERR_01: accessing FACTORYREGION (0x41C40000) via any AHB bus master causes a hard fault when the flash controller is operating with 2 wait states. This occurs when MCLK is sourced from HSCLK (SYSPLL/HFXT), i.e. MCLK > 32 MHz. This affects OpenOCD reads (via DAP AHB-AP) in mspm0_read_part_info(). Fix this by checking SYSCTL_MCLKCFG before reading FACTORYREGION. If USEHSCLK is set and FLASHWAIT == 2, temporarily switch MCLK to SYSOSC (≤ 32 MHz), perform the reads (DID, TRACEID, USERID, SRAMFLASH), and then restore the original MCLK configuration. Restoration is ensured for both success and error paths. The workaround is effectively a no-op on MSPM0L and MSPM0C devices, since they do not reach the required clock conditions. Also handle cases where FACTORYREGION reads fail during probe: if the main flash size is zero, force a re-probe by clearing did. Link: https://www.ti.com/lit/er/slaz758d/slaz758d.pdf Change-Id: I100b02f009b3e200cb3a4482c4a26ffbdb8f5f3e Reported-by: Michael Rodriguez <[email protected]> Tested-by: Michael Rodriguez <[email protected]> Signed-off-by: Nishanth Menon <[email protected]> diff --git a/src/flash/nor/mspm0.c b/src/flash/nor/mspm0.c index 5ff1d71e49..8ceb201358 100644 --- a/src/flash/nor/mspm0.c +++ b/src/flash/nor/mspm0.c @@ -77,6 +77,20 @@ #define SYSCTL_BASE 0x400AF000 #define SYSCTL_SECCFG_SECSTATUS (SYSCTL_BASE + 0x00003048) +/* + * SYSCTL SOCLOCK MCLKCFG register (offset 0x1104 from SYSCTL_BASE). + * Used for the FLASH_ERR_01 workaround: accessing FACTORYREGION while MCLK + * is sourced from HSCLK (SYSPLL/HFXT, implying MCLK > 32 MHz) with flash + * wait-state 2 active causes a hard fault on MSPM0G devices. The flash + * controller enforces its wait-state timing for all AHB masters, including + * the DAP AHB-AP used by OpenOCD. Temporarily switching MCLK to SYSOSC + * (≤ 32 MHz on all MSPM0 variants) before reading FACTORYREGION avoids this. + */ +#define SYSCTL_MCLKCFG (SYSCTL_BASE + 0x00001104) +#define SYSCTL_MCLKCFG_USEHSCLK BIT(16) +#define SYSCTL_MCLKCFG_FLASHWAIT_MASK GENMASK(11, 8) +#define SYSCTL_MCLKCFG_FLASHWAIT_2 (2U << 8) + /* TI manufacturer ID */ #define TI_MANUFACTURER_ID 0x17 @@ -474,30 +488,94 @@ static int mspm0_read_part_info(struct flash_bank *bank) struct target *target = bank->target; const struct mspm0_family_info *minfo = NULL; + /* + * FLASH_ERR_01 workaround: on MSPM0G devices the flash controller + * rejects any bus-master access to FACTORYREGION when MCLK is sourced + * from HSCLK (SYSPLL/HFXT) and flash wait-state 2 is active + * (required for MCLK > 32 MHz). This applies to DAP AHB-AP reads too, + * not just CPU accesses. If both conditions are true, temporarily + * switch MCLK back to SYSOSC (≤ 32 MHz on every MSPM0 variant) for the + * FACTORYREGION reads and restore afterwards. The SYSCTL_MCLKCFG write + * does not take place on L/C parts: USEHSCLK is never set there because + * those cores do not exceed 32 MHz. + */ + uint32_t saved_mclkcfg = 0; + bool mclk_switched = false; + uint32_t mclkcfg; + int retval = target_read_u32(target, SYSCTL_MCLKCFG, &mclkcfg); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read SYSCTL_MCLKCFG to check FLASH_ERR_01"); + return retval; + } + + if ((mclkcfg & SYSCTL_MCLKCFG_USEHSCLK) && + ((mclkcfg & SYSCTL_MCLKCFG_FLASHWAIT_MASK) == SYSCTL_MCLKCFG_FLASHWAIT_2)) { + saved_mclkcfg = mclkcfg; + retval = target_write_u32(target, SYSCTL_MCLKCFG, + mclkcfg & ~SYSCTL_MCLKCFG_USEHSCLK); + if (retval == ERROR_OK) { + mclk_switched = true; + /* + * Read back MCLKCFG to flush the write, then add an + * explicit delay to allow the MCLK source mux to fully + * settle on SYSOSC before the flash controller timing is + * used for FACTORYREGION accesses. + */ + uint32_t dummy; + retval = target_read_u32(target, SYSCTL_MCLKCFG, &dummy); + if (retval != ERROR_OK) { + LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: " + "readback flush failed"); + goto restore_mclk; + } + alive_sleep(1); + LOG_DEBUG("MSPM0: FLASH_ERR_01 workaround ACTIVE: " + "Lowering MCLK before FACTORYREGION read"); + } else { + LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: " + "could not lower MCLK before FACTORYREGION read"); + } + } + /* Read and parse chip identification and flash version register */ uint32_t did; - int retval = target_read_u32(target, MSPM0_DID, &did); + retval = target_read_u32(target, MSPM0_DID, &did); if (retval != ERROR_OK) { LOG_ERROR("Failed to read device ID"); - return retval; + goto restore_mclk; } retval = target_read_u32(target, MSPM0_TRACEID, &mspm0_info->traceid); if (retval != ERROR_OK) { LOG_ERROR("Failed to read trace ID"); - return retval; + goto restore_mclk; } uint32_t userid; retval = target_read_u32(target, MSPM0_USERID, &userid); if (retval != ERROR_OK) { LOG_ERROR("Failed to read user ID"); - return retval; + goto restore_mclk; } uint32_t flashram; retval = target_read_u32(target, MSPM0_SRAMFLASH, &flashram); if (retval != ERROR_OK) { LOG_ERROR("Failed to read sramflash register"); - return retval; + goto restore_mclk; + } + +restore_mclk: + if (mclk_switched) { + int retval2 = target_write_u32(target, SYSCTL_MCLKCFG, saved_mclkcfg); + if (retval2 != ERROR_OK) { + LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: " + "could not restore MCLK after FACTORYREGION read"); + return retval2; + } + LOG_DEBUG("MSPM0: FLASH_ERR_01 workaround: " + "restored MCLK after FACTORYREGION read"); } + if (retval != ERROR_OK) + return retval; + uint32_t flashdesc; retval = target_read_u32(target, FCTL_REG_DESC, &flashdesc); if (retval != ERROR_OK) { @@ -1157,6 +1235,17 @@ static int mspm0_probe(struct flash_bank *bank) mspm0_info->protect_reg_count = 1; break; case MSPM0_FLASH_BASE_MAIN: + if (!mspm0_info->main_flash_size_kb) { + /* FACTORYREGION was unreadable when this bank was probed + * (e.g. device not yet halted, MCLK still at HSCLK on + * first examine). Clear did so the next auto_probe call + * re-runs mspm0_read_part_info with the target in a known + * state. */ + LOG_WARNING("MSPM0: main flash size is 0 — " + "FACTORYREGION data incomplete, scheduling re-probe"); + mspm0_info->did = 0; + return ERROR_FLASH_BANK_NOT_PROBED; + } bank->size = (mspm0_info->main_flash_size_kb * 1024); bank->num_sectors = bank->size / mspm0_info->sector_size; /* --
