openocd/src/flash/nor/ambiqmicro.c
Rick Foos 060e9c3b36 flash/nor: Add Ambiq Micro Apollo flash driver.
Initial release of Ambiq Micro Apollo flash driver
supporting our sub-threshold (low power) Cortex M4F part,
and Evaluation Kit.

We have been shipping openocd to our customers for about one year.

The EVK boards are SWD only using ftdi. We also use two of the
other COM instances to display debug information.

It takes about 15 seconds to flash 512K, and mass erase is
about 5 seconds.

Tested by internal verification group, FAE's, and customer sites.

Merged commit 'refs/changes/17/3417/1' as suggested. Makefile.am
and drivers.c follow the new format to avoid conflicts.

Removed unused fault_capture command.

Added documentation for flash driver.

Change-Id: Iae92d869369c6827244f0071f9cb522d8d91fed8
Signed-off-by: Rick Foos <rfoos@solengtech.com>
Reviewed-on: http://openocd.zylin.com/3230
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2016-05-14 12:18:31 +01:00

905 lines
23 KiB
C

/******************************************************************************
*
* @file ambiqmicro.c
*
* @brief Ambiq Micro flash driver.
*
*****************************************************************************/
/******************************************************************************
* Copyright (c) 2015, David Racine <dracine at ambiqmicro.com>
*
* Copyright (c) 2016, Rick Foos <rfoos at solengtech.com>
*
* Copyright (c) 2015-2016, Ambiq Micro, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "jtag/interface.h"
#include "imp.h"
#include "target/algorithm.h"
#include "target/armv7m.h"
#include "target/cortex_m.h"
/** Check error, log error. */
#define CHECK_STATUS(rc, msg) { \
if (rc != ERROR_OK) { \
LOG_ERROR("status(%d):%s\n", rc, msg); } }
/*
* Address and Key defines.
*/
#define PROGRAM_KEY (0x12344321)
#define OTP_PROGRAM_KEY (0x87655678)
#define FLASH_PROGRAM_MAIN_FROM_SRAM 0x0800005d
#define FLASH_PROGRAM_OTP_FROM_SRAM 0x08000061
#define FLASH_ERASE_LIST_MAIN_PAGES_FROM_SRAM 0x08000065
#define FLASH_MASS_ERASE_MAIN_PAGES_FROM_SRAM 0x08000069
static const uint32_t apollo_flash_size[] = {
1 << 15,
1 << 16,
1 << 17,
1 << 18,
1 << 19,
1 << 20,
1 << 21
};
static const uint32_t apollo_sram_size[] = {
1 << 15,
1 << 16,
1 << 17,
1 << 18,
1 << 19,
1 << 20,
1 << 21
};
struct ambiqmicro_flash_bank {
/* chip id register */
uint32_t probed;
const char *target_name;
uint8_t target_class;
uint32_t sramsiz;
uint32_t flshsiz;
/* flash geometry */
uint32_t num_pages;
uint32_t pagesize;
uint32_t pages_in_lockregion;
/* nv memory bits */
uint16_t num_lockbits;
/* main clock status */
uint32_t rcc;
uint32_t rcc2;
uint8_t mck_valid;
uint8_t xtal_mask;
uint32_t iosc_freq;
uint32_t mck_freq;
const char *iosc_desc;
const char *mck_desc;
};
static struct {
uint8_t class;
uint8_t partno;
const char *partname;
} ambiqmicroParts[6] = {
{0xFF, 0x00, "Unknown"},
{0x01, 0x00, "Apollo"},
{0x02, 0x00, "Apollo2"},
{0x03, 0x00, "Unknown"},
{0x04, 0x00, "Unknown"},
{0x05, 0x00, "Apollo"},
};
static char *ambiqmicroClassname[6] = {
"Unknown", "Apollo", "Apollo2", "Unknown", "Unknown", "Apollo"
};
/***************************************************************************
* openocd command interface *
***************************************************************************/
/* flash_bank ambiqmicro <base> <size> 0 0 <target#>
*/
FLASH_BANK_COMMAND_HANDLER(ambiqmicro_flash_bank_command)
{
struct ambiqmicro_flash_bank *ambiqmicro_info;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
ambiqmicro_info = calloc(sizeof(struct ambiqmicro_flash_bank), 1);
bank->driver_priv = ambiqmicro_info;
ambiqmicro_info->target_name = "Unknown target";
/* part wasn't probed yet */
ambiqmicro_info->probed = 0;
return ERROR_OK;
}
static int get_ambiqmicro_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv;
int printed;
char *classname;
if (ambiqmicro_info->probed == 0) {
LOG_ERROR("Target not probed");
return ERROR_FLASH_BANK_NOT_PROBED;
}
/* Check class name in range. */
if (ambiqmicro_info->target_class < sizeof(ambiqmicroClassname))
classname = ambiqmicroClassname[ambiqmicro_info->target_class];
else
classname = ambiqmicroClassname[0];
printed = snprintf(buf,
buf_size,
"\nAmbiq Micro information: Chip is "
"class %d (%s) %s\n",
ambiqmicro_info->target_class,
classname,
ambiqmicro_info->target_name);
if ((printed < 0))
return ERROR_BUF_TOO_SMALL;
return ERROR_OK;
}
/***************************************************************************
* chip identification and status *
***************************************************************************/
/* Fill in driver info structure */
static int ambiqmicro_read_part_info(struct flash_bank *bank)
{
struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t PartNum = 0;
int retval;
/*
* Read Part Number.
*/
retval = target_read_u32(target, 0x40020000, &PartNum);
if (retval != ERROR_OK) {
LOG_ERROR("status(0x%x):Could not read PartNum.\n", retval);
/* Set PartNum to default device */
PartNum = 0;
}
LOG_DEBUG("Part number: 0x%x", PartNum);
/*
* Determine device class.
*/
ambiqmicro_info->target_class = (PartNum & 0xFF000000) >> 24;
switch (ambiqmicro_info->target_class) {
case 1: /* 1 - Apollo */
case 5: /* 5 - Apollo Bootloader */
bank->base = bank->bank_number * 0x40000;
ambiqmicro_info->pagesize = 2048;
ambiqmicro_info->flshsiz =
apollo_flash_size[(PartNum & 0x00F00000) >> 20];
ambiqmicro_info->sramsiz =
apollo_sram_size[(PartNum & 0x000F0000) >> 16];
ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz /
ambiqmicro_info->pagesize;
if (ambiqmicro_info->num_pages > 128) {
ambiqmicro_info->num_pages = 128;
ambiqmicro_info->flshsiz = 1024 * 256;
}
break;
default:
LOG_INFO("Unknown Class. Using Apollo-64 as default.");
bank->base = bank->bank_number * 0x40000;
ambiqmicro_info->pagesize = 2048;
ambiqmicro_info->flshsiz = apollo_flash_size[1];
ambiqmicro_info->sramsiz = apollo_sram_size[0];
ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz /
ambiqmicro_info->pagesize;
if (ambiqmicro_info->num_pages > 128) {
ambiqmicro_info->num_pages = 128;
ambiqmicro_info->flshsiz = 1024 * 256;
}
break;
}
if (ambiqmicro_info->target_class <
(sizeof(ambiqmicroParts)/sizeof(ambiqmicroParts[0])))
ambiqmicro_info->target_name =
ambiqmicroParts[ambiqmicro_info->target_class].partname;
else
ambiqmicro_info->target_name =
ambiqmicroParts[0].partname;
LOG_DEBUG("num_pages: %d, pagesize: %d, flash: %d, sram: %d",
ambiqmicro_info->num_pages,
ambiqmicro_info->pagesize,
ambiqmicro_info->flshsiz,
ambiqmicro_info->sramsiz);
return ERROR_OK;
}
/***************************************************************************
* flash operations *
***************************************************************************/
static int ambiqmicro_protect_check(struct flash_bank *bank)
{
struct ambiqmicro_flash_bank *ambiqmicro = bank->driver_priv;
int status = ERROR_OK;
uint32_t i;
if (ambiqmicro->probed == 0) {
LOG_ERROR("Target not probed");
return ERROR_FLASH_BANK_NOT_PROBED;
}
for (i = 0; i < (unsigned) bank->num_sectors; i++)
bank->sectors[i].is_protected = -1;
return status;
}
/** Read flash status from bootloader. */
static int check_flash_status(struct target *target, uint32_t address)
{
uint32_t retflash;
int rc;
rc = target_read_u32(target, address, &retflash);
/* target connection failed. */
if (rc != ERROR_OK) {
LOG_DEBUG("%s:%d:%s(): status(0x%x)\n",
__FILE__, __LINE__, __func__, rc);
return rc;
}
/* target flash failed, unknown cause. */
if (retflash != 0) {
LOG_ERROR("Flash not happy: status(0x%x)", retflash);
return ERROR_FLASH_OPERATION_FAILED;
}
return ERROR_OK;
}
static int ambiqmicro_exec_command(struct target *target,
uint32_t command,
uint32_t flash_return_address)
{
int retval, retflash;
retval = target_resume(
target,
false,
command,
true,
true);
CHECK_STATUS(retval, "error executing ambiqmicro command");
/*
* Wait for halt.
*/
for (;; ) {
target_poll(target);
if (target->state == TARGET_HALTED)
break;
else if (target->state == TARGET_RUNNING ||
target->state == TARGET_DEBUG_RUNNING) {
/*
* Keep polling until target halts.
*/
target_poll(target);
alive_sleep(100);
LOG_DEBUG("state = %d", target->state);
} else {
LOG_ERROR("Target not halted or running %d", target->state);
break;
}
}
/*
* Read return value, flash error takes precedence.
*/
retflash = check_flash_status(target, flash_return_address);
if (retflash != ERROR_OK)
retval = retflash;
/* Return code from target_resume OR flash. */
return retval;
}
static int ambiqmicro_mass_erase(struct flash_bank *bank)
{
struct target *target = NULL;
struct ambiqmicro_flash_bank *ambiqmicro_info = NULL;
int retval = ERROR_OK;
ambiqmicro_info = bank->driver_priv;
target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (ambiqmicro_info->probed == 0) {
LOG_ERROR("Target not probed");
return ERROR_FLASH_BANK_NOT_PROBED;
}
/*
* Clear Bootloader bit.
*/
retval = target_write_u32(target, 0x400201a0, 0x0);
CHECK_STATUS(retval, "error clearing bootloader bit.");
/*
* Set up the SRAM.
*/
/*
* Bank.
*/
retval = target_write_u32(target, 0x10000000, bank->bank_number);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Write Key.
*/
retval = target_write_u32(target, 0x10000004, PROGRAM_KEY);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Breakpoint.
*/
retval = target_write_u32(target, 0x10000008, 0xfffffffe);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Erase the main array.
*/
LOG_INFO("Mass erase on bank %d.", bank->bank_number);
/*
* passed pc, addr = ROM function, handle breakpoints, not debugging.
*/
retval = ambiqmicro_exec_command(target, FLASH_MASS_ERASE_MAIN_PAGES_FROM_SRAM, 0x10000008);
CHECK_STATUS(retval, "error executing ambiqmicro flash mass erase.");
if (retval != ERROR_OK)
return retval;
/*
* Set Bootloader bit, regardless of command execution.
*/
retval = target_write_u32(target, 0x400201a0, 0x1);
CHECK_STATUS(retval, "error setting bootloader bit.");
return retval;
}
static int ambiqmicro_erase(struct flash_bank *bank, int first, int last)
{
struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t retval = ERROR_OK;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (ambiqmicro_info->probed == 0) {
LOG_ERROR("Target not probed");
return ERROR_FLASH_BANK_NOT_PROBED;
}
/*
* Check pages.
* Fix num_pages for the device.
*/
if ((first < 0) || (last < first) || (last >= (int)ambiqmicro_info->num_pages))
return ERROR_FLASH_SECTOR_INVALID;
/*
* Just Mass Erase if all pages are given.
* TODO: Fix num_pages for the device
*/
if ((first == 0) && (last == ((int)ambiqmicro_info->num_pages-1)))
return ambiqmicro_mass_erase(bank);
/*
* Clear Bootloader bit.
*/
retval = target_write_u32(target, 0x400201a0, 0x0);
CHECK_STATUS(retval, "error clearing bootloader bit.");
/*
* Set up the SRAM.
*/
/*
* Bank.
*/
retval = target_write_u32(target, 0x10000000, bank->bank_number);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Number of pages to erase.
*/
retval = target_write_u32(target, 0x10000004, 1 + (last-first));
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Write Key.
*/
retval = target_write_u32(target, 0x10000008, PROGRAM_KEY);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Breakpoint.
*/
retval = target_write_u32(target, 0x1000000c, 0xfffffffe);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Pointer to flash address.
*/
retval = target_write_u32(target, 0x10000010, first);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
if (retval != ERROR_OK)
return retval;
/*
* Erase the pages.
*/
LOG_INFO("Erasing pages %d to %d on bank %d", first, last, bank->bank_number);
/*
* passed pc, addr = ROM function, handle breakpoints, not debugging.
*/
retval = ambiqmicro_exec_command(target, FLASH_ERASE_LIST_MAIN_PAGES_FROM_SRAM, 0x1000000C);
CHECK_STATUS(retval, "error executing flash page erase");
if (retval != ERROR_OK)
return retval;
LOG_INFO("%d pages erased!", 1+(last-first));
if (first == 0) {
/*
* Set Bootloader bit.
*/
retval = target_write_u32(target, 0x400201a0, 0x1);
CHECK_STATUS(retval, "error setting bootloader bit.");
if (retval != ERROR_OK)
return retval;
}
return retval;
}
static int ambiqmicro_protect(struct flash_bank *bank, int set, int first, int last)
{
/* struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv;
* struct target *target = bank->target; */
/*
* TODO
*/
LOG_INFO("Not yet implemented");
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
return ERROR_OK;
}
static int ambiqmicro_write_block(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
/* struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; */
struct target *target = bank->target;
uint32_t address = bank->base + offset;
uint32_t buffer_pointer = 0x10000010;
uint32_t maxbuffer;
uint32_t thisrun_count;
int retval = ERROR_OK;
if (((count%4) != 0) || ((offset%4) != 0)) {
LOG_ERROR("write block must be multiple of 4 bytes in offset & length");
return ERROR_FAIL;
}
/*
* Max buffer size for this device.
* Hard code 6kB for the buffer.
*/
maxbuffer = 0x1800;
LOG_INFO("Flashing main array");
while (count > 0) {
if (count > maxbuffer)
thisrun_count = maxbuffer;
else
thisrun_count = count;
/*
* Set up the SRAM.
*/
/*
* Pointer to flash.
*/
retval = target_write_u32(target, 0x10000000, address);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Number of 32-bit words to program.
*/
retval = target_write_u32(target, 0x10000004, thisrun_count/4);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Write Key.
*/
retval = target_write_u32(target, 0x10000008, PROGRAM_KEY);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Breakpoint.
*/
retval = target_write_u32(target, 0x1000000c, 0xfffffffe);
CHECK_STATUS(retval, "error writing target SRAM parameters.");
/*
* Write Buffer.
*/
retval = target_write_buffer(target, buffer_pointer, thisrun_count, buffer);
if (retval != ERROR_OK) {
CHECK_STATUS(retval, "error writing target SRAM parameters.");
break;
}
LOG_DEBUG("address = 0x%08x", address);
retval = ambiqmicro_exec_command(target, FLASH_PROGRAM_MAIN_FROM_SRAM, 0x1000000c);
CHECK_STATUS(retval, "error executing ambiqmicro flash write algorithm");
if (retval != ERROR_OK)
break;
buffer += thisrun_count;
address += thisrun_count;
count -= thisrun_count;
}
LOG_INFO("Main array flashed");
/*
* Clear Bootloader bit.
*/
retval = target_write_u32(target, 0x400201a0, 0x0);
CHECK_STATUS(retval, "error clearing bootloader bit");
return retval;
}
static int ambiqmicro_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
uint32_t retval;
/* try using a block write */
retval = ambiqmicro_write_block(bank, buffer, offset, count);
if (retval != ERROR_OK)
LOG_ERROR("write failed");
return retval;
}
static int ambiqmicro_probe(struct flash_bank *bank)
{
struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv;
uint32_t retval;
/* If this is a ambiqmicro chip, it has flash; probe() is just
* to figure out how much is present. Only do it once.
*/
if (ambiqmicro_info->probed == 1) {
LOG_INFO("Target already probed");
return ERROR_OK;
}
/* ambiqmicro_read_part_info() already handled error checking and
* reporting. Note that it doesn't write, so we don't care about
* whether the target is halted or not.
*/
retval = ambiqmicro_read_part_info(bank);
if (retval != ERROR_OK)
return retval;
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
/* provide this for the benefit of the NOR flash framework */
bank->size = ambiqmicro_info->pagesize * ambiqmicro_info->num_pages;
bank->num_sectors = ambiqmicro_info->num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = i * ambiqmicro_info->pagesize;
bank->sectors[i].size = ambiqmicro_info->pagesize;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
/*
* Part has been probed.
*/
ambiqmicro_info->probed = 1;
return retval;
}
static int ambiqmicro_otp_program(struct flash_bank *bank,
uint32_t offset, uint32_t count)
{
struct target *target = NULL;
struct ambiqmicro_flash_bank *ambiqmicro_info = NULL;
uint32_t retval = ERROR_OK;
ambiqmicro_info = bank->driver_priv;
target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (ambiqmicro_info->probed == 0) {
LOG_ERROR("Target not probed");
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (count > 256) {
LOG_ERROR("Count must be < 256");
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
/*
* Clear Bootloader bit.
*/
retval = target_write_u32(target, 0x400201a0, 0x0);
CHECK_STATUS(retval, "error clearing bootloader bit.");
/*
* Set up the SRAM.
*/
/*
* Bank.
*/
retval = target_write_u32(target, 0x10000000, offset);
CHECK_STATUS(retval, "error setting target SRAM parameters.");
/*
* Num of words to program.
*/
retval = target_write_u32(target, 0x10000004, count);
CHECK_STATUS(retval, "error setting target SRAM parameters.");
/*
* Write Key.
*/
retval = target_write_u32(target, 0x10000008, OTP_PROGRAM_KEY);
CHECK_STATUS(retval, "error setting target SRAM parameters.");
/*
* Breakpoint.
*/
retval = target_write_u32(target, 0x1000000c, 0xfffffffe);
CHECK_STATUS(retval, "error setting target SRAM parameters.");
if (retval != ERROR_OK)
return retval;
/*
* Program OTP.
*/
LOG_INFO("Programming OTP offset 0x%08x", offset);
/*
* passed pc, addr = ROM function, handle breakpoints, not debugging.
*/
retval = ambiqmicro_exec_command(target, FLASH_PROGRAM_OTP_FROM_SRAM, 0x1000000C);
CHECK_STATUS(retval, "error executing ambiqmicro otp program algorithm");
LOG_INFO("Programming OTP finished.");
return retval;
}
COMMAND_HANDLER(ambiqmicro_handle_mass_erase_command)
{
int i;
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
uint32_t retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
if (ambiqmicro_mass_erase(bank) == ERROR_OK) {
/* set all sectors as erased */
for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD_CTX, "ambiqmicro mass erase complete");
} else
command_print(CMD_CTX, "ambiqmicro mass erase failed");
return ERROR_OK;
}
COMMAND_HANDLER(ambiqmicro_handle_page_erase_command)
{
struct flash_bank *bank;
uint32_t first, last;
uint32_t retval;
if (CMD_ARGC < 3)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
if (ambiqmicro_erase(bank, first, last) == ERROR_OK)
command_print(CMD_CTX, "ambiqmicro page erase complete");
else
command_print(CMD_CTX, "ambiqmicro page erase failed");
return ERROR_OK;
}
/**
* Program the otp block.
*/
COMMAND_HANDLER(ambiqmicro_handle_program_otp_command)
{
struct flash_bank *bank;
uint32_t offset, count;
uint32_t retval;
if (CMD_ARGC < 3)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], offset);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
command_print(CMD_CTX, "offset=0x%08x count=%d", offset, count);
CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
retval = ambiqmicro_otp_program(bank, offset, count);
if (retval != ERROR_OK)
LOG_ERROR("error check log");
return ERROR_OK;
}
static const struct command_registration ambiqmicro_exec_command_handlers[] = {
{
.name = "mass_erase",
.usage = "<bank>",
.handler = ambiqmicro_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase entire device",
},
{
.name = "page_erase",
.usage = "<bank> <first> <last>",
.handler = ambiqmicro_handle_page_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase device pages",
},
{
.name = "program_otp",
.handler = ambiqmicro_handle_program_otp_command,
.mode = COMMAND_EXEC,
.usage = "<bank> <offset> <count>",
.help =
"Program OTP (assumes you have already written array starting at 0x10000010)",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration ambiqmicro_command_handlers[] = {
{
.name = "ambiqmicro",
.mode = COMMAND_EXEC,
.help = "ambiqmicro flash command group",
.usage = "Support for Ambiq Micro parts.",
.chain = ambiqmicro_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver ambiqmicro_flash = {
.name = "ambiqmicro",
.commands = ambiqmicro_command_handlers,
.flash_bank_command = ambiqmicro_flash_bank_command,
.erase = ambiqmicro_erase,
.protect = ambiqmicro_protect,
.write = ambiqmicro_write,
.read = default_flash_read,
.probe = ambiqmicro_probe,
.auto_probe = ambiqmicro_probe,
.erase_check = default_flash_blank_check,
.protect_check = ambiqmicro_protect_check,
.info = get_ambiqmicro_info,
};