aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/openocd.texi46
-rw-r--r--src/flash/nor/Makefile.am1
-rw-r--r--src/flash/nor/ambiqmicro.c904
-rw-r--r--src/flash/nor/drivers.c2
4 files changed, 953 insertions, 0 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index ec0e9268..3e7fc7fc 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -4960,6 +4960,52 @@ flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME
@end example
@end deffn
+@deffn {Flash Driver} ambiqmicro
+@cindex ambiqmicro
+@cindex apollo
+All members of the Apollo microcontroller family from
+Ambiq Micro include internal flash and use ARM's Cortex-M4 core.
+The host connects over USB to an FTDI interface that communicates
+with the target using SWD.
+
+The @var{ambiqmicro} driver reads the Chip Information Register detect
+the device class of the MCU.
+The Flash and Sram sizes directly follow device class, and are used
+to set up the flash banks.
+If this fails, the driver will use default values set to the minimum
+sizes of an Apollo chip.
+
+All Apollo chips have two flash banks of the same size.
+In all cases the first flash bank starts at location 0,
+and the second bank starts after the first.
+
+@example
+# Flash bank 0
+flash bank $_FLASHNAME ambiqmicro 0 0x00040000 0 0 $_TARGETNAME
+# Flash bank 1 - same size as bank0, starts after bank 0.
+flash bank $_FLASHNAME ambiqmicro 0x00040000 0x00040000 0 0 $_TARGETNAME
+@end example
+
+Flash is programmed using custom entry points into the bootloader.
+This is the only way to program the flash as no flash control registers
+are available to the user.
+
+The @var{ambiqmicro} driver adds some additional commands:
+
+@deffn Command {ambiqmicro mass_erase} <bank>
+Erase entire bank.
+@end deffn
+@deffn Command {ambiqmicro page_erase} <bank> <first> <last>
+Erase device pages.
+@end deffn
+@deffn Command {ambiqmicro program_otp} <bank> <offset> <count>
+Program OTP is a one time operation to create write protected flash.
+The user writes sectors to sram starting at 0x10000010.
+Program OTP will write these sectors from sram to flash, and write protect
+the flash.
+@end deffn
+@end deffn
+
@anchor{at91samd}
@deffn {Flash Driver} at91samd
@cindex at91samd
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 3386211e..c167e8fd 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -10,6 +10,7 @@ libocdflashnor_la_SOURCES = \
NOR_DRIVERS = \
aduc702x.c \
aducm360.c \
+ ambiqmicro.c \
at91sam4.c \
at91sam4l.c \
at91samd.c \
diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c
new file mode 100644
index 00000000..b2c30e6f
--- /dev/null
+++ b/src/flash/nor/ambiqmicro.c
@@ -0,0 +1,904 @@
+/******************************************************************************
+ *
+ * @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,
+};
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index e39b37e4..57079b4a 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -24,6 +24,7 @@
extern struct flash_driver aduc702x_flash;
extern struct flash_driver aducm360_flash;
+extern struct flash_driver ambiqmicro_flash;
extern struct flash_driver at91sam3_flash;
extern struct flash_driver at91sam4_flash;
extern struct flash_driver at91sam4l_flash;
@@ -75,6 +76,7 @@ extern struct flash_driver xmc4xxx_flash;
static struct flash_driver *flash_drivers[] = {
&aduc702x_flash,
&aducm360_flash,
+ &ambiqmicro_flash,
&at91sam3_flash,
&at91sam4_flash,
&at91sam4l_flash,