Flash, FRAM and EEPROM driver for STM32 QUAD-/OCTOSPI interface

- write speed up to 150 kByte/s on STM32F469I-disco (due to
  SWD clock and USB connection), up to 1 MByte/s on Nucleo-F767ZI
  with external STLink-V3 or Nucleo-G474RE with two W25Q256FV in
  dual 4-line mode or STM32H73BI-Disco in octal mode
- tested with STM32L476G-disco (64MBit flash, 3-byte addr),
  STM32F412G-Disco, STM32F469I-Disco, STM32F746G-Disco, and
  STM32L476G-Disco (all 128Mbit flash, 3-byte addr),
  STM32F723E-Disco, STM32F769I-Disco (512Mbit flash, 4-byte addr)
  STM32L4R9I-Disco, STM32L4P5G-Disco (512MBit octo-flash, DTR, 4-byte addr)
  STM32H745I-Disco, STM32H747I-Disco (two 512MBit flash, 4-byte addr)
  STM32H73BI-Disco, STM32H735G-Disco (512MBit octo-flash, DTR, 4-byte addr)
- suitable cfg for Discovery boards included
- limited parsing of SFDP data if flash device not hardcoded
  (tested only in single/quad mode as most devices either don't
  support SFDP at all or have empty(!) SFDP memory)
- 'set' command for auto detection override (e. g. for EEPROMs)
- 'cmd' command for arbitrary SPI commands (reconfiguration, testing etc.)
- makefile for creation of binary loader files
- tcl/board/stm32f469discovery.cfg superseded by stm32f469i-disco.cfg
- tcl/board/stm32f7discovery.cfg removed as name is ambiguous
  (superseded by stm32f746g-disco.cfg vs. stm32f769i-disco.cfg)
- dual 4-line mode tested on Nucleo-F767ZI, Nucleo-H743ZI and Nucleo-H7A3ZI-Q
  with two W25Q256FV, and on Nucleo-L496ZP-P and Nucleo-L4R5ZI
  with two W25Q128FV, sample cfg files included and on STM32H745I-Disco,
  STM32H747I-Disco, STM32H750B-Disco
- read/verify/erase_check uses indirect read mode to work around silicon bug in
  H7, L4+ and MP1 memory mapped mode (last bytes not readable, accessing last
  bytes causes debug interface to hang)
- octospi supported only in single/dual 1-line, 2-line, 4-line
  and single 8-line modes, (not in hyper flash mode)

Requirements:
GPIOs must be initialized appropriately, and SPI flash chip be configured
appropriately (1-line ..., QPI, 4-byte addresses ...). This is board/chip
specific, cf. included cfg files. The driver infers most parameters from
current setting in CR, CCR, ... registers.

Change-Id: I54858fbbe8758c3a5fe58812e93f5f39514704f8
Signed-off-by: Andreas Bolsch <hyphen0break@gmail.com>
Reviewed-on: http://openocd.zylin.com/4321
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Christopher Head <chead@zaber.com>
This commit is contained in:
Andreas Bolsch
2016-12-21 10:35:58 +01:00
committed by Tomas Vanek
parent 475f42051e
commit e44539d66c
57 changed files with 6709 additions and 33 deletions

View File

@@ -52,10 +52,12 @@ NOR_DRIVERS = \
%D%/psoc5lp.c \
%D%/psoc6.c \
%D%/renesas_rpchf.c \
%D%/sfdp.c \
%D%/sh_qspi.c \
%D%/sim3x.c \
%D%/spi.c \
%D%/stmsmi.c \
%D%/stmqspi.c \
%D%/stellaris.c \
%D%/stm32f1x.c \
%D%/stm32f2x.c \
@@ -83,6 +85,8 @@ NORHEADERS = \
%D%/imp.h \
%D%/non_cfi.h \
%D%/ocl.h \
%D%/sfdp.h \
%D%/spi.h \
%D%/stm32l4x.h \
%D%/stmqspi.h \
%D%/msp432.h

View File

