This is an automated email from Gerrit. "Sameer Srivastava <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9527
-- gerrit commit 99e9a4a6b32116f3ce9331b8e066a183d7d6d537 Author: Sameer Srivastava <[email protected]> Date: Sun Mar 8 12:15:13 2026 +0530 src: flash: nor: added am13e230x flash driver Flashing uses the am13e230x flash loader that runs from SRAM, matching the CC26xx pattern. The algorithm is loaded into SRAM and started via target_start_algorithm. OpenOCD streams sector data into two ping-pong buffers; the algorithm erases each sector and programs it using direct FCTL register access. Signed-off-by: Sameer Srivastava <[email protected]> Change-Id: Ifb910a545146514574fb4efecc3ad5aec38e2576 diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 5c4737f7ac..e2b72dd2b4 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -11,6 +11,7 @@ noinst_LTLIBRARIES += %D%/libocdflashnor.la NOR_DRIVERS = \ %D%/aduc702x.c \ %D%/aducm360.c \ + %D%/am13e230x.c \ %D%/ambiqmicro.c \ %D%/artery.c \ %D%/at91sam4.c \ diff --git a/src/flash/nor/am13e230x.c b/src/flash/nor/am13e230x.c new file mode 100644 index 0000000000..8f9d5632fc --- /dev/null +++ b/src/flash/nor/am13e230x.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/ + * + * NOR flash driver for AM13E230X class of uC from Texas Instruments. + * + * Erase uses direct register writes via the debug probe. + * Write uses an on-device algorithm loaded into SRAM (see + * contrib/loaders/flash/am13e230x/ and am13e230x.h). + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "am13e230x.h" +#include <helper/binarybuffer.h> +#include <helper/bits.h> +#include <helper/time_support.h> +#include <target/algorithm.h> +#include <target/armv7m.h> + +/* Region memory map */ +#define AM13_FLASH_BASE_MAIN 0x00000000 +#define AM13_FLASH_BASE_NONMAIN 0x60100000 +#define AM13_NONMAIN_SIZE_PER_BANK 0x1000 + +/* Factory region registers */ +#define AM13_FACTORYREGION 0x60111000 +#define AM13_TRACEID (AM13_FACTORYREGION + 0x000) +#define AM13_DID (AM13_FACTORYREGION + 0x004) +#define AM13_SRAMFLASH (AM13_FACTORYREGION + 0x01C) + +/* Flash controller (NVMNW) registers */ +#define FLASH_CONTROL_BASE 0x40042000 +#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_CMDDATAINDEX (FLASH_CONTROL_BASE + 0x112C) +#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) + +/* GSC flash semaphore registers */ +#define GSC_BASE 0x40046000 +#define GSC_REG_FPC_FLSEMREQ (GSC_BASE + 0x1800) +#define GSC_REG_FPC_FLSEMCLR (GSC_BASE + 0x1804) + +/* STATCMD bits */ +#define FCTL_STATCMD_CMDDONE 0x00000001 +#define FCTL_STATCMD_CMDPASS 0x00000002 +#define FCTL_STATCMD_CMDINPROGRESS 0x00000004 + +/* CMDEXEC / CMDTYPE constants */ +#define FCTL_CMDEXEC_EXECUTE 0x00000001 +#define FCTL_CMDTYPE_PROGRAM 0x00000001 +#define FCTL_CMDTYPE_ERASE 0x00000002 +#define FCTL_CMDTYPE_CLEARSTATUS 0x00000005 +#define FCTL_CMDTYPE_SIZE_ONEWORD 0x00000000 +#define FCTL_CMDTYPE_SIZE_SECTOR 0x00000040 + +/* 128-bit program with hardware ECC generation (matches SDK PROGRAM_128_WITH_ECC) */ +#define AM13_PROGRAM_128_BYTEN 0x0003FFFF + +#define AM13_FLASH_WORD_SIZE 16 + +#define AM13_FLASH_TIMEOUT_MS 8000 +#define AM13_SECTOR_SIZE_BYTES 0x800 +#define TI_MANUFACTURER_ID 0x17 + +/* Flash loader algorithm binary */ +static const uint8_t am13_algo[] = { +#include "../../../contrib/loaders/flash/am13e230x/am13e230x_algo.inc" +}; + +struct am13_flash_bank { + uint32_t did; + uint32_t traceid; + unsigned int main_flash_size_kb; + unsigned int main_flash_num_banks; + unsigned int sram_size_kb; + unsigned int sector_size; + + /* Algorithm state */ + struct working_area *working_area; + struct armv7m_algorithm armv7m_info; +}; + +static int am13_auto_probe(struct flash_bank *bank); + +/* + * GSC flash semaphore must be held before any flash operation. + * The debug probe and the CPU have separate ownership tracking + * (FLSEMSTAT.DBGACC), so the erase path (debug probe) and the + * write path (on-device algorithm) each acquire it independently. + */ + +static void am13_request_gsc_semaphore(struct flash_bank *bank) +{ + target_write_u32(bank->target, GSC_REG_FPC_FLSEMREQ, 1); +} + +static void am13_clear_gsc_semaphore(struct flash_bank *bank) +{ + target_write_u32(bank->target, GSC_REG_FPC_FLSEMCLR, 1); +} + +/* ---------- Flash controller helpers (erase path only) ---------- */ + +static const struct { + unsigned char bit; + const char *name; +} am13_fctl_errors[] = { + { 2, "CMDINPROGRESS" }, + { 4, "FAILWEPROT" }, + { 5, "FAILVERIFY" }, + { 6, "FAILILLADDR" }, + { 7, "FAILMODE" }, + { 12, "FAILMISC" }, +}; + +static const char *am13_fctl_strerror(uint32_t status) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(am13_fctl_errors); i++) { + if (status & BIT(am13_fctl_errors[i].bit)) + return am13_fctl_errors[i].name; + } + return "FAILUNKNOWN"; +} + +static int am13_fctl_wait_done(struct flash_bank *bank) +{ + struct target *target = bank->target; + uint32_t status = 0; + int64_t start_ms = timeval_ms(); + + while ((status & FCTL_STATCMD_CMDDONE) == 0) { + int retval = target_read_u32(target, FCTL_REG_STATCMD, &status); + if (retval != ERROR_OK) + return retval; + if (timeval_ms() - start_ms > AM13_FLASH_TIMEOUT_MS) + break; + keep_alive(); + } + + if ((status & FCTL_STATCMD_CMDPASS) == 0) { + LOG_ERROR("Flash command failed: %s", am13_fctl_strerror(status)); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int am13_fctl_clear_status(struct flash_bank *bank) +{ + struct target *target = bank->target; + uint32_t status; + int64_t start_ms; + int retval; + + retval = target_write_u32(target, FCTL_REG_CMDTYPE, FCTL_CMDTYPE_CLEARSTATUS); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, FCTL_REG_CMDEXEC, FCTL_CMDEXEC_EXECUTE); + if (retval != ERROR_OK) + return retval; + + start_ms = timeval_ms(); + do { + retval = target_read_u32(target, FCTL_REG_STATCMD, &status); + if (retval != ERROR_OK) + return retval; + if (timeval_ms() - start_ms > AM13_FLASH_TIMEOUT_MS) { + LOG_ERROR("Timeout waiting for clear status"); + return ERROR_FAIL; + } + keep_alive(); + } while (status & FCTL_STATCMD_CMDINPROGRESS); + + return ERROR_OK; +} + +static int am13_fctl_unprotect(struct flash_bank *bank) +{ + struct target *target = bank->target; + int retval; + + switch (bank->base) { + case AM13_FLASH_BASE_MAIN: + retval = target_write_u32(target, FCTL_REG_CMDWEPROTA, 0); + if (retval != ERROR_OK) + return retval; + return target_write_u32(target, FCTL_REG_CMDWEPROTB, 0); + case AM13_FLASH_BASE_NONMAIN: + return target_write_u32(target, FCTL_REG_CMDWEPROTNM, 0); + default: + return ERROR_FLASH_BANK_INVALID; + } +} + +static int am13_fctl_sector_erase(struct flash_bank *bank, uint32_t addr) +{ + struct target *target = bank->target; + int retval; + + retval = am13_fctl_clear_status(bank); + if (retval != ERROR_OK) + return retval; + + retval = am13_fctl_unprotect(bank); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, FCTL_REG_CMDTYPE, + FCTL_CMDTYPE_ERASE | FCTL_CMDTYPE_SIZE_SECTOR); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, FCTL_REG_CMDADDR, addr); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, FCTL_REG_CMDEXEC, FCTL_CMDEXEC_EXECUTE); + if (retval != ERROR_OK) + return retval; + + return am13_fctl_wait_done(bank); +} + +/* ---------- Flash driver callbacks ---------- */ + +FLASH_BANK_COMMAND_HANDLER(am13_flash_bank_command) +{ + switch (bank->base) { + case AM13_FLASH_BASE_MAIN: + case AM13_FLASH_BASE_NONMAIN: + break; + default: + LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FAIL; + } + + struct am13_flash_bank *am13_info = calloc(1, sizeof(*am13_info)); + if (!am13_info) + return ERROR_FAIL; + + bank->driver_priv = am13_info; + am13_info->sector_size = AM13_SECTOR_SIZE_BYTES; + + return ERROR_OK; +} + +static int am13_protect_check(struct flash_bank *bank) +{ + struct am13_flash_bank *am13_info = bank->driver_priv; + + if (!am13_info->did) + return ERROR_FLASH_BANK_NOT_PROBED; + + /* Protection resets after every operation; report as unprotected */ + for (unsigned int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = 0; + + return ERROR_OK; +} + +static int am13_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct am13_flash_bank *am13_info = bank->driver_priv; + int retval; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!am13_info->did) + return ERROR_FLASH_BANK_NOT_PROBED; + + am13_request_gsc_semaphore(bank); + + for (unsigned int s = first; s <= last; s++) { + uint32_t addr; + + if (bank->base == AM13_FLASH_BASE_NONMAIN) + addr = AM13_FLASH_BASE_NONMAIN + s * am13_info->sector_size; + else + addr = s * am13_info->sector_size; + + retval = am13_fctl_sector_erase(bank, addr); + if (retval != ERROR_OK) { + LOG_ERROR("Sector erase failed at 0x%08" PRIx32, addr); + am13_clear_gsc_semaphore(bank); + return retval; + } + } + + am13_clear_gsc_semaphore(bank); + return ERROR_OK; +} + +/* ---------- Direct write fallback (via debug probe) ---------- */ + +/* + * Word-by-word flash write using direct register access from the debug + * probe. Slower than the on-device algorithm but does not require SRAM, + * so it works as a fallback when the algorithm cannot be loaded (e.g., + * SRAM is needed by a RAM-resident application). + */ +static int am13_write_direct(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + uint32_t addr = bank->base + offset; + int retval; + + am13_request_gsc_semaphore(bank); + + while (count > 0) { + uint32_t n = MIN(count, AM13_FLASH_WORD_SIZE); + uint8_t word[AM13_FLASH_WORD_SIZE]; + + /* Pad partial words with 0xFF */ + memset(word, 0xFF, sizeof(word)); + memcpy(word, buffer, n); + + /* Clear status + unprotect before every word (per SDK) */ + retval = am13_fctl_clear_status(bank); + if (retval != ERROR_OK) + break; + + retval = am13_fctl_unprotect(bank); + if (retval != ERROR_OK) + break; + + retval = target_write_u32(target, FCTL_REG_CMDTYPE, + FCTL_CMDTYPE_PROGRAM | FCTL_CMDTYPE_SIZE_ONEWORD); + if (retval != ERROR_OK) + break; + + retval = target_write_u32(target, FCTL_REG_CMDBYTEN, + AM13_PROGRAM_128_BYTEN); + if (retval != ERROR_OK) + break; + + retval = target_write_u32(target, FCTL_REG_CMDADDR, + addr & 0xFFFFFFF0); + if (retval != ERROR_OK) + break; + + retval = target_write_u32(target, FCTL_REG_CMDDATAINDEX, + (addr >> 4) & 3); + if (retval != ERROR_OK) + break; + + retval = target_write_buffer(target, FCTL_REG_CMDDATA0, + AM13_FLASH_WORD_SIZE, word); + if (retval != ERROR_OK) + break; + + retval = target_write_u32(target, FCTL_REG_CMDEXEC, + FCTL_CMDEXEC_EXECUTE); + if (retval != ERROR_OK) + break; + + retval = am13_fctl_wait_done(bank); + if (retval != ERROR_OK) + break; + + addr += n; + buffer += n; + count -= n; + } + + am13_clear_gsc_semaphore(bank); + return retval; +} + +/* ---------- Flash loader algorithm ---------- */ + +static int am13_algo_init(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct am13_flash_bank *am13_info = bank->driver_priv; + int retval; + + retval = am13_auto_probe(bank); + if (retval != ERROR_OK) + return retval; + + /* Allocate SRAM for algorithm + buffers */ + target_free_working_area(target, am13_info->working_area); + am13_info->working_area = NULL; + + retval = target_alloc_working_area(target, AM13_ALGO_WORKING_SIZE, + &am13_info->working_area); + if (retval != ERROR_OK) { + LOG_ERROR("AM13: insufficient SRAM for flash loader (%u bytes)", + AM13_ALGO_WORKING_SIZE); + return retval; + } + + if (am13_info->working_area->address != AM13_ALGO_BASE) { + LOG_ERROR("AM13: working area at wrong address"); + target_free_working_area(target, am13_info->working_area); + am13_info->working_area = NULL; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = target_write_buffer(target, AM13_ALGO_BASE, + sizeof(am13_algo), am13_algo); + if (retval != ERROR_OK) { + LOG_ERROR("AM13: failed to load flash algorithm"); + target_free_working_area(target, am13_info->working_area); + am13_info->working_area = NULL; + return retval; + } + + /* + * Release any debug-held GSC semaphore so the algorithm (CPU) + * can acquire it — the flash controller tracks ownership via + * FLSEMSTAT.DBGACC and rejects mismatched access. + */ + am13_clear_gsc_semaphore(bank); + + /* Disable NVIC — stale Zephyr ISRs would fault on overwritten SRAM */ + for (uint32_t icer = 0xE000E180; icer <= 0xE000E19C; icer += 4) + target_write_u32(target, icer, 0xFFFFFFFF); + + /* Disable MPU — previous app may restrict peripheral access */ + target_write_u32(target, 0xE000ED94, 0x00000000); + + am13_info->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + am13_info->armv7m_info.core_mode = ARM_MODE_THREAD; + + /* + * Force privileged Thread mode via reg_param. OpenOCD's + * armv7m_start_algorithm only updates CONTROL when the requested + * mode differs from current — but if Zephyr was also in Thread + * mode with nPRIV=1, CONTROL is left untouched and the algorithm + * inherits unprivileged mode. + */ + struct reg_param reg_params[1]; + init_reg_param(®_params[0], "pmsk_bpri_fltmsk_ctrl", 32, PARAM_OUT); + buf_set_u32(reg_params[0].value, 0, 32, 0x00000000); + + LOG_DEBUG("AM13: starting flash algorithm"); + retval = target_start_algorithm(target, 0, NULL, 1, reg_params, + AM13_ALGO_BASE, 0, + &am13_info->armv7m_info); + + destroy_reg_param(®_params[0]); + + if (retval != ERROR_OK) { + LOG_ERROR("AM13: failed to start flash algorithm"); + target_free_working_area(target, am13_info->working_area); + am13_info->working_area = NULL; + } + + return retval; +} + +static int am13_algo_quit(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct am13_flash_bank *am13_info = bank->driver_priv; + + (void)target_halt(target); + + int retval = target_wait_algorithm(target, 0, NULL, 0, NULL, + 0, AM13_FLASH_TIMEOUT_MS, + &am13_info->armv7m_info); + + am13_clear_gsc_semaphore(bank); + + target_free_working_area(target, am13_info->working_area); + am13_info->working_area = NULL; + + return retval; +} + +static int am13_algo_wait_done(struct flash_bank *bank, uint32_t params_addr) +{ + struct target *target = bank->target; + uint32_t status = AM13_BUFFER_FULL; + int64_t start_ms = timeval_ms(); + int retval; + + while (status == AM13_BUFFER_FULL) { + retval = target_read_u32(target, params_addr + AM13_STATUS_OFFSET, + &status); + if (retval != ERROR_OK) + return retval; + + int64_t elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > 500) + keep_alive(); + if (elapsed_ms > AM13_FLASH_TIMEOUT_MS) + break; + } + + if (status != AM13_BUFFER_EMPTY) { + LOG_ERROR("AM13: flash algorithm error, status=0x%08" PRIx32, + status); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int am13_write(struct flash_bank *bank, const unsigned char *buffer, + unsigned int offset, unsigned int count) +{ + struct target *target = bank->target; + struct am13_flash_bank *am13_info = bank->driver_priv; + struct am13_algo_params algo_params[2]; + int retval; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!am13_info->did) + return ERROR_FLASH_BANK_NOT_PROBED; + + retval = am13_algo_init(bank); + if (retval != ERROR_OK) { + LOG_INFO("AM13: algorithm unavailable, falling back to direct writes"); + return am13_write_direct(bank, buffer, offset, count); + } + + static const uint32_t params_addr[] = { + AM13_ALGO_PARAMS_0, AM13_ALGO_PARAMS_1 + }; + static const uint32_t buffer_addr[] = { + AM13_ALGO_BUFFER_0, AM13_ALGO_BUFFER_1 + }; + + uint32_t address = bank->base + offset; + uint32_t index = 0; + int64_t start_ms = timeval_ms(); + + buf_set_u32(algo_params[0].cmd, 0, 32, AM13_CMD_ERASE_AND_PROGRAM); + buf_set_u32(algo_params[1].cmd, 0, 32, AM13_CMD_ERASE_AND_PROGRAM); + + while (count > 0) { + uint32_t size = MIN(count, AM13_SECTOR_SIZE_BYTES); + + retval = target_write_buffer(target, buffer_addr[index], + size, buffer); + if (retval != ERROR_OK) + break; + + buf_set_u32(algo_params[index].dest, 0, 32, address); + buf_set_u32(algo_params[index].len, 0, 32, size); + buf_set_u32(algo_params[index].status, 0, 32, AM13_BUFFER_FULL); + + /* Write dest/len/cmd/status only — preserve algorithm's buf_addr */ + retval = target_write_buffer(target, params_addr[index], + offsetof(struct am13_algo_params, buf_addr), + (uint8_t *)&algo_params[index]); + if (retval != ERROR_OK) + break; + + index ^= 1; + retval = am13_algo_wait_done(bank, params_addr[index]); + if (retval != ERROR_OK) + break; + + count -= size; + buffer += size; + address += size; + + if (timeval_ms() - start_ms > 500) + keep_alive(); + } + + /* Wait for the last submitted buffer */ + if (retval == ERROR_OK) { + index ^= 1; + retval = am13_algo_wait_done(bank, params_addr[index]); + } + + (void)am13_algo_quit(bank); + return retval; +} + +/* ---------- Probe ---------- */ + +static int am13_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct am13_flash_bank *am13_info = bank->driver_priv; + uint32_t did, sramflash; + int retval; + + retval = target_read_u32(target, AM13_DID, &did); + if (retval != ERROR_OK) + return retval; + + if (((did & GENMASK(11, 1)) >> 1) != TI_MANUFACTURER_ID) { + LOG_ERROR("AM13: unexpected manufacturer ID in DID=0x%08" PRIx32, + did); + return ERROR_FAIL; + } + + am13_info->did = did; + + retval = target_read_u32(target, AM13_TRACEID, &am13_info->traceid); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, AM13_SRAMFLASH, &sramflash); + if (retval != ERROR_OK) + return retval; + + am13_info->main_flash_size_kb = sramflash & GENMASK(11, 0); + am13_info->main_flash_num_banks = (sramflash & GENMASK(13, 12)) >> 12; + am13_info->sram_size_kb = (sramflash & GENMASK(25, 16)) >> 16; + + free(bank->sectors); + bank->sectors = NULL; + + unsigned int num_sectors; + switch (bank->base) { + case AM13_FLASH_BASE_MAIN: + bank->size = am13_info->main_flash_size_kb * 1024; + num_sectors = bank->size / am13_info->sector_size; + break; + case AM13_FLASH_BASE_NONMAIN: + bank->size = am13_info->main_flash_num_banks * AM13_NONMAIN_SIZE_PER_BANK; + num_sectors = bank->size / am13_info->sector_size; + break; + default: + LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FAIL; + } + + if (num_sectors == 0) { + bank->num_sectors = 0; + bank->size = 0; + return ERROR_OK; + } + + bank->num_sectors = num_sectors; + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); + if (!bank->sectors) + return ERROR_FAIL; + + for (unsigned int i = 0; i < num_sectors; i++) { + bank->sectors[i].offset = i * am13_info->sector_size; + bank->sectors[i].size = am13_info->sector_size; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + LOG_INFO("AM13: %s flash: %u KB (%u sectors), %u bank(s), SRAM: %u KB", + (bank->base == AM13_FLASH_BASE_MAIN) ? "MAIN" : "NONMAIN", + (unsigned int)(bank->size / 1024), num_sectors, + am13_info->main_flash_num_banks, + am13_info->sram_size_kb); + + return ERROR_OK; +} + +static int am13_auto_probe(struct flash_bank *bank) +{ + struct am13_flash_bank *am13_info = bank->driver_priv; + + if (am13_info->did) + return ERROR_OK; + + return am13_probe(bank); +} + +static int get_am13_info(struct flash_bank *bank, + struct command_invocation *cmd) +{ + struct am13_flash_bank *am13_info = bank->driver_priv; + + if (!am13_info->did) + return ERROR_FLASH_BANK_NOT_PROBED; + + command_print_sameline(cmd, "AM13E23X: DID=0x%08" PRIx32 + " TRACEID=0x%08" PRIx32 + " banks=%u", + am13_info->did, am13_info->traceid, + am13_info->main_flash_num_banks); + return ERROR_OK; +} + +const struct flash_driver am13_flash = { + .name = "am13", + .flash_bank_command = am13_flash_bank_command, + .erase = am13_erase, + .protect = NULL, + .write = am13_write, + .read = default_flash_read, + .probe = am13_probe, + .auto_probe = am13_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = am13_protect_check, + .info = get_am13_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/am13e230x.h b/src/flash/nor/am13e230x.h new file mode 100644 index 0000000000..3849e5ad01 --- /dev/null +++ b/src/flash/nor/am13e230x.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/ + * + * Flash loader algorithm parameters for AM13E230X. + * Addresses must match the linker script in + * contrib/loaders/flash/am13e230x/am13e230x.lds + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_AM13E230X_H +#define OPENOCD_FLASH_NOR_AM13E230X_H + +/* Algorithm is loaded at the base of SRAM */ +#define AM13_ALGO_BASE 0x20000000 + +/* Parameter blocks (two, for ping-pong) */ +#define AM13_ALGO_PARAMS_0 0x20002000 +#define AM13_ALGO_PARAMS_1 0x20002014 + +/* Data buffers (each one sector = 2 KB) */ +#define AM13_ALGO_BUFFER_0 0x20002100 +#define AM13_ALGO_BUFFER_1 0x20002900 + +/* Total working area needed */ +#define AM13_ALGO_WORKING_SIZE (AM13_ALGO_BUFFER_1 + 0x800 - AM13_ALGO_BASE) + +/* Handshake values (must match loader main.c) */ +#define AM13_BUFFER_EMPTY 0x00000000 +#define AM13_BUFFER_FULL 0xFFFFFFFF + +/* Offset of the status field within flash_params */ +#define AM13_STATUS_OFFSET 0x0C + +/* Commands (must match loader main.c) */ +#define AM13_CMD_NO_ACTION 0 +#define AM13_CMD_ERASE_ALL 1 +#define AM13_CMD_PROGRAM 2 +#define AM13_CMD_ERASE_AND_PROGRAM 3 +#define AM13_CMD_ERASE_SECTORS 4 + +/* Parameter block layout (matches struct flash_params in loader) */ +struct am13_algo_params { + uint8_t dest[4]; + uint8_t len[4]; + uint8_t cmd[4]; + uint8_t status[4]; + uint8_t buf_addr[4]; +}; + +#endif /* OPENOCD_FLASH_NOR_AM13E230X_H */ diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index afb73a3fb2..3748292c77 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -240,6 +240,7 @@ const struct flash_driver *flash_driver_find_by_name(const char *name); // Keep in alphabetic order this list of drivers extern const struct flash_driver aduc702x_flash; extern const struct flash_driver aducm360_flash; +extern const struct flash_driver am13_flash; extern const struct flash_driver ambiqmicro_flash; extern const struct flash_driver artery_flash; extern const struct flash_driver at91sam3_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 094b5a76ba..fa3f315bac 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -19,6 +19,7 @@ static const struct flash_driver * const flash_drivers[] = { // Keep in alphabetic order the list of drivers &aduc702x_flash, &aducm360_flash, + &am13_flash, &ambiqmicro_flash, &artery_flash, &at91sam3_flash, --
