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 Kumar Gala
parent e7e1596d3e
commit f79c902686
57 changed files with 6709 additions and 33 deletions

View File

@ -0,0 +1,34 @@
BIN2C = ../../../../src/helper/bin2char.sh
SRCS=stmqspi_erase_check.S stmqspi_crc32.S stmqspi_read.S stmqspi_write.S \
stmoctospi_erase_check.S stmoctospi_crc32.S stmoctospi_read.S stmoctospi_write.S
OBJS=$(patsubst %.S,%.inc,$(SRCS))
CROSS_COMPILE ?= arm-none-eabi-
CC=$(CROSS_COMPILE)gcc
OBJCOPY=$(CROSS_COMPILE)objcopy
OBJDUMP=$(CROSS_COMPILE)objdump
LD=$(CROSS_COMPILE)ld
all: $(OBJS)
%.o: %.S Makefile
$(CC) -Wall -Werror -Wa,-adhlmn -o $@ -c $< > $(@:.o=.lst)
@enscript -Easm -T 4 -G -o - $(@:.o=.lst) | ps2pdf - $(@:.o=.pdf) || true
%.elf: %.o
$(LD) -s -defsym=_start=0 -o $@ $<
%.bin: %.elf
$(OBJCOPY) -S -O binary $< $@
%.inc: %.bin
$(BIN2C) < $< > $@
clean:
-rm -f *.o *.elf *.lst *.pdf *.bin *.inc
.PHONY: all clean
.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS))

View File