@@ -94,7 +94,7 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first,
}
int flash_driver_write(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count)
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int retval;
@@ -135,6 +135,43 @@ int default_flash_read(struct flash_bank *bank,
return target_read_buffer(bank->target, offset + bank->base, count, buffer);
}
int flash_driver_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int retval;
retval = bank->driver->verify ? bank->driver->verify(bank, buffer, offset, count) :
default_flash_verify(bank, buffer, offset, count);
if (retval != ERROR_OK) {
LOG_ERROR("verify failed in bank at " TARGET_ADDR_FMT " starting at 0x%8.8" PRIx32,
bank->base, offset);
}
return retval;
}
int default_flash_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
uint32_t target_crc, image_crc;
int retval;
retval = image_calculate_checksum(buffer, count, &image_crc);
if (retval != ERROR_OK)
return retval;
retval = target_checksum_memory(bank->target, offset + bank->base, count, &target_crc);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32,
offset + bank->base, count, ~image_crc, ~target_crc);
if (target_crc == image_crc)
return ERROR_OK;
else
return ERROR_FAIL;
}
void flash_bank_add(struct flash_bank *bank)
{
/* put flash bank in linked list */
@@ -697,8 +734,8 @@ static bool flash_write_check_gap(struct flash_bank *bank,
}
int flash_write_unlock(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock)
int flash_write_unlock_verify(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock, bool write, bool verify)
{
int retval = ERROR_OK;
@@ -932,8 +969,17 @@ int flash_write_unlock(struct target *target, struct image *image,
}
if (retval == ERROR_OK) {
/* write flash sectors */
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
if (write) {
/* write flash sectors */
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
}
}
if (retval == ERROR_OK) {
if (verify) {
/* verify flash sectors */
retval = flash_driver_verify(c, buffer, run_address - c->base, run_size);
}
}
free(buffer);
@@ -957,7 +1003,7 @@ done:
int flash_write(struct target *target, struct image *image,
uint32_t *written, bool erase)
{
return flash_write_unlock(target, image, written, erase, false);
return flash_write_unlock_verify(target, image, written, erase, false, true, false);
}
struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size,

View File

@@ -200,6 +200,7 @@ void default_flash_free_driver_priv(struct flash_bank *bank);
/** Deallocates all flash banks */
void flash_free_all_banks(void);
/**
* Provides default read implementation for flash memory.
* @param bank The bank to read.
@@ -210,6 +211,18 @@ void flash_free_all_banks(void);
*/
int default_flash_read(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Provides default verify implementation for flash memory.
* @param bank The bank to verify.
* @param buffer The data bytes to verify.
* @param offset The offset into the chip to verify.
* @param count The number of bytes to verify.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int default_flash_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Provides default erased-bank check handling. Checks to see if
* the flash driver knows they are erased; if things look uncertain,
@@ -217,7 +230,6 @@ int default_flash_read(struct flash_bank *bank,
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int default_flash_blank_check(struct flash_bank *bank);
/**
* Returns the flash bank specified by @a name, which matches the
* driver name and a suffix (option) specify the driver-specific

View File

@@ -155,6 +155,20 @@ struct flash_driver {
int (*read)(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Verify data in flash. Note CPU address will be
* "bank->base + offset", while the physical address is
* dependent upon current target MMU mappings.
*
* @param bank The bank to verify
* @param buffer The data bytes to verify against.
* @param offset The offset into the chip to verify.
* @param count The number of bytes to verify.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*verify)(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Probe to determine what kind of flash is present.
* This is invoked by the "probe" script command.

View File

@@ -75,6 +75,7 @@ extern const struct flash_driver stm32f2x_flash;
extern const struct flash_driver stm32lx_flash;
extern const struct flash_driver stm32l4x_flash;
extern const struct flash_driver stm32h7x_flash;
extern const struct flash_driver stmqspi_flash;
extern const struct flash_driver stmsmi_flash;
extern const struct flash_driver str7x_flash;
extern const struct flash_driver str9x_flash;
@@ -148,6 +149,7 @@ static const struct flash_driver * const flash_drivers[] = {
&stm32l4x_flash,
&stm32h7x_flash,
&stmsmi_flash,
&stmqspi_flash,
&str7x_flash,
&str9x_flash,
&str9xpec_flash,

View File

@@ -42,12 +42,14 @@ int flash_driver_erase(struct flash_bank *bank, unsigned int first,
int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int last);
int flash_driver_write(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
const uint8_t *buffer, uint32_t offset, uint32_t count);
int flash_driver_read(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
int flash_driver_verify(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count);
/* write (optional verify) an image to flash memory of the given target */
int flash_write_unlock(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock);
int flash_write_unlock_verify(struct target *target, struct image *image,
uint32_t *written, bool erase, bool unlock, bool write, bool verify);
#endif /* OPENOCD_FLASH_NOR_IMP_H */

263
src/flash/nor/sfdp.c Normal file
View File

@@ -0,0 +1,263 @@
/***************************************************************************
* Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de *
* 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 "spi.h"
#include "sfdp.h"
#define SFDP_MAGIC 0x50444653
#define SFDP_ACCESS_PROT 0xFF
#define SFDP_BASIC_FLASH 0xFF00
#define SFDP_4BYTE_ADDR 0xFF84
static const char *sfdp_name = "sfdp";
struct sfdp_hdr {
uint32_t signature;
uint32_t revision;
};
struct sfdp_phdr {
uint32_t revision;
uint32_t ptr;
};
struct sfdp_basic_flash_param {
uint32_t fast_addr; /* 01: fast read and 3/4 address bytes */
uint32_t density; /* 02: memory density */
uint32_t fast_1x4; /* 03: 1-1-4 and 1-4-4 fast read */
uint32_t fast_1x2; /* 04: 1-2-2 and 1-1-2 fast read */
uint32_t fast_444; /* 05: 4-4-4 and 2-2-2 fast read */
uint32_t read_222; /* 06: 2-2-2 fast read instr and dummy */
uint32_t read_444; /* 07: 4-4-4 fast read instr and dummy */
uint32_t erase_t12; /* 08: erase types 1, 2 */
uint32_t erase_t34; /* 09: erase types 3, 4 */
uint32_t erase_time; /* 10: erase times for types 1 - 4 */
uint32_t chip_byte; /* 11: chip erase time, byte prog time, page prog */
uint32_t susp_time; /* 12: suspend and resume times */
uint32_t susp_instr; /* 13: suspend and resume instr */
uint32_t pwrd_instr; /* 14: powerdown instr */
uint32_t quad_req; /* 15: quad enable requirements */
uint32_t addr_reset; /* 16: 3-/4-byte addressing and reset */
uint32_t read_1x8; /* 17: 1-1-8 and 1-8-8 fast read instr and dummy */
uint32_t dtr_drive; /* 18: dtr modes and drive strength */
uint32_t octal_req; /* 19: octal enable requirements */
uint32_t speed_888; /* 20: speed in 8-8-8 modes */
};
struct sfdp_4byte_addr_param {
uint32_t flags; /* 01: various flags */
uint32_t erase_t1234; /* 02: erase commands */
};
/* Try to get parameters from flash via SFDP */
int spi_sfdp(struct flash_bank *bank, struct flash_device *dev,
read_sfdp_block_t read_sfdp_block)
{
struct sfdp_hdr header;
struct sfdp_phdr *pheaders = NULL;
uint32_t *ptable = NULL;
unsigned int j, k, nph;
int retval, erase_type = 0;
memset(dev, 0, sizeof(struct flash_device));
/* retrieve SFDP header */
memset(&header, 0, sizeof(header));
retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *) &header);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision);
if (header.signature != SFDP_MAGIC) {
LOG_INFO("no SDFP found");
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) {
LOG_ERROR("access protocol 0x%02" PRIx8 " not implemented",
(header.revision >> 24) & 0xFF);
return ERROR_FLASH_BANK_NOT_PROBED;
}
/* retrieve table of parameter headers */
nph = ((header.revision >> 16) & 0xFF) + 1;
LOG_DEBUG("parameter headers: %d", nph);
pheaders = malloc(sizeof(struct sfdp_phdr) * nph);
if (pheaders == NULL) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph);
retval = read_sfdp_block(bank, sizeof(header),
(sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *) pheaders);
if (retval != ERROR_OK)
goto err;
for (k = 0; k < nph; k++) {
uint8_t words = (pheaders[k].revision >> 24) & 0xFF;
uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF);
uint32_t ptr = pheaders[k].ptr & 0xFFFFFF;
LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16
" ptr=0x%06" PRIx32, k, words, id, ptr);
/* retrieve parameter table */
ptable = malloc(words << 2);
if (ptable == NULL) {
LOG_ERROR("not enough memory");
retval = ERROR_FAIL;
goto err;
}
retval = read_sfdp_block(bank, ptr, words, ptable);
if (retval != ERROR_OK)
goto err;
for (j = 0; j < words; j++)
LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]);
if (id == SFDP_BASIC_FLASH) {
struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *) ptable;
uint16_t erase;
if (words < 9) {
LOG_ERROR("id=0x%04" PRIx16 " invalid length %d", id, words);
retval = ERROR_FLASH_BANK_NOT_PROBED;
goto err;
}
LOG_DEBUG("basic flash parameter table");
/* dummy device name */
dev->name = sfdp_name;
/* default instructions */
dev->read_cmd = SPIFLASH_READ;
dev->pprog_cmd = SPIFLASH_PAGE_PROGRAM;
dev->chip_erase_cmd = SPIFLASH_MASS_ERASE;
/* get device size */
if (table->density & (1UL << 31))
dev->size_in_bytes = 1UL << ((table->density & ~(1UL << 31)) - 3);
else
dev->size_in_bytes = (table->density + 1) >> 3;
/* 2-2-2 read instruction, not used */
if (table->fast_444 & (1UL << 0))
dev->qread_cmd = (table->read_222 >> 24) & 0xFF;
/* 4-4-4 read instruction */
if (table->fast_444 & (1UL << 4))
dev->qread_cmd = (table->read_444 >> 24) & 0xFF;
/* find the largest erase block size and instruction */
erase = (table->erase_t12 >> 0) & 0xFFFF;
erase_type = 1;
if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t12 >> 16) & 0xFFFF;
erase_type = 2;
}
if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t34 >> 0) & 0xFFFF;
erase_type = 3;
}
if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t34 >> 16) & 0xFFFF;
erase_type = 4;
}
dev->erase_cmd = (erase >> 8) & 0xFF;
dev->sectorsize = 1UL << (erase & 0xFF);
if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) {
/* get Program Page Size, if chip_byte present, that's optional */
dev->pagesize = 1UL << ((table->chip_byte >> 4) & 0x0F);
} else {
/* no explicit page size specified ... */
if (table->fast_addr & (1UL << 2)) {
/* Write Granularity = 1, use 64 bytes */
dev->pagesize = 1UL << 6;
} else {
/* Write Granularity = 0, use 16 bytes */
dev->pagesize = 1UL << 4;
}
}
if (dev->size_in_bytes > (1UL << 24)) {
if (((table->fast_addr >> 17) & 0x3) == 0x0)
LOG_ERROR("device needs paging - not implemented");
/* 4-byte addresses needed if more than 16 MBytes */
if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) &&
(table->addr_reset & (1UL << 29))) {
/* dedicated 4-byte-address instructions, hopefully these ...
* this entry is unfortunately optional as well
* a subsequent 4-byte address table may overwrite this */
dev->read_cmd = 0x13;
dev->pprog_cmd = 0x12;
dev->erase_cmd = 0xDC;
if (dev->qread_cmd != 0)
dev->qread_cmd = 0xEC;
} else if (((table->fast_addr >> 17) & 0x3) == 0x1)
LOG_INFO("device has to be switched to 4-byte addresses");
}
} else if (id == SFDP_4BYTE_ADDR) {
struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *) ptable;
if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234)
+ sizeof(table->erase_t1234)) >> 2) {
LOG_INFO("4-byte address parameter table");
/* read and page program instructions */
if (table->flags & (1UL << 0))
dev->read_cmd = 0x13;
if (table->flags & (1UL << 5))
dev->qread_cmd = 0xEC;
if (table->flags & (1UL << 6))
dev->pprog_cmd = 0x12;
/* erase instructions */
if ((erase_type == 1) && (table->flags & (1UL << 9)))
dev->erase_cmd = (table->erase_t1234 >> 0) & 0xFF;
else if ((erase_type == 2) && (table->flags & (1UL << 10)))
dev->erase_cmd = (table->erase_t1234 >> 8) & 0xFF;
else if ((erase_type == 3) && (table->flags & (1UL << 11)))
dev->erase_cmd = (table->erase_t1234 >> 16) & 0xFF;
else if ((erase_type == 4) && (table->flags & (1UL << 12)))
dev->erase_cmd = (table->erase_t1234 >> 24) & 0xFF;
} else
LOG_ERROR("parameter table id=0x%04" PRIx16 " invalid length %d", id, words);
} else
LOG_DEBUG("unimplemented parameter table id=0x%04" PRIx16, id);
free(ptable);
ptable = NULL;
}
if (erase_type != 0) {
LOG_INFO("valid SFDP detected");
retval = ERROR_OK;
} else {
LOG_ERROR("incomplete/invalid SFDP");
retval = ERROR_FLASH_BANK_NOT_PROBED;
}
err:
free(pheaders);
free(ptable);
return retval;
}

