From: OpenOCD-Gerrit <ope...@us...> - 2020-11-08 22:46:53
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via e44539d66c8929679321704768125df9ba7d5f67 (commit) from 475f42051e13d64bc4d1960306ad1d2ea3c7962a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e44539d66c8929679321704768125df9ba7d5f67 Author: Andreas Bolsch <hyp...@gm...> Date: Wed Dec 21 10:35:58 2016 +0100 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 <hyp...@gm...> Reviewed-on: http://openocd.zylin.com/4321 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI <tar...@gm...> Reviewed-by: Tomas Vanek <va...@fb...> Reviewed-by: Christopher Head <ch...@za...> diff --git a/contrib/loaders/flash/stmqspi/Makefile b/contrib/loaders/flash/stmqspi/Makefile new file mode 100644 index 000000000..810c7e87c --- /dev/null +++ b/contrib/loaders/flash/stmqspi/Makefile @@ -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)) diff --git a/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl new file mode 100755 index 000000000..b7538640e --- /dev/null +++ b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl @@ -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); diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S new file mode 100644 index 000000000..941ea42c6 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S @@ -0,0 +1,123 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * and...@mn... * + * * + * 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 */ diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc new file mode 100644 index 000000000..afc616883 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc @@ -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, diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S new file mode 100644 index 000000000..3af82d4d8 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * and...@mn... * + * * + * 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, . + diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc new file mode 100644 index 000000000..c0e124ac0 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc @@ -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, diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_read.S b/contrib/loaders/flash/stmqspi/stmoctospi_read.S new file mode 100644 index 000000000..fb5ff1ff9 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_read.S @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * and...@mn... * + * * + * 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 */ diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_read.inc b/contrib/loaders/flash/stmqspi/stmoctospi_read.inc new file mode 100644 index 000000000..583f31666 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_read.inc @@ -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, diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_write.S b/contrib/loaders/flash/stmqspi/stmoctospi_write.S new file mode 100644 index 000000000..867a02483 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_write.S @@ -0,0 +1,219 @@ +/*************************************************************************** + * Copyright (C) 2018 by Andreas Bolsch * + * and...@mn... * + * * + * 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 */ diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_write.inc b/contrib/loaders/flash/stmqspi/stmoctospi_write.inc new file mode 100644 index 000000000..81781a2ca --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_write.inc @@ -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, diff --git a/contrib/loaders/flash/stmqspi/stmqspi_crc32.S b/contrib/loaders/flash/stmqspi/stmqspi_crc32.S new file mode 100644 index 000000000..bfb2662ca --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmqspi_crc32.S @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * and...@mn... * + * * + * 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 */ diff --git a/contrib/loade... [truncated message content] |