aboutsummaryrefslogtreecommitdiff
path: root/src/flash/nor
diff options
context:
space:
mode:
Diffstat (limited to 'src/flash/nor')
-rw-r--r--src/flash/nor/Makefile.am2
-rw-r--r--src/flash/nor/aduc702x.c14
-rw-r--r--src/flash/nor/aducm360.c16
-rw-r--r--src/flash/nor/at91sam3.c24
-rw-r--r--src/flash/nor/at91samd.c29
-rw-r--r--src/flash/nor/ath79.c53
-rw-r--r--src/flash/nor/atsame5.c955
-rw-r--r--src/flash/nor/avrf.c16
-rw-r--r--src/flash/nor/cc26xx.c18
-rw-r--r--src/flash/nor/cc3220sf.c32
-rw-r--r--src/flash/nor/cfi.c5
-rw-r--r--src/flash/nor/core.c9
-rw-r--r--src/flash/nor/driver.h4
-rw-r--r--src/flash/nor/drivers.c4
-rw-r--r--src/flash/nor/efm32.c2
-rw-r--r--src/flash/nor/esirisc_flash.c94
-rw-r--r--src/flash/nor/faux.c13
-rw-r--r--src/flash/nor/fespi.c24
-rw-r--r--src/flash/nor/fm4.c6
-rw-r--r--src/flash/nor/jtagspi.c43
-rw-r--r--src/flash/nor/kinetis.c2
-rw-r--r--src/flash/nor/lpc2000.c71
-rw-r--r--src/flash/nor/lpc288x.c14
-rw-r--r--src/flash/nor/lpc2900.c20
-rw-r--r--src/flash/nor/lpcspifi.c26
-rw-r--r--src/flash/nor/mdr.c12
-rw-r--r--src/flash/nor/mrvlqspi.c36
-rw-r--r--src/flash/nor/msp432.c13
-rw-r--r--src/flash/nor/nrf5.c3
-rw-r--r--src/flash/nor/ocl.c19
-rw-r--r--src/flash/nor/psoc5lp.c22
-rw-r--r--src/flash/nor/spi.c171
-rw-r--r--src/flash/nor/spi.h58
-rw-r--r--src/flash/nor/stellaris.c6
-rw-r--r--src/flash/nor/stm32f1x.c32
-rw-r--r--src/flash/nor/stm32l4x.c105
-rw-r--r--src/flash/nor/stm32lx.c10
-rw-r--r--src/flash/nor/stmsmi.c42
-rw-r--r--src/flash/nor/tcl.c16
-rw-r--r--src/flash/nor/w600.c390
40 files changed, 1917 insertions, 514 deletions
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 6393305..135128e 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -17,6 +17,7 @@ NOR_DRIVERS = \
%D%/at91sam7.c \
%D%/ath79.c \
%D%/atsamv.c \
+ %D%/atsame5.c \
%D%/avrf.c \
%D%/bluenrg-x.c \
%D%/cc3220sf.c \
@@ -64,6 +65,7 @@ NOR_DRIVERS = \
%D%/str9xpec.c \
%D%/tms470.c \
%D%/virtual.c \
+ %D%/w600.c \
%D%/xcf.c \
%D%/xmc1xxx.c \
%D%/xmc4xxx.c
diff --git a/src/flash/nor/aduc702x.c b/src/flash/nor/aduc702x.c
index 34cc362..824112b 100644
--- a/src/flash/nor/aduc702x.c
+++ b/src/flash/nor/aduc702x.c
@@ -74,12 +74,6 @@ static int aduc702x_build_sector_list(struct flash_bank *bank)
return ERROR_OK;
}
-static int aduc702x_protect_check(struct flash_bank *bank)
-{
- printf("aduc702x_protect_check not implemented yet.\n");
- return ERROR_OK;
-}
-
static int aduc702x_erase(struct flash_bank *bank, int first, int last)
{
/* int res; */
@@ -130,12 +124,6 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
-static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last)
-{
- printf("aduc702x_protect not implemented yet.\n");
- return ERROR_FLASH_OPERATION_FAILED;
-}
-
/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
* back to another mechanism that does not require onboard RAM
*
@@ -394,11 +382,9 @@ struct flash_driver aduc702x_flash = {
.name = "aduc702x",
.flash_bank_command = aduc702x_flash_bank_command,
.erase = aduc702x_erase,
- .protect = aduc702x_protect,
.write = aduc702x_write,
.read = default_flash_read,
.probe = aduc702x_probe,
.auto_probe = aduc702x_probe,
.erase_check = default_flash_blank_check,
- .protect_check = aduc702x_protect_check,
};
diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c
index 8681a25..7663783 100644
--- a/src/flash/nor/aducm360.c
+++ b/src/flash/nor/aducm360.c
@@ -103,13 +103,6 @@ static int aducm360_build_sector_list(struct flash_bank *bank)
}
/* ----------------------------------------------------------------------- */
-static int aducm360_protect_check(struct flash_bank *bank)
-{
- LOG_WARNING("aducm360_protect_check not implemented.");
- return ERROR_OK;
-}
-
-/* ----------------------------------------------------------------------- */
static int aducm360_mass_erase(struct target *target)
{
uint32_t value;
@@ -195,13 +188,6 @@ static int aducm360_erase(struct flash_bank *bank, int first, int last)
}
/* ----------------------------------------------------------------------- */
-static int aducm360_protect(struct flash_bank *bank, int set, int first, int last)
-{
- LOG_ERROR("aducm360_protect not implemented.");
- return ERROR_FLASH_OPERATION_FAILED;
-}
-
-/* ----------------------------------------------------------------------- */
static int aducm360_write_block_sync(
struct flash_bank *bank,
const uint8_t *buffer,
@@ -572,11 +558,9 @@ struct flash_driver aducm360_flash = {
.name = "aducm360",
.flash_bank_command = aducm360_flash_bank_command,
.erase = aducm360_erase,
- .protect = aducm360_protect,
.write = aducm360_write,
.read = default_flash_read,
.probe = aducm360_probe,
.auto_probe = aducm360_probe,
.erase_check = default_flash_blank_check,
- .protect_check = aducm360_protect_check,
};
diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c
index d80b6fe..7119188 100644
--- a/src/flash/nor/at91sam3.c
+++ b/src/flash/nor/at91sam3.c
@@ -2991,28 +2991,6 @@ static int sam3_GetInfo(struct sam3_chip *pChip)
return ERROR_OK;
}
-static int sam3_erase_check(struct flash_bank *bank)
-{
- int x;
-
- LOG_DEBUG("Here");
- if (bank->target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
- if (0 == bank->num_sectors) {
- LOG_ERROR("Target: not supported/not probed");
- return ERROR_FAIL;
- }
-
- LOG_INFO("sam3 - supports auto-erase, erase_check ignored");
- for (x = 0; x < bank->num_sectors; x++)
- bank->sectors[x].is_erased = 1;
-
- LOG_DEBUG("Done");
- return ERROR_OK;
-}
-
static int sam3_protect_check(struct flash_bank *bank)
{
int r;
@@ -3785,7 +3763,7 @@ struct flash_driver at91sam3_flash = {
.read = default_flash_read,
.probe = sam3_probe,
.auto_probe = sam3_auto_probe,
- .erase_check = sam3_erase_check,
+ .erase_check = default_flash_blank_check,
.protect_check = sam3_protect_check,
.free_driver_priv = sam3_free_driver_priv,
};
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index db000b5..7f51bd6 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -180,6 +180,28 @@ static const struct samd_part samd21_parts[] = {
{ 0x24, "SAMD21G15B", 32, 4 },
{ 0x26, "SAMD21E16B", 64, 8 },
{ 0x27, "SAMD21E15B", 32, 4 },
+
+ /* Known SAMDA1 parts.
+ SAMD-A1 series uses the same series identifier like the SAMD21
+ taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */
+ { 0x29, "SAMDA1J16A", 64, 8 },
+ { 0x2A, "SAMDA1J15A", 32, 4 },
+ { 0x2B, "SAMDA1J14A", 16, 4 },
+ { 0x2C, "SAMDA1G16A", 64, 8 },
+ { 0x2D, "SAMDA1G15A", 32, 4 },
+ { 0x2E, "SAMDA1G14A", 16, 4 },
+ { 0x2F, "SAMDA1E16A", 64, 8 },
+ { 0x30, "SAMDA1E15A", 32, 4 },
+ { 0x31, "SAMDA1E14A", 16, 4 },
+ { 0x64, "SAMDA1J16B", 64, 8 },
+ { 0x65, "SAMDA1J15B", 32, 4 },
+ { 0x66, "SAMDA1J14B", 16, 4 },
+ { 0x67, "SAMDA1G16B", 64, 8 },
+ { 0x68, "SAMDA1G15B", 32, 4 },
+ { 0x69, "SAMDA1G14B", 16, 4 },
+ { 0x6A, "SAMDA1E16B", 64, 8 },
+ { 0x6B, "SAMDA1E15B", 32, 4 },
+ { 0x6C, "SAMDA1E14B", 16, 4 },
};
/* Known SAML21 parts. */
@@ -208,6 +230,9 @@ static const struct samd_part saml21_parts[] = {
/* SAMR30 parts have integrated SAML21 with a radio */
{ 0x1E, "SAMR30G18A", 256, 32 },
{ 0x1F, "SAMR30E18A", 256, 32 },
+
+ /* SAMR34/R35 parts have integrated SAML21 with a lora radio */
+ { 0x28, "SAMR34J18", 256, 32 },
};
/* Known SAML22 parts. */
@@ -237,6 +262,8 @@ static const struct samd_part samc20_parts[] = {
{ 0x0B, "SAMC20E17A", 128, 16 },
{ 0x0C, "SAMC20E16A", 64, 8 },
{ 0x0D, "SAMC20E15A", 32, 4 },
+ { 0x20, "SAMC20N18A", 256, 32 },
+ { 0x21, "SAMC20N17A", 128, 16 },
};
/* Known SAMC21 parts. */
@@ -253,6 +280,8 @@ static const struct samd_part samc21_parts[] = {
{ 0x0B, "SAMC21E17A", 128, 16 },
{ 0x0C, "SAMC21E16A", 64, 8 },
{ 0x0D, "SAMC21E15A", 32, 4 },
+ { 0x20, "SAMC21N18A", 256, 32 },
+ { 0x21, "SAMC21N17A", 128, 16 },
};
/* Each family of parts contains a parts table in the DEVSEL field of DID. The
diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c
index 04d183c..e34146a 100644
--- a/src/flash/nor/ath79.c
+++ b/src/flash/nor/ath79.c
@@ -522,6 +522,9 @@ static int ath79_erase(struct flash_bank *bank, int first, int last)
return ERROR_FLASH_BANK_NOT_PROBED;
}
+ if (ath79_info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
for (sector = first; sector <= last; sector++) {
if (bank->sectors[sector].is_protected) {
LOG_ERROR("Flash sector %d protected", sector);
@@ -560,7 +563,11 @@ static int ath79_write_page(struct flash_bank *bank, const uint8_t *buffer,
address,
};
int retval;
- uint32_t i;
+ uint32_t i, pagesize;
+
+ /* if no write pagesize, use reasonable default */
+ pagesize = ath79_info->dev->pagesize ?
+ ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
if (address & 0xff) {
LOG_ERROR("ath79_write_page: unaligned write address: %08x",
@@ -573,7 +580,7 @@ static int ath79_write_page(struct flash_bank *bank, const uint8_t *buffer,
}
if (len > ath79_info->dev->pagesize) {
LOG_ERROR("ath79_write_page: len bigger than page size %d: %d",
- ath79_info->dev->pagesize, len);
+ pagesize, len);
return ERROR_FAIL;
}
@@ -611,12 +618,16 @@ static int ath79_write_buffer(struct flash_bank *bank, const uint8_t *buffer,
uint32_t address, uint32_t len)
{
struct ath79_flash_bank *ath79_info = bank->driver_priv;
- const uint32_t page_size = ath79_info->dev->pagesize;
+ uint32_t page_size;
int retval;
LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32,
__func__, address, len);
+ /* if no valid page_size, use reasonable default */
+ page_size = ath79_info->dev->pagesize ?
+ ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
+
while (len > 0) {
int page_len = len > page_size ? page_size : len;
@@ -642,13 +653,6 @@ static int ath79_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
__func__, offset, count);
- if (offset < bank->base || offset >= bank->base + bank->size) {
- LOG_ERROR("Start address out of range");
- return ERROR_FAIL;
- }
-
- offset -= bank->base;
-
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -718,13 +722,6 @@ static int ath79_read(struct flash_bank *bank, uint8_t *buffer,
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
__func__, offset, count);
- if (offset < bank->base || offset >= bank->base + bank->size) {
- LOG_ERROR("Start address out of range");
- return ERROR_FAIL;
- }
-
- offset -= bank->base;
-
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -775,6 +772,7 @@ static int ath79_probe(struct flash_bank *bank)
struct ath79_flash_bank *ath79_info = bank->driver_priv;
struct flash_sector *sectors;
uint32_t id = 0; /* silence uninitialized warning */
+ uint32_t pagesize, sectorsize;
const struct ath79_target *target_device;
int retval;
@@ -820,16 +818,27 @@ static int ath79_probe(struct flash_bank *bank)
/* Set correct size value */
bank->size = ath79_info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+ if (bank->size > (1UL << 24))
+ LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = ath79_info->dev->sectorsize ?
+ ath79_info->dev->sectorsize : ath79_info->dev->size_in_bytes;
/* create and fill sectors array */
- bank->num_sectors =
- ath79_info->dev->size_in_bytes / ath79_info->dev->sectorsize;
+ bank->num_sectors = ath79_info->dev->size_in_bytes / sectorsize;
sectors = calloc(1, sizeof(struct flash_sector) * bank->num_sectors);
if (!sectors) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
- ath79_info->spi.page_buf = malloc(ath79_info->dev->pagesize);
+
+ /* if no write pagesize, use reasonable default */
+ pagesize = ath79_info->dev->pagesize ? ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
+
+ ath79_info->spi.page_buf = malloc(pagesize);
if (!ath79_info->spi.page_buf) {
LOG_ERROR("not enough memory");
free(sectors);
@@ -837,8 +846,8 @@ static int ath79_probe(struct flash_bank *bank)
}
for (int sector = 0; sector < bank->num_sectors; sector++) {
- sectors[sector].offset = sector * ath79_info->dev->sectorsize;
- sectors[sector].size = ath79_info->dev->sectorsize;
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
sectors[sector].is_erased = 0;
sectors[sector].is_protected = 1;
}
diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c
new file mode 100644
index 0000000..7490d0e
--- /dev/null
+++ b/src/flash/nor/atsame5.c
@@ -0,0 +1,955 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Tomas Vanek *
+ * vanekt@fbl.cz *
+ * *
+ * Based on at91samd.c *
+ * Copyright (C) 2013 by Andrey Yurovsky *
+ * Andrey Yurovsky <yurovsky@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "helper/binarybuffer.h"
+
+#include <target/cortex_m.h>
+
+/* A note to prefixing.
+ * Definitions and functions ingerited from at91samd.c without
+ * any change retained the original prefix samd_ so they eventualy
+ * may go to samd_common.h and .c
+ * As currently there are olny 3 short functions identical with
+ * the original source, no common file was created. */
+
+#define SAME5_PAGES_PER_BLOCK 16
+#define SAME5_NUM_PROT_BLOCKS 32
+#define SAMD_PAGE_SIZE_MAX 1024
+
+#define SAMD_FLASH 0x00000000 /* physical Flash memory */
+#define SAMD_USER_ROW 0x00804000 /* User Row of Flash */
+
+#define SAME5_PAC 0x40000000 /* Peripheral Access Control */
+
+#define SAMD_DSU 0x41002000 /* Device Service Unit */
+#define SAMD_NVMCTRL 0x41004000 /* Non-volatile memory controller */
+
+#define SAMD_DSU_STATUSA 1 /* DSU status register */
+#define SAMD_DSU_DID 0x18 /* Device ID register */
+#define SAMD_DSU_CTRL_EXT 0x100 /* CTRL register, external access */
+
+#define SAME5_NVMCTRL_CTRLA 0x00 /* NVM control A register */
+#define SAME5_NVMCTRL_CTRLB 0x04 /* NVM control B register */
+#define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */
+#define SAME5_NVMCTRL_INTFLAG 0x10 /* NVM interrupt flag register */
+#define SAME5_NVMCTRL_STATUS 0x12 /* NVM status register */
+#define SAME5_NVMCTRL_ADDR 0x14 /* NVM address register */
+#define SAME5_NVMCTRL_LOCK 0x18 /* NVM Lock section register */
+
+#define SAMD_CMDEX_KEY 0xA5UL
+#define SAMD_NVM_CMD(n) ((SAMD_CMDEX_KEY << 8) | (n & 0x7F))
+
+/* NVMCTRL commands. */
+#define SAME5_NVM_CMD_EP 0x00 /* Erase Page (User Page only) */
+#define SAME5_NVM_CMD_EB 0x01 /* Erase Block */
+#define SAME5_NVM_CMD_WP 0x03 /* Write Page */
+#define SAME5_NVM_CMD_WQW 0x04 /* Write Quad Word */
+#define SAME5_NVM_CMD_LR 0x11 /* Lock Region */
+#define SAME5_NVM_CMD_UR 0x12 /* Unlock Region */
+#define SAME5_NVM_CMD_PBC 0x15 /* Page Buffer Clear */
+#define SAME5_NVM_CMD_SSB 0x16 /* Set Security Bit */
+
+/* NVMCTRL bits */
+#define SAME5_NVMCTRL_CTRLA_WMODE_MASK 0x30
+
+#define SAME5_NVMCTRL_INTFLAG_DONE (1 << 0)
+#define SAME5_NVMCTRL_INTFLAG_ADDRE (1 << 1)
+#define SAME5_NVMCTRL_INTFLAG_PROGE (1 << 2)
+#define SAME5_NVMCTRL_INTFLAG_LOCKE (1 << 3)
+#define SAME5_NVMCTRL_INTFLAG_ECCSE (1 << 4)
+#define SAME5_NVMCTRL_INTFLAG_ECCDE (1 << 5)
+#define SAME5_NVMCTRL_INTFLAG_NVME (1 << 6)
+
+
+/* Known identifiers */
+#define SAMD_PROCESSOR_M0 0x01
+#define SAMD_PROCESSOR_M4 0x06
+#define SAMD_FAMILY_D 0x00
+#define SAMD_FAMILY_E 0x03
+#define SAMD_SERIES_51 0x06
+#define SAME_SERIES_51 0x01
+#define SAME_SERIES_53 0x03
+#define SAME_SERIES_54 0x04
+
+/* Device ID macros */
+#define SAMD_GET_PROCESSOR(id) (id >> 28)
+#define SAMD_GET_FAMILY(id) (((id >> 23) & 0x1F))
+#define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F))
+#define SAMD_GET_DEVSEL(id) (id & 0xFF)
+
+/* Bits to mask user row */
+#define NVMUSERROW_SAM_E5_D5_MASK ((uint64_t)0x7FFF00FF3C007FFF)
+
+struct samd_part {
+ uint8_t id;
+ const char *name;
+ uint32_t flash_kb;
+ uint32_t ram_kb;
+};
+
+/* See SAM D5x/E5x Family Silicon Errata and Data Sheet Clarification
+ * DS80000748B */
+/* Known SAMD51 parts. */
+static const struct samd_part samd51_parts[] = {
+ { 0x00, "SAMD51P20A", 1024, 256 },
+ { 0x01, "SAMD51P19A", 512, 192 },
+ { 0x02, "SAMD51N20A", 1024, 256 },
+ { 0x03, "SAMD51N19A", 512, 192 },
+ { 0x04, "SAMD51J20A", 1024, 256 },
+ { 0x05, "SAMD51J19A", 512, 192 },
+ { 0x06, "SAMD51J18A", 256, 128 },
+ { 0x07, "SAMD51G19A", 512, 192 },
+ { 0x08, "SAMD51G18A", 256, 128 },
+};
+
+/* Known SAME51 parts. */
+static const struct samd_part same51_parts[] = {
+ { 0x00, "SAME51N20A", 1024, 256 },
+ { 0x01, "SAME51N19A", 512, 192 },
+ { 0x02, "SAME51J19A", 512, 192 },
+ { 0x03, "SAME51J18A", 256, 128 },
+ { 0x04, "SAME51J20A", 1024, 256 },
+};
+
+/* Known SAME53 parts. */
+static const struct samd_part same53_parts[] = {
+ { 0x02, "SAME53N20A", 1024, 256 },
+ { 0x03, "SAME53N19A", 512, 192 },
+ { 0x04, "SAME53J20A", 1024, 256 },
+ { 0x05, "SAME53J19A", 512, 192 },
+ { 0x06, "SAME53J18A", 256, 128 },
+};
+
+/* Known SAME54 parts. */
+static const struct samd_part same54_parts[] = {
+ { 0x00, "SAME54P20A", 1024, 256 },
+ { 0x01, "SAME54P19A", 512, 192 },
+ { 0x02, "SAME54N20A", 1024, 256 },
+ { 0x03, "SAME54N19A", 512, 192 },
+};
+
+/* Each family of parts contains a parts table in the DEVSEL field of DID. The
+ * processor ID, family ID, and series ID are used to determine which exact
+ * family this is and then we can use the corresponding table. */
+struct samd_family {
+ uint8_t processor;
+ uint8_t family;
+ uint8_t series;
+ const struct samd_part *parts;
+ size_t num_parts;
+};
+
+/* Known SAMD families */
+static const struct samd_family samd_families[] = {
+ { SAMD_PROCESSOR_M4, SAMD_FAMILY_D, SAMD_SERIES_51,
+ samd51_parts, ARRAY_SIZE(samd51_parts) },
+ { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_51,
+ same51_parts, ARRAY_SIZE(same51_parts) },
+ { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_53,
+ same53_parts, ARRAY_SIZE(same53_parts) },
+ { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54,
+ same54_parts, ARRAY_SIZE(same54_parts) },
+};
+
+struct samd_info {
+ const struct samd_params *par;
+ uint32_t page_size;
+ int num_pages;
+ int sector_size;
+ int prot_block_size;
+
+ bool probed;
+ struct target *target;
+};
+
+
+/**
+ * Gives the family structure to specific device id.
+ * @param id The id of the device.
+ * @return On failure NULL, otherwise a pointer to the structure.
+ */
+static const struct samd_family *samd_find_family(uint32_t id)
+{
+ uint8_t processor = SAMD_GET_PROCESSOR(id);
+ uint8_t family = SAMD_GET_FAMILY(id);
+ uint8_t series = SAMD_GET_SERIES(id);
+
+ for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) {
+ if (samd_families[i].processor == processor &&
+ samd_families[i].series == series &&
+ samd_families[i].family == family)
+ return &samd_families[i];
+ }
+
+ return NULL;
+}
+
+/**
+ * Gives the part structure to specific device id.
+ * @param id The id of the device.
+ * @return On failure NULL, otherwise a pointer to the structure.
+ */
+static const struct samd_part *samd_find_part(uint32_t id)
+{
+ uint8_t devsel = SAMD_GET_DEVSEL(id);
+ const struct samd_family *family = samd_find_family(id);
+ if (family == NULL)
+ return NULL;
+
+ for (unsigned i = 0; i < family->num_parts; i++) {
+ if (family->parts[i].id == devsel)
+ return &family->parts[i];
+ }
+
+ return NULL;
+}
+
+static int same5_protect_check(struct flash_bank *bank)
+{
+ int res, prot_block;
+ uint32_t lock;
+
+ res = target_read_u32(bank->target,
+ SAMD_NVMCTRL + SAME5_NVMCTRL_LOCK, &lock);
+ if (res != ERROR_OK)
+ return res;
+
+ /* Lock bits are active-low */
+ for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++)
+ bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block));
+
+ return ERROR_OK;
+}
+
+static int samd_get_flash_page_info(struct target *target,
+ uint32_t *sizep, int *nump)
+{
+ int res;
+ uint32_t param;
+
+ res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_PARAM, &param);
+ if (res == ERROR_OK) {
+ /* The PSZ field (bits 18:16) indicate the page size bytes as 2^(3+n)
+ * so 0 is 8KB and 7 is 1024KB. */
+ if (sizep)
+ *sizep = (8 << ((param >> 16) & 0x7));
+ /* The NVMP field (bits 15:0) indicates the total number of pages */
+ if (nump)
+ *nump = param & 0xFFFF;
+ } else {
+ LOG_ERROR("Couldn't read NVM Parameters register");
+ }
+
+ return res;
+}
+
+static int same5_probe(struct flash_bank *bank)
+{
+ uint32_t id;
+ int res;
+ struct samd_info *chip = (struct samd_info *)bank->driver_priv;
+ const struct samd_part *part;
+
+ if (chip->probed)
+ return ERROR_OK;
+
+ res = target_read_u32(bank->target, SAMD_DSU + SAMD_DSU_DID, &id);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't read Device ID register");
+ return res;
+ }
+
+ part = samd_find_part(id);
+ if (part == NULL) {
+ LOG_ERROR("Couldn't find part corresponding to DID %08" PRIx32, id);
+ return ERROR_FAIL;
+ }
+
+ bank->size = part->flash_kb * 1024;
+
+ res = samd_get_flash_page_info(bank->target, &chip->page_size,
+ &chip->num_pages);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't determine Flash page size");
+ return res;
+ }
+
+ /* Sanity check: the total flash size in the DSU should match the page size
+ * multiplied by the number of pages. */
+ if (bank->size != chip->num_pages * chip->page_size) {
+ LOG_WARNING("SAM: bank size doesn't match NVM parameters. "
+ "Identified %" PRIu32 "KB Flash but NVMCTRL reports %u %" PRIu32 "B pages",
+ part->flash_kb, chip->num_pages, chip->page_size);
+ }
+
+ /* Erase granularity = 1 block = 16 pages */
+ chip->sector_size = chip->page_size * SAME5_PAGES_PER_BLOCK;
+
+ /* Allocate the sector table */
+ bank->num_sectors = chip->num_pages / SAME5_PAGES_PER_BLOCK;
+ bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors);
+ if (!bank->sectors)
+ return ERROR_FAIL;
+
+ /* 16 protection blocks per device */
+ chip->prot_block_size = bank->size / SAME5_NUM_PROT_BLOCKS;
+
+ /* Allocate the table of protection blocks */
+ bank->num_prot_blocks = SAME5_NUM_PROT_BLOCKS;
+ bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks);
+ if (!bank->prot_blocks)
+ return ERROR_FAIL;
+
+ same5_protect_check(bank);
+
+ /* Done */
+ chip->probed = true;
+
+ LOG_INFO("SAM MCU: %s (%" PRIu32 "KB Flash, %" PRIu32 "KB RAM)", part->name,
+ part->flash_kb, part->ram_kb);
+
+ return ERROR_OK;
+}
+
+static int same5_wait_and_check_error(struct target *target)
+{
+ int ret, ret2;
+ int rep_cnt = 100;
+ uint16_t intflag;
+
+ do {
+ ret = target_read_u16(target,
+ SAMD_NVMCTRL + SAME5_NVMCTRL_INTFLAG, &intflag);
+ if (ret == ERROR_OK && intflag & SAME5_NVMCTRL_INTFLAG_DONE)
+ break;
+ } while (--rep_cnt);
+
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Can't read NVM INTFLAG");
+ return ret;
+ }
+#if 0
+ if (intflag & SAME5_NVMCTRL_INTFLAG_ECCSE)
+ LOG_ERROR("SAM: ECC Single Error");
+
+ if (intflag & SAME5_NVMCTRL_INTFLAG_ECCDE) {
+ LOG_ERROR("SAM: ECC Double Error");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ }
+#endif
+ if (intflag & SAME5_NVMCTRL_INTFLAG_ADDRE) {
+ LOG_ERROR("SAM: Addr Error");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (intflag & SAME5_NVMCTRL_INTFLAG_NVME) {
+ LOG_ERROR("SAM: NVM Error");
+ ret = ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (intflag & SAME5_NVMCTRL_INTFLAG_LOCKE) {
+ LOG_ERROR("SAM: NVM lock error");
+ ret = ERROR_FLASH_PROTECTED;
+ }
+
+ if (intflag & SAME5_NVMCTRL_INTFLAG_PROGE) {
+ LOG_ERROR("SAM: NVM programming error");
+ ret = ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
+ /* Clear the error conditions by writing a one to them */
+ ret2 = target_write_u16(target,
+ SAMD_NVMCTRL + SAME5_NVMCTRL_INTFLAG, intflag);
+ if (ret2 != ERROR_OK)
+ LOG_ERROR("Can't clear NVM error conditions");
+
+ return ret;
+}
+
+static int same5_issue_nvmctrl_command(struct target *target, uint16_t cmd)
+{
+ int res;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Issue the NVM command */
+ /* 32-bit write is used to ensure atomic operation on ST-Link */
+ res = target_write_u32(target,
+ SAMD_NVMCTRL + SAME5_NVMCTRL_CTRLB, SAMD_NVM_CMD(cmd));
+ if (res != ERROR_OK)
+ return res;
+
+ /* Check to see if the NVM command resulted in an error condition. */
+ return same5_wait_and_check_error(target);
+}
+
+/**
+ * Erases a flash block or page at the given address.
+ * @param target Pointer to the target structure.
+ * @param address The address of the row.
+ * @return On success ERROR_OK, on failure an errorcode.
+ */
+static int same5_erase_block(struct target *target, uint32_t address)
+{
+ int res;
+
+ /* Set an address contained in the block to be erased */
+ res = target_write_u32(target,
+ SAMD_NVMCTRL + SAME5_NVMCTRL_ADDR, address);
+
+ /* Issue the Erase Block command. */
+ if (res == ERROR_OK)
+ res = same5_issue_nvmctrl_command(target,
+ address == SAMD_USER_ROW ? SAME5_NVM_CMD_EP : SAME5_NVM_CMD_EB);
+
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to erase block containing %08" PRIx32, address);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+
+static int same5_pre_write_check(struct target *target)
+{
+ int res;
+ uint32_t nvm_ctrla;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Check if manual write mode is set */
+ res = target_read_u32(target, SAMD_NVMCTRL + SAME5_NVMCTRL_CTRLA, &nvm_ctrla);
+ if (res != ERROR_OK)
+ return res;
+
+ if (nvm_ctrla & SAME5_NVMCTRL_CTRLA_WMODE_MASK) {
+ LOG_ERROR("The flash controller must be in manual write mode. Issue 'reset init' and retry.");
+ return ERROR_FAIL;
+ }
+
+ return res;
+}
+
+
+/**
+ * Modify the contents of the User Row in Flash. The User Row itself
+ * has a size of one page and contains a combination of "fuses" and
+ * calibration data. Bits which have a value of zero in the mask will
+ * not be changed.
+ * @param target Pointer to the target structure.
+ * @param data Pointer to the value to write.
+ * @param mask Pointer to bitmask, 0 -> value stays untouched.
+ * @param offset Offset in user row where new data will be applied.
+ * @param count Size of buffer and mask in bytes.
+ * @return On success ERROR_OK, on failure an errorcode.
+ */
+static int same5_modify_user_row_masked(struct target *target,
+ const uint8_t *data, const uint8_t *mask,
+ uint32_t offset, uint32_t count)
+{
+ int res;
+
+ /* Retrieve the MCU's flash page size, in bytes. */
+ uint32_t page_size;
+ res = samd_get_flash_page_info(target, &page_size, NULL);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't determine Flash page size");
+ return res;
+ }
+
+ /* Make sure the size is sane. */
+ assert(page_size <= SAMD_PAGE_SIZE_MAX &&
+ page_size >= offset + count);
+
+ uint8_t buf[SAMD_PAGE_SIZE_MAX];
+ /* Read the user row (comprising one page) by words. */
+ res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
+ if (res != ERROR_OK)
+ return res;
+
+ /* Modify buffer and check if really changed */
+ bool changed = false;
+ uint32_t i;
+ for (i = 0; i < count; i++) {
+ uint8_t old_b = buf[offset+i];
+ uint8_t new_b = (old_b & ~mask[i]) | (data[i] & mask[i]);
+ buf[offset+i] = new_b;
+ if (old_b != new_b)
+ changed = true;
+ }
+
+ if (!changed)
+ return ERROR_OK;
+
+ res = same5_pre_write_check(target);
+ if (res != ERROR_OK)
+ return res;
+
+ res = same5_erase_block(target, SAMD_USER_ROW);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Couldn't erase user row");
+ return res;
+ }
+
+ /* Write the page buffer back out to the target using Write Quad Word */
+ for (i = 0; i < page_size; i += 4 * 4) {
+ res = target_write_memory(target, SAMD_USER_ROW + i, 4, 4, buf + i);
+ if (res != ERROR_OK)
+ return res;
+
+ /* Trigger flash write */
+ res = same5_issue_nvmctrl_command(target, SAME5_NVM_CMD_WQW);
+ if (res != ERROR_OK)
+ return res;
+ }
+
+ return res;
+}
+
+/**
+ * Modifies the user row register to the given value.
+ * @param target Pointer to the target structure.
+ * @param value The value to write.
+ * @param startb The bit-offset by which the given value is shifted.
+ * @param endb The bit-offset of the last bit in value to write.
+ * @return On success ERROR_OK, on failure an errorcode.
+ */
+static int same5_modify_user_row(struct target *target, uint32_t value,
+ uint8_t startb, uint8_t endb)
+{
+ uint8_t buf_val[8] = { 0 };
+ uint8_t buf_mask[8] = { 0 };
+
+ assert(startb <= endb && endb < 64);
+ buf_set_u32(buf_val, startb, endb + 1 - startb, value);
+ buf_set_u32(buf_mask, startb, endb + 1 - startb, 0xffffffff);
+
+ return same5_modify_user_row_masked(target,
+ buf_val, buf_mask, 0, 8);
+}
+
+static int same5_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl)
+{
+ int res = ERROR_OK;
+ int prot_block;
+
+ /* We can issue lock/unlock region commands with the target running but
+ * the settings won't persist unless we're able to modify the LOCK regions
+ * and that requires the target to be halted. */
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) {
+ if (set != bank->prot_blocks[prot_block].is_protected) {
+ /* Load an address that is within this protection block (we use offset 0) */
+ res = target_write_u32(bank->target,
+ SAMD_NVMCTRL + SAME5_NVMCTRL_ADDR,
+ bank->prot_blocks[prot_block].offset);
+ if (res != ERROR_OK)
+ goto exit;
+
+ /* Tell the controller to lock that block */
+ res = same5_issue_nvmctrl_command(bank->target,
+ set ? SAME5_NVM_CMD_LR : SAME5_NVM_CMD_UR);
+ if (res != ERROR_OK)
+ goto exit;
+ }
+ }
+
+ /* We've now applied our changes, however they will be undone by the next
+ * reset unless we also apply them to the LOCK bits in the User Page.
+ * A '1' means unlocked and a '0' means locked. */
+ const uint8_t lock[4] = { 0, 0, 0, 0 };
+ const uint8_t unlock[4] = { 0xff, 0xff, 0xff, 0xff };
+ uint8_t mask[4] = { 0, 0, 0, 0 };
+
+ buf_set_u32(mask, first_prot_bl, last_prot_bl + 1 - first_prot_bl, 0xffffffff);
+
+ res = same5_modify_user_row_masked(bank->target,
+ set ? lock : unlock, mask, 8, 4);
+ if (res != ERROR_OK)
+ LOG_WARNING("SAM: protect settings were not made persistent!");
+
+ res = ERROR_OK;
+
+exit:
+ same5_protect_check(bank);
+
+ return res;
+}
+
+static int same5_erase(struct flash_bank *bank, int first_sect, int last_sect)
+{
+ int res, s;
+ struct samd_info *chip = (struct samd_info *)bank->driver_priv;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!chip->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /* For each sector to be erased */
+ for (s = first_sect; s <= last_sect; s++) {
+ res = same5_erase_block(bank->target, bank->sectors[s].offset);
+ if (res != ERROR_OK) {
+ LOG_ERROR("SAM: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset);
+ return res;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+
+static int same5_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ int res;
+ uint32_t address;
+ uint32_t pg_offset;
+ uint32_t nb;
+ uint32_t nw;
+ struct samd_info *chip = (struct samd_info *)bank->driver_priv;
+ uint8_t *pb = NULL;
+
+ res = same5_pre_write_check(bank->target);
+ if (res != ERROR_OK)
+ return res;
+
+ if (!chip->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ res = same5_issue_nvmctrl_command(bank->target, SAME5_NVM_CMD_PBC);
+ if (res != ERROR_OK) {
+ LOG_ERROR("%s: %d", __func__, __LINE__);
+ return res;
+ }
+
+ while (count) {
+ nb = chip->page_size - offset % chip->page_size;
+ if (count < nb)
+ nb = count;
+
+ address = bank->base + offset;
+ pg_offset = offset % chip->page_size;
+
+ if (offset % 4 || (offset + nb) % 4) {
+ /* Either start or end of write is not word aligned */
+ if (!pb) {
+ pb = malloc(chip->page_size);
+ if (!pb)
+ return ERROR_FAIL;
+ }
+
+ /* Set temporary page buffer to 0xff and overwrite the relevant part */
+ memset(pb, 0xff, chip->page_size);
+ memcpy(pb + pg_offset, buffer, nb);
+
+ /* Align start address to a word boundary */
+ address -= offset % 4;
+ pg_offset -= offset % 4;
+ assert(pg_offset % 4 == 0);
+
+ /* Extend length to whole words */
+ nw = (nb + offset % 4 + 3) / 4;
+ assert(pg_offset + 4 * nw <= chip->page_size);
+
+ /* Now we have original data extended by 0xff bytes
+ * to the nearest word boundary on both start and end */
+ res = target_write_memory(bank->target, address, 4, nw, pb + pg_offset);
+ } else {
+ assert(nb % 4 == 0);
+ nw = nb / 4;
+ assert(pg_offset + 4 * nw <= chip->page_size);
+
+ /* Word aligned data, use direct write from buffer */
+ res = target_write_memory(bank->target, address, 4, nw, buffer);
+ }
+ if (res != ERROR_OK) {
+ LOG_ERROR("%s: %d", __func__, __LINE__);
+ goto free_pb;
+ }
+
+ res = same5_issue_nvmctrl_command(bank->target, SAME5_NVM_CMD_WP);
+ if (res != ERROR_OK) {
+ LOG_ERROR("%s: write failed at address 0x%08" PRIx32, __func__, address);
+ goto free_pb;
+ }
+
+ /* We're done with the page contents */
+ count -= nb;
+ offset += nb;
+ buffer += nb;
+ }
+
+free_pb:
+ if (pb)
+ free(pb);
+
+ return res;
+}
+
+
+FLASH_BANK_COMMAND_HANDLER(same5_flash_bank_command)
+{
+ if (bank->base != SAMD_FLASH) {
+ LOG_ERROR("Address 0x%08" PRIx32 " invalid bank address (try 0x%08" PRIx32
+ "[same5] )",
+ bank->base, SAMD_FLASH);
+ return ERROR_FAIL;
+ }
+
+ struct samd_info *chip;
+ chip = calloc(1, sizeof(*chip));
+ if (!chip) {
+ LOG_ERROR("No memory for flash bank chip info");
+ return ERROR_FAIL;
+ }
+
+ chip->target = bank->target;
+ chip->probed = false;
+
+ bank->driver_priv = chip;
+
+ return ERROR_OK;
+}
+
+
+COMMAND_HANDLER(same5_handle_chip_erase_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (!target)
+ return ERROR_FAIL;
+
+ /* Enable access to the DSU by disabling the write protect bit */
+ target_write_u32(target, SAME5_PAC, (1<<16) | (1<<5) | (1<<1));
+ /* intentionally without error checking - not accessible on secured chip */
+
+ /* Tell the DSU to perform a full chip erase. It takes about 240ms to
+ * perform the erase. */
+ int res = target_write_u8(target, SAMD_DSU + SAMD_DSU_CTRL_EXT, (1<<4));
+ if (res == ERROR_OK)
+ command_print(CMD_CTX, "chip erase started");
+ else
+ command_print(CMD_CTX, "write to DSU CTRL failed");
+
+ return res;
+}
+
+
+COMMAND_HANDLER(same5_handle_userpage_command)
+{
+ int res = ERROR_OK;
+ struct target *target = get_current_target(CMD_CTX);
+ if (!target)
+ return ERROR_FAIL;
+
+ if (CMD_ARGC > 2) {
+ command_print(CMD_CTX, "Too much Arguments given.");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (CMD_ARGC >= 1) {
+ uint64_t mask = NVMUSERROW_SAM_E5_D5_MASK;
+ uint64_t value = strtoull(CMD_ARGV[0], NULL, 0);
+
+ if (CMD_ARGC == 2) {
+ uint64_t mask_temp = strtoull(CMD_ARGV[1], NULL, 0);
+ mask &= mask_temp;
+ }
+
+ uint8_t val_buf[8], mask_buf[8];
+ target_buffer_set_u64(target, val_buf, value);
+ target_buffer_set_u64(target, mask_buf, mask);
+
+ res = same5_modify_user_row_masked(target,
+ val_buf, mask_buf, 0, sizeof(val_buf));
+ }
+
+ uint8_t buffer[8];
+ int res2 = target_read_memory(target, SAMD_USER_ROW, 4, 2, buffer);
+ if (res2 == ERROR_OK) {
+ uint64_t value = target_buffer_get_u64(target, buffer);
+ command_print(CMD_CTX, "USER PAGE: 0x%016"PRIX64, value);
+ } else {
+ LOG_ERROR("USER PAGE could not be read.");
+ }
+
+ if (CMD_ARGC >= 1)
+ return res;
+ else
+ return res2;
+}
+
+
+COMMAND_HANDLER(same5_handle_bootloader_command)
+{
+ int res = ERROR_OK;
+ struct target *target = get_current_target(CMD_CTX);
+ if (!target)
+ return ERROR_FAIL;
+
+ if (CMD_ARGC >= 1) {
+ unsigned long size = strtoul(CMD_ARGV[0], NULL, 0);
+ uint32_t code = (size + 8191) / 8192;
+ if (code > 15) {
+ command_print(CMD_CTX, "Invalid bootloader size. Please "
+ "see datasheet for a list valid sizes.");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ res = same5_modify_user_row(target, 15 - code, 26, 29);
+ }
+
+ uint32_t val;
+ int res2 = target_read_u32(target, SAMD_USER_ROW, &val);
+ if (res2 == ERROR_OK) {
+ uint32_t code = (val >> 26) & 0xf; /* grab size code */
+ uint32_t size = (15 - code) * 8192;
+ command_print(CMD_CTX, "Bootloader protected in the first %"
+ PRIu32 " bytes", size);
+ }
+
+ if (CMD_ARGC >= 1)
+ return res;
+ else
+ return res2;
+}
+
+
+COMMAND_HANDLER(samd_handle_reset_deassert)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ int res = ERROR_OK;
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+ if (!target)
+ return ERROR_FAIL;
+
+ /* If the target has been unresponsive before, try to re-establish
+ * communication now - CPU is held in reset by DSU, DAP is working */
+ if (!target_was_examined(target))
+ target_examine_one(target);
+ target_poll(target);
+
+ /* In case of sysresetreq, debug retains state set in cortex_m_assert_reset()
+ * so we just release reset held by DSU
+ *
+ * n_RESET (srst) clears the DP, so reenable debug and set vector catch here
+ *
+ * After vectreset DSU release is not needed however makes no harm
+ */
+ if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) {
+ res = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
+ if (res == ERROR_OK)
+ res = target_write_u32(target, DCB_DEMCR,
+ TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
+ /* do not return on error here, releasing DSU reset is more important */
+ }
+
+ /* clear CPU Reset Phase Extension bit */
+ int res2 = target_write_u8(target, SAMD_DSU + SAMD_DSU_STATUSA, (1<<1));
+ if (res2 != ERROR_OK)
+ return res2;
+
+ return res;
+}
+
+static const struct command_registration same5_exec_command_handlers[] = {
+ {
+ .name = "dsu_reset_deassert",
+ .handler = samd_handle_reset_deassert,
+ .mode = COMMAND_EXEC,
+ .help = "Deasert internal reset held by DSU."
+ },
+ {
+ .name = "chip-erase",
+ .handler = same5_handle_chip_erase_command,
+ .mode = COMMAND_EXEC,
+ .help = "Erase the entire Flash by using the Chip-"
+ "Erase feature in the Device Service Unit (DSU).",
+ },
+ {
+ .name = "bootloader",
+ .usage = "[size_in_bytes]",
+ .handler = same5_handle_bootloader_command,
+ .mode = COMMAND_EXEC,
+ .help = "Show or set the bootloader protection size, stored in the User Row. "
+ "Changes are stored immediately but take affect after the MCU is "
+ "reset.",
+ },
+ {
+ .name = "userpage",
+ .usage = "[value] [mask]",
+ .handler = same5_handle_userpage_command,
+ .mode = COMMAND_EXEC,
+ .help = "Show or set the first 64-bit part of user page "
+ "located at address 0x804000. Use the optional mask argument "
+ "to prevent changes at positions where the bitvalue is zero. "
+ "For security reasons the reserved-bits are masked out "
+ "in background and therefore cannot be changed.",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration same5_command_handlers[] = {
+ {
+ .name = "atsame5",
+ .mode = COMMAND_ANY,
+ .help = "atsame5 flash command group",
+ .usage = "",
+ .chain = same5_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver atsame5_flash = {
+ .name = "atsame5",
+ .commands = same5_command_handlers,
+ .flash_bank_command = same5_flash_bank_command,
+ .erase = same5_erase,
+ .protect = same5_protect,
+ .write = same5_write,
+ .read = default_flash_read,
+ .probe = same5_probe,
+ .auto_probe = same5_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = same5_protect_check,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c
index 65ac601..b88f6f6 100644
--- a/src/flash/nor/avrf.c
+++ b/src/flash/nor/avrf.c
@@ -233,12 +233,6 @@ static int avrf_erase(struct flash_bank *bank, int first, int last)
return avr_jtagprg_leaveprogmode(avr);
}
-static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
-{
- LOG_INFO("%s", __func__);
- return ERROR_OK;
-}
-
static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
@@ -338,7 +332,7 @@ static int avrf_probe(struct flash_bank *bank)
bank->sectors[i].offset = i * avr_info->flash_page_size;
bank->sectors[i].size = avr_info->flash_page_size;
bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 1;
+ bank->sectors[i].is_protected = -1;
}
avrf_info->probed = 1;
@@ -360,12 +354,6 @@ static int avrf_auto_probe(struct flash_bank *bank)
return avrf_probe(bank);
}
-static int avrf_protect_check(struct flash_bank *bank)
-{
- LOG_INFO("%s", __func__);
- return ERROR_OK;
-}
-
static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct target *target = bank->target;
@@ -479,13 +467,11 @@ struct flash_driver avr_flash = {
.commands = avrf_command_handlers,
.flash_bank_command = avrf_flash_bank_command,
.erase = avrf_erase,
- .protect = avrf_protect,
.write = avrf_write,
.read = default_flash_read,
.probe = avrf_probe,
.auto_probe = avrf_auto_probe,
.erase_check = default_flash_blank_check,
- .protect_check = avrf_protect_check,
.info = avrf_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/cc26xx.c b/src/flash/nor/cc26xx.c
index e6e9e59..0320e92 100644
--- a/src/flash/nor/cc26xx.c
+++ b/src/flash/nor/cc26xx.c
@@ -312,12 +312,6 @@ static int cc26xx_erase(struct flash_bank *bank, int first, int last)
return retval;
}
-static int cc26xx_protect(struct flash_bank *bank, int set, int first,
- int last)
-{
- return ERROR_OK;
-}
-
static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
@@ -497,22 +491,12 @@ static int cc26xx_auto_probe(struct flash_bank *bank)
int retval = ERROR_OK;
- if (bank->bank_number != 0) {
- /* Invalid bank number somehow */
- return ERROR_FAIL;
- }
-
if (!cc26xx_bank->probed)
retval = cc26xx_probe(bank);
return retval;
}
-static int cc26xx_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
@@ -555,13 +539,11 @@ struct flash_driver cc26xx_flash = {
.name = "cc26xx",
.flash_bank_command = cc26xx_flash_bank_command,
.erase = cc26xx_erase,
- .protect = cc26xx_protect,
.write = cc26xx_write,
.read = default_flash_read,
.probe = cc26xx_probe,
.auto_probe = cc26xx_auto_probe,
.erase_check = default_flash_blank_check,
- .protect_check = cc26xx_protect_check,
.info = cc26xx_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c
index af45743..2441124 100644
--- a/src/flash/nor/cc3220sf.c
+++ b/src/flash/nor/cc3220sf.c
@@ -173,12 +173,6 @@ static int cc3220sf_erase(struct flash_bank *bank, int first, int last)
return retval;
}
-static int cc3220sf_protect(struct flash_bank *bank, int set, int first,
- int last)
-{
- return ERROR_OK;
-}
-
static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
@@ -436,18 +430,10 @@ static int cc3220sf_probe(struct flash_bank *bank)
uint32_t base;
uint32_t size;
int num_sectors;
- int bank_id;
- bank_id = bank->bank_number;
-
- if (0 == bank_id) {
- base = FLASH_BASE_ADDR;
- size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
- num_sectors = FLASH_NUM_SECTORS;
- } else {
- /* Invalid bank number somehow */
- return ERROR_FAIL;
- }
+ base = FLASH_BASE_ADDR;
+ size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
+ num_sectors = FLASH_NUM_SECTORS;
if (NULL != bank->sectors) {
free(bank->sectors);
@@ -485,22 +471,12 @@ static int cc3220sf_auto_probe(struct flash_bank *bank)
int retval = ERROR_OK;
- if (0 != bank->bank_number) {
- /* Invalid bank number somehow */
- return ERROR_FAIL;
- }
-
if (!cc3220sf_bank->probed)
retval = cc3220sf_probe(bank);
return retval;
}
-static int cc3220sf_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
{
int printed;
@@ -517,13 +493,11 @@ struct flash_driver cc3220sf_flash = {
.name = "cc3220sf",
.flash_bank_command = cc3220sf_flash_bank_command,
.erase = cc3220sf_erase,
- .protect = cc3220sf_protect,
.write = cc3220sf_write,
.read = default_flash_read,
.probe = cc3220sf_probe,
.auto_probe = cc3220sf_auto_probe,
.erase_check = default_flash_blank_check,
- .protect_check = cc3220sf_protect_check,
.info = cc3220sf_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c
index 8bf17ac..8257db7 100644
--- a/src/flash/nor/cfi.c
+++ b/src/flash/nor/cfi.c
@@ -1098,11 +1098,6 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_TARGET_NOT_HALTED;
}
- if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
- LOG_ERROR("Invalid sector range");
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
if (cfi_info->qry[0] != 'Q')
return ERROR_FLASH_BANK_NOT_PROBED;
diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c
index 8f8a9ce..d26894b 100644
--- a/src/flash/nor/core.c
+++ b/src/flash/nor/core.c
@@ -68,6 +68,11 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
/* force "set" to 0/1 */
set = !!set;
+ if (bank->driver->protect == NULL) {
+ LOG_ERROR("Flash protection is not supported.");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
/* DANGER!
*
* We must not use any cached information about protection state!!!!
@@ -319,8 +324,8 @@ static int default_flash_mem_blank_check(struct flash_bank *bank)
for (j = 0; j < bank->sectors[i].size; j += buffer_size) {
uint32_t chunk;
chunk = buffer_size;
- if (chunk > (j - bank->sectors[i].size))
- chunk = (j - bank->sectors[i].size);
+ if (chunk > (bank->sectors[i].size - j))
+ chunk = (bank->sectors[i].size - j);
retval = target_read_memory(target,
bank->base + bank->sectors[i].offset + j,
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index e7b3234..ef69a0f 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -109,6 +109,8 @@ struct flash_driver {
/**
* Bank/sector protection routine (target-specific).
*
+ * If protection is not implemented, set method to NULL
+ *
* When called, the driver should enable/disable protection
* for MINIMUM the range covered by first..last sectors
* inclusive. Some chips have alignment requirements will
@@ -178,6 +180,8 @@ struct flash_driver {
* flash_sector_s::is_protected field for each of the flash
* bank's sectors.
*
+ * If protection is not implemented, set method to NULL
+ *
* @param bank - the bank to check
* @returns ERROR_OK if successful; otherwise, an error code.
*/
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 62db3fe..31caa5a 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -29,6 +29,7 @@ extern struct flash_driver at91sam4l_flash;
extern struct flash_driver at91sam7_flash;
extern struct flash_driver at91samd_flash;
extern struct flash_driver ath79_flash;
+extern struct flash_driver atsame5_flash;
extern struct flash_driver atsamv_flash;
extern struct flash_driver avr_flash;
extern struct flash_driver bluenrgx_flash;
@@ -78,6 +79,7 @@ extern struct flash_driver str9x_flash;
extern struct flash_driver str9xpec_flash;
extern struct flash_driver tms470_flash;
extern struct flash_driver virtual_flash;
+extern struct flash_driver w600_flash;
extern struct flash_driver xcf_flash;
extern struct flash_driver xmc1xxx_flash;
extern struct flash_driver xmc4xxx_flash;
@@ -96,6 +98,7 @@ static struct flash_driver *flash_drivers[] = {
&at91sam7_flash,
&at91samd_flash,
&ath79_flash,
+ &atsame5_flash,
&atsamv_flash,
&avr_flash,
&bluenrgx_flash,
@@ -148,6 +151,7 @@ static struct flash_driver *flash_drivers[] = {
&xcf_flash,
&xmc1xxx_flash,
&xmc4xxx_flash,
+ &w600_flash,
NULL,
};
diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c
index 1d70bd5..8ff689c 100644
--- a/src/flash/nor/efm32.c
+++ b/src/flash/nor/efm32.c
@@ -429,7 +429,7 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
*/
int ret = 0;
uint32_t status = 0;
-
+ addr += bank->base;
LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr);
ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr);
diff --git a/src/flash/nor/esirisc_flash.c b/src/flash/nor/esirisc_flash.c
index f3833df..9e11571 100644
--- a/src/flash/nor/esirisc_flash.c
+++ b/src/flash/nor/esirisc_flash.c
@@ -104,9 +104,12 @@ struct esirisc_flash_bank {
uint32_t wait_states;
};
+static const struct command_registration esirisc_flash_command_handlers[];
+
FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
{
struct esirisc_flash_bank *esirisc_info;
+ struct command *esirisc_cmd;
if (CMD_ARGC < 9)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -119,6 +122,10 @@ FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
bank->driver_priv = esirisc_info;
+ /* register commands using existing esirisc context */
+ esirisc_cmd = command_find_in_context(CMD_CTX, "esirisc");
+ register_commands(CMD_CTX, esirisc_cmd, esirisc_flash_command_handlers);
+
return ERROR_OK;
}
@@ -149,7 +156,7 @@ static int esirisc_flash_disable_protect(struct flash_bank *bank)
if (!(control & CONTROL_WP))
return ERROR_OK;
- esirisc_flash_unlock(bank);
+ (void)esirisc_flash_unlock(bank);
control &= ~CONTROL_WP;
@@ -168,7 +175,7 @@ static int esirisc_flash_enable_protect(struct flash_bank *bank)
if (control & CONTROL_WP)
return ERROR_OK;
- esirisc_flash_unlock(bank);
+ (void)esirisc_flash_unlock(bank);
control |= CONTROL_WP;
@@ -254,7 +261,7 @@ static int esirisc_flash_erase(struct flash_bank *bank, int first, int last)
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- esirisc_flash_disable_protect(bank);
+ (void)esirisc_flash_disable_protect(bank);
for (int page = first; page < last; ++page) {
uint32_t address = page * PAGE_SIZE;
@@ -268,7 +275,7 @@ static int esirisc_flash_erase(struct flash_bank *bank, int first, int last)
}
}
- esirisc_flash_enable_protect(bank);
+ (void)esirisc_flash_enable_protect(bank);
return retval;
}
@@ -282,7 +289,7 @@ static int esirisc_flash_mass_erase(struct flash_bank *bank)
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- esirisc_flash_disable_protect(bank);
+ (void)esirisc_flash_disable_protect(bank);
target_write_u32(target, esirisc_info->cfg + ADDRESS, 0);
@@ -290,7 +297,7 @@ static int esirisc_flash_mass_erase(struct flash_bank *bank)
if (retval != ERROR_OK)
LOG_ERROR("%s: failed to mass erase", bank->name);
- esirisc_flash_enable_protect(bank);
+ (void)esirisc_flash_enable_protect(bank);
return retval;
}
@@ -308,32 +315,17 @@ static int esirisc_flash_ref_erase(struct flash_bank *bank)
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- esirisc_flash_disable_protect(bank);
+ (void)esirisc_flash_disable_protect(bank);
retval = esirisc_flash_control(bank, CONTROL_ERC);
if (retval != ERROR_OK)
LOG_ERROR("%s: failed to erase reference cell", bank->name);
- esirisc_flash_enable_protect(bank);
+ (void)esirisc_flash_enable_protect(bank);
return retval;
}
-static int esirisc_flash_protect(struct flash_bank *bank, int set, int first, int last)
-{
- struct target *target = bank->target;
-
- if (target->state != TARGET_HALTED)
- return ERROR_TARGET_NOT_HALTED;
-
- if (set)
- esirisc_flash_enable_protect(bank);
- else
- esirisc_flash_disable_protect(bank);
-
- return ERROR_OK;
-}
-
static int esirisc_flash_fill_pb(struct flash_bank *bank,
const uint8_t *buffer, uint32_t count)
{
@@ -375,7 +367,7 @@ static int esirisc_flash_write(struct flash_bank *bank,
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- esirisc_flash_disable_protect(bank);
+ (void)esirisc_flash_disable_protect(bank);
/*
* The address register is auto-incremented based on the contents of
@@ -406,7 +398,7 @@ static int esirisc_flash_write(struct flash_bank *bank,
count -= num_bytes;
}
- esirisc_flash_enable_protect(bank);
+ (void)esirisc_flash_enable_protect(bank);
return retval;
}
@@ -432,11 +424,11 @@ static int esirisc_flash_init(struct flash_bank *bank)
uint32_t value;
int retval;
- esirisc_flash_disable_protect(bank);
+ (void)esirisc_flash_disable_protect(bank);
/* initialize timing registers */
- value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH)) |
- TIMING0_R(esirisc_info->wait_states);
+ value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH))
+ | TIMING0_R(esirisc_info->wait_states);
LOG_DEBUG("TIMING0: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING0, value);
@@ -446,9 +438,9 @@ static int esirisc_flash_init(struct flash_bank *bank)
LOG_DEBUG("TIMING1: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING1, value);
- value = TIMING2_T(esirisc_flash_num_cycles(bank, 10)) |
- TIMING2_H(esirisc_flash_num_cycles(bank, 100)) |
- TIMING2_P(esirisc_flash_num_cycles(bank, TPROG));
+ value = TIMING2_T(esirisc_flash_num_cycles(bank, 10))
+ | TIMING2_H(esirisc_flash_num_cycles(bank, 100))
+ | TIMING2_P(esirisc_flash_num_cycles(bank, TPROG));
LOG_DEBUG("TIMING2: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING2, value);
@@ -458,7 +450,7 @@ static int esirisc_flash_init(struct flash_bank *bank)
if (retval != ERROR_OK)
LOG_ERROR("%s: failed to recall trim code", bank->name);
- esirisc_flash_enable_protect(bank);
+ (void)esirisc_flash_enable_protect(bank);
return retval;
}
@@ -475,13 +467,6 @@ static int esirisc_flash_probe(struct flash_bank *bank)
bank->num_sectors = bank->size / PAGE_SIZE;
bank->sectors = alloc_block_array(0, PAGE_SIZE, bank->num_sectors);
- /*
- * Register write protection is enforced using a single protection
- * block for the entire bank. This is as good as it gets.
- */
- bank->num_prot_blocks = 1;
- bank->prot_blocks = alloc_block_array(0, bank->size, bank->num_prot_blocks);
-
retval = esirisc_flash_init(bank);
if (retval != ERROR_OK) {
LOG_ERROR("%s: failed to initialize bank", bank->name);
@@ -503,23 +488,6 @@ static int esirisc_flash_auto_probe(struct flash_bank *bank)
return esirisc_flash_probe(bank);
}
-static int esirisc_flash_protect_check(struct flash_bank *bank)
-{
- struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
- struct target *target = bank->target;
- uint32_t control;
-
- if (target->state != TARGET_HALTED)
- return ERROR_TARGET_NOT_HALTED;
-
- target_read_u32(target, esirisc_info->cfg + CONTROL, &control);
-
- /* single protection block (also see: esirisc_flash_probe()) */
- bank->prot_blocks[0].is_protected = !!(control & CONTROL_WP);
-
- return ERROR_OK;
-}
-
static int esirisc_flash_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
@@ -579,14 +547,14 @@ static const struct command_registration esirisc_flash_exec_command_handlers[] =
.name = "mass_erase",
.handler = handle_esirisc_flash_mass_erase_command,
.mode = COMMAND_EXEC,
- .help = "erases all pages in data memory",
+ .help = "erase all pages in data memory",
.usage = "bank_id",
},
{
.name = "ref_erase",
.handler = handle_esirisc_flash_ref_erase_command,
.mode = COMMAND_EXEC,
- .help = "erases reference cell (uncommon)",
+ .help = "erase reference cell (uncommon)",
.usage = "bank_id",
},
COMMAND_REGISTRATION_DONE
@@ -594,9 +562,9 @@ static const struct command_registration esirisc_flash_exec_command_handlers[] =
static const struct command_registration esirisc_flash_command_handlers[] = {
{
- .name = "esirisc_flash",
- .mode = COMMAND_ANY,
- .help = "eSi-RISC flash command group",
+ .name = "flash",
+ .mode = COMMAND_EXEC,
+ .help = "eSi-TSMC Flash command group",
.usage = "",
.chain = esirisc_flash_exec_command_handlers,
},
@@ -605,17 +573,15 @@ static const struct command_registration esirisc_flash_command_handlers[] = {
struct flash_driver esirisc_flash = {
.name = "esirisc",
- .commands = esirisc_flash_command_handlers,
.usage = "flash bank bank_id 'esirisc' base_address size_bytes 0 0 target "
"cfg_address clock_hz wait_states",
.flash_bank_command = esirisc_flash_bank_command,
.erase = esirisc_flash_erase,
- .protect = esirisc_flash_protect,
.write = esirisc_flash_write,
.read = default_flash_read,
.probe = esirisc_flash_probe,
.auto_probe = esirisc_flash_auto_probe,
.erase_check = default_flash_blank_check,
- .protect_check = esirisc_flash_protect_check,
.info = esirisc_flash_info,
+ .free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/faux.c b/src/flash/nor/faux.c
index 46eda72..d68940f 100644
--- a/src/flash/nor/faux.c
+++ b/src/flash/nor/faux.c
@@ -85,12 +85,6 @@ static int faux_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
-static int faux_protect(struct flash_bank *bank, int set, int first, int last)
-{
- LOG_USER("set protection sector %d to %d to %s", first, last, set ? "on" : "off");
- return ERROR_OK;
-}
-
static int faux_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct faux_flash_bank *info = bank->driver_priv;
@@ -98,11 +92,6 @@ static int faux_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
return ERROR_OK;
}
-static int faux_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
static int faux_info(struct flash_bank *bank, char *buf, int buf_size)
{
snprintf(buf, buf_size, "faux flash driver");
@@ -129,13 +118,11 @@ struct flash_driver faux_flash = {
.commands = faux_command_handlers,
.flash_bank_command = faux_flash_bank_command,
.erase = faux_erase,
- .protect = faux_protect,
.write = faux_write,
.read = default_flash_read,
.probe = faux_probe,
.auto_probe = faux_probe,
.erase_check = default_flash_blank_check,
- .protect_check = faux_protect_check,
.info = faux_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c
index 4c3aadd..1e8251c 100644
--- a/src/flash/nor/fespi.c
+++ b/src/flash/nor/fespi.c
@@ -391,6 +391,9 @@ static int fespi_erase(struct flash_bank *bank, int first, int last)
}
}
+ if (fespi_info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
if (fespi_write_reg(bank, FESPI_REG_TXCTRL, FESPI_TXWM(1)) != ERROR_OK)
return ERROR_FAIL;
retval = fespi_txwm_wait(bank);
@@ -795,7 +798,9 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
data_wa_size /= 2;
}
- page_size = fespi_info->dev->pagesize;
+ /* If no valid page_size, use reasonable default. */
+ page_size = fespi_info->dev->pagesize ?
+ fespi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
fespi_txwm_wait(bank);
@@ -911,6 +916,7 @@ static int fespi_probe(struct flash_bank *bank)
uint32_t id = 0; /* silence uninitialized warning */
const struct fespi_target *target_device;
int retval;
+ uint32_t sectorsize;
if (fespi_info->probed)
free(bank->sectors);
@@ -972,9 +978,17 @@ static int fespi_probe(struct flash_bank *bank)
/* Set correct size value */
bank->size = fespi_info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+ if (bank->size > (1UL << 24))
+ LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = fespi_info->dev->sectorsize ?
+ fespi_info->dev->sectorsize : fespi_info->dev->size_in_bytes;
+
/* create and fill sectors array */
- bank->num_sectors =
- fespi_info->dev->size_in_bytes / fespi_info->dev->sectorsize;
+ bank->num_sectors = fespi_info->dev->size_in_bytes / sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) {
LOG_ERROR("not enough memory");
@@ -982,8 +996,8 @@ static int fespi_probe(struct flash_bank *bank)
}
for (int sector = 0; sector < bank->num_sectors; sector++) {
- sectors[sector].offset = sector * fespi_info->dev->sectorsize;
- sectors[sector].size = fespi_info->dev->sectorsize;
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0;
}
diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c
index f5eab9c..d4d0f76 100644
--- a/src/flash/nor/fm4.c
+++ b/src/flash/nor/fm4.c
@@ -537,11 +537,6 @@ static int fm4_auto_probe(struct flash_bank *bank)
return fm4_probe(bank);
}
-static int fm4_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
{
struct fm4_flash_bank *fm4_bank = bank->driver_priv;
@@ -714,7 +709,6 @@ struct flash_driver fm4_flash = {
.info = fm4_get_info_command,
.probe = fm4_probe,
.auto_probe = fm4_auto_probe,
- .protect_check = fm4_protect_check,
.read = default_flash_read,
.erase = fm4_flash_erase,
.erase_check = default_flash_blank_check,
diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c
index c28ad22..0750fdf 100644
--- a/src/flash/nor/jtagspi.c
+++ b/src/flash/nor/jtagspi.c
@@ -166,7 +166,7 @@ static int jtagspi_probe(struct flash_bank *bank)
struct jtagspi_flash_bank *info = bank->driver_priv;
struct flash_sector *sectors;
uint8_t in_buf[3];
- uint32_t id;
+ uint32_t id, sectorsize;
if (info->probed)
free(bank->sectors);
@@ -199,10 +199,17 @@ static int jtagspi_probe(struct flash_bank *bank)
/* Set correct size value */
bank->size = info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+ if (bank->size > (1UL << 24))
+ LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = info->dev->sectorsize ?
+ info->dev->sectorsize : info->dev->size_in_bytes;
/* create and fill sectors array */
- bank->num_sectors =
- info->dev->size_in_bytes / info->dev->sectorsize;
+ bank->num_sectors = info->dev->size_in_bytes / sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) {
LOG_ERROR("not enough memory");
@@ -210,8 +217,8 @@ static int jtagspi_probe(struct flash_bank *bank)
}
for (int sector = 0; sector < bank->num_sectors; sector++) {
- sectors[sector].offset = sector * info->dev->sectorsize;
- sectors[sector].size = info->dev->sectorsize;
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0;
}
@@ -269,6 +276,9 @@ static int jtagspi_bulk_erase(struct flash_bank *bank)
int retval;
int64_t t0 = timeval_ms();
+ if (info->dev->chip_erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
retval = jtagspi_write_enable(bank);
if (retval != ERROR_OK)
return retval;
@@ -328,6 +338,9 @@ static int jtagspi_erase(struct flash_bank *bank, int first, int last)
LOG_WARNING("Bulk flash erase failed. Falling back to sector erase.");
}
+ if (info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
for (sector = first; sector <= last; sector++) {
retval = jtagspi_sector_erase(bank, sector);
if (retval != ERROR_OK) {
@@ -343,21 +356,11 @@ static int jtagspi_protect(struct flash_bank *bank, int set, int first, int last
{
int sector;
- if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
- LOG_ERROR("Flash sector invalid");
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
for (sector = first; sector <= last; sector++)
bank->sectors[sector].is_protected = set;
return ERROR_OK;
}
-static int jtagspi_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
static int jtagspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct jtagspi_flash_bank *info = bank->driver_priv;
@@ -386,16 +389,19 @@ static int jtagspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_
{
struct jtagspi_flash_bank *info = bank->driver_priv;
int retval;
- uint32_t n;
+ uint32_t n, pagesize;
if (!(info->probed)) {
LOG_ERROR("Flash bank not yet probed.");
return ERROR_FLASH_BANK_NOT_PROBED;
}
- for (n = 0; n < count; n += info->dev->pagesize) {
+ /* if no write pagesize, use reasonable default */
+ pagesize = info->dev->pagesize ? info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
+
+ for (n = 0; n < count; n += pagesize) {
retval = jtagspi_page_write(bank, buffer + n, offset + n,
- MIN(count - n, info->dev->pagesize));
+ MIN(count - n, pagesize));
if (retval != ERROR_OK) {
LOG_ERROR("page write error");
return retval;
@@ -431,7 +437,6 @@ struct flash_driver jtagspi_flash = {
.probe = jtagspi_probe,
.auto_probe = jtagspi_probe,
.erase_check = default_flash_blank_check,
- .protect_check = jtagspi_protect_check,
.info = jtagspi_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c
index 9e93570..1d53907 100644
--- a/src/flash/nor/kinetis.c
+++ b/src/flash/nor/kinetis.c
@@ -1035,7 +1035,7 @@ static int kinetis_disable_wdog_algo(struct target *target, size_t code_size, co
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
- init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
+ init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
buf_set_u32(reg_params[0].value, 0, 32, wdog_base);
retval = target_run_algorithm(target, 0, NULL, 1, reg_params,
diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c
index b14e5ca..bced291 100644
--- a/src/flash/nor/lpc2000.c
+++ b/src/flash/nor/lpc2000.c
@@ -12,6 +12,9 @@
* by Nemui Trinomius *
* nemuisan_kawausogasuki@live.jp *
* *
+ * LPC8N04/HNS31xx support Copyright (C) 2018 *
+ * by Jean-Christian de Rivaz jcdr [at] innodelec [dot] ch *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
@@ -38,7 +41,7 @@
/**
* @file
- * flash programming support for NXP LPC8xx,LPC1xxx,LPC4xxx,LP5410x and LPC2xxx devices.
+ * flash programming support for NXP LPC8xx,LPC1xxx,LPC4xxx,LP5410x,LPC2xxx and NHS31xx devices.
*
* @todo Provide a way to update CCLK after declaring the flash bank. The value which is correct after chip reset will
* rarely still work right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz).
@@ -77,6 +80,9 @@
* lpc800:
* - 810 | 1 | 2 (tested with LPC810/LPC811/LPC812)
* - 822 | 4 (tested with LPC824)
+ * - 8N04
+ * - NHS31xx (tested with NHS3100)
+ * - 844 | 5 (tested with LPC845)
*
* lpc1100:
* - 11xx
@@ -111,6 +117,8 @@
* - 408x
* - 81x
* - 82x
+ * - 8N04
+ * - NHS31xx
*/
/* Part IDs for autodetection */
@@ -257,6 +265,20 @@
#define LPC824_201 0x00008241
#define LPC824_201_1 0x00008242
+#define LPC8N04 0x00008A04
+#define NHS3100 0x4e310020
+#define NHS3152 0x4e315220
+#define NHS3153 0x4e315320 /* Only specified in Rev.1 of the datasheet */
+
+#define LPC844_201 0x00008441
+#define LPC844_201_1 0x00008442
+#define LPC844_201_2 0x00008444
+
+#define LPC845_301 0x00008451
+#define LPC845_301_1 0x00008452
+#define LPC845_301_2 0x00008453
+#define LPC845_301_3 0x00008454
+
#define IAP_CODE_LEN 0x34
#define LPC11xx_REG_SECTORS 24
@@ -282,6 +304,7 @@ struct lpc2000_flash_bank {
int checksum_vector;
uint32_t iap_max_stack;
uint32_t lpc4300_bank;
+ uint32_t iap_entry_alternative;
bool probed;
};
@@ -526,10 +549,18 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
case 16 * 1024:
bank->num_sectors = 16;
break;
+ case 30 * 1024:
+ lpc2000_info->cmd51_max_buffer = 1024; /* For LPC8N04 and NHS31xx, have 8kB of SRAM */
+ bank->num_sectors = 30; /* There have only 30kB of writable Flash out of 32kB */
+ break;
case 32 * 1024:
lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */
bank->num_sectors = 32;
break;
+ case 64 * 1024:
+ lpc2000_info->cmd51_max_buffer = 1024; /* For LPC844, has 8kB of SRAM */
+ bank->num_sectors = 64;
+ break;
default:
LOG_ERROR("BUG: unknown bank->size encountered");
exit(-1);
@@ -741,6 +772,9 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo
exit(-1);
}
+ if (lpc2000_info->iap_entry_alternative != 0x0)
+ iap_entry_point = lpc2000_info->iap_entry_alternative;
+
struct mem_param mem_params[2];
/* command parameter table */
@@ -938,6 +972,8 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
lpc2000_info->calc_checksum = 1;
}
+ if (CMD_ARGC >= 10 && !lpc2000_info->iap_entry_alternative)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[9], lpc2000_info->iap_entry_alternative);
return ERROR_OK;
}
@@ -1018,12 +1054,6 @@ static int lpc2000_erase(struct flash_bank *bank, int first, int last)
return retval;
}
-static int lpc2000_protect(struct flash_bank *bank, int set, int first, int last)
-{
- /* can't protect/unprotect on the lpc2000 */
- return ERROR_OK;
-}
-
static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
@@ -1458,6 +1488,25 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank)
bank->size = 32 * 1024;
break;
+ case LPC8N04:
+ case NHS3100:
+ case NHS3152:
+ case NHS3153:
+ lpc2000_info->variant = lpc800;
+ bank->size = 30 * 1024;
+ break;
+
+ case LPC844_201:
+ case LPC844_201_1:
+ case LPC844_201_2:
+ case LPC845_301:
+ case LPC845_301_1:
+ case LPC845_301_2:
+ case LPC845_301_3:
+ lpc2000_info->variant = lpc800;
+ bank->size = 64 * 1024;
+ break;
+
default:
LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id);
exit(-1);
@@ -1501,12 +1550,6 @@ static int lpc2000_erase_check(struct flash_bank *bank)
return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
}
-static int lpc2000_protect_check(struct flash_bank *bank)
-{
- /* sectors are always protected */
- return ERROR_OK;
-}
-
static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
@@ -1571,13 +1614,11 @@ struct flash_driver lpc2000_flash = {
.commands = lpc2000_command_handlers,
.flash_bank_command = lpc2000_flash_bank_command,
.erase = lpc2000_erase,
- .protect = lpc2000_protect,
.write = lpc2000_write,
.read = default_flash_read,
.probe = lpc2000_probe,
.auto_probe = lpc2000_probe,
.erase_check = lpc2000_erase_check,
- .protect_check = lpc2000_protect_check,
.info = get_lpc2000_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/lpc288x.c b/src/flash/nor/lpc288x.c
index 2472913..afa8d79 100644
--- a/src/flash/nor/lpc288x.c
+++ b/src/flash/nor/lpc288x.c
@@ -167,6 +167,7 @@ static int lpc288x_read_part_info(struct flash_bank *bank)
return ERROR_OK;
}
+/* TODO: Revisit! Is it impossible to read protection status? */
static int lpc288x_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
@@ -231,17 +232,6 @@ static uint32_t lpc288x_system_ready(struct flash_bank *bank)
return ERROR_OK;
}
-static int lpc288x_erase_check(struct flash_bank *bank)
-{
- uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
- if (status != ERROR_OK) {
- LOG_INFO("Processor not halted/not probed");
- return status;
- }
-
- return ERROR_OK;
-}
-
static int lpc288x_erase(struct flash_bank *bank, int first, int last)
{
uint32_t status;
@@ -431,7 +421,7 @@ struct flash_driver lpc288x_flash = {
.read = default_flash_read,
.probe = lpc288x_probe,
.auto_probe = lpc288x_probe,
- .erase_check = lpc288x_erase_check,
+ .erase_check = default_flash_blank_check,
.protect_check = lpc288x_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/lpc2900.c b/src/flash/nor/lpc2900.c
index 1c65933..022fb82 100644
--- a/src/flash/nor/lpc2900.c
+++ b/src/flash/nor/lpc2900.c
@@ -1035,18 +1035,13 @@ static int lpc2900_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
-static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last)
-{
- /* This command is not supported.
- * "Protection" in LPC2900 terms is handled transparently. Sectors will
- * automatically be unprotected as needed.
- * Instead we use the concept of sector security. A secured sector is shown
- * as "protected" in OpenOCD. Sector security is a permanent feature, and
- * cannot be disabled once activated.
- */
-
- return ERROR_OK;
-}
+/* lpc2900_protect command is not supported.
+* "Protection" in LPC2900 terms is handled transparently. Sectors will
+* automatically be unprotected as needed.
+* Instead we use the concept of sector security. A secured sector is shown
+* as "protected" in OpenOCD. Sector security is a permanent feature, and
+* cannot be disabled once activated.
+*/
/**
* Write data to flash.
@@ -1591,7 +1586,6 @@ struct flash_driver lpc2900_flash = {
.commands = lpc2900_command_handlers,
.flash_bank_command = lpc2900_flash_bank_command,
.erase = lpc2900_erase,
- .protect = lpc2900_protect,
.write = lpc2900_write,
.read = default_flash_read,
.probe = lpc2900_probe,
diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c
index 828c60c..a50584f 100644
--- a/src/flash/nor/lpcspifi.c
+++ b/src/flash/nor/lpcspifi.c
@@ -387,6 +387,9 @@ static int lpcspifi_bulk_erase(struct flash_bank *bank)
uint32_t value;
int retval = ERROR_OK;
+ if (lpcspifi_info->dev->chip_erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
retval = lpcspifi_set_sw_mode(bank);
if (retval == ERROR_OK)
@@ -460,6 +463,9 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase.");
}
+ if (lpcspifi_info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
retval = lpcspifi_set_hw_mode(bank);
if (retval != ERROR_OK)
return retval;
@@ -613,7 +619,9 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
}
}
- page_size = lpcspifi_info->dev->pagesize;
+ /* if no valid page_size, use reasonable default */
+ page_size = lpcspifi_info->dev->pagesize ?
+ lpcspifi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
retval = lpcspifi_set_hw_mode(bank);
if (retval != ERROR_OK)
@@ -839,6 +847,7 @@ static int lpcspifi_probe(struct flash_bank *bank)
struct flash_sector *sectors;
uint32_t id = 0; /* silence uninitialized warning */
int retval;
+ uint32_t sectorsize;
/* If we've already probed, we should be fine to skip this time. */
if (lpcspifi_info->probed)
@@ -876,10 +885,17 @@ static int lpcspifi_probe(struct flash_bank *bank)
/* Set correct size value */
bank->size = lpcspifi_info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+ if (bank->size > (1UL << 24))
+ LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = lpcspifi_info->dev->sectorsize ?
+ lpcspifi_info->dev->sectorsize : lpcspifi_info->dev->size_in_bytes;
/* create and fill sectors array */
- bank->num_sectors =
- lpcspifi_info->dev->size_in_bytes / lpcspifi_info->dev->sectorsize;
+ bank->num_sectors = lpcspifi_info->dev->size_in_bytes / sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) {
LOG_ERROR("not enough memory");
@@ -887,8 +903,8 @@ static int lpcspifi_probe(struct flash_bank *bank)
}
for (int sector = 0; sector < bank->num_sectors; sector++) {
- sectors[sector].offset = sector * lpcspifi_info->dev->sectorsize;
- sectors[sector].size = lpcspifi_info->dev->sectorsize;
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0;
}
diff --git a/src/flash/nor/mdr.c b/src/flash/nor/mdr.c
index f3916de..c4a4458 100644
--- a/src/flash/nor/mdr.c
+++ b/src/flash/nor/mdr.c
@@ -86,11 +86,6 @@ FLASH_BANK_COMMAND_HANDLER(mdr_flash_bank_command)
return ERROR_OK;
}
-static int mdr_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
static int mdr_mass_erase(struct flash_bank *bank)
{
struct target *target = bank->target;
@@ -217,11 +212,6 @@ reset_pg_and_lock:
return retval;
}
-static int mdr_protect(struct flash_bank *bank, int set, int first, int last)
-{
- return ERROR_OK;
-}
-
static int mdr_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
@@ -625,13 +615,11 @@ struct flash_driver mdr_flash = {
"<type>: 0 for main memory, 1 for info memory",
.flash_bank_command = mdr_flash_bank_command,
.erase = mdr_erase,
- .protect = mdr_protect,
.write = mdr_write,
.read = mdr_read,
.probe = mdr_probe,
.auto_probe = mdr_auto_probe,
.erase_check = default_flash_blank_check,
- .protect_check = mdr_protect_check,
.info = get_mdr_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c
index eda6cc1..cb2cfdb 100644
--- a/src/flash/nor/mrvlqspi.c
+++ b/src/flash/nor/mrvlqspi.c
@@ -503,6 +503,9 @@ static int mrvlqspi_bulk_erase(struct flash_bank *bank)
int retval;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
+ if (mrvlqspi_info->dev->chip_erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
/* Set flash write enable */
retval = mrvlqspi_set_write_status(bank, WRITE_ENABLE);
if (retval != ERROR_OK)
@@ -570,6 +573,9 @@ static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last)
" Falling back to sector-by-sector erase.");
}
+ if (mrvlqspi_info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
for (sector = first; sector <= last; sector++) {
retval = mrvlqspi_block_erase(bank,
sector * mrvlqspi_info->dev->sectorsize);
@@ -619,7 +625,9 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
}
}
- page_size = mrvlqspi_info->dev->pagesize;
+ /* if no valid page_size, use reasonable default */
+ page_size = mrvlqspi_info->dev->pagesize ?
+ mrvlqspi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
/* See contrib/loaders/flash/mrvlqspi.S for src */
static const uint8_t mrvlqspi_flash_write_code[] = {
@@ -826,6 +834,7 @@ static int mrvlqspi_probe(struct flash_bank *bank)
uint32_t id = 0;
int retval;
struct flash_sector *sectors;
+ uint32_t sectorsize;
/* If we've already probed, we should be fine to skip this time. */
if (mrvlqspi_info->probed)
@@ -859,12 +868,20 @@ static int mrvlqspi_probe(struct flash_bank *bank)
LOG_INFO("Found flash device \'%s\' ID 0x%08" PRIx32,
mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id);
+
/* Set correct size value */
bank->size = mrvlqspi_info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+ if (bank->size > (1UL << 24))
+ LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = mrvlqspi_info->dev->sectorsize ?
+ mrvlqspi_info->dev->sectorsize : mrvlqspi_info->dev->size_in_bytes;
/* create and fill sectors array */
- bank->num_sectors = mrvlqspi_info->dev->size_in_bytes /
- mrvlqspi_info->dev->sectorsize;
+ bank->num_sectors = mrvlqspi_info->dev->size_in_bytes / sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) {
LOG_ERROR("not enough memory");
@@ -872,9 +889,8 @@ static int mrvlqspi_probe(struct flash_bank *bank)
}
for (int sector = 0; sector < bank->num_sectors; sector++) {
- sectors[sector].offset =
- sector * mrvlqspi_info->dev->sectorsize;
- sectors[sector].size = mrvlqspi_info->dev->sectorsize;
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0;
}
@@ -899,12 +915,6 @@ static int mrvlqspi_flash_erase_check(struct flash_bank *bank)
return ERROR_OK;
}
-static int mrvlqspi_protect_check(struct flash_bank *bank)
-{
- /* Not implemented yet */
- return ERROR_OK;
-}
-
int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
@@ -947,13 +957,11 @@ struct flash_driver mrvlqspi_flash = {
.name = "mrvlqspi",
.flash_bank_command = mrvlqspi_flash_bank_command,
.erase = mrvlqspi_flash_erase,
- .protect = NULL,
.write = mrvlqspi_flash_write,
.read = mrvlqspi_flash_read,
.probe = mrvlqspi_probe,
.auto_probe = mrvlqspi_auto_probe,
.erase_check = mrvlqspi_flash_erase_check,
- .protect_check = mrvlqspi_protect_check,
.info = mrvlqspi_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c
index 5caa052..e2e65d4 100644
--- a/src/flash/nor/msp432.c
+++ b/src/flash/nor/msp432.c
@@ -655,12 +655,6 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
return retval;
}
-static int msp432_protect(struct flash_bank *bank, int set, int first,
- int last)
-{
- return ERROR_OK;
-}
-
static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
@@ -985,11 +979,6 @@ static int msp432_auto_probe(struct flash_bank *bank)
return retval;
}
-static int msp432_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
static int msp432_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct msp432_bank *msp432_bank = bank->driver_priv;
@@ -1091,13 +1080,11 @@ struct flash_driver msp432_flash = {
.commands = msp432_command_handlers,
.flash_bank_command = msp432_flash_bank_command,
.erase = msp432_erase,
- .protect = msp432_protect,
.write = msp432_write,
.read = default_flash_read,
.probe = msp432_probe,
.auto_probe = msp432_auto_probe,
.erase_check = default_flash_blank_check,
- .protect_check = msp432_protect_check,
.info = msp432_info,
.free_driver_priv = msp432_flash_free_driver_priv,
};
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index 9c48e1a..5f6204a 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -211,6 +211,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
+ NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512),
/* nRF52840 Devices */
NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
@@ -248,7 +249,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
{
uint32_t ready;
int res;
- int timeout_ms = 200;
+ int timeout_ms = 340;
int64_t ts_start = timeval_ms();
do {
diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c
index 895c4af..acc464b 100644
--- a/src/flash/nor/ocl.c
+++ b/src/flash/nor/ocl.c
@@ -30,16 +30,6 @@ struct ocl_priv {
unsigned int bufalign;
};
-static int ocl_erase_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
-static int ocl_protect_check(struct flash_bank *bank)
-{
- return ERROR_OK;
-}
-
/* flash_bank ocl 0 0 0 0 <target#> */
FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
{
@@ -111,11 +101,6 @@ static int ocl_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
-static int ocl_protect(struct flash_bank *bank, int set, int first, int last)
-{
- return ERROR_OK;
-}
-
static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct ocl_priv *ocl = bank->driver_priv;
@@ -333,12 +318,10 @@ struct flash_driver ocl_flash = {
.name = "ocl",
.flash_bank_command = ocl_flash_bank_command,
.erase = ocl_erase,
- .protect = ocl_protect,
.write = ocl_write,
.read = default_flash_read,
.probe = ocl_probe,
- .erase_check = ocl_erase_check,
- .protect_check = ocl_protect_check,
+ .erase_check = default_flash_blank_check,
.auto_probe = ocl_auto_probe,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c
index b88abbb..d8e1c15 100644
--- a/src/flash/nor/psoc5lp.c
+++ b/src/flash/nor/psoc5lp.c
@@ -753,16 +753,6 @@ static int psoc5lp_nvl_write(struct flash_bank *bank,
return ERROR_OK;
}
-static int psoc5lp_nvl_protect_check(struct flash_bank *bank)
-{
- int i;
-
- for (i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_protected = -1;
-
- return ERROR_OK;
-}
-
static int psoc5lp_nvl_get_info_command(struct flash_bank *bank,
char *buf, int buf_size)
{
@@ -855,7 +845,6 @@ struct flash_driver psoc5lp_nvl_flash = {
.info = psoc5lp_nvl_get_info_command,
.probe = psoc5lp_nvl_probe,
.auto_probe = psoc5lp_nvl_auto_probe,
- .protect_check = psoc5lp_nvl_protect_check,
.read = psoc5lp_nvl_read,
.erase = psoc5lp_nvl_erase,
.erase_check = psoc5lp_nvl_erase_check,
@@ -945,16 +934,6 @@ static int psoc5lp_eeprom_write(struct flash_bank *bank,
return ERROR_OK;
}
-static int psoc5lp_eeprom_protect_check(struct flash_bank *bank)
-{
- int i;
-
- for (i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_protected = -1;
-
- return ERROR_OK;
-}
-
static int psoc5lp_eeprom_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
{
struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv;
@@ -1064,7 +1043,6 @@ struct flash_driver psoc5lp_eeprom_flash = {
.info = psoc5lp_eeprom_get_info_command,
.probe = psoc5lp_eeprom_probe,
.auto_probe = psoc5lp_eeprom_auto_probe,
- .protect_check = psoc5lp_eeprom_protect_check,
.read = default_flash_read,
.erase = psoc5lp_eeprom_erase,
.erase_check = default_flash_blank_check,
diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c
index 6ac253d..af72ffc 100644
--- a/src/flash/nor/spi.c
+++ b/src/flash/nor/spi.c
@@ -1,4 +1,7 @@
/***************************************************************************
+ * Copyright (C) 2018 by Andreas Bolsch *
+ * andreas.bolsch@mni.thm.de *
+ * *
* Copyright (C) 2012 by George Harris *
* george@luminairecoffee.com *
* *
@@ -30,58 +33,118 @@
/* Shared table of known SPI flash devices for SPI-based flash drivers. Taken
* from device datasheets and Linux SPI flash drivers. */
const struct flash_device flash_devices[] = {
- /* name, erase_cmd, chip_erase_cmd, device_id, pagesize, sectorsize, size_in_bytes */
- FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000),
- FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000),
- FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000),
- FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000),
- FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000),
- FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000),
- FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000),
- FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000),
- FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000),
- FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
- FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
- FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
- FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
- FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000),
- FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000),
- FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000),
- FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000),
- FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000),
- FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000),
- FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000),
- FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000),
- FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000),
- FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000),
- FLASH_ID("cy s25fl256", 0xd8, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000),
- FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000),
- FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000),
- FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000),
- FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000),
- FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000),
- FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000),
- FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000),
- FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000),
- FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000),
- FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000),
- FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000),
- FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000),
- FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000),
- FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000),
- FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000),
- FLASH_ID("micron n25q256 3v", 0xd8, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000),
- FLASH_ID("micron n25q256 1.8v", 0xd8, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000),
- FLASH_ID("issi is25lp128", 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000),
- FLASH_ID("issi is25wp256d", 0xd8, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000),
- FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000),
- FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000),
- FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000),
- FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000),
- FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000),
- FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000),
- FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000),
- FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000),
- FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
- FLASH_ID(NULL, 0, 0, 0, 0, 0, 0)
+ /* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id,
+ * pagesize, sectorsize, size_in_bytes */
+ FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000),
+ FLASH_ID("st m25p10", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000),
+ FLASH_ID("st m25p20", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000),
+ FLASH_ID("st m25p40", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000),
+ FLASH_ID("st m25p80", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000),
+ FLASH_ID("st m25p16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000),
+ FLASH_ID("st m25p32", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000),
+ FLASH_ID("st m25p64", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000),
+ FLASH_ID("st m25p128", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000),
+ FLASH_ID("st m45pe10", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
+ FLASH_ID("st m45pe20", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
+ FLASH_ID("st m45pe40", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
+ FLASH_ID("st m45pe80", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
+ FLASH_ID("sp s25fl004", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000),
+ FLASH_ID("sp s25fl008", 0x03, 0x08, 0x02, 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000),
+ FLASH_ID("sp s25fl016", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000),
+ FLASH_ID("sp s25fl116k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000),
+ FLASH_ID("sp s25fl032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000),
+ FLASH_ID("sp s25fl132k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000),
+ FLASH_ID("sp s25fl064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000),
+ FLASH_ID("sp s25fl164k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000),
+ FLASH_ID("sp s25fl128s", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("sp s25fl256s", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("sp s25fl512s", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00200201, 0x200, 0x40000, 0x4000000),
+ FLASH_ID("cyp s25fl064l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00176001, 0x100, 0x10000, 0x800000),
+ FLASH_ID("cyp s25fl128l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00186001, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("cyp s25fl256l", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("atmel 25f512", 0x03, 0x00, 0x02, 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000),
+ FLASH_ID("atmel 25f1024", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000),
+ FLASH_ID("atmel 25f2048", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000),
+ FLASH_ID("atmel 25f4096", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000),
+ FLASH_ID("atmel 25fs040", 0x03, 0x00, 0x02, 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000),
+ FLASH_ID("adesto 25df081a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001451f, 0x100, 0x10000, 0x100000),
+ FLASH_ID("mac 25l512", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000),
+ FLASH_ID("mac 25l1005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000),
+ FLASH_ID("mac 25l2005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000),
+ FLASH_ID("mac 25l4005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000),
+ FLASH_ID("mac 25l8005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000),
+ FLASH_ID("mac 25l1605", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000),
+ FLASH_ID("mac 25l3205", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000),
+ FLASH_ID("mac 25l6405", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000),
+ FLASH_ID("mac 25l12845", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001820c2, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("mac 25l25645", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001920c2, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("mac 25l51245", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a20c2, 0x100, 0x10000, 0x4000000),
+ FLASH_ID("mac 25lm51245", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003a85c2, 0x100, 0x10000, 0x4000000),
+ FLASH_ID("mac 25r512f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001028c2, 0x100, 0x10000, 0x10000),
+ FLASH_ID("mac 25r1035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001128c2, 0x100, 0x10000, 0x20000),
+ FLASH_ID("mac 25r2035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001228c2, 0x100, 0x10000, 0x40000),
+ FLASH_ID("mac 25r4035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001328c2, 0x100, 0x10000, 0x80000),
+ FLASH_ID("mac 25r8035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001428c2, 0x100, 0x10000, 0x100000),
+ FLASH_ID("mac 25r1635f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001528c2, 0x100, 0x10000, 0x200000),
+ FLASH_ID("mac 25r3235f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001628c2, 0x100, 0x10000, 0x400000),
+ FLASH_ID("mac 25r6435f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001728c2, 0x100, 0x10000, 0x800000),
+ FLASH_ID("micron n25q064", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000),
+ FLASH_ID("micron n25q128", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("micron n25q256 3v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("micron n25q256 1.8v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("micron mt25ql512", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0020ba20, 0x100, 0x10000, 0x4000000),
+ FLASH_ID("micron mt25ql01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021ba20, 0x100, 0x10000, 0x8000000),
+ FLASH_ID("micron mt25ql02", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0022ba20, 0x100, 0x10000, 0x10000000),
+ FLASH_ID("win w25q80bv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000),
+ FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000),
+ FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001570ef, 0x100, 0x10000, 0x200000), /* QPI / DTR */
+ FLASH_ID("win w25q32fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000),
+ FLASH_ID("win w25q32fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), /* QPI mode */
+ FLASH_ID("win w25q32jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001670ef, 0x100, 0x10000, 0x400000),
+ FLASH_ID("win w25q64fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000),
+ FLASH_ID("win w25q64fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001760ef, 0x100, 0x10000, 0x800000), /* QPI mode */
+ FLASH_ID("win w25q64jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001770ef, 0x100, 0x10000, 0x800000),
+ FLASH_ID("win w25q128fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("win w25q128fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001860ef, 0x100, 0x10000, 0x1000000), /* QPI mode */
+ FLASH_ID("win w25q128jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001870ef, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("win w25q256fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001940ef, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("win w25q256fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001960ef, 0x100, 0x10000, 0x2000000), /* QPI mode */
+ FLASH_ID("win w25q256jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001970ef, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("gd gd25q512", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001040c8, 0x100, 0x1000, 0x10000),
+ FLASH_ID("gd gd25q10", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001140c8, 0x100, 0x1000, 0x20000),
+ FLASH_ID("gd gd25q20", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001240c8, 0x100, 0x1000, 0x40000),
+ FLASH_ID("gd gd25q40", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001340c8, 0x100, 0x1000, 0x80000),
+ FLASH_ID("gd gd25q16c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000),
+ FLASH_ID("gd gd25q32c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000),
+ FLASH_ID("gd gd25q64c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001740c8, 0x100, 0x10000, 0x800000),
+ FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000),
+ FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),
+ FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000),
+ FLASH_ID("issi is25lp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("issi is25wp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018709d, 0x100, 0x10000, 0x1000000),
+ FLASH_ID("issi is25lp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019609d, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("issi is25wp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000),
+ FLASH_ID("issi is25lp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a609d, 0x100, 0x10000, 0x4000000),
+ FLASH_ID("issi is25wp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a709d, 0x100, 0x10000, 0x4000000),
+
+ /* FRAM, no erase commands, no write page or sectors */
+ FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800),
+ FRAM_ID("fu mb85rs32v", 0x03, 0, 0x02, 0x00010204, 0x1000), /* exists ? */
+ FRAM_ID("fu mb85rs64v", 0x03, 0, 0x02, 0x00020304, 0x2000),
+ FRAM_ID("fu mb85rs128b", 0x03, 0, 0x02, 0x00090404, 0x4000),
+ FRAM_ID("fu mb85rs256b", 0x03, 0, 0x02, 0x00090504, 0x8000),
+ FRAM_ID("fu mb85rs512t", 0x03, 0, 0x02, 0x00032604, 0x10000),
+ FRAM_ID("fu mb85rs1mt", 0x03, 0, 0x02, 0x00032704, 0x20000),
+ FRAM_ID("fu mb85rs2mta", 0x03, 0, 0x02, 0x00034804, 0x40000),
+ FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x000821c2, 0x4000),
+ FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x000022c2, 0x8000),
+ FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x000822c2, 0x8000),
+ FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x000023c2, 0x10000),
+ FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x000024c2, 0x20000),
+ FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x000825c2, 0x40000),
+ FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x004026c2, 0x80000),
+
+ FLASH_ID(NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0)
};
diff --git a/src/flash/nor/spi.h b/src/flash/nor/spi.h
index a184998..11c381f 100644
--- a/src/flash/nor/spi.h
+++ b/src/flash/nor/spi.h
@@ -1,4 +1,7 @@
/***************************************************************************
+ * Copyright (C) 2018 by Andreas Bolsch *
+ * andreas.bolsch@mni.thm.de *
+ * *
* Copyright (C) 2012 by George Harris *
* george@luminairecoffee.com *
* *
@@ -22,40 +25,69 @@
#ifndef OPENOCD_FLASH_NOR_SPI_H
#define OPENOCD_FLASH_NOR_SPI_H
+#ifndef __ASSEMBLER__
+
/* data structure to maintain flash ids from different vendors */
struct flash_device {
char *name;
+ uint8_t read_cmd;
+ uint8_t qread_cmd;
+ uint8_t pprog_cmd;
uint8_t erase_cmd;
uint8_t chip_erase_cmd;
uint32_t device_id;
uint32_t pagesize;
- unsigned long sectorsize;
- unsigned long size_in_bytes;
+ uint32_t sectorsize;
+ uint32_t size_in_bytes;
};
-#define FLASH_ID(n, es, ces, id, psize, ssize, size) \
-{ \
- .name = n, \
- .erase_cmd = es, \
- .chip_erase_cmd = ces, \
- .device_id = id, \
- .pagesize = psize, \
- .sectorsize = ssize, \
- .size_in_bytes = size \
+#define FLASH_ID(n, re, qr, pp, es, ces, id, psize, ssize, size) \
+{ \
+ .name = n, \
+ .read_cmd = re, \
+ .qread_cmd = qr, \
+ .pprog_cmd = pp, \
+ .erase_cmd = es, \
+ .chip_erase_cmd = ces, \
+ .device_id = id, \
+ .pagesize = psize, \
+ .sectorsize = ssize, \
+ .size_in_bytes = size, \
+}
+
+#define FRAM_ID(n, re, qr, pp, id, size) \
+{ \
+ .name = n, \
+ .read_cmd = re, \
+ .qread_cmd = qr, \
+ .pprog_cmd = pp, \
+ .erase_cmd = 0x00, \
+ .chip_erase_cmd = 0x00, \
+ .device_id = id, \
+ .pagesize = 0, \
+ .sectorsize = 0, \
+ .size_in_bytes = size, \
}
extern const struct flash_device flash_devices[];
+#endif
+
/* fields in SPI flash status register */
-#define SPIFLASH_BSY_BIT 0x00000001 /* WIP Bit of SPI SR on SMI SR */
-#define SPIFLASH_WE_BIT 0x00000002 /* WEL Bit of SPI SR on SMI SR */
+#define SPIFLASH_BSY 0
+#define SPIFLASH_BSY_BIT (1 << SPIFLASH_BSY) /* WIP Bit of SPI SR */
+#define SPIFLASH_WE 1
+#define SPIFLASH_WE_BIT (1 << SPIFLASH_WE) /* WEL Bit of SPI SR */
/* SPI Flash Commands */
#define SPIFLASH_READ_ID 0x9F /* Read Flash Identification */
+#define SPIFLASH_READ_MID 0xAF /* Read Flash Identification, multi-io */
#define SPIFLASH_READ_STATUS 0x05 /* Read Status Register */
#define SPIFLASH_WRITE_ENABLE 0x06 /* Write Enable */
#define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */
#define SPIFLASH_FAST_READ 0x0B /* Fast Read */
#define SPIFLASH_READ 0x03 /* Normal Read */
+#define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */
+
#endif /* OPENOCD_FLASH_NOR_SPI_H */
diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c
index 79aaf3b..8731f8b 100644
--- a/src/flash/nor/stellaris.c
+++ b/src/flash/nor/stellaris.c
@@ -1355,6 +1355,7 @@ COMMAND_HANDLER(stellaris_handle_mass_erase_command)
COMMAND_HANDLER(stellaris_handle_recover_command)
{
struct flash_bank *bank;
+ struct arm *arm;
int retval;
if (CMD_ARGC != 0)
@@ -1383,12 +1384,13 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
}
adapter_assert_reset();
+ arm = target_to_arm(bank->target);
for (int i = 0; i < 5; i++) {
- retval = dap_to_swd(bank->target);
+ retval = dap_to_swd(arm->dap);
if (retval != ERROR_OK)
goto done;
- retval = dap_to_jtag(bank->target);
+ retval = dap_to_jtag(arm->dap);
if (retval != ERROR_OK)
goto done;
}
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c
index fbd7598..cd060da 100644
--- a/src/flash/nor/stm32f1x.c
+++ b/src/flash/nor/stm32f1x.c
@@ -131,7 +131,7 @@ struct stm32x_flash_bank {
static int stm32x_mass_erase(struct flash_bank *bank);
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id);
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count);
+ uint32_t address, uint32_t count);
/* flash bank stm32x <base> <size> 0 0 <target#>
*/
@@ -343,8 +343,7 @@ static int stm32x_write_options(struct flash_bank *bank)
target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff);
target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff);
- uint32_t offset = STM32_OB_RDP - bank->base;
- retval = stm32x_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2);
+ retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2);
if (retval != ERROR_OK) {
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
LOG_ERROR("working area required to erase options bytes");
@@ -443,8 +442,10 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
return retval;
retval = stm32x_erase_options(bank);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ LOG_ERROR("stm32x failed to erase options");
return retval;
+ }
for (int i = first; i <= last; i++) {
if (set)
@@ -457,14 +458,13 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
}
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
+ uint32_t address, uint32_t count)
{
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t buffer_size = 16384;
struct working_area *write_algorithm;
struct working_area *source;
- uint32_t address = bank->base + offset;
struct reg_param reg_params[5];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
@@ -599,7 +599,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
goto cleanup;
/* try using a block write */
- retval = stm32x_write_block(bank, buffer, offset, words_remaining);
+ retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining);
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
/* if block write failed (no sufficient working area),
@@ -1227,12 +1227,12 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
return retval;
if (stm32x_erase_options(bank) != ERROR_OK) {
- command_print(CMD_CTX, "stm32x failed to unlock device");
+ command_print(CMD_CTX, "stm32x failed to erase options");
return ERROR_OK;
}
if (stm32x_write_options(bank) != ERROR_OK) {
- command_print(CMD_CTX, "stm32x failed to lock device");
+ command_print(CMD_CTX, "stm32x failed to unlock device");
return ERROR_OK;
}
@@ -1313,7 +1313,8 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
{
struct target *target = NULL;
struct stm32x_flash_bank *stm32x_info = NULL;
- uint16_t optionbyte;
+ uint8_t optionbyte;
+ uint16_t useropt;
if (CMD_ARGC < 2)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1342,6 +1343,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
/* start with current options */
optionbyte = stm32x_info->option_bytes.user;
+ useropt = stm32x_info->option_bytes.data;
/* skip over flash bank */
CMD_ARGC--;
@@ -1360,6 +1362,13 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
optionbyte |= (1 << 2);
else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0)
optionbyte &= ~(1 << 2);
+ else if (strcmp("USEROPT", CMD_ARGV[0]) == 0) {
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt);
+ CMD_ARGC--;
+ CMD_ARGV++;
+ }
else if (stm32x_info->has_dual_banks) {
if (strcmp("BOOT0", CMD_ARGV[0]) == 0)
optionbyte |= (1 << 3);
@@ -1379,6 +1388,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
}
stm32x_info->option_bytes.user = optionbyte;
+ stm32x_info->option_bytes.data = useropt;
if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32x failed to write options");
@@ -1536,7 +1546,7 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.mode = COMMAND_EXEC,
.usage = "bank_id ('SWWDG'|'HWWDG') "
"('RSTSTNDBY'|'NORSTSTNDBY') "
- "('RSTSTOP'|'NORSTSTOP')",
+ "('RSTSTOP'|'NORSTSTOP') ('USEROPT' user_data)",
.help = "Replace bits in device option bytes.",
},
{
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index ad17921..7c5811e 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -33,6 +33,9 @@
* RM0394 (STM32L43x/44x/45x/46x)
* http://www.st.com/resource/en/reference_manual/dm00151940.pdf
*
+ * RM0432 (STM32L4R/4Sxx)
+ * http://www.st.com/resource/en/reference_manual/dm00310109.pdf
+ *
* STM32L476RG Datasheet (for erase timing)
* http://www.st.com/resource/en/datasheet/stm32l476rg.pdf
*
@@ -43,6 +46,14 @@
*
* RM0394 devices have a single bank only.
*
+ * RM0432 devices have single and dual bank operating modes.
+ * The FLASH size is 1Mbyte or 2Mbyte.
+ * Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode).
+ *
+ * Bank mode is controlled by two different bits in option bytes register.
+ * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
+ * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
+ *
*/
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
@@ -82,7 +93,7 @@
#define FLASH_BSY (1 << 16)
/* Fast programming not used => related errors not used*/
#define FLASH_PGSERR (1 << 7) /* Programming sequence error */
-#define FLASH_SIZERR (1 << 6) /* Size error */
+#define FLASH_SIZERR (1 << 6) /* Size error */
#define FLASH_PGAERR (1 << 5) /* Programming alignment error */
#define FLASH_WRPERR (1 << 4) /* Write protection error */
#define FLASH_PROGERR (1 << 3) /* Programming error */
@@ -93,7 +104,8 @@
/* STM32_FLASH_OBR bit definitions (reading) */
-#define OPT_DUALBANK 21 /* dual flash bank only */
+#define OPT_DBANK_LE_1M (1 << 21) /* dual bank for devices up to 1M flash */
+#define OPT_DBANK_GE_2M (1 << 22) /* dual bank for devices with 2M flash */
/* register unlock keys */
@@ -325,7 +337,7 @@ static int stm32l4_protect_check(struct flash_bank *bank)
bank->sectors[i].is_protected = 0;
} else {
uint8_t snb;
- snb = i - stm32l4_info->bank2_start + 256;
+ snb = i - stm32l4_info->bank2_start;
if (((snb >= wrp2a_start) &&
(snb <= wrp2a_end)) ||
((snb >= wrp2b_start) &&
@@ -362,7 +374,7 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last)
1. Check that no Flash memory operation is ongoing by
checking the BSY bit in the FLASH_SR register
2. Set the PER bit and select the page and bank
- you wish to erase in the FLASH_CR register
+ you wish to erase in the FLASH_CR register
3. Set the STRT bit in the FLASH_CR register
4. Wait for the BSY bit to be cleared
*/
@@ -372,9 +384,9 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last)
uint32_t erase_flags;
erase_flags = FLASH_PER | FLASH_STRT;
- if (i >= stm32l4_info->bank2_start) {
+ if (i >= stm32l4_info->bank2_start) {
uint8_t snb;
- snb = (i - stm32l4_info->bank2_start) + 256;
+ snb = i - stm32l4_info->bank2_start;
erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
} else
erase_flags |= i << FLASH_PAGE_SHIFT;
@@ -473,7 +485,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
* buffer, free the algorithm */
target_free_working_area(target, write_algorithm);
- LOG_WARNING("no large enough working area available, can't do block memory writes");
+ LOG_WARNING("large enough working area not available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
}
@@ -594,6 +606,9 @@ static int stm32l4_probe(struct flash_bank *bank)
/* set max flash size depending on family */
switch (device_id & 0xfff) {
+ case 0x470:
+ max_flash_size_in_kb = 2048;
+ break;
case 0x461:
case 0x415:
max_flash_size_in_kb = 1024;
@@ -605,7 +620,7 @@ static int stm32l4_probe(struct flash_bank *bank)
max_flash_size_in_kb = 256;
break;
default:
- LOG_WARNING("Cannot identify target as a STM32L4 family.");
+ LOG_WARNING("Cannot identify target as an STM32L4 family device.");
return ERROR_FAIL;
}
@@ -622,45 +637,77 @@ static int stm32l4_probe(struct flash_bank *bank)
LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
- /* did we assign flash size? */
- assert(flash_size_in_kb != 0xffff);
+ /* did we assign a flash size? */
+ assert((flash_size_in_kb != 0xffff) && flash_size_in_kb);
- /* get options to for DUAL BANK. */
+ /* get options for DUAL BANK. */
retval = target_read_u32(target, STM32_FLASH_OPTR, &options);
if (retval != ERROR_OK)
return retval;
- /* only devices with < 1024 kiB may be set to single bank dual banks */
- if ((flash_size_in_kb == 1024) || !(options & OPT_DUALBANK))
- stm32l4_info->bank2_start = 256;
- else
- stm32l4_info->bank2_start = flash_size_in_kb << 9;
-
- /* did we assign flash size? */
- assert((flash_size_in_kb != 0xffff) && flash_size_in_kb);
-
- /* calculate numbers of pages */
- int num_pages = flash_size_in_kb / 2;
+ int num_pages = 0;
+ int page_size = 0;
- /* check that calculation result makes sense */
- assert(num_pages > 0);
+ switch (device_id & 0xfff) {
+ case 0x470:
+ /* L4R/S have 1M or 2M FLASH and dual/single bank mode.
+ * Page size is 4K or 8K.*/
+ if (flash_size_in_kb == 2048) {
+ stm32l4_info->bank2_start = 256;
+ if (options & OPT_DBANK_GE_2M) {
+ page_size = 4096;
+ num_pages = 512;
+ } else {
+ page_size = 8192;
+ num_pages = 256;
+ }
+ break;
+ }
+ if (flash_size_in_kb == 1024) {
+ stm32l4_info->bank2_start = 128;
+ if (options & OPT_DBANK_LE_1M) {
+ page_size = 4096;
+ num_pages = 256;
+ } else {
+ page_size = 8192;
+ num_pages = 128;
+ }
+ break;
+ }
+ /* Invalid FLASH size for this device. */
+ LOG_WARNING("Invalid flash size for STM32L4+ family device.");
+ return ERROR_FAIL;
+ default:
+ /* Other L4 family devices have 2K pages. */
+ page_size = 2048;
+ num_pages = flash_size_in_kb / 2;
+ /* check that calculation result makes sense */
+ assert(num_pages > 0);
+ if ((flash_size_in_kb == 1024) || !(options & OPT_DBANK_LE_1M))
+ stm32l4_info->bank2_start = 256;
+ else
+ stm32l4_info->bank2_start = num_pages / 2;
+ break;
+ }
+ /* Release sector table if allocated. */
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
+ /* Set bank configuration and construct sector table. */
bank->base = base_address;
- bank->size = num_pages * (1 << 11);
+ bank->size = num_pages * page_size;
bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
if (!bank->sectors)
return ERROR_FAIL; /* Checkme: What better error to use?*/
for (i = 0; i < num_pages; i++) {
- bank->sectors[i].offset = i << 11;
- bank->sectors[i].size = 1 << 11;
+ bank->sectors[i].offset = i * page_size;
+ bank->sectors[i].size = page_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
@@ -703,6 +750,10 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
const char *device_str;
switch (device_id) {
+ case 0x470:
+ device_str = "STM32L4R/4Sxx";
+ break;
+
case 0x461:
device_str = "STM32L496/4A6";
break;
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index 7d43842..255ca3b 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -424,13 +424,6 @@ static int stm32lx_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
-static int stm32lx_protect(struct flash_bank *bank, int set, int first,
- int last)
-{
- LOG_WARNING("protection of the STM32L flash is not implemented");
- return ERROR_OK;
-}
-
static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
@@ -863,7 +856,7 @@ static int stm32lx_probe(struct flash_bank *bank)
bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
bank->sectors[i].size = FLASH_SECTOR_SIZE;
bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 1;
+ bank->sectors[i].is_protected = -1;
}
stm32lx_info->probed = 1;
@@ -956,7 +949,6 @@ struct flash_driver stm32lx_flash = {
.commands = stm32lx_command_handlers,
.flash_bank_command = stm32lx_flash_bank_command,
.erase = stm32lx_erase,
- .protect = stm32lx_protect,
.write = stm32lx_write,
.read = default_flash_read,
.probe = stm32lx_probe,
diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c
index c454291..7603305 100644
--- a/src/flash/nor/stmsmi.c
+++ b/src/flash/nor/stmsmi.c
@@ -269,17 +269,14 @@ static int smi_write_enable(struct flash_bank *bank)
static uint32_t erase_command(struct stmsmi_flash_bank *stmsmi_info,
uint32_t offset)
{
- union {
- uint32_t command;
- uint8_t x[4];
- } cmd;
-
- cmd.x[0] = stmsmi_info->dev->erase_cmd;
- cmd.x[1] = offset >> 16;
- cmd.x[2] = offset >> 8;
- cmd.x[3] = offset;
-
- return cmd.command;
+ uint8_t cmd_bytes[] = {
+ stmsmi_info->dev->erase_cmd,
+ offset >> 16,
+ offset >> 8,
+ offset
+ };
+
+ return le_to_h_u32(cmd_bytes);
}
static int smi_erase_sector(struct flash_bank *bank, int sector)
@@ -348,6 +345,9 @@ static int stmsmi_erase(struct flash_bank *bank, int first, int last)
}
}
+ if (stmsmi_info->dev->erase_cmd == 0x00)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
for (sector = first; sector <= last; sector++) {
retval = smi_erase_sector(bank, sector);
if (retval != ERROR_OK)
@@ -431,7 +431,9 @@ static int stmsmi_write(struct flash_bank *bank, const uint8_t *buffer,
}
}
- page_size = stmsmi_info->dev->pagesize;
+ /* if no valid page_size, use reasonable default */
+ page_size = stmsmi_info->dev->pagesize ?
+ stmsmi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
/* unaligned buffer head */
if (count > 0 && (offset & 3) != 0) {
@@ -524,7 +526,7 @@ static int stmsmi_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv;
- uint32_t io_base;
+ uint32_t io_base, sectorsize;
struct flash_sector *sectors;
uint32_t id = 0; /* silence uninitialized warning */
const struct stmsmi_target *target_device;
@@ -589,10 +591,18 @@ static int stmsmi_probe(struct flash_bank *bank)
/* Set correct size value */
bank->size = stmsmi_info->dev->size_in_bytes;
+ if (bank->size <= (1UL << 16))
+ LOG_WARNING("device needs 2-byte addresses - not implemented");
+ if (bank->size > (1UL << 24))
+ LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
+
+ /* if no sectors, treat whole bank as single sector */
+ sectorsize = stmsmi_info->dev->sectorsize ?
+ stmsmi_info->dev->sectorsize : stmsmi_info->dev->size_in_bytes;
/* create and fill sectors array */
bank->num_sectors =
- stmsmi_info->dev->size_in_bytes / stmsmi_info->dev->sectorsize;
+ stmsmi_info->dev->size_in_bytes / sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) {
LOG_ERROR("not enough memory");
@@ -600,8 +610,8 @@ static int stmsmi_probe(struct flash_bank *bank)
}
for (int sector = 0; sector < bank->num_sectors; sector++) {
- sectors[sector].offset = sector * stmsmi_info->dev->sectorsize;
- sectors[sector].size = stmsmi_info->dev->sectorsize;
+ sectors[sector].offset = sector * sectorsize;
+ sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1;
sectors[sector].is_protected = 1;
}
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index 9ed55ec..0e7a34e 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -98,10 +98,18 @@ COMMAND_HANDLER(handle_flash_info_command)
if (retval != ERROR_OK)
return retval;
- /* We must query the hardware to avoid printing stale information! */
- retval = p->driver->protect_check(p);
- if (retval != ERROR_OK)
- return retval;
+ /* If the driver does not implement protection, we show the default
+ * state of is_protected array - usually protection state unknown */
+ if (p->driver->protect_check == NULL) {
+ retval = ERROR_FLASH_OPER_UNSUPPORTED;
+ } else {
+ /* We must query the hardware to avoid printing stale information! */
+ retval = p->driver->protect_check(p);
+ if (retval != ERROR_OK && retval != ERROR_FLASH_OPER_UNSUPPORTED)
+ return retval;
+ }
+ if (retval == ERROR_FLASH_OPER_UNSUPPORTED)
+ LOG_WARNING("Flash protection check is not implemented.");
command_print(CMD_CTX,
"#%d : %s at 0x%8.8" TARGET_PRIxADDR ", size 0x%8.8" PRIx32
diff --git a/src/flash/nor/w600.c b/src/flash/nor/w600.c
new file mode 100644
index 0000000..3d37616
--- /dev/null
+++ b/src/flash/nor/w600.c
@@ -0,0 +1,390 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Simon Qian *
+ * SimonQian@SimonQian.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+#define W600_FLASH_SECSIZE 0x1000
+#define W600_FLASH_PAGESIZE 0x100
+#define W600_FLASH_BASE 0x08000000
+#define W600_FLASH_PROTECT_SIZE 0x2000
+
+/* w600 register locations */
+
+#define QFLASH_REGBASE 0X40002000
+#define QFLASH_CMD_INFO (QFLASH_REGBASE + 0)
+#define QFLASH_CMD_START (QFLASH_REGBASE + 4)
+#define QFLASH_BUFFER (QFLASH_REGBASE + 0X200)
+
+#define QFLASH_CMD_READ (1ul << 14)
+#define QFLASH_CMD_WRITE 0
+#define QFLASH_CMD_ADDR (1ul << 31)
+#define QFLASH_CMD_DATA (1ul << 15)
+#define QFLASH_CMD_DATALEN(len) (((len) & 0x3FF) << 16)
+
+#define QFLASH_CMD_RDID (QFLASH_CMD_READ | 0x9F)
+#define QFLASH_CMD_WREN (QFLASH_CMD_WRITE | 0x06)
+#define QFLASH_CMD_WRDI (QFLASH_CMD_WRITE | 0x04)
+#define QFLASH_CMD_SE (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 11) | 0x20)
+#define QFLASH_CMD_PP (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 12) | 0x02)
+
+#define QFLASH_START (1ul << 28)
+#define QFLASH_ADDR(addr) (((addr) & 0xFFFFF) << 8)
+#define QFLASH_CRM(crm) (((crm) & 0xFF) << 0)
+
+struct w600_flash_param {
+ uint8_t id;
+ uint8_t se_delay;
+ uint8_t pp_delay;
+};
+static const struct w600_flash_param w600_param[] = {
+ {
+ .id = 0x85,
+ .se_delay = 8,
+ .pp_delay = 2,
+ },
+ {
+ .id = 0x1C,
+ .se_delay = 50,
+ .pp_delay = 1,
+ },
+ {
+ .id = 0xC8,
+ .se_delay = 45,
+ .pp_delay = 1,
+ },
+ {
+ .id = 0x0B,
+ .se_delay = 60,
+ .pp_delay = 1,
+ },
+ {
+ .id = 0x68,
+ .se_delay = 50,
+ .pp_delay = 1,
+ },
+};
+
+struct w600_flash_bank {
+ int probed;
+
+ uint32_t id;
+ const struct w600_flash_param *param;
+ uint32_t register_base;
+ uint32_t user_bank_size;
+};
+
+/* flash bank w600 <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(w600_flash_bank_command)
+{
+ struct w600_flash_bank *w600_info;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ w600_info = malloc(sizeof(struct w600_flash_bank));
+
+ bank->driver_priv = w600_info;
+ w600_info->probed = 0;
+ w600_info->register_base = QFLASH_REGBASE;
+ w600_info->user_bank_size = bank->size;
+
+ return ERROR_OK;
+}
+
+static int w600_get_delay(struct flash_bank *bank, uint32_t cmd)
+{
+ struct w600_flash_bank *w600_info = bank->driver_priv;
+
+ if (!w600_info->param)
+ return 0;
+
+ switch (cmd) {
+ case QFLASH_CMD_SE:
+ return w600_info->param->se_delay;
+ case QFLASH_CMD_PP:
+ return w600_info->param->pp_delay;
+ default:
+ return 0;
+ }
+}
+
+static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
+ uint32_t len, int timeout)
+{
+ struct target *target = bank->target;
+
+ if (len > 0)
+ cmd |= QFLASH_CMD_DATALEN(len - 1) | QFLASH_CMD_DATA;
+
+ LOG_DEBUG("WRITE CMD: 0x%08" PRIx32 "", cmd);
+ int retval = target_write_u32(target, QFLASH_CMD_INFO, cmd);
+ if (retval != ERROR_OK)
+ return retval;
+
+ addr |= QFLASH_START;
+ LOG_DEBUG("WRITE START: 0x%08" PRIx32 "", addr);
+ retval = target_write_u32(target, QFLASH_CMD_START, addr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_DEBUG("DELAY %dms", timeout);
+ alive_sleep(timeout);
+
+ int retry = 100;
+ uint32_t status;
+ for (;;) {
+ LOG_DEBUG("READ START...");
+ retval = target_read_u32(target, QFLASH_CMD_START, &status);
+ if (retval == ERROR_OK)
+ LOG_DEBUG("READ START: 0x%08" PRIx32 "", status);
+ else
+ LOG_DEBUG("READ START FAILED");
+
+ if ((retval != ERROR_OK) || (status & QFLASH_START)) {
+ if (retry-- <= 0) {
+ LOG_ERROR("timed out waiting for flash");
+ return ERROR_FAIL;
+ }
+ continue;
+ }
+ break;
+ }
+
+ return retval;
+}
+
+static int w600_write_enable(struct flash_bank *bank)
+{
+ return w600_start_do(bank, QFLASH_CMD_WREN, 0, 0, 0);
+}
+
+static int w600_write_disable(struct flash_bank *bank)
+{
+ return w600_start_do(bank, QFLASH_CMD_WRDI, 0, 0, 0);
+}
+
+static int w600_start(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
+ uint32_t len)
+{
+ int retval = w600_write_enable(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = w600_start_do(bank, cmd, addr, len, w600_get_delay(bank, cmd));
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = w600_write_disable(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return retval;
+}
+
+static int w600_erase(struct flash_bank *bank, int first, int last)
+{
+ int retval = ERROR_OK;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+ if (first < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE) {
+ LOG_ERROR("can not erase protected area");
+ return ERROR_FAIL;
+ }
+
+ for (int i = first; i <= last; i++) {
+ retval = w600_start(bank, QFLASH_CMD_SE,
+ QFLASH_ADDR(bank->sectors[i].offset), 0);
+ if (retval != ERROR_OK)
+ break;
+ }
+
+ return retval;
+}
+
+static int w600_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ int retval = ERROR_OK;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((offset % W600_FLASH_PAGESIZE) != 0) {
+ LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
+ offset, W600_FLASH_PAGESIZE);
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ }
+
+ if ((count % W600_FLASH_PAGESIZE) != 0) {
+ LOG_WARNING("count 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
+ offset, W600_FLASH_PAGESIZE);
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ }
+
+ while (count > 0) {
+ retval = target_write_buffer(target, QFLASH_BUFFER, W600_FLASH_PAGESIZE, buffer);
+ if (retval != ERROR_OK)
+ break;
+
+ retval = w600_start(bank, QFLASH_CMD_PP, QFLASH_ADDR(offset),
+ W600_FLASH_PAGESIZE);
+ if (retval != ERROR_OK)
+ break;
+
+ count -= W600_FLASH_PAGESIZE;
+ offset += W600_FLASH_PAGESIZE;
+ buffer += W600_FLASH_PAGESIZE;
+ }
+
+ return retval;
+}
+
+static int w600_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
+{
+ struct target *target = bank->target;
+
+ int retval = w600_start(bank, QFLASH_CMD_RDID, 0, 4);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return target_read_u32(target, QFLASH_BUFFER, flash_id);
+}
+
+static int w600_probe(struct flash_bank *bank)
+{
+ struct w600_flash_bank *w600_info = bank->driver_priv;
+ uint32_t flash_size;
+ uint32_t flash_id;
+ size_t i;
+
+ w600_info->probed = 0;
+
+ /* read stm32 device id register */
+ int retval = w600_get_flash_id(bank, &flash_id);
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_INFO("flash_id id = 0x%08" PRIx32 "", flash_id);
+ w600_info->id = flash_id;
+ w600_info->param = NULL;
+ for (i = 0; i < ARRAY_SIZE(w600_param); i++) {
+ if (w600_param[i].id == (flash_id & 0xFF)) {
+ w600_info->param = &w600_param[i];
+ break;
+ }
+ }
+ if (!w600_info->param) {
+ LOG_ERROR("flash_id not supported for w600");
+ return ERROR_FAIL;
+ }
+
+ /* if the user sets the size manually then ignore the probed value
+ * this allows us to work around devices that have a invalid flash size register value */
+ if (w600_info->user_bank_size) {
+ LOG_INFO("ignoring flash probed value, using configured bank size");
+ flash_size = w600_info->user_bank_size;
+ } else {
+ flash_size = ((flash_id & 0xFFFFFF) >> 16) & 0xFF;
+ if ((flash_size != 0x14) && (flash_size != 0x13)) {
+ LOG_ERROR("w600 flash size failed, probe inaccurate");
+ return ERROR_FAIL;
+ }
+
+ flash_size = 1 << flash_size;
+ }
+
+ LOG_INFO("flash size = %dkbytes", flash_size / 1024);
+
+ /* calculate numbers of pages */
+ size_t num_pages = flash_size / W600_FLASH_SECSIZE;
+
+ /* check that calculation result makes sense */
+ assert(num_pages > 0);
+
+ if (bank->sectors) {
+ free(bank->sectors);
+ bank->sectors = NULL;
+ }
+
+ bank->base = W600_FLASH_BASE;
+ bank->size = num_pages * W600_FLASH_SECSIZE;
+ bank->num_sectors = num_pages;
+ bank->write_start_alignment = W600_FLASH_PAGESIZE;
+ bank->write_end_alignment = W600_FLASH_PAGESIZE;
+ bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+
+ for (i = 0; i < num_pages; i++) {
+ bank->sectors[i].offset = i * W600_FLASH_SECSIZE;
+ bank->sectors[i].size = W600_FLASH_SECSIZE;
+ bank->sectors[i].is_erased = -1;
+ /* offset 0 to W600_FLASH_PROTECT_SIZE shoule be protected */
+ bank->sectors[i].is_protected = (i < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE);
+ }
+
+ w600_info->probed = 1;
+
+ return ERROR_OK;
+}
+
+static int w600_auto_probe(struct flash_bank *bank)
+{
+ struct w600_flash_bank *w600_info = bank->driver_priv;
+ if (w600_info->probed)
+ return ERROR_OK;
+ return w600_probe(bank);
+}
+
+static int get_w600_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ uint32_t flash_id;
+
+ /* read w600 device id register */
+ int retval = w600_get_flash_id(bank, &flash_id);
+ if (retval != ERROR_OK)
+ return retval;
+
+ snprintf(buf, buf_size, "w600 : 0x%08" PRIx32 "", flash_id);
+ return ERROR_OK;
+}
+
+struct flash_driver w600_flash = {
+ .name = "w600",
+ .flash_bank_command = w600_flash_bank_command,
+ .erase = w600_erase,
+ .write = w600_write,
+ .read = default_flash_read,
+ .probe = w600_probe,
+ .auto_probe = w600_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .info = get_w600_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};