34
src/flash/nor/sfdp.h Normal file
View File

@@ -0,0 +1,34 @@
/***************************************************************************
* Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de *
* 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/>. *
***************************************************************************/
#ifndef OPENOCD_FLASH_NOR_SFDP_H
#define OPENOCD_FLASH_NOR_SFDP_H
/* per JESD216D 'addr' is *byte* based but must be word aligned,
* 'buffer' is word based, word aligned and always little-endian encoded,
* in the flash, 'addr_len' is 3 or 4, 'dummy' ***usually*** 8
*
* the actual number of dummy clocks should be worked out by this function
* dynamically, i.e. by scanning the first few bytes for the SFDP signature
*
* buffer contents is supposed to be returned in ***host*** endianness */
typedef int (*read_sfdp_block_t)(struct flash_bank *bank, uint32_t addr,
uint32_t words, uint32_t *buffer);
extern int spi_sfdp(struct flash_bank *bank, struct flash_device *dev,
read_sfdp_block_t read_sfdp_block);
#endif /* OPENOCD_FLASH_NOR_SFDP_H */

View File

@@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2018 by Andreas Bolsch *
* Copyright (C) 2018-2019 by Andreas Bolsch *
* andreas.bolsch@mni.thm.de *
* *
* Copyright (C) 2012 by George Harris *
@@ -29,7 +29,7 @@
/* data structure to maintain flash ids from different vendors */
struct flash_device {
char *name;
const char *name;
uint8_t read_cmd;
uint8_t qread_cmd;
uint8_t pprog_cmd;
@@ -87,6 +87,8 @@ extern const struct flash_device flash_devices[];
#define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */
#define SPIFLASH_FAST_READ 0x0B /* Fast Read */
#define SPIFLASH_READ 0x03 /* Normal Read */
#define SPIFLASH_MASS_ERASE 0xC7 /* Mass Erase */
#define SPIFLASH_READ_SFDP 0x5A /* Read Serial Flash Discoverable Parameters */
#define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */

2452
src/flash/nor/stmqspi.c Normal file

File diff suppressed because it is too large Load Diff

125
src/flash/nor/stmqspi.h Normal file
View File

@@ -0,0 +1,125 @@
/***************************************************************************
* Copyright (C) 2016 - 2018 by Andreas Bolsch *
* andreas.bolsch@mni.thm.de *
* *
* 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/>. *
***************************************************************************/
#ifndef OPENOCD_FLASH_NOR_STMQSPI_H
#define OPENOCD_FLASH_NOR_STMQSPI_H
#include "spi.h"
/* QSPI register offsets */
#define QSPI_CR (0x00) /* Control register */
#define QSPI_DCR (0x04) /* Device configuration register */
#define QSPI_SR (0x08) /* Status register */
#define QSPI_FCR (0x0C) /* Flag clear register */
#define QSPI_DLR (0x10) /* Data length register */
#define QSPI_CCR (0x14) /* Communication configuration register */
#define QSPI_AR (0x18) /* Address register */
#define QSPI_ABR (0x1C) /* Alternate bytes register */
#define QSPI_DR (0x20) /* Data register */
/* common bits in QSPI_CR and OCTOSPI_CR */
#define SPI_FSEL_FLASH 7 /* Select flash 2 */
#define SPI_DUAL_FLASH 6 /* Dual flash mode */
#define SPI_ABORT 1 /* Abort bit */
/* common bits in QSPI_DCR and OCTOSPI_DCR1 */
#define SPI_FSIZE_POS 16 /* bit position of FSIZE */
#define SPI_FSIZE_LEN 5 /* width of FSIZE field */
/* common bits in QSPI_SR/FCR and OCTOSPI_SR/FCR */
#define SPI_BUSY 5 /* Busy flag */
#define SPI_FTF 2 /* FIFO threshold flag */
#define SPI_TCF 1 /* Transfer complete flag */
/* fields in QSPI_CCR */
#define QSPI_DDRM 31 /* position of DDRM bit */
#define SPI_DMODE_POS 24 /* bit position of DMODE */
#define QSPI_DCYC_POS 18 /* bit position of DCYC */
#define QSPI_DCYC_LEN 5 /* width of DCYC field */
#define QSPI_DCYC_MASK (((1U<<QSPI_DCYC_LEN) - 1)<<QSPI_DCYC_POS)
#define SPI_ADSIZE_POS 12 /* bit position of ADSIZE */
#define QSPI_WRITE_MODE 0x00000000U /* indirect write mode */
#define QSPI_READ_MODE 0x04000000U /* indirect read mode */
#define QSPI_MM_MODE 0x0C000000U /* memory mapped mode */
#define QSPI_ALTB_MODE 0x0003C000U /* alternate byte mode */
#define QSPI_4LINE_MODE 0x03000F00U /* 4 lines for data, addr, instr */
#define QSPI_NO_DATA (~0x03000000U) /* no data */
#define QSPI_NO_ALTB (~QSPI_ALTB_MODE) /* no alternate */
#define QSPI_NO_ADDR (~0x00000C00U) /* no address */
#define QSPI_ADDR3 (0x2U<<SPI_ADSIZE_POS) /* 3 byte address */
#define QSPI_ADDR4 (0x3U<<SPI_ADSIZE_POS) /* 4 byte address */
/* OCTOSPI register offsets */
#define OCTOSPI_CR (0x000) /* Control register */
#define OCTOSPI_DCR1 (0x008) /* Device configuration register 1 */
#define OCTOSPI_DCR2 (0x00C) /* Device configuration register 2 */
#define OCTOSPI_DCR3 (0x010) /* Device configuration register 3 */
#define OCTOSPI_SR (0x020) /* Status register */
#define OCTOSPI_FCR (0x024) /* Flag clear register */
#define OCTOSPI_DLR (0x040) /* Data length register */
#define OCTOSPI_AR (0x048) /* Address register */
#define OCTOSPI_DR (0x050) /* Data register */
#define OCTOSPI_CCR (0x100) /* Communication configuration register */
#define OCTOSPI_TCR (0x108) /* Timing configuration register */
#define OCTOSPI_IR (0x110) /* Instruction register */
#define OCTOSPI_WCCR (0x180) /* Write communication configuration register */
#define OCTOSPI_WIR (0x190) /* Write instruction register */
#define OCTOSPI_MAGIC (0x3FC) /* Magic ID register, deleted from RM, why? */
#define OCTO_MAGIC_ID 0xA3C5DD01 /* Magic ID, deleted from RM, why? */
/* additional bits in OCTOSPI_CR */
#define OCTOSPI_WRITE_MODE 0x00000000U /* indirect write mode */
#define OCTOSPI_READ_MODE 0x10000000U /* indirect read mode */
#define OCTOSPI_MM_MODE 0x30000000U /* memory mapped mode */
/* additional fields in OCTOSPI_DCR1 */
#define OCTOSPI_MTYP_POS (24) /* bit position of MTYP */
#define OCTOSPI_MTYP_LEN (3) /* width of MTYP field */
#define OCTOSPI_MTYP_MASK (((1U<<OCTOSPI_MTYP_LEN) - 1)<<OCTOSPI_MTYP_POS)
/* fields in OCTOSPI_CCR */
#define OCTOSPI_ALTB_MODE 0x001F0000U /* alternate byte mode */
#define OCTOSPI_8LINE_MODE 0x0F003F3FU /* 8 lines DTR for data, addr, instr */
#define OCTOSPI_NO_DATA (~0x0F000000U) /* no data */
#define OCTOSPI_NO_ALTB (~OCTOSPI_ALTB_MODE) /* no alternate */
#define OCTOSPI_NO_ADDR (~0x00000F00U) /* no address */
#define OCTOSPI_ADDR3 (0x2U<<SPI_ADSIZE_POS) /* 3 byte address */
#define OCTOSPI_ADDR4 (0x3U<<SPI_ADSIZE_POS) /* 4 byte address */
#define OCTOSPI_DQSEN 29 /* DQS enable */
#define OCTOSPI_DDTR 27 /* DTR for data */
#define OCTOSPI_NO_DDTR (~(1U<<OCTOSPI_DDTR)) /* no DTR for data, but maybe still DQS */
#define OCTOSPI_ISIZE_MASK (0x30) /* ISIZE field */
/* fields in OCTOSPI_TCR */
#define OCTOSPI_DCYC_POS 0 /* bit position of DCYC */
#define OCTOSPI_DCYC_LEN 5 /* width of DCYC field */
#define OCTOSPI_DCYC_MASK (((1U<<OCTOSPI_DCYC_LEN) - 1)<<OCTOSPI_DCYC_POS)
#define IS_OCTOSPI (stmqspi_info->octo)
#define SPI_CR (IS_OCTOSPI ? OCTOSPI_CR : QSPI_CR)
#define SPI_DCR (IS_OCTOSPI ? OCTOSPI_DCR1 : QSPI_DCR)
#define SPI_SR (IS_OCTOSPI ? OCTOSPI_SR : QSPI_SR)
#define SPI_FCR (IS_OCTOSPI ? OCTOSPI_FCR : QSPI_FCR)
#define SPI_DLR (IS_OCTOSPI ? OCTOSPI_DLR : QSPI_DLR)
#define SPI_AR (IS_OCTOSPI ? OCTOSPI_AR : QSPI_AR)
#define SPI_DR (IS_OCTOSPI ? OCTOSPI_DR : QSPI_DR)
#define SPI_CCR (IS_OCTOSPI ? OCTOSPI_CCR : QSPI_CCR)
#endif /* OPENOCD_FLASH_NOR_STMQSPI_H */

View File

@@ -44,31 +44,31 @@
#define SMI_READ_REG(a) (_SMI_READ_REG(a))
#define _SMI_READ_REG(a) \
{ \
int __a; \
uint32_t __v; \
int _ret; \
uint32_t _value; \
\
__a = target_read_u32(target, io_base + (a), &__v); \
if (__a != ERROR_OK) \
return __a; \
__v; \
_ret = target_read_u32(target, io_base + (a), &_value); \
if (_ret != ERROR_OK) \
return _ret; \
_value; \
}
#define SMI_WRITE_REG(a, v) \
{ \
int __r; \
int _retval; \
\
__r = target_write_u32(target, io_base + (a), (v)); \
if (__r != ERROR_OK) \
return __r; \
_retval = target_write_u32(target, io_base + (a), (v)); \
if (_retval != ERROR_OK) \
return _retval; \
}
#define SMI_POLL_TFF(timeout) \
{ \
int __r; \
int _retval; \
\
__r = poll_tff(target, io_base, timeout); \
if (__r != ERROR_OK) \
return __r; \
_retval = poll_tff(target, io_base, timeout); \
if (_retval != ERROR_OK) \
return _retval; \
}
#define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \

View File

@@ -454,7 +454,8 @@ COMMAND_HANDLER(handle_flash_write_image_command)
if (retval != ERROR_OK)
return retval;
retval = flash_write_unlock(target, &image, &written, auto_erase, auto_unlock);
retval = flash_write_unlock_verify(target, &image, &written, auto_erase,
auto_unlock, true, false);
if (retval != ERROR_OK) {
image_close(&image);
return retval;
@@ -471,6 +472,58 @@ COMMAND_HANDLER(handle_flash_write_image_command)
return retval;
}
COMMAND_HANDLER(handle_flash_verify_image_command)
{
struct target *target = get_current_target(CMD_CTX);
struct image image;
uint32_t verified;
int retval;
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!target) {
LOG_ERROR("no target selected");
return ERROR_FAIL;
}
struct duration bench;
duration_start(&bench);
if (CMD_ARGC >= 2) {
image.base_address_set = 1;
COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address);
} else {
image.base_address_set = 0;
image.base_address = 0x0;
}
image.start_address_set = 0;
retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL);
if (retval != ERROR_OK)
return retval;
retval = flash_write_unlock_verify(target, &image, &verified, false,
false, false, true);
if (retval != ERROR_OK) {
image_close(&image);
return retval;
}
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD, "verified %" PRIu32 " bytes from file %s "
"in %fs (%0.3f KiB/s)", verified, CMD_ARGV[0],
duration_elapsed(&bench), duration_kbps(&bench, verified));
}
image_close(&image);
return retval;
}
COMMAND_HANDLER(handle_flash_fill_command)
{
target_addr_t address;
@@ -1142,7 +1195,15 @@ static const struct command_registration flash_exec_command_handlers[] = {
.mode = COMMAND_EXEC,
.usage = "[erase] [unlock] filename [offset [file_type]]",
.help = "Write an image to flash. Optionally first unprotect "
"and/or erase the region to be used. Allow optional "
"and/or erase the region to be used. Allow optional "
"offset from beginning of bank (defaults to zero)",
},
{
.name = "verify_image",
.handler = handle_flash_verify_image_command,
.mode = COMMAND_EXEC,
.usage = "filename [offset [file_type]]",
.help = "Verify an image against flash. Allow optional "
"offset from beginning of bank (defaults to zero)",
},
{