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:
parent
475f42051e
commit
e44539d66c
|
@ -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))
|
|
@ -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);
|
|
@ -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 */
|
|
@ -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,
|
|
@ -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, .
|
||||||
|
|
|
@ -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,
|
|
@ -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 */
|
|
@ -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,
|
|
@ -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 */
|
|
@ -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,
|
|
@ -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 */
|
|
@ -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,
|
|
@ -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, .
|
||||||
|
|
|
@ -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,
|
|
@ -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 */
|
|
@ -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,
|
|
@ -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 */
|
|
@ -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,
|
123
doc/openocd.texi
123
doc/openocd.texi
|
@ -5253,6 +5253,18 @@ it has been removed by the @option{unlock} flag.
|
||||||
|
|
||||||
@end deffn
|
@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
|
@section Other Flash commands
|
||||||
@cindex flash protection
|
@cindex flash protection
|
||||||
|
|
||||||
|
@ -5511,6 +5523,117 @@ flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME
|
||||||
|
|
||||||
@end deffn
|
@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
|
@deffn {Flash Driver} mrvlqspi
|
||||||
This driver supports QSPI flash controller of Marvell's Wireless
|
This driver supports QSPI flash controller of Marvell's Wireless
|
||||||
Microcontroller platform.
|
Microcontroller platform.
|
||||||
|
|
|
@ -52,10 +52,12 @@ NOR_DRIVERS = \
|
||||||
%D%/psoc5lp.c \
|
%D%/psoc5lp.c \
|
||||||
%D%/psoc6.c \
|
%D%/psoc6.c \
|
||||||
%D%/renesas_rpchf.c \
|
%D%/renesas_rpchf.c \
|
||||||
|
%D%/sfdp.c \
|
||||||
%D%/sh_qspi.c \
|
%D%/sh_qspi.c \
|
||||||
%D%/sim3x.c \
|
%D%/sim3x.c \
|
||||||
%D%/spi.c \
|
%D%/spi.c \
|
||||||
%D%/stmsmi.c \
|
%D%/stmsmi.c \
|
||||||
|
%D%/stmqspi.c \
|
||||||
%D%/stellaris.c \
|
%D%/stellaris.c \
|
||||||
%D%/stm32f1x.c \
|
%D%/stm32f1x.c \
|
||||||
%D%/stm32f2x.c \
|
%D%/stm32f2x.c \
|
||||||
|
@ -83,6 +85,8 @@ NORHEADERS = \
|
||||||
%D%/imp.h \
|
%D%/imp.h \
|
||||||
%D%/non_cfi.h \
|
%D%/non_cfi.h \
|
||||||
%D%/ocl.h \
|
%D%/ocl.h \
|
||||||
|
%D%/sfdp.h \
|
||||||
%D%/spi.h \
|
%D%/spi.h \
|
||||||
%D%/stm32l4x.h \
|
%D%/stm32l4x.h \
|
||||||
|
%D%/stmqspi.h \
|
||||||
%D%/msp432.h
|
%D%/msp432.h
|
||||||
|
|
|
@ -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,
|
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;
|
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);
|
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)
|
void flash_bank_add(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
/* put flash bank in linked list */
|
/* 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,
|
int flash_write_unlock_verify(struct target *target, struct image *image,
|
||||||
uint32_t *written, bool erase, bool unlock)
|
uint32_t *written, bool erase, bool unlock, bool write, bool verify)
|
||||||
{
|
{
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
@ -932,9 +969,18 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval == ERROR_OK) {
|
if (retval == ERROR_OK) {
|
||||||
|
if (write) {
|
||||||
/* write flash sectors */
|
/* write flash sectors */
|
||||||
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
|
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);
|
free(buffer);
|
||||||
|
|
||||||
|
@ -957,7 +1003,7 @@ done:
|
||||||
int flash_write(struct target *target, struct image *image,
|
int flash_write(struct target *target, struct image *image,
|
||||||
uint32_t *written, bool erase)
|
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,
|
struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size,
|
||||||
|
|
|
@ -200,6 +200,7 @@ void default_flash_free_driver_priv(struct flash_bank *bank);
|
||||||
|
|
||||||
/** Deallocates all flash banks */
|
/** Deallocates all flash banks */
|
||||||
void flash_free_all_banks(void);
|
void flash_free_all_banks(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides default read implementation for flash memory.
|
* Provides default read implementation for flash memory.
|
||||||
* @param bank The bank to read.
|
* @param bank The bank to read.
|
||||||
|
@ -210,6 +211,18 @@ void flash_free_all_banks(void);
|
||||||
*/
|
*/
|
||||||
int default_flash_read(struct flash_bank *bank,
|
int default_flash_read(struct flash_bank *bank,
|
||||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
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
|
* Provides default erased-bank check handling. Checks to see if
|
||||||
* the flash driver knows they are erased; if things look uncertain,
|
* 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.
|
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||||
*/
|
*/
|
||||||
int default_flash_blank_check(struct flash_bank *bank);
|
int default_flash_blank_check(struct flash_bank *bank);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the flash bank specified by @a name, which matches the
|
* Returns the flash bank specified by @a name, which matches the
|
||||||
* driver name and a suffix (option) specify the driver-specific
|
* driver name and a suffix (option) specify the driver-specific
|
||||||
|
|
|
@ -155,6 +155,20 @@ struct flash_driver {
|
||||||
int (*read)(struct flash_bank *bank,
|
int (*read)(struct flash_bank *bank,
|
||||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
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.
|
* Probe to determine what kind of flash is present.
|
||||||
* This is invoked by the "probe" script command.
|
* This is invoked by the "probe" script command.
|
||||||
|
|
|
@ -75,6 +75,7 @@ extern const struct flash_driver stm32f2x_flash;
|
||||||
extern const struct flash_driver stm32lx_flash;
|
extern const struct flash_driver stm32lx_flash;
|
||||||
extern const struct flash_driver stm32l4x_flash;
|
extern const struct flash_driver stm32l4x_flash;
|
||||||
extern const struct flash_driver stm32h7x_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 stmsmi_flash;
|
||||||
extern const struct flash_driver str7x_flash;
|
extern const struct flash_driver str7x_flash;
|
||||||
extern const struct flash_driver str9x_flash;
|
extern const struct flash_driver str9x_flash;
|
||||||
|
@ -148,6 +149,7 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||||
&stm32l4x_flash,
|
&stm32l4x_flash,
|
||||||
&stm32h7x_flash,
|
&stm32h7x_flash,
|
||||||
&stmsmi_flash,
|
&stmsmi_flash,
|
||||||
|
&stmqspi_flash,
|
||||||
&str7x_flash,
|
&str7x_flash,
|
||||||
&str9x_flash,
|
&str9x_flash,
|
||||||
&str9xpec_flash,
|
&str9xpec_flash,
|
||||||
|
|
|
@ -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,
|
int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first,
|
||||||
unsigned int last);
|
unsigned int last);
|
||||||
int flash_driver_write(struct flash_bank *bank,
|
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,
|
int flash_driver_read(struct flash_bank *bank,
|
||||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
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 */
|
/* write (optional verify) an image to flash memory of the given target */
|
||||||
int flash_write_unlock(struct target *target, struct image *image,
|
int flash_write_unlock_verify(struct target *target, struct image *image,
|
||||||
uint32_t *written, bool erase, bool unlock);
|
uint32_t *written, bool erase, bool unlock, bool write, bool verify);
|
||||||
|
|
||||||
#endif /* OPENOCD_FLASH_NOR_IMP_H */
|
#endif /* OPENOCD_FLASH_NOR_IMP_H */
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 */
|
|
@ -1,5 +1,5 @@
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2018 by Andreas Bolsch *
|
* Copyright (C) 2018-2019 by Andreas Bolsch *
|
||||||
* andreas.bolsch@mni.thm.de *
|
* andreas.bolsch@mni.thm.de *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2012 by George Harris *
|
* Copyright (C) 2012 by George Harris *
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
/* data structure to maintain flash ids from different vendors */
|
/* data structure to maintain flash ids from different vendors */
|
||||||
struct flash_device {
|
struct flash_device {
|
||||||
char *name;
|
const char *name;
|
||||||
uint8_t read_cmd;
|
uint8_t read_cmd;
|
||||||
uint8_t qread_cmd;
|
uint8_t qread_cmd;
|
||||||
uint8_t pprog_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_PAGE_PROGRAM 0x02 /* Page Program */
|
||||||
#define SPIFLASH_FAST_READ 0x0B /* Fast Read */
|
#define SPIFLASH_FAST_READ 0x0B /* Fast Read */
|
||||||
#define SPIFLASH_READ 0x03 /* Normal 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) */
|
#define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -44,31 +44,31 @@
|
||||||
#define SMI_READ_REG(a) (_SMI_READ_REG(a))
|
#define SMI_READ_REG(a) (_SMI_READ_REG(a))
|
||||||
#define _SMI_READ_REG(a) \
|
#define _SMI_READ_REG(a) \
|
||||||
{ \
|
{ \
|
||||||
int __a; \
|
int _ret; \
|
||||||
uint32_t __v; \
|
uint32_t _value; \
|
||||||
\
|
\
|
||||||
__a = target_read_u32(target, io_base + (a), &__v); \
|
_ret = target_read_u32(target, io_base + (a), &_value); \
|
||||||
if (__a != ERROR_OK) \
|
if (_ret != ERROR_OK) \
|
||||||
return __a; \
|
return _ret; \
|
||||||
__v; \
|
_value; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SMI_WRITE_REG(a, v) \
|
#define SMI_WRITE_REG(a, v) \
|
||||||
{ \
|
{ \
|
||||||
int __r; \
|
int _retval; \
|
||||||
\
|
\
|
||||||
__r = target_write_u32(target, io_base + (a), (v)); \
|
_retval = target_write_u32(target, io_base + (a), (v)); \
|
||||||
if (__r != ERROR_OK) \
|
if (_retval != ERROR_OK) \
|
||||||
return __r; \
|
return _retval; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SMI_POLL_TFF(timeout) \
|
#define SMI_POLL_TFF(timeout) \
|
||||||
{ \
|
{ \
|
||||||
int __r; \
|
int _retval; \
|
||||||
\
|
\
|
||||||
__r = poll_tff(target, io_base, timeout); \
|
_retval = poll_tff(target, io_base, timeout); \
|
||||||
if (__r != ERROR_OK) \
|
if (_retval != ERROR_OK) \
|
||||||
return __r; \
|
return _retval; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \
|
#define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \
|
||||||
|
|
|
@ -454,7 +454,8 @@ COMMAND_HANDLER(handle_flash_write_image_command)
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
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) {
|
if (retval != ERROR_OK) {
|
||||||
image_close(&image);
|
image_close(&image);
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -471,6 +472,58 @@ COMMAND_HANDLER(handle_flash_write_image_command)
|
||||||
return retval;
|
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)
|
COMMAND_HANDLER(handle_flash_fill_command)
|
||||||
{
|
{
|
||||||
target_addr_t address;
|
target_addr_t address;
|
||||||
|
@ -1145,6 +1198,14 @@ static const struct command_registration flash_exec_command_handlers[] = {
|
||||||
"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)",
|
"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)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "read_bank",
|
.name = "read_bank",
|
||||||
.handler = handle_flash_read_bank_command,
|
.handler = handle_flash_read_bank_command,
|
||||||
|
|
|
@ -1019,7 +1019,7 @@ void image_close(struct image *image)
|
||||||
image->sections = NULL;
|
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;
|
uint32_t crc = 0xffffffff;
|
||||||
LOG_DEBUG("Calculating checksum");
|
LOG_DEBUG("Calculating checksum");
|
||||||
|
|
|
@ -99,7 +99,7 @@ void image_close(struct image *image);
|
||||||
int image_add_section(struct image *image, uint32_t base, uint32_t size,
|
int image_add_section(struct image *image, uint32_t base, uint32_t size,
|
||||||
int flags, uint8_t const *data);
|
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);
|
uint32_t *checksum);
|
||||||
|
|
||||||
#define ERROR_IMAGE_FORMAT_ERROR (-1400)
|
#define ERROR_IMAGE_FORMAT_ERROR (-1400)
|
||||||
|
|
|
@ -1031,11 +1031,11 @@ int target_run_flash_async_algorithm(struct target *target,
|
||||||
* programming. The exact delay shouldn't matter as long as it's
|
* programming. The exact delay shouldn't matter as long as it's
|
||||||
* less than buffer size / flash speed. This is very unlikely to
|
* less than buffer size / flash speed. This is very unlikely to
|
||||||
* run when using high latency connections such as USB. */
|
* 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
|
/* 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 */
|
* 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");
|
LOG_ERROR("timeout waiting for algorithm, a target reset is recommended");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -1049,6 +1049,10 @@ int target_run_flash_async_algorithm(struct target *target,
|
||||||
if (thisrun_bytes > count * block_size)
|
if (thisrun_bytes > count * block_size)
|
||||||
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 */
|
/* Write data to fifo */
|
||||||
retval = target_write_buffer(target, wp, thisrun_bytes, buffer);
|
retval = target_write_buffer(target, wp, thisrun_bytes, buffer);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
|
@ -1098,6 +1102,156 @@ int target_run_flash_async_algorithm(struct target *target,
|
||||||
return retval;
|
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,
|
int target_read_memory(struct target *target,
|
||||||
target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
|
target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -577,6 +577,18 @@ int target_run_flash_async_algorithm(struct target *target,
|
||||||
uint32_t entry_point, uint32_t exit_point,
|
uint32_t entry_point, uint32_t exit_point,
|
||||||
void *arch_info);
|
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
|
* Read @a count items of @a size bytes from the memory of @a target at
|
||||||
* the @a address given.
|
* the @a address given.
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -52,6 +52,12 @@ flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME
|
||||||
|
|
||||||
flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 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
|
# 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
|
# Since we may be running of an RC oscilator, we crank down the speed a
|
||||||
|
|
|
@ -64,6 +64,12 @@ flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME
|
||||||
# the Flash via ITCM alias as virtual
|
# the Flash via ITCM alias as virtual
|
||||||
flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME
|
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 should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz
|
||||||
adapter speed 2000
|
adapter speed 2000
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,23 @@ if {[set $_CHIPNAME.DUAL_CORE]} {
|
||||||
# Make sure that cpu0 is selected
|
# Make sure that cpu0 is selected
|
||||||
targets $_CHIPNAME.cpu0
|
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
|
# Clock after reset is HSI at 64 MHz, no need of PLL
|
||||||
adapter speed 1800
|
adapter speed 1800
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,23 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE
|
||||||
set _FLASHNAME $_CHIPNAME.flash
|
set _FLASHNAME $_CHIPNAME.flash
|
||||||
flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
|
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.
|
# 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
|
# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on
|
||||||
# the safe side.
|
# the safe side.
|
||||||
|
|
Loading…
Reference in New Issue