diff options
author | Tim Newsome <tim@sifive.com> | 2019-02-08 14:39:47 -0800 |
---|---|---|
committer | Tim Newsome <tim@sifive.com> | 2019-02-08 14:39:47 -0800 |
commit | 1c6d52cd88076cf22e55e0294cbb9751a3492470 (patch) | |
tree | aaa36ec90b01caccadfe2c07932f2a22e3967d0c /src/flash/nor | |
parent | 80ef54dba2411f9354b3793d5832c5d8ad871b4b (diff) | |
parent | 6c2020eb48803b941a94d600e2a96728d05a7da9 (diff) | |
download | riscv-openocd-1c6d52cd88076cf22e55e0294cbb9751a3492470.zip riscv-openocd-1c6d52cd88076cf22e55e0294cbb9751a3492470.tar.gz riscv-openocd-1c6d52cd88076cf22e55e0294cbb9751a3492470.tar.bz2 |
Merge branch 'master' into from_upstream
Conflicts:
README
contrib/loaders/flash/fespi/Makefile
src/flash/nor/fespi.c
src/flash/nor/spi.c
Change-Id: I78a4e73685cc95daace95e9d16066a6fb51034fb
Diffstat (limited to 'src/flash/nor')
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, ¶m); + 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(®_params[0], "r0", 32, PARAM_IN); + init_reg_param(®_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, +}; |