@ -0,0 +1,679 @@
#!/usr/bin/perl
#
# Helper for generating GPIO setup for STM32F0, F4, F7, H7, L0, L1, L4, L4+
# and F1 (for 'stmqspi' and 'cmspi' drivers).
#
# Each pin is configured by "PortAndBit:Conf:Speed"
# 'PortAndBit' specifies Port and bit number
# 'Conf' is one of 'AFx' (alternate), 'P' (output), 'IN' (input),
# (each optionally by 'P' (push-pull) or 'O' (open-drain)),
# (all optionally followed by 'UP' (pull-up), or 'DO' (pull-down))
# 'Speed' is one of 'L' (low), 'M' (medium), 'H' (high), 'V' (very high)
#
# Port configuration can be given on command line as a single string (pins separated by commas)
# or via CubeMX generated file. The latter must consist of the quadspi.c / octospi.c and the
# corresponding header. The precise spelling in these files doesn't seem to be consistent, though ...
#
# Pins have to be ordered this way:
# - I2C: SDA, SCL
# - SPI (1 line): NCS, CLK, IO1/MISO, IO0/MOSI
# - DPI (2 lines): NCS, CLK, IO1/MISO, IO0/MOSI
# - QPI (4 lines): NCS, CLK, IO3/NHOLD, IO2/NWP, IO1/MISO, IO0/MOSI
# For dual flash: BK_1 first, then BK_2. If single NCS for both, omit NCS in BK_2
# For octal flash: NCS, CLK, DQS, IO7 down to IO0
use strict;
use Getopt::Std;
my $GPIO_BASE;
my $Conf;
my $STM32F1 = 0;
# "Blue-Pill stm32f103cbt6 board w/ cmspi
#$STM32F1 = 1;
#$GPIO_BASE = 0x40010800;
#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB15:INUP:V";
#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB01:INUP:V";
#$STM32F1 = 1;
#$GPIO_BASE = 0x40010800;
#$Conf = "PB07:INUP:V, PB06:INUP:V";
# mini-stm32f030f4p6 board w/ cmspi
#$GPIO_BASE = 0x48000000;
#$Conf = "PB01:PP:V, PA05:PP:V, PA06:INUP:V, PA07:INUP:V";
# stm32f407vet6 board w/ cmspi
#$GPIO_BASE = 0x40020000;
#$Conf = "PB00:PP:M, PB03:PP:V, PB04:INUP:V, PB05:INUP:V";
# stm32f412g-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V";
# stm32f413h-disco
#$GPIO_BASE = 0x40020000;
#$Conf = "PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V";
# stm32f469i-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V";
# w/ cmspi
#$Conf = "PB06:PP:M, PF10:PP:V, PF06:INUP:V, PF07:INUP:V, PF09:INUP:V, PF08:INUP:V";
# stm32f723e-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
# stm32f746g-disco quad
#$GPIO_BASE = 0x40020000;
#Conf = "PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
# w/ cmspi
#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PD12:INUP:V, PD11:INUP:V";
# stm32f769i-disco quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
# w/ cmspi
#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PC10:INUP:V, PC09:INUP:V, ";
# b-l475e-iot01a quad
#$GPIO_BASE = 0x48000000;
#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
# stm32l476g-disco quad
#$GPIO_BASE = 0x48000000;
#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
# stm32l496g-disco quad
#$GPIO_BASE = 0x48000000;
#$Conf = "PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V";
# stm32l4r9i-disco octal
#$GPIO_BASE = 0x48000000;
#$Conf = "PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V, "
# . "PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V";
# stm32l4p5g-disco octal/octal
#$GPIO_BASE = 0x48000000;
#$Conf = "PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V, "
# . "PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V";
#$Conf = "PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V, "
# . "PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V";
# nucleo-f767zi dual quad
#$GPIO_BASE = 0x40020000;
#$Conf = "PB06:AF10:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
# w/ cmspi
#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
# nucleo-h743zi dual quad
#$GPIO_BASE = 0x58020000;
#$Conf = "PB10:AF09:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
# w/ cmspi
#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
# nucleo-h7a3zi dual quad
#$GPIO_BASE = 0x58020000;
#$Conf = "PB10:AF09:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V, "
# . "PC11:AF09:V, PE10:AF10:V, PD06:AF10:V, PE08:AF10:V, PE07:AF10:V";
# w/ cmspi
#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PD06:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
# nucleo-l4r5zi one dual quad single NCS
#$GPIO_BASE = 0x48000000;
#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
# w/ cmspi
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
# nucleo-l552ze-q dual quad with single NCS
#$GPIO_BASE = 0x42020000;
#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
# w/ cmspi
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
# nucleo-g071rb dual quad
#$GPIO_BASE = 0x50000000;
#$Conf = "PA00:PPUP:H, PA04:PPUP:V, PB03:INPUP:V, PA10:INPUP:V, PB11:INPUP:H, PB01:INPUP:H";
#$Conf = "PA01:PPUP:H, PA04:PPUP:V, PA08:INPUP:V, PB14:INPUP:V, PB04:INPUP:V, PB05:INPUP:V";
# nucleo-g474re dual quad with single NCS
#$GPIO_BASE = 0x48000000;
#$Conf = "PB11:AF10:H, PB10:AF10:V, PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V, "
# . "PC04:AF10:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V";
# w/ cmspi
#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PA06:INPUP:V, PA07:INPUP:V, PB00:INPUP:V, PB01:INPUP:V";
#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PC04:INPUP:V, PC03:INPUP:V, PC02:INPUP:V, PC01:INPUP:V";
# stm32h745i-disco dual quad with single NCS
#$GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:H, PF10:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
# stm32h747i-disco dual quad with single NCS
#GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:H, PB02:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
# stm32h7b3i-disco octal
#$GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:V, PB02:AF09:V, PC05:AF10:V, PD07:AF10:V, PG09:AF09:V, PH03:AF09:V, PC01:AF10:V, "
# . "PF06:AF10:V, PF07:AF10:V, PF09:AF10:V, PD11:AF09:V";
# stm32h735g-disco octal
#$GPIO_BASE = 0x58020000;
#$Conf = "PG06:AF10:V, PF10:AF09:V, PB02:AF10:V, PD07:AF10:V, PG09:AF09:V, PD05:AF10:V, PD04:AF10:V, "
# . "PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
# stm32l562e-disco octal
#$GPIO_BASE = 0x42020000;
#$Conf = "PA02:AF10:V, PA03:AF10:V, PB02:AF10:V, PC00:AF03:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V, "
# . "PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V";
&getopts('b:c:f:t');
if ($Getopt::Std::opt_b eq '')
{
if ($GPIO_BASE eq '')
{
die("usage: $0 [ -1 ] -b io_base [ -c port_configuration ] [ -f conf_file ]");
}
}
else
{
$GPIO_BASE = eval $Getopt::Std::opt_b;
}
if ($Getopt::Std::opt_c eq '')
{
if (($Conf eq '') && ($Getopt::Std::opt_f eq ''))
{
die("usage: $0 [ -b io_base ] ( -c port_configuration | -f conf_file )");
}
}#
else
{
$Conf = $Getopt::Std::opt_c . ',';
}
$STM32F1 = $Getopt::Std::opt_t;
my $Sep = "\t";
my $Form = "${Sep}mmw 0x%08X 0x%08X 0x%08X\t;# ";
my $GPIO_OFFS;
my $GPIO_CRL;
my $GPIO_CRH;
my $GPIO_MODER;
my $GPIO_OTYPER;
my $GPIO_OSPEEDR;
my $GPIO_PUPDR;
my $GPIO_IDR;
my $GPIO_ODR;
my $GPIO_AFRL;
my $GPIO_AFRH;
if ($STM32F1)
{
# offsets for F1 devices
$GPIO_OFFS = 0x400;
$GPIO_CRL = 0x00;
$GPIO_CRH = 0x04;
$GPIO_IDR = 0x08;
$GPIO_ODR = 0x0C;
}
else
{
# these offsets are identical on all F0, F4, F7, H7, L4, L4+ devices up to now
$GPIO_OFFS = 0x400;
$GPIO_MODER = 0x00;
$GPIO_OTYPER = 0x04;
$GPIO_OSPEEDR = 0x08;
$GPIO_PUPDR = 0x0C;
$GPIO_IDR = 0x10;
$GPIO_ODR = 0x14;
$GPIO_AFRL = 0x20;
$GPIO_AFRH = 0x24;
}
my @Out = ( { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { } );
my @Port = ( );
my $Exor;
my %Conf;
my $Pins = "${Sep}#";
my $pins;
my $altn;
my %defs;
if ($Getopt::Std::opt_f ne '')
{
open(CONF_FILE, '<', $Getopt::Std::opt_f) || die("can't open $Getopt::Std::opt_f");
while (my $line = <CONF_FILE>)
{
if ($line =~ /^\s*#define\s+.?(QSPI|QUAD_?SPI|OCTOSPI[^_]*)\w+_(Port|Pin)\s/)
{
if ($line =~ /#define\s+(\w+)\s+(\w+)/)
{
$defs{$1} = $2;
}
else
{
die($line);
}
}
elsif ($line =~ /^\s*(P[A-Z])([0-9]+)\s*-+>\s+.?(QSPI|QUAD_?SPI|OCTO_?SPI[^_]*)_(\w+)/)
{
$Conf{$4} = sprintf("%s%02d", $1, $2);
}
elsif ($line =~ /^\s*GPIO_InitStruct.Pin\s*=\s*([^;]+\w)/)
{
$pins = $1;
while ($line !~ /;/)
{
$line = <CONF_FILE>;
$line =~ /^\s*([^;]+\w)/;
$pins .= $1;
}
}
elsif ($line =~ /^\s*GPIO_InitStruct.Alternate\s*=\s*GPIO_AF([0-9]+)/)
{
$altn = $1;
}
elsif ($line =~ /^\s*HAL_GPIO_Init\s*\(\s*(\w+)\s*,/)
{
my $port = $1;
if ($port =~ /GPIO([A-Z])/)
{
$port = $1;
}
elsif (exists($defs{$port}))
{
$defs{$port} =~ /GPIO([A-Z])/;
$port = $1;
}
else
{
printf("\n");
next;
}
my @pin = split(/\s*\|\s*/, $pins);
foreach my $pin (@pin)
{
my $bit;
if (exists($defs{$pin}))
{
$defs{$pin} =~ /GPIO_PIN_([0-9]+)/;
$bit = $1;
}
else
{
$pin =~ /GPIO_PIN_([0-9]+)/;
$bit = $1;
}
$Conf .= sprintf("P%s%02d:AF%02d:V, ", $port, $bit, $altn);
}
$pins = '';
$altn = 0;
}
}
close(CONF_FILE);
}
else
{
my @names = ( );
my @conf = split(/\s*,\s*/, $Conf);
if (@conf == 2)
{
push(@names, 'SDA', 'SCL');
} else {
if (@conf == 3)
{
push(@names, 'NCS', 'CLK', 'IO0/DIO');
}
elsif (@conf == 4)
{
push(@names, 'NCS', 'CLK','IO1/MISO', 'IO0/MOSI');
}
elsif (@conf == 6)
{
push(@names, 'NCS', 'CLK', 'IO3/NHOLD', 'IO2/NWP', 'IO1/MISO', 'IO0/MOSI');
}
elsif (@conf == 10)
{
push(@names, 'NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
push(@names, 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
}
elsif (@conf == 11)
{
push(@names, 'BK_1_NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
push(@names, 'BK_2_NCS', 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
}
else
{
die("invalid config");
}
}
for (my $index = 0; $index < @conf; $index++)
{
uc($conf[$index]) =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
$Pins .= sprintf(" %s: P%s%02d,", $names[$index], $1, $2);
}
chop($Pins);
}
if (exists $Conf{'BK1_IO0'})
{
# QuadSPI on F4, F7, H7
my $line;
for my $i ('NCS', 'BK1_NCS', 'CLK', 'BK1_IO3', 'BK1_IO2', 'BK1_IO1', 'BK1_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
if (exists $Conf{'BK2_IO0'})
{
# QuadSPI on F4, F7, H7
my $line;
for my $i ('NCS', 'BK2_NCS', 'CLK', 'BK2_IO3', 'BK2_IO2', 'BK2_IO1', 'BK2_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
if (exists $Conf{'P1_IO0'})
{
# OctoSPI on L4+, L5, H7
my $line;
for my $i ('P1_NCS', 'P1_CLK', 'P1_DQS', 'P1_IO7', 'P1_IO6', 'P1_IO5', 'P1_IO4',
'P1_IO3', 'P1_IO2', 'P1_IO1', 'P1_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
if (exists $Conf{'P2_IO0'})
{
# OctoSPI on L4+, H7
my $line;
for my $i ('P2_NCS', 'P2_CLK', 'P2_DQS', 'P2_IO7', 'P2_IO6', 'P2_IO5', 'P2_IO4',
'P2_IO3', 'P2_IO2', 'P2_IO1', 'P2_IO0')
{
(exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
}
}
my @Col = ( );
my @conf = split(/\s*,\s*/, $Conf);
if (@conf == 3)
{
splice(@conf, 2, 0, 'NONE', 'NONE', 'NONE');
}
elsif (@conf == 4)
{
splice(@conf, 2, 0, 'NONE', 'NONE');
}
foreach my $line (@conf)
{
$line = uc($line);
$line =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
my $port = $1;
my $pin = $2;
my $conf = $3;
my $speed = $4;
my $MODER = 0x0;
my $OTYPER = 0x0;
my $OSPEEDR = 0x0;
my $PUPDR = 0x0;
my $AFR = 0x0;
my $num = ord(${port}) - ord('A');
my $out = $Out[$num];
(exists $$out{'DEF'}) || ($$out{'DEF'} = 0);
if ($conf eq '')
{
if ($line ne 'NONE')
{
printf(STDERR "invalid conf %s\n", $line);
}
next;
}
elsif ($conf =~ /^AF([0-9]+)(|P|O)(|UP|DO)$/)
{
if ($STM32F1)
{
printf(STDERR "no alternate %s for F1 family\n", $line);
next;
}
if (($1 < 0) || ($1 > 15))
{
printf(STDERR "invalid alternate %s\n", $line);
next;
}
$MODER = 0x2;
$AFR = $1;
if ($pin <= 7)
{
$$out{'AFRL_H'} |= ($AFR << (${pin} << 2));
$$out{'AFRL_L'} |= (($AFR ^ 0xF) << (${pin} << 2));
}
else
{
$$out{'AFRH_H'} |= ($AFR << ((${pin} - 8) << 2));
$$out{'AFRH_L'} |= (($AFR ^ 0xF) << ((${pin} - 8) << 2));
}
if ($2 ne '') {
$OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
$$out{'OTYPER_H'} |= ($OTYPER << $pin);
$$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
}
$PUPDR = ($3 eq 'UP') ? 0x1 : (($3 eq 'DO') ? 0x2 : 0x0);
$$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
$$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
$conf = sprintf("AF%02d%s%s", $AFR, $2, $3);
}
elsif ($conf =~ /^IN(|P|O)(|UP|DO)$/)
{
if ($STM32F1)
{
$MODER = ($1 eq '') ? 0x4 : 0x8;
($2 eq 'UP') && ($$out{'PUPDR_H'} |= (1 << ${pin}));
($2 eq 'DO') && ($$out{'PUPDR_L'} |= (1 << ${pin}));
}
else
{
$MODER = 0x0;
if ($1 ne '')
{
$OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
$$out{'OTYPER_H'} |= ($OTYPER << $pin);
$$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
}
$PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
$$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
$$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
}
($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
}
elsif ($conf =~ /^P(P|O)(|UP|DO)$/)
{
if ($STM32F1)
{
$MODER = ($1 eq 'O') ? 0x4 : 0x0;
$MODER |= (($speed eq 'V') ? 0x03 : (($speed eq 'L') ? 0x2 : 0x1));
if ($2 ne '')
{
printf(STDERR "WARNING: no output w/ pull-up/pull-down for F1 family %s\n", $line);
}
}
else
{
$MODER = 0x1;
$OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
$$out{'OTYPER_H'} |= ($OTYPER << $pin);
$$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
$PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
$$out{'PUPDR_H'} |= ($PUPDR << ($pin << 1));
$$out{'PUPDR_L'} |= (($PUPDR ^ 0x3) << ($pin << 1));
}
($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
}
else
{
printf(STDERR "invalid conf %s\n", $line);
next;
}
if ($$out{'DEF'} & (1<< ${pin}))
{
printf(STDERR "redefinition: %s\n", $line);
}
if ($STM32F1)
{
if ($pin >= 8)
{
$$out{'CRH_H'} |= ($MODER << (($pin & 0x7) << 2));
$$out{'CRH_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
}
else
{
$$out{'CRL_H'} |= ($MODER << (($pin & 0x7) << 2));
$$out{'CRL_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
}
$Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
my $exor = 0xB << (($pin & 0x7) << 2);
(($MODER & 0x3) == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X",
((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF,
((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, $exor));
}
else
{
$$out{'DEF'} |= (1 << ${pin});
$$out{'MODER_H'} |= ($MODER << (${pin} << 1));
$$out{'MODER_L'} |= (($MODER ^ 0x3) << (${pin} << 1));
$OSPEEDR = (($speed eq 'V') ? 0x3 : (($speed eq 'H') ? 0x2 : (($speed eq 'M') ? 0x1 : 0x0)));
$$out{'OSPEEDR_H'} |= ($OSPEEDR << (${pin} << 1));
$$out{'OSPEEDR_L'} |= (($OSPEEDR ^ 0x3) << (${pin} << 1));
$Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
my $exor = (0x1 << ($pin << 1));
($MODER == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF,
(${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, $exor));
}
push(@{$Port[$num]}, sprintf("P%s%02d:%s:%s", $port, $pin, $conf, $speed));
push(@Col, $Exor);
}
my $Col = sprintf("${Sep}0x%03X ", (${GPIO_IDR}-${GPIO_ODR}) & 0x3FF);
for (my $i = 0; $i < @Col; $i++)
{
if (($i != 0) && (($i % 2) == 0))
{
(($i + 1) < @Col) && ($Col .= "\\\n${Sep}");
}
$Col .= sprintf("%s ", $Col[$i]);
}
printf("%s\n", $Col);
my @Col = ( );
my $Set;
for (my $i = 0; $i < @Out; $i++)
{
my $out = $Out[$i];
my $addr = ${GPIO_BASE} + $i * ${GPIO_OFFS};
my $count = 0;
if ($STM32F1)
{
if (($$out{'CRH_H'} | $$out{'CRH_L'} | $$out{'CRL_H'} | $$out{'CRL_L'} |
$$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0)
{
push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
$Set .= sprintf("\n%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
join(", ", sort({ $b cmp $a } @{$Port[$i]})));
(($$out{'CRL_H'} | $$out{'CRL_L'}) != 0) &&
($Set .= sprintf("${Form}CRL\n", $addr + ${GPIO_CRL}, $$out{'CRL_H'}, $$out{'CRL_L'}));
(($$out{'CRH_H'} | $$out{'CRH_L'}) != 0) &&
($Set .= sprintf("${Form}CRH\n", $addr + ${GPIO_CRH}, $$out{'CRH_H'}, $$out{'CRH_L'}));
(($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
($Set .= sprintf("${Form}ODR/PUPDR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
}
}
else
{
if (($$out{'MODER_H'} | $$out{'MODER_L'} |
$$out{'OTYPER_H'} | $$out{'OTYPER_L'} |
$$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'} |
$$out{'PUPDR_H'} | $$out{'PUPDR_L'} |
$$out{'ODR_H'} | $$out{'ODR_L'} |
$$out{'AFRL_H'} | $$out{'AFRL_L'} |
$$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0)
{
push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
$Set .= sprintf("%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
join(", ", sort({ $b cmp $a } @{$Port[$i]})));
(($$out{'MODER_H'} | $$out{'MODER_L'}) != 0) &&
($Set .= sprintf("${Form}MODER\n", $addr + ${GPIO_MODER}, $$out{'MODER_H'}, $$out{'MODER_L'}));
(($$out{'OTYPER_H'} | $$out{'OTYPER_L'}) != 0) &&
($Set .= sprintf("${Form}OTYPER\n", $addr + ${GPIO_OTYPER}, $$out{'OTYPER_H'}, $$out{'OTYPER_L'}));
(($$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'}) != 0) &&
($Set .= sprintf("${Form}OSPEEDR\n", $addr + ${GPIO_OSPEEDR}, $$out{'OSPEEDR_H'}, $$out{'OSPEEDR_L'}));
(($$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) &&
($Set .= sprintf("${Form}PUPDR\n", $addr + ${GPIO_PUPDR}, $$out{'PUPDR_H'}, $$out{'PUPDR_L'}));
(($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
($Set .= sprintf("${Form}ODR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
(($$out{'AFRL_H'} | $$out{'AFRL_L'}) != 0) &&
($Set .= sprintf("${Form}AFRL\n", $addr + ${GPIO_AFRL}, $$out{'AFRL_H'}, $$out{'AFRL_L'}));
(($$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) &&
($Set .= sprintf("${Form}AFRH\n", $addr + ${GPIO_AFRH}, $$out{'AFRH_H'}, $$out{'AFRH_L'}));
}
}
}
my $Col = '';
for (my $i = 0; $i < @Col; $i++)
{
if (($i % 6) == 0)
{
chop($Col);
(($i + 1) < @Col) && ($Col .= "\n${Sep}#");
}
$Col .= sprintf(" %s,", $Col[$i]);
}
chop($Col);
#printf("\n%s\n", $Pins);
printf("%s\n", $Col);
printf("%s\n", $Set);

View File

@ -0,0 +1,123 @@
/***************************************************************************
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), crc32 (out)
* r1 - flash page size
* r2 - address offset into flash
* r3 - OCTOSPI io_base
* Clobbered:
* r4 - tmp
* r5 - address of OCTOSPI_DR
* r6 - address of OCTOSPI_CCR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
movs r4, #0x00 /* initialize crc */
mvns r4, r4 /* to 0xFFFFFFFF */
start_read:
octospi_abort /* start in clean state */
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r5, r5, r3 /* address of OCTOSPI_DR */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r5 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_page_read /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then read to end of page */
mov r7, r0 /* else read all remaining */
write_dlr:
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_read /* TCR for read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_read /* IR for read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
ldr r6, =0x04C11DB7 /* CRC32 polynomial */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
lsls r7, r7, #24 /* shift into msb */
eors r4, r4, r7
.rept 8 /* unrolled bit loop */
asrs r7, r4, #31 /* copy bit 31 into bits 0 to 31 */
ands r7, r7, r6 /* r7 neg. -> CRC32XOR, pos. -> 0x0 */
lsls r4, r4, #1 /* shift result */
eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */
.endr
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
.pool
exit:
mvns r0, r4 /* invert to get final result */
octospi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
cr_page_read:
.space 4 /* OCTOSPI_CR value for read command */
ccr_page_read:
.space 4 /* OCTOSPI_CCR value for read command */
tcr_page_read:
.space 4 /* OCTOSPI_TCR value for read command */
ir_page_read:
.space 4 /* OCTOSPI_IR value for read command */

View File

@ -0,0 +1,13 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,
0x5f,0x62,0x22,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,
0x07,0x46,0x1f,0x64,0x1e,0x4f,0x37,0x60,0x1e,0x4f,0xb7,0x60,0x1e,0x4f,0x37,0x61,
0x9a,0x64,0x15,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,0x05,0xd4,
0x0a,0x42,0xd7,0xd1,0xb8,0xe7,0x00,0x00,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,108 @@
/***************************************************************************
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - sector count
* r1 - QSPI io_base
* Clobbered:
* r2 - r7 tmp */
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r1, #OCTOSPI_CR] /* get OCTOSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r1, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r1, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r1, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
adr r2, buffer /* pointer to start of buffer */
movs r3, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r3, r3, r1 /* address of OCTOSPI_DR */
sector_start:
octospi_abort /* start in clean state */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r3 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_page_read /* indirect read mode */
str r7, [r1, #OCTOSPI_CR] /* set mode */
ldmia r2!, {r4, r5} /* load address offset, length */
subs r2, r2, #4 /* point to length */
subs r5, r5, #1 /* decrement sector length for DLR */
str r5, [r1, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_read /* TCR for read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_read /* IR for read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r4, [r1, #OCTOSPI_AR] /* store SPI start address */
ldr r6, [r2, #4] /* load initial value */
read_loop:
ldrb r4, [r3, #0] /* read next byte from DR */
movs r7, #0xFF /* fill bits 8-15 */
lsls r7, r7, #8 /* with ones */
orrs r4, r4, r7 /* copy ones to left of read byte */
ands r6, r6, r4 /* and read byte to result */
lsls r4, r4, #8 /* shift result into higher byte */
orrs r6, r6, r4 /* or read byte to result */
subs r5, r5, #1 /* decrement byte (count-1) */
bpl read_loop /* again if sector not completed */
adds r5, r5, #1 /* increment count due to the -1 */
stmia r2!, {r5, r6} /* save final count and result for sector */
subs r0, r0, #1 /* decrement sector count */
bne sector_start /* next sector? */
octospi_abort /* to idle state */
exit:
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
cr_page_read:
.space 4 /* OCTOSPI_CR value for read command */
ccr_page_read:
.space 4 /* OCTOSPI_CCR value for read command */
tcr_page_read:
.space 4 /* OCTOSPI_TCR value for read command */
ir_page_read:
.space 4 /* OCTOSPI_IR value for read command */
.equ buffer, .

View File

@ -0,0 +1,8 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x1b,0xa2,0x50,0x23,0x5b,0x18,0x02,0x25,0x0f,0x68,0x2f,0x43,0x0f,0x60,0xb0,0x26,
0xf6,0x18,0x0f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x4f,0x62,0x10,0x4f,0x0f,0x60,
0x30,0xca,0x04,0x3a,0x01,0x3d,0x0d,0x64,0x0e,0x4f,0x37,0x60,0x0e,0x4f,0xb7,0x60,
0x0e,0x4f,0x37,0x61,0x8c,0x64,0x56,0x68,0x1c,0x78,0xff,0x27,0x3f,0x02,0x3c,0x43,
0x26,0x40,0x24,0x02,0x26,0x43,0x01,0x3d,0xf6,0xd5,0x01,0x35,0x60,0xc2,0x01,0x38,
0xd9,0xd1,0x02,0x25,0x0f,0x68,0x2f,0x43,0x0f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,142 @@
/***************************************************************************
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - OCTOSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - wp
* r5 - address of OCTOSPI_DR
* r6 - address of OCTOSPI_CCR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, wp /* load wp */
start_read:
octospi_abort /* start in clean state */
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r5, r5, r3 /* address of OCTOSPI_DR */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r5 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_page_read /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then write to end of page */
mov r7, r0 /* else write all remaining */
write_dlr:
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_read /* TCR for read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_read /* IR for read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
strb r7, [r4, #0] /* write next byte */
adds r4, r4, #1 /* increment internal wp */
cmp r4, r9 /* internal wp beyond end? */
blo wait_fifo /* if no, then ok */
mov r4, r8 /* else wrap around */
wait_fifo:
ldr r7, rp /* get rp */
cmp r7, #0 /* if rp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo full */
beq wait_fifo /* wait until not full */
adr r7, wp /* get address of wp */
str r4, [r7] /* store updated wp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
octospi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
cr_page_read:
.space 4 /* OCTOSPI_CR value for read command */
ccr_page_read:
.space 4 /* OCTOSPI_CCR value for read command */
tcr_page_read:
.space 4 /* OCTOSPI_TCR value for read command */
ir_page_read:
.space 4 /* OCTOSPI_IR value for read command */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,12 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x27,0x4c,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x50,0x25,
0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,
0x1c,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,
0x1f,0x64,0x19,0x4f,0x37,0x60,0x19,0x4f,0xb7,0x60,0x19,0x4f,0x37,0x61,0x9a,0x64,
0x2f,0x78,0x27,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x16,0x4f,0x00,0x2f,
0x09,0xd0,0xbc,0x42,0xfa,0xd0,0x13,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,0x02,0xd4,
0x0a,0x42,0xed,0xd1,0xcf,0xe7,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,219 @@
/***************************************************************************
* Copyright (C) 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - OCTOSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - rp
* r5 - address of OCTOSPI_DR
* r6 - address of OCTOSPI_CCR
* r7 - tmp
* r10 - single 0x0 / dual 0x1
*/
#include "../../../../src/flash/nor/stmqspi.h"
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
.macro octospi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, rp /* load rp */
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI_CR register */
lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
mov r10, r7 /* save in r10 */
wip_loop:
octospi_abort /* start in clean state */
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
adds r5, r5, r3 /* address of OCTOSPI_DR */
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
adds r6, r6, r5 /* address of OCTOSPI_CCR */
wait_busy
ldr r7, cr_read_status /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r10 /* get dual bit */
str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
ldr r7, tcr_read_status /* TCR for status read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_read_status /* IR for status read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
movs r7, #0 /* dummy address */
str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
bcs wip_loop /* then poll again */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq write_enable /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
bcs wip_loop /* then poll again */
write_enable:
tst r0, r0 /* test residual count */
bmi exit /* if negative, then finished */
wait_busy
ldr r7, cr_write_enable /* indirect write mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
ldr r7, ccr_write_enable /* CCR for write enable */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate write enable */
ldr r7, tcr_write_enable /* TCR for write enable */
str r7, [r6, #OCTOSPI_TCR_CCR] /* write enable instruction */
ldr r7, ir_write_enable /* IR for write enable */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
movs r7, #0 /* silicon bug in L5? dummy write */
str r7, [r3, #OCTOSPI_AR] /* into AR resolves issue */
wait_busy
ldr r7, cr_read_status /* indirect read mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r10 /* get dual count */
str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
ldr r7, tcr_read_status /* TCR for status read */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_read_status /* IR for status read */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
movs r7, #0 /* dummy address */
str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
bcc error /* write enabled, then error */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq start_write /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
bcc error /* write enabled, then error */
start_write:
wait_busy
ldr r7, cr_page_write /* indirect write mode */
str r7, [r3, #OCTOSPI_CR] /* set mode */
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then write to end of page */
mov r7, r0 /* else write all remaining */
write_dlr:
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_write /* CCR for page write */
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
ldr r7, tcr_page_write /* TCR for page write */
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
ldr r7, ir_page_write /* IR for page write */
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
write_loop:
ldr r7, wp /* get wp */
cmp r7, #0 /* if wp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo empty */
beq write_loop /* wait until not empty */
ldrb r7, [r4, #0] /* read next byte */
strb r7, [r5] /* write next byte to DR */
adds r4, r4, #1 /* increment internal rp */
cmp r4, r9 /* internal rp beyond end? */
blo upd_write /* if no, then ok */
mov r4, r8 /* else wrap around */
upd_write:
adr r7, rp /* get address of rp */
str r4, [r7] /* store updated rp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi page_end /* stop if no data left */
tst r2, r1 /* page end ? */
bne write_loop /* if not, then next byte */
page_end:
ldr r7, [r3, #OCTOSPI_SR] /* load status */
lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
bcc page_end /* loop until TCF set */
bal wip_loop /* then next page */
error:
movs r0, #0 /* return 0xFFFFFFFF */
subs r0, r0, #2 /* for error */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
octospi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
cr_read_status:
.space 4 /* OCTOSPI_CR value for READ_STATUS command */
ccr_read_status:
.space 4 /* OCTOSPI_CCR value for READ_STATUS command */
tcr_read_status:
.space 4 /* OCTOSPI_TCR value for READ_STATUS command */
ir_read_status:
.space 4 /* OCTOSPI_IR value for READ_STATUS command */
cr_write_enable:
.space 4 /* OCTOSPI_CR value for WRITE_ENABLE command */
ccr_write_enable:
.space 4 /* OCTOSPI_CCR value for WRITE_ENABLE command */
tcr_write_enable:
.space 4 /* OCTOSPI_TCR value for WRITE_ENABLE command */
ir_write_enable:
.space 4 /* OCTOSPI_IR value for WRITE_ENABLE command */
cr_page_write:
.space 4 /* OCTOSPI_CR value for PAGE_PROG command */
ccr_page_write:
.space 4 /* OCTOSPI_CCR value for PAGE_PROG command */
tcr_page_write:
.space 4 /* OCTOSPI_TCR value for PAGE_PROG command */
ir_page_write:
.space 4 /* OCTOSPI_IR value for PAGE_PROG command */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,21 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x4f,0x4c,0x1f,0x68,0x7f,0x06,0xff,0x0f,0xba,0x46,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,
0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,0x39,0x4f,0x1f,0x60,0x57,0x46,0x1f,0x64,
0x38,0x4f,0x37,0x60,0x38,0x4f,0xb7,0x60,0x38,0x4f,0x37,0x61,0x00,0x27,0x9f,0x64,
0x2f,0x78,0x7f,0x08,0xe3,0xd2,0x57,0x46,0x3f,0x42,0x02,0xd0,0x2f,0x78,0x7f,0x08,
0xdd,0xd2,0x00,0x42,0x55,0xd4,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,
0x2f,0x4f,0x1f,0x60,0x2f,0x4f,0x37,0x60,0x2f,0x4f,0xb7,0x60,0x2f,0x4f,0x37,0x61,
0x00,0x27,0x9f,0x64,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,0x24,0x4f,
0x1f,0x60,0x57,0x46,0x1f,0x64,0x23,0x4f,0x37,0x60,0x23,0x4f,0xb7,0x60,0x23,0x4f,
0x37,0x61,0x00,0x27,0x9f,0x64,0x2f,0x78,0xbf,0x08,0x30,0xd3,0x57,0x46,0x3f,0x42,
0x02,0xd0,0x2f,0x78,0xbf,0x08,0x2a,0xd3,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,
0x5f,0x62,0x1f,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,
0x07,0x46,0x1f,0x64,0x1b,0x4f,0x37,0x60,0x1b,0x4f,0xb7,0x60,0x1b,0x4f,0x37,0x61,
0x9a,0x64,0x1b,0x4f,0x00,0x2f,0x14,0xd0,0xbc,0x42,0xfa,0xd0,0x27,0x78,0x2f,0x70,
0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x16,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,
0x01,0xd4,0x0a,0x42,0xed,0xd1,0x1f,0x6a,0xbf,0x08,0xfc,0xd3,0x87,0xe7,0x00,0x20,
0x02,0x38,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x00,0xbe,0xc0,0x46,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,108 @@
/***************************************************************************
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), crc32 (out)
* r1 - flash page size
* r2 - address offset into flash
* r3 - QSPI io_base
* Clobbered:
* r4 - rp
* r5 - address of QSPI_DR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
movs r4, #0x00 /* initialize crc */
mvns r4, r4 /* to 0xFFFFFFFF */
start_read:
qspi_abort /* start in clean state */
movs r5, #QSPI_DR /* load QSPI_DR address offset */
adds r5, r5, r3 /* address of QSPI_DR */
wait_busy
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then read to end of page */
mov r7, r0 /* else read all remaining */
write_dlr:
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for page read */
str r7, [r3, #QSPI_CCR] /* initiate transfer */
str r2, [r3, #QSPI_AR] /* store SPI start address */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
ldr r6, =0x04C11DB7 /* CRC32 polynomial */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
lsls r7, r7, #24 /* shift into msb */
eors r4, r4, r7
.rept 8 /* unrolled bit loop */
asrs r7, r4, #31 /* copy bit 31 into bits 0 to 31 */
ands r7, r7, r6 /* r7 neg. -> CRC32XOR, pos. -> 0x0 */
lsls r4, r4, #1 /* shift result */
eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */
.endr
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
.pool
exit:
mvns r0, r4 /* invert to get final result */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
ccr_page_read:
.space 4 /* QSPI_CCR value for read command */
.space 4 /* not used */
.space 4 /* not used */

View File

@ -0,0 +1,12 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46,
0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x1c,0x4f,0x5f,0x61,
0x9a,0x61,0x9f,0x68,0x14,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,
0x04,0xd4,0x0a,0x42,0xd7,0xd1,0xbf,0xe7,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,91 @@
/***************************************************************************
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - sector count
* r1 - QSPI io_base
* Clobbered:
* r2 - r7 tmp */
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r4, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r1, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r4 /* set abort bit */
str r7, [r1, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r1, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r1, #QSPI_FCR] /* clear TCF flag */
.endm
start:
adr r2, buffer /* pointer to start of buffer */
movs r3, #QSPI_DR /* load QSPI_DR address offset */
add r3, r3, r1 /* address of QSPI_DR */
sector_start:
qspi_abort /* start in clean state */
ldmia r2!, {r4, r5, r6} /* load address offset, length, initial value */
subs r2, r2, #8 /* point to length */
subs r5, r5, #1 /* decrement sector length for DLR */
wait_busy
str r5, [r1, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for page read */
str r7, [r1, #QSPI_CCR] /* initiate transfer */
str r4, [r1, #QSPI_AR] /* store SPI start address */
ldr r7, [r1, #QSPI_SR] /* wait for command startup */
read_loop:
ldrb r4, [r3] /* read next byte from DR */
movs r7, #0xFF /* fill bits 8-15 */
lsls r7, r7, #8 /* with ones */
orrs r4, r4, r7 /* copy ones to left of read byte */
ands r6, r6, r4 /* and read byte to result */
lsls r4, r4, #8 /* shift result into higher byte */
orrs r6, r6, r4 /* or read byte to result */
subs r5, r5, #1 /* decrement byte (count-1) */
bpl read_loop /* again if sector not completed */
adds r5, r5, #1 /* increment count due to the -1 */
stmia r2!, {r5, r6} /* save final count and result for sector */
subs r0, r0, #1 /* decrement sector count */
bne sector_start /* next sector? */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
ccr_page_read:
.space 4 /* QSPI_CCR value for read command */
.space 4 /* not used */
.space 4 /* not used */
.equ buffer, .

View File

@ -0,0 +1,7 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x17,0xa2,0x20,0x23,0x0b,0x44,0x02,0x24,0x0f,0x68,0x27,0x43,0x0f,0x60,0x70,0xca,
0x08,0x3a,0x01,0x3d,0x8f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xcf,0x60,0x0d,0x61,
0x0c,0x4f,0x4f,0x61,0x8c,0x61,0x8f,0x68,0x1c,0x78,0xff,0x27,0x3f,0x02,0x3c,0x43,
0x26,0x40,0x24,0x02,0x26,0x43,0x01,0x3d,0xf6,0xd5,0x01,0x35,0x60,0xc2,0x01,0x38,
0xe1,0xd1,0x02,0x24,0x0f,0x68,0x27,0x43,0x0f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,127 @@
/***************************************************************************
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - QSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - wp
* r5 - address of QSPI_DR
* r7 - tmp
*/
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, wp /* load wp */
start_read:
qspi_abort /* start in clean state */
movs r5, #QSPI_DR /* load QSPI_DR address offset */
adds r5, r5, r3 /* address of QSPI_DR */
wait_busy
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then read to end of page */
mov r7, r0 /* else read all remaining */
write_dlr:
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_read /* CCR for page read */
str r7, [r3, #QSPI_CCR] /* initiate transfer */
str r2, [r3, #QSPI_AR] /* store SPI start address */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
read_loop:
ldrb r7, [r5] /* read next byte from DR */
strb r7, [r4, #0] /* write next byte */
adds r4, r4, #1 /* increment internal wp */
cmp r4, r9 /* internal wp beyond end? */
blo wait_fifo /* if no, then ok */
mov r4, r8 /* else wrap around */
wait_fifo:
ldr r7, rp /* get rp */
cmp r7, #0 /* if rp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo full */
beq wait_fifo /* wait until not full */
adr r7, wp /* get address of wp */
str r4, [r7] /* store updated wp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi exit /* stop if no data left */
tst r2, r1 /* page end ? */
bne read_loop /* if not, then next byte */
page_end:
bal start_read /* then next page */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
ccr_page_read:
.space 4 /* QSPI_CCR value for read command */
.space 4 /* not used */
.space 4 /* not used */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,11 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x24,0x4c,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x20,0x25,
0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46,0x0f,0x43,
0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x18,0x4f,0x5f,0x61,0x9a,0x61,
0x9f,0x68,0x2f,0x78,0x27,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x17,0x4f,
0x00,0x2f,0x09,0xd0,0xbc,0x42,0xfa,0xd0,0x13,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,
0x02,0xd4,0x0a,0x42,0xed,0xd1,0xd6,0xe7,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,
0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,177 @@
/***************************************************************************
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Params:
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
* r1 - flash page size
* r2 - address offset into flash
* r3 - QSPI io_base
* r8 - fifo start
* r9 - fifo end + 1
* Clobbered:
* r4 - rp
* r5 - address of QSPI_DR
* r7 - tmp
* r10 - single 0x0 / dual 0x1
*/
#include "../../../../src/flash/nor/stmqspi.h"
.macro qspi_abort
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
orrs r7, r7, r5 /* set abort bit */
str r7, [r3, #QSPI_CR] /* store new CR register */
.endm
.macro wait_busy
0:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
bcs 0b /* loop until BUSY cleared */
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
.endm
start:
subs r0, r0, #1 /* decrement count for DLR */
subs r1, r1, #1 /* page size mask and for DLR */
ldr r4, rp /* load rp */
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
mov r10, r7 /* save in r10 */
wip_loop:
qspi_abort /* start in clean state */
movs r5, #QSPI_DR /* load QSPI_DR address offset */
adds r5, r5, r3 /* address of QSPI_DR */
wait_busy
mov r7, r10 /* get dual bit */
str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r3, #QSPI_CCR] /* initiate status read */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
bcs wip_loop /* then poll again */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq write_enable /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
bcs wip_loop /* then poll again */
write_enable:
tst r0, r0 /* test residual count */
bmi exit /* if negative, then finished */
wait_busy
ldr r7, ccr_write_enable /* CCR for write enable */
str r7, [r3, #QSPI_CCR] /* initiate write enable */
wait_busy
mov r7, r10 /* get dual bit */
str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
ldr r7, ccr_read_status /* CCR for status read */
str r7, [r3, #QSPI_CCR] /* initiate status read */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
ldrb r7, [r5] /* get first status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
bcc error /* write enabled, then error */
mov r7, r10 /* get dual bit */
tst r7, r7 /* dual mode ? */
beq start_write /* not dual, then ok */
ldrb r7, [r5] /* get second status register */
lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
bcc error /* write enabled, then error */
start_write:
wait_busy
mov r7, r2 /* get current start address */
orrs r7, r7, r1 /* end of current page */
subs r7, r7, r2 /* count-1 to end of page */
cmp r7, r0 /* if this count <= remaining */
bls write_dlr /* then write to end of page */
mov r7, r0 /* else write all remaining */
write_dlr:
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
ldr r7, ccr_page_write /* CCR for page write */
str r7, [r3, #QSPI_CCR] /* initiate transfer */
str r2, [r3, #QSPI_AR] /* store SPI start address */
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
write_loop:
ldr r7, wp /* get wp */
cmp r7, #0 /* if wp equals 0 */
beq exit /* then abort */
cmp r4, r7 /* check if fifo empty */
beq write_loop /* wait until not empty */
ldrb r7, [r4, #0] /* read next byte */
strb r7, [r5] /* write next byte to DR */
adds r4, r4, #1 /* increment internal rp */
cmp r4, r9 /* internal rp beyond end? */
blo upd_write /* if no, then ok */
mov r4, r8 /* else wrap around */
upd_write:
adr r7, rp /* get address of rp */
str r4, [r7] /* store updated rp */
adds r2, r2, #1 /* increment address */
subs r0, r0, #1 /* decrement (count-1) */
bmi page_end /* stop if no data left */
tst r2, r1 /* page end ? */
bne write_loop /* if not, then next byte */
page_end:
ldr r7, [r3, #QSPI_SR] /* load status */
lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
bcc page_end /* loop until TCF set */
bal wip_loop /* then next page */
error:
movs r0, #0 /* return 0xFFFFFFFF */
subs r0, r0, #2 /* for error */
exit:
adds r0, r0, #1 /* increment count due to the -1 */
qspi_abort /* to idle state */
.align 2 /* align to word, bkpt is 4 words */
bkpt #0 /* before code end for exit_point */
.align 2 /* align to word */
.space 4 /* not used */
ccr_read_status:
.space 4 /* QSPI_CCR value for READ_STATUS command */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
ccr_write_enable:
.space 4 /* QSPI_CCR value for WRITE_ENABLE command */
.space 4 /* not used */
.space 4 /* not used */
.space 4 /* not used */
ccr_page_write:
.space 4 /* QSPI_CCR value for PAGE_PROG command */
.space 4 /* not used */
.space 4 /* not used */
.equ wp, . /* wp, uint32_t */
.equ rp, wp + 4 /* rp, uint32_t */
.equ buffer, rp + 4 /* buffer follows right away */

View File

@ -0,0 +1,18 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x01,0x38,0x01,0x39,0x41,0x4c,0x1f,0x68,0x7f,0x06,0xff,0x0f,0xba,0x46,0x02,0x25,
0x1f,0x68,0x2f,0x43,0x1f,0x60,0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,
0x02,0x27,0xdf,0x60,0x57,0x46,0x1f,0x61,0x2c,0x4f,0x5f,0x61,0x9f,0x68,0x2f,0x78,
0x7f,0x08,0xec,0xd2,0x57,0x46,0x3f,0x42,0x02,0xd0,0x2f,0x78,0x7f,0x08,0xe6,0xd2,
0x00,0x42,0x41,0xd4,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x27,0x4f,
0x5f,0x61,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x57,0x46,0x1f,0x61,
0x1e,0x4f,0x5f,0x61,0x9f,0x68,0x2f,0x78,0xbf,0x08,0x2b,0xd3,0x57,0x46,0x3f,0x42,
0x02,0xd0,0x2f,0x78,0xbf,0x08,0x25,0xd3,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,
0xdf,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,
0x1a,0x4f,0x5f,0x61,0x9a,0x61,0x9f,0x68,0x1b,0x4f,0x00,0x2f,0x14,0xd0,0xbc,0x42,
0xfa,0xd0,0x27,0x78,0x2f,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x17,0xa7,
0x3c,0x60,0x01,0x32,0x01,0x38,0x01,0xd4,0x0a,0x42,0xed,0xd1,0x9f,0x68,0xbf,0x08,
0xfc,0xd3,0xa4,0xe7,0x00,0x20,0x02,0x38,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,
0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

View File

@ -5253,6 +5253,18 @@ it has been removed by the @option{unlock} flag.
@end deffn
@deffn Command {flash verify_image} filename [offset] [type]
Verify the image @file{filename} to the current target's flash bank(s).
Parameters follow the description of 'flash write_image'.
In contrast to the 'verify_image' command, for banks with specific
verify method, that one is used instead of the usual target's read
memory methods. This is necessary for flash banks not readable by
ordinary memory reads.
This command gives only an overall good/bad result for each bank, not
addresses of individual failed bytes as it's intended only as quick
check for successful programming.
@end deffn
@section Other Flash commands
@cindex flash protection
@ -5511,6 +5523,117 @@ flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME
@end deffn
@deffn {Flash Driver} stmqspi
@cindex STMicroelectronics QuadSPI/OctoSPI Interface
@cindex QuadSPI
@cindex OctoSPI
@cindex stmqspi
Some devices from STMicroelectronics include a proprietary ``QuadSPI Interface''
(e.g. STM32F4, STM32F7, STM32L4) or ``OctoSPI Interface'' (e.g. STM32L4+)
controller able to drive one or even two (dual mode) external SPI flash devices.
The OctoSPI is a superset of QuadSPI, its presence is detected automatically.
Currently only the regular command mode is supported, whereas the HyperFlash
mode is not.
QuadSPI/OctoSPI makes the flash contents directly accessible in the CPU address
space; in case of dual mode both devices must be of the same type and are
mapped in the same memory bank (even and odd addresses interleaved).
CPU can directly read data, execute code (but not boot) from QuadSPI bank.
The 'flash bank' command only requires the @var{base} parameter and the extra
parameter @var{io_base} in order to identify the memory bank. Both are fixed
by hardware, see datasheet or RM. All other parameters are ignored.
The controller must be initialized after each reset and properly configured
for memory-mapped read operation for the particular flash chip(s), for the full
list of available register settings cf. the controller's RM. This setup is quite
board specific (that's why booting from this memory is not possible). The
flash driver infers all parameters from current controller register values when
'flash probe @var{bank_id}' is executed.
Normal OpenOCD commands like @command{mdw} can be used to display the flash content,
but only after proper controller initialization as decribed above. However,
due to a silicon bug in some devices, attempting to access the very last word
should be avoided.
It is possible to use two (even different) flash chips alternatingly, if individual
bank chip selects are available. For some package variants, this is not the case
due to limited pin count. To switch from one to another, adjust FSEL bit accordingly
and re-issue 'flash probe bank_id'. Note that the bank base address will @emph{not}
change, so the address spaces of both devices will overlap. In dual flash mode
both chips must be identical regarding size and most other properties.
Block or sector protection internal to the flash chip is not handled by this
driver at all, but can be dealt with manually by the 'cmd' command, see below.
The sector protection via 'flash protect' command etc. is completely internal to
openocd, intended only to prevent accidental erase or overwrite and it does not
persist across openocd invocations.
OpenOCD contains a hardcoded list of flash devices with their properties,
these are auto-detected. If a device is not included in this list, SFDP discovery
is attempted. If this fails or gives inappropriate results, manual setting is
required (see 'set' command).
@example
flash bank $_FLASHNAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
flash bank $_FLASHNAME stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400
@end example
There are three specific commands
@deffn Command {stmqspi mass_erase} bank_id
Clears sector protections and performs a mass erase. Works only if there is no
chip specific write protection engaged.
@end deffn
@deffn Command {stmqspi set} bank_id name total_size page_size read_cmd fread_cmd pprg_cmd mass_erase_cmd sector_size sector_erase_cmd
Set flash parameters: @var{name} human readable string, @var{total_size} size
in bytes, @var{page_size} is write page size. @var{read_cmd}, @var{fread_cmd} and @var{pprg_cmd}
are commands for reading and page programming. @var{fread_cmd} is used in DPI and QPI modes,
@var{read_cmd} in normal SPI (single line) mode. @var{mass_erase_cmd}, @var{sector_size}
and @var{sector_erase_cmd} are optional.
This command is required if chip id is not hardcoded yet and e.g. for EEPROMs or FRAMs
which don't support an id command.
In dual mode parameters of both chips are set identically. The parameters refer to
a single chip, so the whole bank gets twice the specified capacity etc.
@end deffn
@deffn Command {stmqspi cmd} bank_id resp_num cmd_byte ...
If @var{resp_num} is zero, sends command @var{cmd_byte} and following data
bytes. In dual mode command byte is sent to @emph{both} chips but data bytes are
sent @emph{alternatingly} to chip 1 and 2, first to flash 1, second to flash 2, etc.,
i.e. the total number of bytes (including cmd_byte) must be odd.
If @var{resp_num} is not zero, cmd and at most four following data bytes are
sent, in dual mode @emph{simultaneously} to both chips. Then @var{resp_num} bytes
are read interleaved from both chips starting with chip 1. In this case
@var{resp_num} must be even.
Note the hardware dictated subtle difference of those two cases in dual-flash mode.
To check basic communication settings, issue
@example
stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 1 0x05; stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 1 0x05
@end example
for single flash mode or
@example
stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 2 0x05; stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 2 0x05
@end example
for dual flash mode. This should return the status register contents.
In 8-line mode, @var{cmd_byte} is sent twice - first time as given, second time
complemented. Additionally, in 8-line mode only, some commands (e.g. Read Status)
need a dummy address, e.g.
@example
stmqspi cmd bank_id 1 0x05 0x00 0x00 0x00 0x00
@end example
should return the status register contents.
@end deffn
@end deffn
@deffn {Flash Driver} mrvlqspi
This driver supports QSPI flash controller of Marvell's Wireless
Microcontroller platform.

View File

@ -53,10 +53,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 \
@ -84,6 +86,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

@ -76,6 +76,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;
@ -150,6 +151,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)",
},
{

View File

@ -1019,7 +1019,7 @@ void image_close(struct image *image)
image->sections = NULL;
}
int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksum)
int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum)
{
uint32_t crc = 0xffffffff;
LOG_DEBUG("Calculating checksum");

View File

@ -99,7 +99,7 @@ void image_close(struct image *image);
int image_add_section(struct image *image, uint32_t base, uint32_t size,
int flags, uint8_t const *data);
int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes,
int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes,
uint32_t *checksum);
#define ERROR_IMAGE_FORMAT_ERROR (-1400)

View File

@ -1033,11 +1033,11 @@ int target_run_flash_async_algorithm(struct target *target,
* programming. The exact delay shouldn't matter as long as it's
* less than buffer size / flash speed. This is very unlikely to
* run when using high latency connections such as USB. */
alive_sleep(10);
alive_sleep(2);
/* to stop an infinite loop on some targets check and increment a timeout
* this issue was observed on a stellaris using the new ICDI interface */
if (timeout++ >= 500) {
if (timeout++ >= 2500) {
LOG_ERROR("timeout waiting for algorithm, a target reset is recommended");
return ERROR_FLASH_OPERATION_FAILED;
}
@ -1051,6 +1051,10 @@ int target_run_flash_async_algorithm(struct target *target,
if (thisrun_bytes > count * block_size)
thisrun_bytes = count * block_size;
/* Force end of large blocks to be word aligned */
if (thisrun_bytes >= 16)
thisrun_bytes -= (rp + thisrun_bytes) & 0x03;
/* Write data to fifo */
retval = target_write_buffer(target, wp, thisrun_bytes, buffer);
if (retval != ERROR_OK)
@ -1100,6 +1104,156 @@ int target_run_flash_async_algorithm(struct target *target,
return retval;
}
int target_run_read_async_algorithm(struct target *target,
uint8_t *buffer, uint32_t count, int block_size,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t buffer_start, uint32_t buffer_size,
uint32_t entry_point, uint32_t exit_point, void *arch_info)
{
int retval;
int timeout = 0;
const uint8_t *buffer_orig = buffer;
/* Set up working area. First word is write pointer, second word is read pointer,
* rest is fifo data area. */
uint32_t wp_addr = buffer_start;
uint32_t rp_addr = buffer_start + 4;
uint32_t fifo_start_addr = buffer_start + 8;
uint32_t fifo_end_addr = buffer_start + buffer_size;
uint32_t wp = fifo_start_addr;
uint32_t rp = fifo_start_addr;
/* validate block_size is 2^n */
assert(!block_size || !(block_size & (block_size - 1)));
retval = target_write_u32(target, wp_addr, wp);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, rp_addr, rp);
if (retval != ERROR_OK)
return retval;
/* Start up algorithm on target */
retval = target_start_algorithm(target, num_mem_params, mem_params,
num_reg_params, reg_params,
entry_point,
exit_point,
arch_info);
if (retval != ERROR_OK) {
LOG_ERROR("error starting target flash read algorithm");
return retval;
}
while (count > 0) {
retval = target_read_u32(target, wp_addr, &wp);
if (retval != ERROR_OK) {
LOG_ERROR("failed to get write pointer");
break;
}
LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
(size_t) (buffer - buffer_orig), count, wp, rp);
if (wp == 0) {
LOG_ERROR("flash read algorithm aborted by target");
retval = ERROR_FLASH_OPERATION_FAILED;
break;
}
if (((wp - fifo_start_addr) & (block_size - 1)) || wp < fifo_start_addr || wp >= fifo_end_addr) {
LOG_ERROR("corrupted fifo write pointer 0x%" PRIx32, wp);
break;
}
/* Count the number of bytes available in the fifo without
* crossing the wrap around. */
uint32_t thisrun_bytes;
if (wp >= rp)
thisrun_bytes = wp - rp;
else
thisrun_bytes = fifo_end_addr - rp;
if (thisrun_bytes == 0) {
/* Throttle polling a bit if transfer is (much) faster than flash
* reading. The exact delay shouldn't matter as long as it's
* less than buffer size / flash speed. This is very unlikely to
* run when using high latency connections such as USB. */
alive_sleep(2);
/* to stop an infinite loop on some targets check and increment a timeout
* this issue was observed on a stellaris using the new ICDI interface */
if (timeout++ >= 2500) {
LOG_ERROR("timeout waiting for algorithm, a target reset is recommended");
return ERROR_FLASH_OPERATION_FAILED;
}
continue;
}
/* Reset our timeout */
timeout = 0;
/* Limit to the amount of data we actually want to read */
if (thisrun_bytes > count * block_size)
thisrun_bytes = count * block_size;
/* Force end of large blocks to be word aligned */
if (thisrun_bytes >= 16)
thisrun_bytes -= (rp + thisrun_bytes) & 0x03;
/* Read data from fifo */
retval = target_read_buffer(target, rp, thisrun_bytes, buffer);
if (retval != ERROR_OK)
break;
/* Update counters and wrap write pointer */
buffer += thisrun_bytes;
count -= thisrun_bytes / block_size;
rp += thisrun_bytes;
if (rp >= fifo_end_addr)
rp = fifo_start_addr;
/* Store updated write pointer to target */
retval = target_write_u32(target, rp_addr, rp);
if (retval != ERROR_OK)
break;
/* Avoid GDB timeouts */
keep_alive();
}
if (retval != ERROR_OK) {
/* abort flash write algorithm on target */
target_write_u32(target, rp_addr, 0);
}
int retval2 = target_wait_algorithm(target, num_mem_params, mem_params,
num_reg_params, reg_params,
exit_point,
10000,
arch_info);
if (retval2 != ERROR_OK) {
LOG_ERROR("error waiting for target flash write algorithm");
retval = retval2;
}
if (retval == ERROR_OK) {
/* check if algorithm set wp = 0 after fifo writer loop finished */
retval = target_read_u32(target, wp_addr, &wp);
if (retval == ERROR_OK && wp == 0) {
LOG_ERROR("flash read algorithm aborted by target");
retval = ERROR_FLASH_OPERATION_FAILED;
}
}
return retval;
}
int target_read_memory(struct target *target,
target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{

View File

@ -577,6 +577,18 @@ int target_run_flash_async_algorithm(struct target *target,
uint32_t entry_point, uint32_t exit_point,
void *arch_info);
/**
* This routine is a wrapper for asynchronous algorithms.
*
*/
int target_run_read_async_algorithm(struct target *target,
uint8_t *buffer, uint32_t count, int block_size,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t buffer_start, uint32_t buffer_size,
uint32_t entry_point, uint32_t exit_point,
void *arch_info);
/**
* Read @a count items of @a size bytes from the memory of @a target at
* the @a address given.

View File

@ -0,0 +1,56 @@
# This is an B-L475E-IOT01A Discovery kit for IoT node with a single STM32L475VGT6 chip.
# http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 96KB
set WORKAREASIZE 0x18000
# enable stmqspi
set QUADSPI 1
source [find target/stm32l4x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks)
mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0
# PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V
# Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V
mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER
mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR
mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# memory-mapped read mode with 3-byte addresses
mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK
sleep 1
mmw 0x40021000 0x00000100 0x00000000 ;# HSI on
mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI
mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1
mmw 0x40021000 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,70 @@
# This is an STM32F412G discovery board with a single STM32F412ZGT6 chip.
# http://www.st.com/en/evaluation-tools/32f412gdiscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 128KB
set WORKAREASIZE 0x20000
# enable stmqspi
set QUADSPI 1
source [find target/stm32f4x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks)
mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PB02: CLK, PG06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0
# PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V
# Port B: PB02:AF09:V
mmw 0x40020400 0x00000020 0x00000010 ;# MODER
mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x40020420 0x00000900 0x00000600 ;# AFRL
# Port F: PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V
mmw 0x40021400 0x000AA000 0x00055000 ;# MODER
mmw 0x40021408 0x000FF000 0x00000000 ;# OSPEEDR
mmw 0x40021420 0x99000000 0x66000000 ;# AFRL
mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH
# Port G: PG06:AF10:V
mmw 0x40021800 0x00002000 0x00001000 ;# MODER
mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR
mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# 1-line spi mode
mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
sleep 1
# memory-mapped read mode with 3-byte addresses
mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK
sleep 1
mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2
mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1
mmw 0x40023800 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,83 @@
# This is an STM32F413H discovery board with a single STM32F413ZHT6 chip.
# http://www.st.com/en/evaluation-tools/32f413hdiscovery.html
#
# Untested!!!
#
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 128KB
set WORKAREASIZE 0x20000
# enable stmqspi
set QUADSPI 1
source [find target/stm32f4x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks)
mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PG06: BK1_NCS, PB02: CLK, PD13: BK1_IO3, PE02: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0
# PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V
# Port B: PB02:AF09:V
mmw 0x40020400 0x00000020 0x00000010 ;# MODER
mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x40020420 0x00000900 0x00000600 ;# AFRL
# Port D: PD13:AF09:V
mmw 0x40020C00 0x08000000 0x04000000 ;# MODER
mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR
mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH
# Port E: PE02:AF09:V
mmw 0x40021000 0x00000020 0x00000010 ;# MODER
mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x40021020 0x00000900 0x00000600 ;# AFRL
# Port F: PF09:AF10:V, PF08:AF10:V
mmw 0x40021400 0x000A0000 0x00050000 ;# MODER
mmw 0x40021408 0x000F0000 0x00000000 ;# OSPEEDR
mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH
# Port G: PG06:AF10:V
mmw 0x40021800 0x00002000 0x00001000 ;# MODER
mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR
mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# 1-line spi mode
mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
sleep 1
# memory-mapped read mode with 3-byte addresses
mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK
sleep 1
mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2
mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1
mmw 0x40023800 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,65 @@
# This is an STM32F469I discovery board with a single STM32F469NIH6 chip.
# http://www.st.com/en/evaluation-tools/32f469idiscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 128KB
set WORKAREASIZE 0x20000
# enable stmqspi
set QUADSPI 1
source [find target/stm32f4x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PF10: CLK, PB06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0
# PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V
# Port B: PB06:AF10:V
mmw 0x40020400 0x00002000 0x00001000 ;# MODER
mmw 0x40020408 0x00003000 0x00000000 ;# OSPEEDR
mmw 0x40020420 0x0A000000 0x05000000 ;# AFRL
# Port F: PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V
mmw 0x40021400 0x002AA000 0x00155000 ;# MODER
mmw 0x40021408 0x003FF000 0x00000000 ;# OSPEEDR
mmw 0x40021420 0x99000000 0x66000000 ;# AFRL
mmw 0x40021424 0x000009AA 0x00000655 ;# AFRH
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# 1-line spi mode
mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
sleep 1
# memory-mapped read mode with 3-byte addresses
mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mww 0x40023C00 0x00000005 ;# 5 WS for 160 MHz HCLK
sleep 1
mww 0x40023804 0x24002808 ;# 160 MHz: HSI, PLLM=8, PLLN=160, PLLP=2
mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2
mmw 0x40023800 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,74 @@
# This is an STM32F723E discovery board with a single STM32F723IEK6 chip.
# http://www.st.com/en/evaluation-tools/32f723ediscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 128KB
set WORKAREASIZE 0x20000
# enable stmqspi
set QUADSPI 1
source [find target/stm32f7x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0
# PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V
# Port B: PB06:AF10:V, PB02:AF09:V
mmw 0x40020400 0x00002020 0x00001010 ;# MODER
mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR
mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL
# Port C: PC10:AF09:V, PC09:AF09:V
mmw 0x40020800 0x00280000 0x00140000 ;# MODER
mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR
mmw 0x40020824 0x00000990 0x00000660 ;# AFRH
# Port D: PD13:AF09:V
mmw 0x40020C00 0x08000000 0x04000000 ;# MODER
mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR
mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH
# Port E: PE02:AF09:V
mmw 0x40021000 0x00000020 0x00000010 ;# MODER
mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x40021020 0x00000900 0x00000600 ;# AFRL
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# 1-line spi mode
mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
sleep 1
# memory-mapped read mode with 4-byte addresses
mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK
sleep 1
mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2
mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2
mmw 0x40023800 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,69 @@
# This is an STM32F746G discovery board with a single STM32F746NGH6 chip.
# http://www.st.com/en/evaluation-tools/32f746gdiscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 256KB
set WORKAREASIZE 0x40000
# enable stmqspi
set QUADSPI 1
source [find target/stm32f7x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0
# PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PE02:AF09:V
# Port B: PB06:AF10:V, PB02:AF09:V
mmw 0x40020400 0x00002020 0x00001010 ;# MODER
mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR
mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL
# Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V
mmw 0x40020C00 0x0A800000 0x05400000 ;# MODER
mmw 0x40020C08 0x0FC00000 0x00000000 ;# OSPEEDR
mmw 0x40020C24 0x00999000 0x00666000 ;# AFRH
# Port E: PE02:AF09:V
mmw 0x40021000 0x00000020 0x00000010 ;# MODER
mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x40021020 0x00000900 0x00000600 ;# AFRL
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# 1-line spi mode
mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
sleep 1
# memory-mapped read mode with 3-byte addresses
mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK
sleep 1
mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2
mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2
mmw 0x40023800 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,79 @@
# This is an STM32F769I discovery board with a single STM32F769NIH6 chip.
# http://www.st.com/en/evaluation-tools/32f769idiscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 256KB
set WORKAREASIZE 0x40000
# enable stmqspi
set QUADSPI 1
source [find target/stm32f7x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0
# PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V
# Port B: PB06:AF10:V, PB02:AF09:V
mmw 0x40020400 0x00002020 0x00001010 ;# MODER
mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR
mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL
# Port C: PC10:AF09:V, PC09:AF09:V
mmw 0x40020800 0x00280000 0x00140000 ;# MODER
mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR
mmw 0x40020824 0x00000990 0x00000660 ;# AFRH
# Port D: PD13:AF09:V
mmw 0x40020C00 0x08000000 0x04000000 ;# MODER
mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR
mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH
# Port E: PE02:AF09:V
mmw 0x40021000 0x00000020 0x00000010 ;# MODER
mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x40021020 0x00000900 0x00000600 ;# AFRL
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# exit qpi mode
mww 0xA0001014 0x000033f5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
# 1-line memory-mapped read mode with 4-byte addresses
mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ
# 4-line qpi mode
mww 0xA0001014 0x00003135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=EQIO
# 4-line memory-mapped read mode with 4-byte addresses
mww 0xA0001014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0xA, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=4READ4B
}
$_TARGETNAME configure -event reset-init {
mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK
sleep 1
mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2
mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2
mmw 0x40023800 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,122 @@
# This is a stm32h735g-dk with a single STM32H735IGK6 chip.
# https://www.st.com/en/evaluation-tools/stm32h735g-dk.html
#
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
set CHIPNAME stm32h735igk6
# enable stmqspi
if {![info exists OCTOSPI1]} {
set OCTOSPI1 1
set OCTOSPI2 0
}
source [find target/stm32h7x.cfg]
# OCTOSPI initialization
# octo: 8-line mode
proc octospi_init { octo } {
global a b
mmw 0x58024540 0x000006FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks)
sleep 1 ;# Wait for clock startup
mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1
mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2
# PG06: OCSPI1_NCS, PF10: OCSPI1_CLK, PB02: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PD05: OCSPI1_IO5,
# PD04: OCSPI1_IO4, PD13: OCSPI1_IO3, PE02: OCSPI1_IO2, PD12: OCSPI1_IO1, PD11: OCSPI1_IO0
# PB02:AF10:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V
# PD04:AF10:V, PE02:AF09:V, PF10:AF09:V, PG09:AF09:V, PG06:AF10:V
# Port B: PB02:AF10:V
mmw 0x58020400 0x00000020 0x00000010 ;# MODER
mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR
mmw 0x58020420 0x00000A00 0x00000500 ;# AFRL
# Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V
mmw 0x58020C00 0x0A808A00 0x05404500 ;# MODER
mmw 0x58020C08 0x0FC0CF00 0x00000000 ;# OSPEEDR
mmw 0x58020C0C 0x00000000 0x0FC0CF00 ;# PUPDR
mmw 0x58020C20 0xA0AA0000 0x50550000 ;# AFRL
mmw 0x58020C24 0x00999000 0x00666000 ;# AFRH
# Port E: PE02:AF09:V
mmw 0x58021000 0x00000020 0x00000010 ;# MODER
mmw 0x58021008 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x5802100C 0x00000000 0x00000030 ;# PUPDR
mmw 0x58021020 0x00000900 0x00000600 ;# AFRL
# Port F: PF10:AF09:V
mmw 0x58021400 0x00200000 0x00100000 ;# MODER
mmw 0x58021408 0x00300000 0x00000000 ;# OSPEEDR
mmw 0x5802140C 0x00000000 0x00300000 ;# PUPDR
mmw 0x58021424 0x00000900 0x00000600 ;# AFRH
# Port G: PG09:AF09:V, PG06:AF10:V
mmw 0x58021800 0x00082000 0x00041000 ;# MODER
mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR
mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR
mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL
mmw 0x58021824 0x00000090 0x00000060 ;# AFRH
# OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses
mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0
mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0
mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5
mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0
mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1
mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B
flash probe $a ;# load configuration from CR, TCR, CCR, IR register values
if { $octo == 1 } {
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 ;# Read Status Register
stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable
# OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses
mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1
mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6
mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4
mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read
flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 0 0x04 ;# Write Disable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
}
}
$_CHIPNAME.cpu0 configure -event reset-init {
global OCTOSPI1
global OCTOSPI2
mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK
mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on
mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock
mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1
mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2
mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2
mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI
mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide
mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24
mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1
sleep 1
mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock
sleep 1
adapter speed 24000
if { $OCTOSPI1 } {
octospi_init 1
}
}

View File

@ -0,0 +1,45 @@
# This is a stm32h745i-disco with a single STM32H745XIH6 chip.
# www.st.com/en/product/stm32h745i-disco.html
#
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
set CHIPNAME stm32h745xih6
# enable stmqspi
if {![info exists QUADSPI]} {
set QUADSPI 1
}
source [find target/stm32h7x_dual_bank.cfg]
source [find board/stm32h7x_dual_qspi.cfg]
$_CHIPNAME.cpu0 configure -event reset-init {
global QUADSPI
mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK
mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on
mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock
mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1
mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2
mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2
mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI
mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide
mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24
mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1
sleep 1
mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock
sleep 1
adapter speed 24000
if { $QUADSPI } {
qspi_init 1
}
}

View File

@ -0,0 +1,136 @@
# This is a stm32h747i-disco with a single STM32H747XIH6 chip.
# www.st.com/en/product/stm32h747i-disco.html
#
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
set CHIPNAME stm32h747xih6
# enable stmqspi
if {![info exists QUADSPI]} {
set QUADSPI 1
}
source [find target/stm32h7x_dual_bank.cfg]
# QUADSPI initialization
# qpi: 4-line mode
proc qspi_init { qpi } {
global a
mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PG06: BK1_NCS, PB02: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0,
# PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0
# PB02:AF09:V, PD11:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H
# PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V
# Port B: PB02:AF09:V
mmw 0x58020400 0x00000020 0x00000010 ;# MODER
mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x58020420 0x00000900 0x00000600 ;# AFRL
# Port D: PD11:AF09:V
mmw 0x58020C00 0x00800000 0x00400000 ;# MODER
mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR
mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH
# Port F: PF09:AF10:V, PF07:AF09:V, PF06:AF09:V
mmw 0x58021400 0x0008A000 0x00045000 ;# MODER
mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR
mmw 0x58021420 0x99000000 0x66000000 ;# AFRL
mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH
# Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H
mmw 0x58021800 0x20082000 0x10041000 ;# MODER
mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR
mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL
mmw 0x58021824 0x09000090 0x06000060 ;# AFRH
# Port H: PH03:AF09:V, PH02:AF09:V
mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER
mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR
mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL
# correct FSIZE is 0x1A, however, this causes trouble when
# reading the last bytes at end of bank in *memory mapped* mode
# for dual flash mode 2 * mt25ql512
mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1
mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0
mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1
mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1
# Exit QPI mode
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI
sleep 1
if { $qpi == 1 } {
# Write Enable
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable
sleep 1
# Configure dummy clocks via volatile configuration register
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes
mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg.
mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks
sleep 1
# Write Enable
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable
sleep 1
# Enable QPI mode via enhanced volatile configuration register
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes
mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg.
mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode
sleep 1
# Enter QPI mode
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI
sleep 1
# memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only)
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ
} else {
# memory-mapped read mode with 4-byte addresses
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
}
$_CHIPNAME.cpu0 configure -event reset-init {
global QUADSPI
mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK
mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on
mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock
mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1
mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2
mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2
mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI
mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide
mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24
mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1
sleep 1
mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock
sleep 1
adapter speed 24000
if { $QUADSPI } {
qspi_init 1
}
}

View File

@ -0,0 +1,45 @@
# This is a stm32h750b-dk with a single STM32H750XBH6 chip.
# www.st.com/en/product/stm32h750b-dk.html
#
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
set CHIPNAME stm32h750xbh6
# enable stmqspi
if {![info exists QUADSPI]} {
set QUADSPI 1
}
source [find target/stm32h7x.cfg]
source [find board/stm32h7x_dual_qspi.cfg]
$_CHIPNAME.cpu0 configure -event reset-init {
global QUADSPI
mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK
mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on
mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock
mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1
mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2
mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2
mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI
mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide
mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24
mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1
sleep 1
mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock
sleep 1
adapter speed 24000
if { $QUADSPI } {
qspi_init 1
}
}

View File

@ -0,0 +1,128 @@
# This is a stm32h7b3i-dk with a single STM32H7B3LIH6Q chip.
# https://www.st.com/en/evaluation-tools/stm32h7b3i-dk.html
#
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
set CHIPNAME stm32h7b3lih6q
# enable stmqspi
if {![info exists OCTOSPI1]} {
set OCTOSPI1 1
set OCTOSPI2 0
}
source [find target/stm32h7x_dual_bank.cfg]
# OCTOSPI initialization
# octo: 8-line mode
proc octospi_init { octo } {
global a b
mmw 0x58024540 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks)
sleep 1 ;# Wait for clock startup
mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1
mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2
# PG06: OCSPI1_NCS, PB02: OCSPI1_CLK, PC05: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PH03: OCSPI1_IO5,
# PC01: OCSPI1_IO4, PF06: OCSPI1_IO3, PF07: OCSPI1_IO2, PF09: OCSPI1_IO1, PD11: OCSPI1_IO0
# PB02:AF09:V, PC05:AF10:V, PC01:AF10:V, PD11:AF09:V, PD07:AF10:V, PF09:AF10:V
# PF07:AF10:V, PF06:AF10:V, PG09:AF09:V, PG06:AF10:V, PH03:AF09:V
# Port B: PB02:AF09:V
mmw 0x58020400 0x00000020 0x00000010 ;# MODER
mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR
mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR
mmw 0x58020420 0x00000900 0x00000600 ;# AFRL
# Port C: PC05:AF10:V, PC01:AF10:V
mmw 0x58020800 0x00000808 0x00000404 ;# MODER
mmw 0x58020808 0x00000C0C 0x00000000 ;# OSPEEDR
mmw 0x5802080C 0x00000000 0x00000C0C ;# PUPDR
mmw 0x58020820 0x00A000A0 0x00500050 ;# AFRL
# Port D: PD11:AF09:V, PD07:AF10:V
mmw 0x58020C00 0x00808000 0x00404000 ;# MODER
mmw 0x58020C08 0x00C0C000 0x00000000 ;# OSPEEDR
mmw 0x58020C0C 0x00000000 0x00C0C000 ;# PUPDR
mmw 0x58020C20 0xA0000000 0x50000000 ;# AFRL
mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH
# Port F: PF09:AF10:V, PF07:AF10:V, PF06:AF10:V
mmw 0x58021400 0x0008A000 0x00045000 ;# MODER
mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR
mmw 0x5802140C 0x00000000 0x000CF000 ;# PUPDR
mmw 0x58021420 0xAA000000 0x55000000 ;# AFRL
mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH
# Port G: PG09:AF09:V, PG06:AF10:V
mmw 0x58021800 0x00082000 0x00041000 ;# MODER
mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR
mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR
mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL
mmw 0x58021824 0x00000090 0x00000060 ;# AFRH
# Port H: PH03:AF09:V
mmw 0x58021C00 0x00000080 0x00000040 ;# MODER
mmw 0x58021C08 0x000000C0 0x00000000 ;# OSPEEDR
mmw 0x58021C0C 0x00000000 0x000000C0 ;# PUPDR
mmw 0x58021C20 0x00009000 0x00006000 ;# AFRL
# OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses
mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0
mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0
mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5
mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0
mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1
mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B
flash probe $a ;# load configuration from CR, TCR, CCR, IR register values
if { $octo == 1 } {
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 ;# Read Status Register
stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable
# OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses
mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1
mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6
mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4
mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read
flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 0 0x04 ;# Write Disable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
}
}
$_CHIPNAME.cpu0 configure -event reset-init {
global OCTOSPI1
global OCTOSPI2
mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK
mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on
mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock
mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1
mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2
mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2
mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI
mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide
mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24
mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1
sleep 1
mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock
sleep 1
adapter speed 24000
if { $OCTOSPI1 } {
octospi_init 1
}
}

View File

@ -0,0 +1,90 @@
# stm32h754i-disco and stm32h750b-dk dual quad qspi.
# QUADSPI initialization
# qpi: 4-line mode
proc qspi_init { qpi } {
global a
mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PG06: BK1_NCS, PF10: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0,
# PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0
# PD11:AF09:V, PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H
# PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V
# Port D: PD11:AF09:V
mmw 0x58020C00 0x00800000 0x00400000 ;# MODER
mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR
mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH
# Port F: PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V
mmw 0x58021400 0x0028A000 0x00145000 ;# MODER
mmw 0x58021408 0x003CF000 0x00000000 ;# OSPEEDR
mmw 0x58021420 0x99000000 0x66000000 ;# AFRL
mmw 0x58021424 0x000009A0 0x00000650 ;# AFRH
# Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H
mmw 0x58021800 0x20082000 0x10041000 ;# MODER
mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR
mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL
mmw 0x58021824 0x09000090 0x06000060 ;# AFRH
# Port H: PH03:AF09:V, PH02:AF09:V
mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER
mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR
mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL
# correct FSIZE is 0x1A, however, this causes trouble when
# reading the last bytes at end of bank in *memory mapped* mode
# for dual flash mode 2 * mt25ql512
mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1
mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0
mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1
mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1
# Exit QPI mode
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI
sleep 1
if { $qpi == 1 } {
# Write Enable
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable
sleep 1
# Configure dummy clocks via volatile configuration register
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes
mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg.
mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks
sleep 1
# Write Enable
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable
sleep 1
# Enable QPI mode via enhanced volatile configuration register
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes
mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg.
mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode
sleep 1
# Enter QPI mode
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI
sleep 1
# memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only)
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ
} else {
# memory-mapped read mode with 4-byte addresses
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
}

View File

@ -0,0 +1,56 @@
# This is an STM32L476G discovery board with a single STM32L476VGT6 chip.
# http://www.st.com/en/evaluation-tools/32l476gdiscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 96KB
set WORKAREASIZE 0x18000
# enable stmqspi
set QUADSPI 1
source [find target/stm32l4x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks)
mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0
# PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V
# Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V
mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER
mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR
mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# memory-mapped read mode with 3-byte addresses
mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK
sleep 1
mmw 0x40021000 0x00000100 0x00000000 ;# HSI on
mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI
mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1
mmw 0x40021000 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,66 @@
# This is an STM32L496G discovery board with a single STM32L496AGI6 chip.
# http://www.st.com/en/evaluation-tools/32l496gdiscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 96KB
set WORKAREASIZE 0x18000
# enable stmqspi
set QUADSPI 1
source [find target/stm32l4x.cfg]
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks)
mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PB11: BK1_NCS, PA03: CLK, PA06: BK1_IO3, PA07: BK1_IO2, PB00: BK1_IO1, PB01: BK1_IO0
# PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V
# Port A: PA07:AF10:V, PA06:AF10:V, PA03:AF10:V
mmw 0x48000000 0x0000A080 0x00005040 ;# MODER
mmw 0x48000008 0x0000F0C0 0x00000000 ;# OSPEEDR
mmw 0x48000020 0xAA00A000 0x55005000 ;# AFRL
# Port B: PB11:AF10:V, PB01:AF10:V, PB00:AF10:V
mmw 0x48000400 0x0080000A 0x00400005 ;# MODER
mmw 0x48000408 0x00C0000F 0x00000000 ;# OSPEEDR
mmw 0x48000420 0x000000AA 0x00000055 ;# AFRL
mmw 0x48000424 0x0000A000 0x00005000 ;# AFRH
mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1
mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0
mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1
# 1-line spi mode
mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO
sleep 1
# memory-mapped read mode with 3-byte addresses
mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ
}
$_TARGETNAME configure -event reset-init {
mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK
sleep 1
mmw 0x40021000 0x00000100 0x00000000 ;# HSI on
mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI
mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1
mmw 0x40021000 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
qspi_init
}

View File

@ -0,0 +1,130 @@
# This is a STM32L4P5G discovery board with a single STM32L4R9AGI6 chip.
# http://www.st.com/en/evaluation-tools/stm32l4p5g-dk.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 96KB
set WORKAREASIZE 0x18000
# enable stmqspi
set OCTOSPI1 1
set OCTOSPI2 0
source [find target/stm32l4x.cfg]
# OCTOSPI initialization
# octo: 8-line mode
proc octospi_init { octo } {
global a b
mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks)
mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks)
mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock)
sleep 1 ;# Wait for clock startup
mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432)
mww 0x50061C04 0x07050333 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI2
mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1
# PE11: P1_NCS, PE10: P1_CLK, PG06: P1_DQS, PD07: P1_IO7, PC03: P1_IO6, PD05: P1_IO5
# PD04: P1_IO4, PA06: P1_IO3, PA07: P1_IO2, PE13: P1_IO1, PE11: P1_IO0
# PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V
# PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V
# Port A: PA07:AF10:V, PA06:AF10:V
mmw 0x48000000 0x0000A000 0x00005000 ;# MODER
mmw 0x48000008 0x0000F000 0x00000000 ;# OSPEEDR
mmw 0x4800000C 0x00000000 0x0000F000 ;# PUPDR
mmw 0x48000020 0xAA000000 0x55000000 ;# AFRL
# Port C: PC03:AF10:V
mmw 0x48000800 0x00000080 0x00000040 ;# MODER
mmw 0x48000808 0x000000C0 0x00000000 ;# OSPEEDR
mmw 0x4800080C 0x00000000 0x000000C0 ;# PUPDR
mmw 0x48000820 0x0000A000 0x00005000 ;# AFRL
# Port D: PD07:AF10:V, PD05:AF10:V, PD04:AF10:V
mmw 0x48000C00 0x00008A00 0x00004500 ;# MODER
mmw 0x48000C08 0x0000CF00 0x00000000 ;# OSPEEDR
mmw 0x48000C0C 0x00000000 0x0000CF00 ;# PUPDR
mmw 0x48000C20 0xA0AA0000 0x50550000 ;# AFRL
# Port E: PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V
mmw 0x48001000 0x0AA00000 0x05500000 ;# MODER
mmw 0x48001008 0x0FF00000 0x00000000 ;# OSPEEDR
mmw 0x4800100C 0x00000000 0x0FF00000 ;# PUPDR
mmw 0x48001024 0x00AAAA00 0x00555500 ;# AFRH
# Port G: PG06:AF03:V
mmw 0x48001800 0x00002000 0x00001000 ;# MODER
mmw 0x48001808 0x00003000 0x00000000 ;# OSPEEDR
mmw 0x4800180C 0x00000000 0x00003000 ;# PUPDR
mmw 0x48001820 0x03000000 0x0C000000 ;# AFRL
# PG12: P2_NCS, PF04: P2_CLK, PF12: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PG01: P2_IO5
# PG00: P2_IO4, PF03: P2_IO3, PF02: P2_IO2, PF01: P2_IO1, PF00: P2_IO0
# PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V
# PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V
# Port F: PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V
mmw 0x48001400 0x020002AA 0x01000155 ;# MODER
mmw 0x48001408 0x030003FF 0x00000000 ;# OSPEEDR
mmw 0x4800140C 0x00000000 0x030003FF ;# PUPDR
mmw 0x48001420 0x00055555 0x000AAAAA ;# AFRL
mmw 0x48001424 0x00050000 0x000A0000 ;# AFRH
# Port G: PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V
mmw 0x48001800 0x0228000A 0x01140005 ;# MODER
mmw 0x48001808 0x033C000F 0x00000000 ;# OSPEEDR
mmw 0x4800180C 0x00000000 0x033C000F ;# PUPDR
mmw 0x48001820 0x00000055 0x000000AA ;# AFRL
mmw 0x48001824 0x00050550 0x000A0AA0 ;# AFRH
# OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses
mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0
mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0
mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1
mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0
mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1
mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B
if { $octo == 1 } {
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 ;# Read Status Register
stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable
# OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses
mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1
mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6
mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4
mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read
flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 0 0x04 ;# Write Disable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
}
}
$_TARGETNAME configure -event reset-init {
mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK
sleep 1
mmw 0x40021000 0x00000100 0x00000000 ;# HSI on
mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI
mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1
mmw 0x40021000 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL
sleep 1
adapter speed 24000
octospi_init 1
}

View File

@ -0,0 +1,100 @@
# This is a STM32L4R9I discovery board with a single STM32L4R9AII6 chip.
# http://www.st.com/en/evaluation-tools/32l4r9idiscovery.html
# This is for using the onboard STLINK
source [find interface/stlink.cfg]
transport select hla_swd
# increase working area to 96KB
set WORKAREASIZE 0x18000
# enable stmqspi
set OCTOSPI1 1
set OCTOSPI2 0
source [find target/stm32l4x.cfg]
# OCTOSPI initialization
# octo: 8-line mode
proc octospi_init { octo } {
global a b
mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks)
mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks)
mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock)
sleep 1 ;# Wait for clock startup
mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432)
mww 0x50061C04 0x00000000 ;# OCTOSPIM_P1CR: disable Port 1
mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1
# PG12: P2_NCS, PI06: P2_CLK, PG15: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PH10: P2_IO5,
# PH09: P2_IO4, PH08: P2_IO3, PI09: P2_IO2, PI10: P2_IO1, PI11: P2_IO0
# PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V
# PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V
# Port G: PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V
mmw 0x48001800 0x82280000 0x41140000 ;# MODER
mmw 0x48001808 0xC33C0000 0x00000000 ;# OSPEEDR
mmw 0x48001824 0x50050550 0xA00A0AA0 ;# AFRH
# Port H: PH10:AF05:V, PH09:AF05:V, PH08:AF05:V
mmw 0x48001C00 0x002A0000 0x00150000 ;# MODER
mmw 0x48001C08 0x003F0000 0x00000000 ;# OSPEEDR
mmw 0x48001C24 0x00000555 0x00000AAA ;# AFRH
# Port I: PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V
mmw 0x48002000 0x00A82000 0x00541000 ;# MODER
mmw 0x48002008 0x00FC3000 0x00000000 ;# OSPEEDR
mmw 0x48002020 0x05000000 0x0A000000 ;# AFRL
mmw 0x48002024 0x00005550 0x0000AAA0 ;# AFRH
# OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses
mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0
mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0
mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1
mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0
mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1
mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B
if { $octo == 1 } {
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 ;# Read Status Register
stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable
# OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses
mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1
mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6
mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4
mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read
flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values
stmqspi cmd $a 0 0x06 ;# Write Enable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 0 0x04 ;# Write Disable
stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode)
stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits
}
}
$_TARGETNAME configure -event reset-init {
mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK
sleep 1
mmw 0x40021000 0x00000100 0x00000000 ;# HSI on
mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI
mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1
mmw 0x40021000 0x01000000 0x00000000 ;# PLL on
sleep 1
mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL
sleep 1
adapter speed 4000
octospi_init 1
}

View File

@ -52,6 +52,12 @@ flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME
flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME
if { [info exists QUADSPI] && $QUADSPI } {
set a [llength [flash list]]
set _QSPINAME $_CHIPNAME.qspi
flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
}
# JTAG speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz
#
# Since we may be running of an RC oscilator, we crank down the speed a

View File

@ -12,7 +12,7 @@ if { [info exists CHIPNAME] } {
set _CHIPNAME stm32f7x
}
set _ENDIAN little
set _ENDIAN little
# Work-area is a space in RAM used for flash programming
# By default use 128kB
@ -64,6 +64,12 @@ flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME
# the Flash via ITCM alias as virtual
flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME
if { [info exists QUADSPI] && $QUADSPI } {
set a [llength [flash list]]
set _QSPINAME $_CHIPNAME.qspi
flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
}
# adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz
adapter speed 2000

View File

@ -104,6 +104,23 @@ if {[set $_CHIPNAME.DUAL_CORE]} {
# Make sure that cpu0 is selected
targets $_CHIPNAME.cpu0
if { [info exists QUADSPI] && $QUADSPI } {
set a [llength [flash list]]
set _QSPINAME $_CHIPNAME.qspi
flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000
} else {
if { [info exists OCTOSPI1] && $OCTOSPI1 } {
set a [llength [flash list]]
set _OCTOSPINAME1 $_CHIPNAME.octospi1
flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000
}
if { [info exists OCTOSPI2] && $OCTOSPI2 } {
set b [llength [flash list]]
set _OCTOSPINAME2 $_CHIPNAME.octospi2
flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_CHIPNAME.cpu0 0x5200A000
}
}
# Clock after reset is HSI at 64 MHz, no need of PLL
adapter speed 1800

View File

@ -50,6 +50,23 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
if { [info exists QUADSPI] && $QUADSPI } {
set a [llength [flash list]]
set _QSPINAME $_CHIPNAME.qspi
flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
} else {
if { [info exists OCTOSPI1] && $OCTOSPI1 } {
set a [llength [flash list]]
set _OCTOSPINAME1 $_CHIPNAME.octospi1
flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
}
if { [info exists OCTOSPI2] && $OCTOSPI2 } {
set b [llength [flash list]]
set _OCTOSPINAME2 $_CHIPNAME.octospi2
flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400
}
}
# Common knowledges tells JTAG speed should be <= F_CPU/6.
# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on
# the safe side.