mirror of
https://github.com/linux-msm/openocd.git
synced 2026-02-25 13:15:07 -08:00
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:
committed by
Tomas Vanek
parent
475f42051e
commit
e44539d66c
34
contrib/loaders/flash/stmqspi/Makefile
Normal file
34
contrib/loaders/flash/stmqspi/Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
BIN2C = ../../../../src/helper/bin2char.sh
|
||||
|
||||
SRCS=stmqspi_erase_check.S stmqspi_crc32.S stmqspi_read.S stmqspi_write.S \
|
||||
stmoctospi_erase_check.S stmoctospi_crc32.S stmoctospi_read.S stmoctospi_write.S
|
||||
OBJS=$(patsubst %.S,%.inc,$(SRCS))
|
||||
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
OBJCOPY=$(CROSS_COMPILE)objcopy
|
||||
OBJDUMP=$(CROSS_COMPILE)objdump
|
||||
LD=$(CROSS_COMPILE)ld
|
||||
|
||||
all: $(OBJS)
|
||||
|
||||
%.o: %.S Makefile
|
||||
$(CC) -Wall -Werror -Wa,-adhlmn -o $@ -c $< > $(@:.o=.lst)
|
||||
@enscript -Easm -T 4 -G -o - $(@:.o=.lst) | ps2pdf - $(@:.o=.pdf) || true
|
||||
|
||||
%.elf: %.o
|
||||
$(LD) -s -defsym=_start=0 -o $@ $<
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
%.inc: %.bin
|
||||
$(BIN2C) < $< > $@
|
||||
|
||||
clean:
|
||||
-rm -f *.o *.elf *.lst *.pdf *.bin *.inc
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS))
|
||||
679
contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl
Executable file
679
contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl
Executable file
File diff suppressed because it is too large
Load Diff
123
contrib/loaders/flash/stmqspi/stmoctospi_crc32.S
Normal file
123
contrib/loaders/flash/stmqspi/stmoctospi_crc32.S
Normal file
@@ -0,0 +1,123 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2019 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - total count (bytes), crc32 (out)
|
||||
* r1 - flash page size
|
||||
* r2 - address offset into flash
|
||||
* r3 - OCTOSPI io_base
|
||||
|
||||
* Clobbered:
|
||||
* r4 - tmp
|
||||
* r5 - address of OCTOSPI_DR
|
||||
* r6 - address of OCTOSPI_CCR
|
||||
* r7 - tmp
|
||||
*/
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
|
||||
|
||||
.macro octospi_abort
|
||||
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
|
||||
orrs r7, r7, r5 /* set abort bit */
|
||||
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r3, #OCTOSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
subs r0, r0, #1 /* decrement count for DLR */
|
||||
subs r1, r1, #1 /* page size mask and for DLR */
|
||||
movs r4, #0x00 /* initialize crc */
|
||||
mvns r4, r4 /* to 0xFFFFFFFF */
|
||||
start_read:
|
||||
octospi_abort /* start in clean state */
|
||||
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
|
||||
adds r5, r5, r3 /* address of OCTOSPI_DR */
|
||||
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
|
||||
adds r6, r6, r5 /* address of OCTOSPI_CCR */
|
||||
wait_busy
|
||||
ldr r7, cr_page_read /* indirect read mode */
|
||||
str r7, [r3, #OCTOSPI_CR] /* set mode */
|
||||
mov r7, r2 /* get current start address */
|
||||
orrs r7, r7, r1 /* end of current page */
|
||||
subs r7, r7, r2 /* count-1 to end of page */
|
||||
cmp r7, r0 /* if this count <= remaining */
|
||||
bls write_dlr /* then read to end of page */
|
||||
mov r7, r0 /* else read all remaining */
|
||||
write_dlr:
|
||||
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_read /* CCR for read */
|
||||
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
|
||||
ldr r7, tcr_page_read /* TCR for read */
|
||||
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
|
||||
ldr r7, ir_page_read /* IR for read */
|
||||
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
|
||||
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
|
||||
ldr r6, =0x04C11DB7 /* CRC32 polynomial */
|
||||
read_loop:
|
||||
ldrb r7, [r5] /* read next byte from DR */
|
||||
lsls r7, r7, #24 /* shift into msb */
|
||||
eors r4, r4, r7
|
||||
.rept 8 /* unrolled bit loop */
|
||||
asrs r7, r4, #31 /* copy bit 31 into bits 0 to 31 */
|
||||
ands r7, r7, r6 /* r7 neg. -> CRC32XOR, pos. -> 0x0 */
|
||||
lsls r4, r4, #1 /* shift result */
|
||||
eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */
|
||||
.endr
|
||||
adds r2, r2, #1 /* increment address */
|
||||
subs r0, r0, #1 /* decrement (count-1) */
|
||||
bmi exit /* stop if no data left */
|
||||
tst r2, r1 /* page end ? */
|
||||
bne read_loop /* if not, then next byte */
|
||||
page_end:
|
||||
bal start_read /* then next page */
|
||||
.pool
|
||||
|
||||
exit:
|
||||
mvns r0, r4 /* invert to get final result */
|
||||
octospi_abort /* to idle state */
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
cr_page_read:
|
||||
.space 4 /* OCTOSPI_CR value for read command */
|
||||
ccr_page_read:
|
||||
.space 4 /* OCTOSPI_CCR value for read command */
|
||||
tcr_page_read:
|
||||
.space 4 /* OCTOSPI_TCR value for read command */
|
||||
ir_page_read:
|
||||
.space 4 /* OCTOSPI_IR value for read command */
|
||||
13
contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc
Normal file
13
contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc
Normal file
@@ -0,0 +1,13 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
|
||||
0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,
|
||||
0x5f,0x62,0x22,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,
|
||||
0x07,0x46,0x1f,0x64,0x1e,0x4f,0x37,0x60,0x1e,0x4f,0xb7,0x60,0x1e,0x4f,0x37,0x61,
|
||||
0x9a,0x64,0x15,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
|
||||
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
|
||||
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
|
||||
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,
|
||||
0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,0x05,0xd4,
|
||||
0x0a,0x42,0xd7,0xd1,0xb8,0xe7,0x00,0x00,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25,
|
||||
0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
108
contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S
Normal file
108
contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S
Normal file
@@ -0,0 +1,108 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2019 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - sector count
|
||||
* r1 - QSPI io_base
|
||||
|
||||
* Clobbered:
|
||||
* r2 - r7 tmp */
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
|
||||
|
||||
.macro octospi_abort
|
||||
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r1, #OCTOSPI_CR] /* get OCTOSPI_CR register */
|
||||
orrs r7, r7, r5 /* set abort bit */
|
||||
str r7, [r1, #OCTOSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r1, #OCTOSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r1, #OCTOSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
adr r2, buffer /* pointer to start of buffer */
|
||||
movs r3, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
|
||||
adds r3, r3, r1 /* address of OCTOSPI_DR */
|
||||
sector_start:
|
||||
octospi_abort /* start in clean state */
|
||||
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
|
||||
adds r6, r6, r3 /* address of OCTOSPI_CCR */
|
||||
wait_busy
|
||||
ldr r7, cr_page_read /* indirect read mode */
|
||||
str r7, [r1, #OCTOSPI_CR] /* set mode */
|
||||
ldmia r2!, {r4, r5} /* load address offset, length */
|
||||
subs r2, r2, #4 /* point to length */
|
||||
subs r5, r5, #1 /* decrement sector length for DLR */
|
||||
str r5, [r1, #OCTOSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_read /* CCR for read */
|
||||
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
|
||||
ldr r7, tcr_page_read /* TCR for read */
|
||||
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
|
||||
ldr r7, ir_page_read /* IR for read */
|
||||
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
|
||||
str r4, [r1, #OCTOSPI_AR] /* store SPI start address */
|
||||
ldr r6, [r2, #4] /* load initial value */
|
||||
read_loop:
|
||||
ldrb r4, [r3, #0] /* read next byte from DR */
|
||||
movs r7, #0xFF /* fill bits 8-15 */
|
||||
lsls r7, r7, #8 /* with ones */
|
||||
orrs r4, r4, r7 /* copy ones to left of read byte */
|
||||
ands r6, r6, r4 /* and read byte to result */
|
||||
lsls r4, r4, #8 /* shift result into higher byte */
|
||||
orrs r6, r6, r4 /* or read byte to result */
|
||||
subs r5, r5, #1 /* decrement byte (count-1) */
|
||||
bpl read_loop /* again if sector not completed */
|
||||
adds r5, r5, #1 /* increment count due to the -1 */
|
||||
stmia r2!, {r5, r6} /* save final count and result for sector */
|
||||
subs r0, r0, #1 /* decrement sector count */
|
||||
bne sector_start /* next sector? */
|
||||
octospi_abort /* to idle state */
|
||||
|
||||
exit:
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
cr_page_read:
|
||||
.space 4 /* OCTOSPI_CR value for read command */
|
||||
ccr_page_read:
|
||||
.space 4 /* OCTOSPI_CCR value for read command */
|
||||
tcr_page_read:
|
||||
.space 4 /* OCTOSPI_TCR value for read command */
|
||||
ir_page_read:
|
||||
.space 4 /* OCTOSPI_IR value for read command */
|
||||
|
||||
.equ buffer, .
|
||||
|
||||
8
contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc
Normal file
8
contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc
Normal file
@@ -0,0 +1,8 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x1b,0xa2,0x50,0x23,0x5b,0x18,0x02,0x25,0x0f,0x68,0x2f,0x43,0x0f,0x60,0xb0,0x26,
|
||||
0xf6,0x18,0x0f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x4f,0x62,0x10,0x4f,0x0f,0x60,
|
||||
0x30,0xca,0x04,0x3a,0x01,0x3d,0x0d,0x64,0x0e,0x4f,0x37,0x60,0x0e,0x4f,0xb7,0x60,
|
||||
0x0e,0x4f,0x37,0x61,0x8c,0x64,0x56,0x68,0x1c,0x78,0xff,0x27,0x3f,0x02,0x3c,0x43,
|
||||
0x26,0x40,0x24,0x02,0x26,0x43,0x01,0x3d,0xf6,0xd5,0x01,0x35,0x60,0xc2,0x01,0x38,
|
||||
0xd9,0xd1,0x02,0x25,0x0f,0x68,0x2f,0x43,0x0f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
142
contrib/loaders/flash/stmqspi/stmoctospi_read.S
Normal file
142
contrib/loaders/flash/stmqspi/stmoctospi_read.S
Normal file
@@ -0,0 +1,142 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2019 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
|
||||
* r1 - flash page size
|
||||
* r2 - address offset into flash
|
||||
* r3 - OCTOSPI io_base
|
||||
* r8 - fifo start
|
||||
* r9 - fifo end + 1
|
||||
|
||||
* Clobbered:
|
||||
* r4 - wp
|
||||
* r5 - address of OCTOSPI_DR
|
||||
* r6 - address of OCTOSPI_CCR
|
||||
* r7 - tmp
|
||||
*/
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
|
||||
|
||||
.macro octospi_abort
|
||||
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
|
||||
orrs r7, r7, r5 /* set abort bit */
|
||||
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r3, #OCTOSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
subs r0, r0, #1 /* decrement count for DLR */
|
||||
subs r1, r1, #1 /* page size mask and for DLR */
|
||||
ldr r4, wp /* load wp */
|
||||
start_read:
|
||||
octospi_abort /* start in clean state */
|
||||
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
|
||||
adds r5, r5, r3 /* address of OCTOSPI_DR */
|
||||
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
|
||||
adds r6, r6, r5 /* address of OCTOSPI_CCR */
|
||||
wait_busy
|
||||
ldr r7, cr_page_read /* indirect read mode */
|
||||
str r7, [r3, #OCTOSPI_CR] /* set mode */
|
||||
mov r7, r2 /* get current start address */
|
||||
orrs r7, r7, r1 /* end of current page */
|
||||
subs r7, r7, r2 /* count-1 to end of page */
|
||||
cmp r7, r0 /* if this count <= remaining */
|
||||
bls write_dlr /* then write to end of page */
|
||||
mov r7, r0 /* else write all remaining */
|
||||
write_dlr:
|
||||
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_read /* CCR for read */
|
||||
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
|
||||
ldr r7, tcr_page_read /* TCR for read */
|
||||
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
|
||||
ldr r7, ir_page_read /* IR for read */
|
||||
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
|
||||
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
|
||||
read_loop:
|
||||
ldrb r7, [r5] /* read next byte from DR */
|
||||
strb r7, [r4, #0] /* write next byte */
|
||||
adds r4, r4, #1 /* increment internal wp */
|
||||
cmp r4, r9 /* internal wp beyond end? */
|
||||
blo wait_fifo /* if no, then ok */
|
||||
mov r4, r8 /* else wrap around */
|
||||
wait_fifo:
|
||||
ldr r7, rp /* get rp */
|
||||
cmp r7, #0 /* if rp equals 0 */
|
||||
beq exit /* then abort */
|
||||
cmp r4, r7 /* check if fifo full */
|
||||
beq wait_fifo /* wait until not full */
|
||||
adr r7, wp /* get address of wp */
|
||||
str r4, [r7] /* store updated wp */
|
||||
adds r2, r2, #1 /* increment address */
|
||||
subs r0, r0, #1 /* decrement (count-1) */
|
||||
bmi exit /* stop if no data left */
|
||||
tst r2, r1 /* page end ? */
|
||||
bne read_loop /* if not, then next byte */
|
||||
page_end:
|
||||
bal start_read /* then next page */
|
||||
|
||||
exit:
|
||||
adds r0, r0, #1 /* increment count due to the -1 */
|
||||
octospi_abort /* to idle state */
|
||||
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
cr_page_read:
|
||||
.space 4 /* OCTOSPI_CR value for read command */
|
||||
ccr_page_read:
|
||||
.space 4 /* OCTOSPI_CCR value for read command */
|
||||
tcr_page_read:
|
||||
.space 4 /* OCTOSPI_TCR value for read command */
|
||||
ir_page_read:
|
||||
.space 4 /* OCTOSPI_IR value for read command */
|
||||
|
||||
.equ wp, . /* wp, uint32_t */
|
||||
.equ rp, wp + 4 /* rp, uint32_t */
|
||||
.equ buffer, rp + 4 /* buffer follows right away */
|
||||
12
contrib/loaders/flash/stmqspi/stmoctospi_read.inc
Normal file
12
contrib/loaders/flash/stmqspi/stmoctospi_read.inc
Normal file
@@ -0,0 +1,12 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x01,0x38,0x01,0x39,0x27,0x4c,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x50,0x25,
|
||||
0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,
|
||||
0x1c,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,
|
||||
0x1f,0x64,0x19,0x4f,0x37,0x60,0x19,0x4f,0xb7,0x60,0x19,0x4f,0x37,0x61,0x9a,0x64,
|
||||
0x2f,0x78,0x27,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x16,0x4f,0x00,0x2f,
|
||||
0x09,0xd0,0xbc,0x42,0xfa,0xd0,0x13,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,0x02,0xd4,
|
||||
0x0a,0x42,0xed,0xd1,0xcf,0xe7,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
|
||||
0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
219
contrib/loaders/flash/stmqspi/stmoctospi_write.S
Normal file
219
contrib/loaders/flash/stmqspi/stmoctospi_write.S
Normal file
@@ -0,0 +1,219 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2018 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
|
||||
* r1 - flash page size
|
||||
* r2 - address offset into flash
|
||||
* r3 - OCTOSPI io_base
|
||||
* r8 - fifo start
|
||||
* r9 - fifo end + 1
|
||||
|
||||
* Clobbered:
|
||||
* r4 - rp
|
||||
* r5 - address of OCTOSPI_DR
|
||||
* r6 - address of OCTOSPI_CCR
|
||||
* r7 - tmp
|
||||
* r10 - single 0x0 / dual 0x1
|
||||
*/
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
|
||||
#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
|
||||
|
||||
.macro octospi_abort
|
||||
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
|
||||
orrs r7, r7, r5 /* set abort bit */
|
||||
str r7, [r3, #OCTOSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r3, #OCTOSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
subs r0, r0, #1 /* decrement count for DLR */
|
||||
subs r1, r1, #1 /* page size mask and for DLR */
|
||||
ldr r4, rp /* load rp */
|
||||
ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI_CR register */
|
||||
lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
|
||||
lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
|
||||
mov r10, r7 /* save in r10 */
|
||||
wip_loop:
|
||||
octospi_abort /* start in clean state */
|
||||
movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
|
||||
adds r5, r5, r3 /* address of OCTOSPI_DR */
|
||||
movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
|
||||
adds r6, r6, r5 /* address of OCTOSPI_CCR */
|
||||
wait_busy
|
||||
ldr r7, cr_read_status /* indirect read mode */
|
||||
str r7, [r3, #OCTOSPI_CR] /* set mode */
|
||||
mov r7, r10 /* get dual bit */
|
||||
str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
|
||||
ldr r7, ccr_read_status /* CCR for status read */
|
||||
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
|
||||
ldr r7, tcr_read_status /* TCR for status read */
|
||||
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
|
||||
ldr r7, ir_read_status /* IR for status read */
|
||||
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
|
||||
movs r7, #0 /* dummy address */
|
||||
str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
|
||||
ldrb r7, [r5] /* get first status register */
|
||||
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
|
||||
bcs wip_loop /* then poll again */
|
||||
mov r7, r10 /* get dual bit */
|
||||
tst r7, r7 /* dual mode ? */
|
||||
beq write_enable /* not dual, then ok */
|
||||
ldrb r7, [r5] /* get second status register */
|
||||
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
|
||||
bcs wip_loop /* then poll again */
|
||||
write_enable:
|
||||
tst r0, r0 /* test residual count */
|
||||
bmi exit /* if negative, then finished */
|
||||
wait_busy
|
||||
ldr r7, cr_write_enable /* indirect write mode */
|
||||
str r7, [r3, #OCTOSPI_CR] /* set mode */
|
||||
ldr r7, ccr_write_enable /* CCR for write enable */
|
||||
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate write enable */
|
||||
ldr r7, tcr_write_enable /* TCR for write enable */
|
||||
str r7, [r6, #OCTOSPI_TCR_CCR] /* write enable instruction */
|
||||
ldr r7, ir_write_enable /* IR for write enable */
|
||||
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
|
||||
movs r7, #0 /* silicon bug in L5? dummy write */
|
||||
str r7, [r3, #OCTOSPI_AR] /* into AR resolves issue */
|
||||
wait_busy
|
||||
ldr r7, cr_read_status /* indirect read mode */
|
||||
str r7, [r3, #OCTOSPI_CR] /* set mode */
|
||||
mov r7, r10 /* get dual count */
|
||||
str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
|
||||
ldr r7, ccr_read_status /* CCR for status read */
|
||||
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
|
||||
ldr r7, tcr_read_status /* TCR for status read */
|
||||
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
|
||||
ldr r7, ir_read_status /* IR for status read */
|
||||
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
|
||||
movs r7, #0 /* dummy address */
|
||||
str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
|
||||
ldrb r7, [r5] /* get first status register */
|
||||
lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
|
||||
bcc error /* write enabled, then error */
|
||||
mov r7, r10 /* get dual bit */
|
||||
tst r7, r7 /* dual mode ? */
|
||||
beq start_write /* not dual, then ok */
|
||||
ldrb r7, [r5] /* get second status register */
|
||||
lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
|
||||
bcc error /* write enabled, then error */
|
||||
start_write:
|
||||
wait_busy
|
||||
ldr r7, cr_page_write /* indirect write mode */
|
||||
str r7, [r3, #OCTOSPI_CR] /* set mode */
|
||||
mov r7, r2 /* get current start address */
|
||||
orrs r7, r7, r1 /* end of current page */
|
||||
subs r7, r7, r2 /* count-1 to end of page */
|
||||
cmp r7, r0 /* if this count <= remaining */
|
||||
bls write_dlr /* then write to end of page */
|
||||
mov r7, r0 /* else write all remaining */
|
||||
write_dlr:
|
||||
str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_write /* CCR for page write */
|
||||
str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
|
||||
ldr r7, tcr_page_write /* TCR for page write */
|
||||
str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
|
||||
ldr r7, ir_page_write /* IR for page write */
|
||||
str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
|
||||
str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
|
||||
write_loop:
|
||||
ldr r7, wp /* get wp */
|
||||
cmp r7, #0 /* if wp equals 0 */
|
||||
beq exit /* then abort */
|
||||
cmp r4, r7 /* check if fifo empty */
|
||||
beq write_loop /* wait until not empty */
|
||||
ldrb r7, [r4, #0] /* read next byte */
|
||||
strb r7, [r5] /* write next byte to DR */
|
||||
adds r4, r4, #1 /* increment internal rp */
|
||||
cmp r4, r9 /* internal rp beyond end? */
|
||||
blo upd_write /* if no, then ok */
|
||||
mov r4, r8 /* else wrap around */
|
||||
upd_write:
|
||||
adr r7, rp /* get address of rp */
|
||||
str r4, [r7] /* store updated rp */
|
||||
adds r2, r2, #1 /* increment address */
|
||||
subs r0, r0, #1 /* decrement (count-1) */
|
||||
bmi page_end /* stop if no data left */
|
||||
tst r2, r1 /* page end ? */
|
||||
bne write_loop /* if not, then next byte */
|
||||
page_end:
|
||||
ldr r7, [r3, #OCTOSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
|
||||
bcc page_end /* loop until TCF set */
|
||||
bal wip_loop /* then next page */
|
||||
|
||||
error:
|
||||
movs r0, #0 /* return 0xFFFFFFFF */
|
||||
subs r0, r0, #2 /* for error */
|
||||
exit:
|
||||
adds r0, r0, #1 /* increment count due to the -1 */
|
||||
octospi_abort /* to idle state */
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
cr_read_status:
|
||||
.space 4 /* OCTOSPI_CR value for READ_STATUS command */
|
||||
ccr_read_status:
|
||||
.space 4 /* OCTOSPI_CCR value for READ_STATUS command */
|
||||
tcr_read_status:
|
||||
.space 4 /* OCTOSPI_TCR value for READ_STATUS command */
|
||||
ir_read_status:
|
||||
.space 4 /* OCTOSPI_IR value for READ_STATUS command */
|
||||
|
||||
cr_write_enable:
|
||||
.space 4 /* OCTOSPI_CR value for WRITE_ENABLE command */
|
||||
ccr_write_enable:
|
||||
.space 4 /* OCTOSPI_CCR value for WRITE_ENABLE command */
|
||||
tcr_write_enable:
|
||||
.space 4 /* OCTOSPI_TCR value for WRITE_ENABLE command */
|
||||
ir_write_enable:
|
||||
.space 4 /* OCTOSPI_IR value for WRITE_ENABLE command */
|
||||
|
||||
cr_page_write:
|
||||
.space 4 /* OCTOSPI_CR value for PAGE_PROG command */
|
||||
ccr_page_write:
|
||||
.space 4 /* OCTOSPI_CCR value for PAGE_PROG command */
|
||||
tcr_page_write:
|
||||
.space 4 /* OCTOSPI_TCR value for PAGE_PROG command */
|
||||
ir_page_write:
|
||||
.space 4 /* OCTOSPI_IR value for PAGE_PROG command */
|
||||
|
||||
.equ wp, . /* wp, uint32_t */
|
||||
.equ rp, wp + 4 /* rp, uint32_t */
|
||||
.equ buffer, rp + 4 /* buffer follows right away */
|
||||
21
contrib/loaders/flash/stmqspi/stmoctospi_write.inc
Normal file
21
contrib/loaders/flash/stmqspi/stmoctospi_write.inc
Normal file
@@ -0,0 +1,21 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x01,0x38,0x01,0x39,0x4f,0x4c,0x1f,0x68,0x7f,0x06,0xff,0x0f,0xba,0x46,0x02,0x25,
|
||||
0x1f,0x68,0x2f,0x43,0x1f,0x60,0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,
|
||||
0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,0x39,0x4f,0x1f,0x60,0x57,0x46,0x1f,0x64,
|
||||
0x38,0x4f,0x37,0x60,0x38,0x4f,0xb7,0x60,0x38,0x4f,0x37,0x61,0x00,0x27,0x9f,0x64,
|
||||
0x2f,0x78,0x7f,0x08,0xe3,0xd2,0x57,0x46,0x3f,0x42,0x02,0xd0,0x2f,0x78,0x7f,0x08,
|
||||
0xdd,0xd2,0x00,0x42,0x55,0xd4,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,
|
||||
0x2f,0x4f,0x1f,0x60,0x2f,0x4f,0x37,0x60,0x2f,0x4f,0xb7,0x60,0x2f,0x4f,0x37,0x61,
|
||||
0x00,0x27,0x9f,0x64,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,0x5f,0x62,0x24,0x4f,
|
||||
0x1f,0x60,0x57,0x46,0x1f,0x64,0x23,0x4f,0x37,0x60,0x23,0x4f,0xb7,0x60,0x23,0x4f,
|
||||
0x37,0x61,0x00,0x27,0x9f,0x64,0x2f,0x78,0xbf,0x08,0x30,0xd3,0x57,0x46,0x3f,0x42,
|
||||
0x02,0xd0,0x2f,0x78,0xbf,0x08,0x2a,0xd3,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27,
|
||||
0x5f,0x62,0x1f,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,
|
||||
0x07,0x46,0x1f,0x64,0x1b,0x4f,0x37,0x60,0x1b,0x4f,0xb7,0x60,0x1b,0x4f,0x37,0x61,
|
||||
0x9a,0x64,0x1b,0x4f,0x00,0x2f,0x14,0xd0,0xbc,0x42,0xfa,0xd0,0x27,0x78,0x2f,0x70,
|
||||
0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x16,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,
|
||||
0x01,0xd4,0x0a,0x42,0xed,0xd1,0x1f,0x6a,0xbf,0x08,0xfc,0xd3,0x87,0xe7,0x00,0x20,
|
||||
0x02,0x38,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x00,0xbe,0xc0,0x46,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
108
contrib/loaders/flash/stmqspi/stmqspi_crc32.S
Normal file
108
contrib/loaders/flash/stmqspi/stmqspi_crc32.S
Normal file
@@ -0,0 +1,108 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2019 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - total count (bytes), crc32 (out)
|
||||
* r1 - flash page size
|
||||
* r2 - address offset into flash
|
||||
* r3 - QSPI io_base
|
||||
|
||||
* Clobbered:
|
||||
* r4 - rp
|
||||
* r5 - address of QSPI_DR
|
||||
* r7 - tmp
|
||||
*/
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
.macro qspi_abort
|
||||
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
|
||||
orrs r7, r7, r5 /* set abort bit */
|
||||
str r7, [r3, #QSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r3, #QSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
subs r0, r0, #1 /* decrement count for DLR */
|
||||
subs r1, r1, #1 /* page size mask and for DLR */
|
||||
movs r4, #0x00 /* initialize crc */
|
||||
mvns r4, r4 /* to 0xFFFFFFFF */
|
||||
start_read:
|
||||
qspi_abort /* start in clean state */
|
||||
movs r5, #QSPI_DR /* load QSPI_DR address offset */
|
||||
adds r5, r5, r3 /* address of QSPI_DR */
|
||||
wait_busy
|
||||
mov r7, r2 /* get current start address */
|
||||
orrs r7, r7, r1 /* end of current page */
|
||||
subs r7, r7, r2 /* count-1 to end of page */
|
||||
cmp r7, r0 /* if this count <= remaining */
|
||||
bls write_dlr /* then read to end of page */
|
||||
mov r7, r0 /* else read all remaining */
|
||||
write_dlr:
|
||||
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_read /* CCR for page read */
|
||||
str r7, [r3, #QSPI_CCR] /* initiate transfer */
|
||||
str r2, [r3, #QSPI_AR] /* store SPI start address */
|
||||
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
|
||||
ldr r6, =0x04C11DB7 /* CRC32 polynomial */
|
||||
read_loop:
|
||||
ldrb r7, [r5] /* read next byte from DR */
|
||||
lsls r7, r7, #24 /* shift into msb */
|
||||
eors r4, r4, r7
|
||||
.rept 8 /* unrolled bit loop */
|
||||
asrs r7, r4, #31 /* copy bit 31 into bits 0 to 31 */
|
||||
ands r7, r7, r6 /* r7 neg. -> CRC32XOR, pos. -> 0x0 */
|
||||
lsls r4, r4, #1 /* shift result */
|
||||
eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */
|
||||
.endr
|
||||
adds r2, r2, #1 /* increment address */
|
||||
subs r0, r0, #1 /* decrement (count-1) */
|
||||
bmi exit /* stop if no data left */
|
||||
tst r2, r1 /* page end ? */
|
||||
bne read_loop /* if not, then next byte */
|
||||
page_end:
|
||||
bal start_read /* then next page */
|
||||
.pool
|
||||
|
||||
exit:
|
||||
mvns r0, r4 /* invert to get final result */
|
||||
qspi_abort /* to idle state */
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
.space 4 /* not used */
|
||||
ccr_page_read:
|
||||
.space 4 /* QSPI_CCR value for read command */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
12
contrib/loaders/flash/stmqspi/stmqspi_crc32.inc
Normal file
12
contrib/loaders/flash/stmqspi/stmqspi_crc32.inc
Normal file
@@ -0,0 +1,12 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,
|
||||
0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46,
|
||||
0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x1c,0x4f,0x5f,0x61,
|
||||
0x9a,0x61,0x9f,0x68,0x14,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,
|
||||
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
|
||||
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
|
||||
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,
|
||||
0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,
|
||||
0x04,0xd4,0x0a,0x42,0xd7,0xd1,0xbf,0xe7,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25,
|
||||
0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
91
contrib/loaders/flash/stmqspi/stmqspi_erase_check.S
Normal file
91
contrib/loaders/flash/stmqspi/stmqspi_erase_check.S
Normal file
@@ -0,0 +1,91 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2019 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - sector count
|
||||
* r1 - QSPI io_base
|
||||
|
||||
* Clobbered:
|
||||
* r2 - r7 tmp */
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
.macro qspi_abort
|
||||
movs r4, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r1, #QSPI_CR] /* get QSPI_CR register */
|
||||
orrs r7, r7, r4 /* set abort bit */
|
||||
str r7, [r1, #QSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r1, #QSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r1, #QSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
adr r2, buffer /* pointer to start of buffer */
|
||||
movs r3, #QSPI_DR /* load QSPI_DR address offset */
|
||||
add r3, r3, r1 /* address of QSPI_DR */
|
||||
sector_start:
|
||||
qspi_abort /* start in clean state */
|
||||
ldmia r2!, {r4, r5, r6} /* load address offset, length, initial value */
|
||||
subs r2, r2, #8 /* point to length */
|
||||
subs r5, r5, #1 /* decrement sector length for DLR */
|
||||
wait_busy
|
||||
str r5, [r1, #QSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_read /* CCR for page read */
|
||||
str r7, [r1, #QSPI_CCR] /* initiate transfer */
|
||||
str r4, [r1, #QSPI_AR] /* store SPI start address */
|
||||
ldr r7, [r1, #QSPI_SR] /* wait for command startup */
|
||||
read_loop:
|
||||
ldrb r4, [r3] /* read next byte from DR */
|
||||
movs r7, #0xFF /* fill bits 8-15 */
|
||||
lsls r7, r7, #8 /* with ones */
|
||||
orrs r4, r4, r7 /* copy ones to left of read byte */
|
||||
ands r6, r6, r4 /* and read byte to result */
|
||||
lsls r4, r4, #8 /* shift result into higher byte */
|
||||
orrs r6, r6, r4 /* or read byte to result */
|
||||
subs r5, r5, #1 /* decrement byte (count-1) */
|
||||
bpl read_loop /* again if sector not completed */
|
||||
adds r5, r5, #1 /* increment count due to the -1 */
|
||||
stmia r2!, {r5, r6} /* save final count and result for sector */
|
||||
subs r0, r0, #1 /* decrement sector count */
|
||||
bne sector_start /* next sector? */
|
||||
qspi_abort /* to idle state */
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
.space 4 /* not used */
|
||||
ccr_page_read:
|
||||
.space 4 /* QSPI_CCR value for read command */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.equ buffer, .
|
||||
|
||||
7
contrib/loaders/flash/stmqspi/stmqspi_erase_check.inc
Normal file
7
contrib/loaders/flash/stmqspi/stmqspi_erase_check.inc
Normal file
@@ -0,0 +1,7 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x17,0xa2,0x20,0x23,0x0b,0x44,0x02,0x24,0x0f,0x68,0x27,0x43,0x0f,0x60,0x70,0xca,
|
||||
0x08,0x3a,0x01,0x3d,0x8f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xcf,0x60,0x0d,0x61,
|
||||
0x0c,0x4f,0x4f,0x61,0x8c,0x61,0x8f,0x68,0x1c,0x78,0xff,0x27,0x3f,0x02,0x3c,0x43,
|
||||
0x26,0x40,0x24,0x02,0x26,0x43,0x01,0x3d,0xf6,0xd5,0x01,0x35,0x60,0xc2,0x01,0x38,
|
||||
0xe1,0xd1,0x02,0x24,0x0f,0x68,0x27,0x43,0x0f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
127
contrib/loaders/flash/stmqspi/stmqspi_read.S
Normal file
127
contrib/loaders/flash/stmqspi/stmqspi_read.S
Normal file
@@ -0,0 +1,127 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2019 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
|
||||
* r1 - flash page size
|
||||
* r2 - address offset into flash
|
||||
* r3 - QSPI io_base
|
||||
* r8 - fifo start
|
||||
* r9 - fifo end + 1
|
||||
|
||||
* Clobbered:
|
||||
* r4 - wp
|
||||
* r5 - address of QSPI_DR
|
||||
* r7 - tmp
|
||||
*/
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
.macro qspi_abort
|
||||
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
|
||||
orrs r7, r7, r5 /* set abort bit */
|
||||
str r7, [r3, #QSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r3, #QSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
subs r0, r0, #1 /* decrement count for DLR */
|
||||
subs r1, r1, #1 /* page size mask and for DLR */
|
||||
ldr r4, wp /* load wp */
|
||||
start_read:
|
||||
qspi_abort /* start in clean state */
|
||||
movs r5, #QSPI_DR /* load QSPI_DR address offset */
|
||||
adds r5, r5, r3 /* address of QSPI_DR */
|
||||
wait_busy
|
||||
mov r7, r2 /* get current start address */
|
||||
orrs r7, r7, r1 /* end of current page */
|
||||
subs r7, r7, r2 /* count-1 to end of page */
|
||||
cmp r7, r0 /* if this count <= remaining */
|
||||
bls write_dlr /* then read to end of page */
|
||||
mov r7, r0 /* else read all remaining */
|
||||
write_dlr:
|
||||
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_read /* CCR for page read */
|
||||
str r7, [r3, #QSPI_CCR] /* initiate transfer */
|
||||
str r2, [r3, #QSPI_AR] /* store SPI start address */
|
||||
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
|
||||
read_loop:
|
||||
ldrb r7, [r5] /* read next byte from DR */
|
||||
strb r7, [r4, #0] /* write next byte */
|
||||
adds r4, r4, #1 /* increment internal wp */
|
||||
cmp r4, r9 /* internal wp beyond end? */
|
||||
blo wait_fifo /* if no, then ok */
|
||||
mov r4, r8 /* else wrap around */
|
||||
wait_fifo:
|
||||
ldr r7, rp /* get rp */
|
||||
cmp r7, #0 /* if rp equals 0 */
|
||||
beq exit /* then abort */
|
||||
cmp r4, r7 /* check if fifo full */
|
||||
beq wait_fifo /* wait until not full */
|
||||
adr r7, wp /* get address of wp */
|
||||
str r4, [r7] /* store updated wp */
|
||||
adds r2, r2, #1 /* increment address */
|
||||
subs r0, r0, #1 /* decrement (count-1) */
|
||||
bmi exit /* stop if no data left */
|
||||
tst r2, r1 /* page end ? */
|
||||
bne read_loop /* if not, then next byte */
|
||||
page_end:
|
||||
bal start_read /* then next page */
|
||||
|
||||
exit:
|
||||
adds r0, r0, #1 /* increment count due to the -1 */
|
||||
qspi_abort /* to idle state */
|
||||
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.space 4 /* not used */
|
||||
ccr_page_read:
|
||||
.space 4 /* QSPI_CCR value for read command */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.equ wp, . /* wp, uint32_t */
|
||||
.equ rp, wp + 4 /* rp, uint32_t */
|
||||
.equ buffer, rp + 4 /* buffer follows right away */
|
||||
11
contrib/loaders/flash/stmqspi/stmqspi_read.inc
Normal file
11
contrib/loaders/flash/stmqspi/stmqspi_read.inc
Normal file
@@ -0,0 +1,11 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x01,0x38,0x01,0x39,0x24,0x4c,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60,0x20,0x25,
|
||||
0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46,0x0f,0x43,
|
||||
0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x18,0x4f,0x5f,0x61,0x9a,0x61,
|
||||
0x9f,0x68,0x2f,0x78,0x27,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x17,0x4f,
|
||||
0x00,0x2f,0x09,0xd0,0xbc,0x42,0xfa,0xd0,0x13,0xa7,0x3c,0x60,0x01,0x32,0x01,0x38,
|
||||
0x02,0xd4,0x0a,0x42,0xed,0xd1,0xd6,0xe7,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,
|
||||
0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
177
contrib/loaders/flash/stmqspi/stmqspi_write.S
Normal file
177
contrib/loaders/flash/stmqspi/stmqspi_write.S
Normal file
@@ -0,0 +1,177 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2016 - 2018 by Andreas Bolsch *
|
||||
* andreas.bolsch@mni.thm.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
/* Params:
|
||||
* r0 - total count (bytes), remaining bytes (out, 0 means successful)
|
||||
* r1 - flash page size
|
||||
* r2 - address offset into flash
|
||||
* r3 - QSPI io_base
|
||||
* r8 - fifo start
|
||||
* r9 - fifo end + 1
|
||||
|
||||
* Clobbered:
|
||||
* r4 - rp
|
||||
* r5 - address of QSPI_DR
|
||||
* r7 - tmp
|
||||
* r10 - single 0x0 / dual 0x1
|
||||
*/
|
||||
|
||||
#include "../../../../src/flash/nor/stmqspi.h"
|
||||
|
||||
.macro qspi_abort
|
||||
movs r5, #(1<<SPI_ABORT) /* abort bit mask */
|
||||
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
|
||||
orrs r7, r7, r5 /* set abort bit */
|
||||
str r7, [r3, #QSPI_CR] /* store new CR register */
|
||||
.endm
|
||||
|
||||
.macro wait_busy
|
||||
0:
|
||||
ldr r7, [r3, #QSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
|
||||
bcs 0b /* loop until BUSY cleared */
|
||||
movs r7, #(1<<SPI_TCF) /* TCF bitmask */
|
||||
str r7, [r3, #QSPI_FCR] /* clear TCF flag */
|
||||
.endm
|
||||
|
||||
start:
|
||||
subs r0, r0, #1 /* decrement count for DLR */
|
||||
subs r1, r1, #1 /* page size mask and for DLR */
|
||||
ldr r4, rp /* load rp */
|
||||
ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
|
||||
lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
|
||||
lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
|
||||
mov r10, r7 /* save in r10 */
|
||||
wip_loop:
|
||||
qspi_abort /* start in clean state */
|
||||
movs r5, #QSPI_DR /* load QSPI_DR address offset */
|
||||
adds r5, r5, r3 /* address of QSPI_DR */
|
||||
wait_busy
|
||||
mov r7, r10 /* get dual bit */
|
||||
str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
|
||||
ldr r7, ccr_read_status /* CCR for status read */
|
||||
str r7, [r3, #QSPI_CCR] /* initiate status read */
|
||||
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
|
||||
ldrb r7, [r5] /* get first status register */
|
||||
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
|
||||
bcs wip_loop /* then poll again */
|
||||
mov r7, r10 /* get dual bit */
|
||||
tst r7, r7 /* dual mode ? */
|
||||
beq write_enable /* not dual, then ok */
|
||||
ldrb r7, [r5] /* get second status register */
|
||||
lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
|
||||
bcs wip_loop /* then poll again */
|
||||
write_enable:
|
||||
tst r0, r0 /* test residual count */
|
||||
bmi exit /* if negative, then finished */
|
||||
wait_busy
|
||||
ldr r7, ccr_write_enable /* CCR for write enable */
|
||||
str r7, [r3, #QSPI_CCR] /* initiate write enable */
|
||||
wait_busy
|
||||
mov r7, r10 /* get dual bit */
|
||||
str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
|
||||
ldr r7, ccr_read_status /* CCR for status read */
|
||||
str r7, [r3, #QSPI_CCR] /* initiate status read */
|
||||
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
|
||||
ldrb r7, [r5] /* get first status register */
|
||||
lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
|
||||
bcc error /* write enabled, then error */
|
||||
mov r7, r10 /* get dual bit */
|
||||
tst r7, r7 /* dual mode ? */
|
||||
beq start_write /* not dual, then ok */
|
||||
ldrb r7, [r5] /* get second status register */
|
||||
lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
|
||||
bcc error /* write enabled, then error */
|
||||
start_write:
|
||||
wait_busy
|
||||
mov r7, r2 /* get current start address */
|
||||
orrs r7, r7, r1 /* end of current page */
|
||||
subs r7, r7, r2 /* count-1 to end of page */
|
||||
cmp r7, r0 /* if this count <= remaining */
|
||||
bls write_dlr /* then write to end of page */
|
||||
mov r7, r0 /* else write all remaining */
|
||||
write_dlr:
|
||||
str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
|
||||
ldr r7, ccr_page_write /* CCR for page write */
|
||||
str r7, [r3, #QSPI_CCR] /* initiate transfer */
|
||||
str r2, [r3, #QSPI_AR] /* store SPI start address */
|
||||
ldr r7, [r3, #QSPI_SR] /* wait for command startup */
|
||||
write_loop:
|
||||
ldr r7, wp /* get wp */
|
||||
cmp r7, #0 /* if wp equals 0 */
|
||||
beq exit /* then abort */
|
||||
cmp r4, r7 /* check if fifo empty */
|
||||
beq write_loop /* wait until not empty */
|
||||
ldrb r7, [r4, #0] /* read next byte */
|
||||
strb r7, [r5] /* write next byte to DR */
|
||||
adds r4, r4, #1 /* increment internal rp */
|
||||
cmp r4, r9 /* internal rp beyond end? */
|
||||
blo upd_write /* if no, then ok */
|
||||
mov r4, r8 /* else wrap around */
|
||||
upd_write:
|
||||
adr r7, rp /* get address of rp */
|
||||
str r4, [r7] /* store updated rp */
|
||||
adds r2, r2, #1 /* increment address */
|
||||
subs r0, r0, #1 /* decrement (count-1) */
|
||||
bmi page_end /* stop if no data left */
|
||||
tst r2, r1 /* page end ? */
|
||||
bne write_loop /* if not, then next byte */
|
||||
page_end:
|
||||
ldr r7, [r3, #QSPI_SR] /* load status */
|
||||
lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
|
||||
bcc page_end /* loop until TCF set */
|
||||
bal wip_loop /* then next page */
|
||||
|
||||
error:
|
||||
movs r0, #0 /* return 0xFFFFFFFF */
|
||||
subs r0, r0, #2 /* for error */
|
||||
exit:
|
||||
adds r0, r0, #1 /* increment count due to the -1 */
|
||||
qspi_abort /* to idle state */
|
||||
|
||||
.align 2 /* align to word, bkpt is 4 words */
|
||||
bkpt #0 /* before code end for exit_point */
|
||||
.align 2 /* align to word */
|
||||
|
||||
.space 4 /* not used */
|
||||
ccr_read_status:
|
||||
.space 4 /* QSPI_CCR value for READ_STATUS command */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.space 4 /* not used */
|
||||
ccr_write_enable:
|
||||
.space 4 /* QSPI_CCR value for WRITE_ENABLE command */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.space 4 /* not used */
|
||||
ccr_page_write:
|
||||
.space 4 /* QSPI_CCR value for PAGE_PROG command */
|
||||
.space 4 /* not used */
|
||||
.space 4 /* not used */
|
||||
|
||||
.equ wp, . /* wp, uint32_t */
|
||||
.equ rp, wp + 4 /* rp, uint32_t */
|
||||
.equ buffer, rp + 4 /* buffer follows right away */
|
||||
18
contrib/loaders/flash/stmqspi/stmqspi_write.inc
Normal file
18
contrib/loaders/flash/stmqspi/stmqspi_write.inc
Normal file
@@ -0,0 +1,18 @@
|
||||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x01,0x38,0x01,0x39,0x41,0x4c,0x1f,0x68,0x7f,0x06,0xff,0x0f,0xba,0x46,0x02,0x25,
|
||||
0x1f,0x68,0x2f,0x43,0x1f,0x60,0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,
|
||||
0x02,0x27,0xdf,0x60,0x57,0x46,0x1f,0x61,0x2c,0x4f,0x5f,0x61,0x9f,0x68,0x2f,0x78,
|
||||
0x7f,0x08,0xec,0xd2,0x57,0x46,0x3f,0x42,0x02,0xd0,0x2f,0x78,0x7f,0x08,0xe6,0xd2,
|
||||
0x00,0x42,0x41,0xd4,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x27,0x4f,
|
||||
0x5f,0x61,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x57,0x46,0x1f,0x61,
|
||||
0x1e,0x4f,0x5f,0x61,0x9f,0x68,0x2f,0x78,0xbf,0x08,0x2b,0xd3,0x57,0x46,0x3f,0x42,
|
||||
0x02,0xd0,0x2f,0x78,0xbf,0x08,0x25,0xd3,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,
|
||||
0xdf,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,
|
||||
0x1a,0x4f,0x5f,0x61,0x9a,0x61,0x9f,0x68,0x1b,0x4f,0x00,0x2f,0x14,0xd0,0xbc,0x42,
|
||||
0xfa,0xd0,0x27,0x78,0x2f,0x70,0x01,0x34,0x4c,0x45,0x00,0xd3,0x44,0x46,0x17,0xa7,
|
||||
0x3c,0x60,0x01,0x32,0x01,0x38,0x01,0xd4,0x0a,0x42,0xed,0xd1,0x9f,0x68,0xbf,0x08,
|
||||
0xfc,0xd3,0xa4,0xe7,0x00,0x20,0x02,0x38,0x01,0x30,0x02,0x25,0x1f,0x68,0x2f,0x43,
|
||||
0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
123
doc/openocd.texi
123
doc/openocd.texi
@@ -5253,6 +5253,18 @@ it has been removed by the @option{unlock} flag.
|
||||
|
||||
@end deffn
|
||||
|
||||
@deffn Command {flash verify_image} filename [offset] [type]
|
||||
Verify the image @file{filename} to the current target's flash bank(s).
|
||||
Parameters follow the description of 'flash write_image'.
|
||||
In contrast to the 'verify_image' command, for banks with specific
|
||||
verify method, that one is used instead of the usual target's read
|
||||
memory methods. This is necessary for flash banks not readable by
|
||||
ordinary memory reads.
|
||||
This command gives only an overall good/bad result for each bank, not
|
||||
addresses of individual failed bytes as it's intended only as quick
|
||||
check for successful programming.
|
||||
@end deffn
|
||||
|
||||
@section Other Flash commands
|
||||
@cindex flash protection
|
||||
|
||||
@@ -5511,6 +5523,117 @@ flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME
|
||||
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} stmqspi
|
||||
@cindex STMicroelectronics QuadSPI/OctoSPI Interface
|
||||
@cindex QuadSPI
|
||||
@cindex OctoSPI
|
||||
@cindex stmqspi
|
||||
Some devices from STMicroelectronics include a proprietary ``QuadSPI Interface''
|
||||
(e.g. STM32F4, STM32F7, STM32L4) or ``OctoSPI Interface'' (e.g. STM32L4+)
|
||||
controller able to drive one or even two (dual mode) external SPI flash devices.
|
||||
The OctoSPI is a superset of QuadSPI, its presence is detected automatically.
|
||||
Currently only the regular command mode is supported, whereas the HyperFlash
|
||||
mode is not.
|
||||
|
||||
QuadSPI/OctoSPI makes the flash contents directly accessible in the CPU address
|
||||
space; in case of dual mode both devices must be of the same type and are
|
||||
mapped in the same memory bank (even and odd addresses interleaved).
|
||||
CPU can directly read data, execute code (but not boot) from QuadSPI bank.
|
||||
|
||||
The 'flash bank' command only requires the @var{base} parameter and the extra
|
||||
parameter @var{io_base} in order to identify the memory bank. Both are fixed
|
||||
by hardware, see datasheet or RM. All other parameters are ignored.
|
||||
|
||||
The controller must be initialized after each reset and properly configured
|
||||
for memory-mapped read operation for the particular flash chip(s), for the full
|
||||
list of available register settings cf. the controller's RM. This setup is quite
|
||||
board specific (that's why booting from this memory is not possible). The
|
||||
flash driver infers all parameters from current controller register values when
|
||||
'flash probe @var{bank_id}' is executed.
|
||||
|
||||
Normal OpenOCD commands like @command{mdw} can be used to display the flash content,
|
||||
but only after proper controller initialization as decribed above. However,
|
||||
due to a silicon bug in some devices, attempting to access the very last word
|
||||
should be avoided.
|
||||
|
||||
It is possible to use two (even different) flash chips alternatingly, if individual
|
||||
bank chip selects are available. For some package variants, this is not the case
|
||||
due to limited pin count. To switch from one to another, adjust FSEL bit accordingly
|
||||
and re-issue 'flash probe bank_id'. Note that the bank base address will @emph{not}
|
||||
change, so the address spaces of both devices will overlap. In dual flash mode
|
||||
both chips must be identical regarding size and most other properties.
|
||||
|
||||
Block or sector protection internal to the flash chip is not handled by this
|
||||
driver at all, but can be dealt with manually by the 'cmd' command, see below.
|
||||
The sector protection via 'flash protect' command etc. is completely internal to
|
||||
openocd, intended only to prevent accidental erase or overwrite and it does not
|
||||
persist across openocd invocations.
|
||||
|
||||
OpenOCD contains a hardcoded list of flash devices with their properties,
|
||||
these are auto-detected. If a device is not included in this list, SFDP discovery
|
||||
is attempted. If this fails or gives inappropriate results, manual setting is
|
||||
required (see 'set' command).
|
||||
|
||||
@example
|
||||
flash bank $_FLASHNAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000
|
||||
flash bank $_FLASHNAME stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400
|
||||
@end example
|
||||
|
||||
There are three specific commands
|
||||
@deffn Command {stmqspi mass_erase} bank_id
|
||||
Clears sector protections and performs a mass erase. Works only if there is no
|
||||
chip specific write protection engaged.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {stmqspi set} bank_id name total_size page_size read_cmd fread_cmd pprg_cmd mass_erase_cmd sector_size sector_erase_cmd
|
||||
Set flash parameters: @var{name} human readable string, @var{total_size} size
|
||||
in bytes, @var{page_size} is write page size. @var{read_cmd}, @var{fread_cmd} and @var{pprg_cmd}
|
||||
are commands for reading and page programming. @var{fread_cmd} is used in DPI and QPI modes,
|
||||
@var{read_cmd} in normal SPI (single line) mode. @var{mass_erase_cmd}, @var{sector_size}
|
||||
and @var{sector_erase_cmd} are optional.
|
||||
|
||||
This command is required if chip id is not hardcoded yet and e.g. for EEPROMs or FRAMs
|
||||
which don't support an id command.
|
||||
|
||||
In dual mode parameters of both chips are set identically. The parameters refer to
|
||||
a single chip, so the whole bank gets twice the specified capacity etc.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {stmqspi cmd} bank_id resp_num cmd_byte ...
|
||||
If @var{resp_num} is zero, sends command @var{cmd_byte} and following data
|
||||
bytes. In dual mode command byte is sent to @emph{both} chips but data bytes are
|
||||
sent @emph{alternatingly} to chip 1 and 2, first to flash 1, second to flash 2, etc.,
|
||||
i.e. the total number of bytes (including cmd_byte) must be odd.
|
||||
|
||||
If @var{resp_num} is not zero, cmd and at most four following data bytes are
|
||||
sent, in dual mode @emph{simultaneously} to both chips. Then @var{resp_num} bytes
|
||||
are read interleaved from both chips starting with chip 1. In this case
|
||||
@var{resp_num} must be even.
|
||||
|
||||
Note the hardware dictated subtle difference of those two cases in dual-flash mode.
|
||||
|
||||
To check basic communication settings, issue
|
||||
@example
|
||||
stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 1 0x05; stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 1 0x05
|
||||
@end example
|
||||
for single flash mode or
|
||||
@example
|
||||
stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 2 0x05; stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 2 0x05
|
||||
@end example
|
||||
for dual flash mode. This should return the status register contents.
|
||||
|
||||
In 8-line mode, @var{cmd_byte} is sent twice - first time as given, second time
|
||||
complemented. Additionally, in 8-line mode only, some commands (e.g. Read Status)
|
||||
need a dummy address, e.g.
|
||||
@example
|
||||
stmqspi cmd bank_id 1 0x05 0x00 0x00 0x00 0x00
|
||||
@end example
|
||||
should return the status register contents.
|
||||
|
||||
@end deffn
|
||||
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} mrvlqspi
|
||||
This driver supports QSPI flash controller of Marvell's Wireless
|
||||
Microcontroller platform.
|
||||
|
||||
@@ -52,10 +52,12 @@ NOR_DRIVERS = \
|
||||
%D%/psoc5lp.c \
|
||||
%D%/psoc6.c \
|
||||
%D%/renesas_rpchf.c \
|
||||
%D%/sfdp.c \
|
||||
%D%/sh_qspi.c \
|
||||
%D%/sim3x.c \
|
||||
%D%/spi.c \
|
||||
%D%/stmsmi.c \
|
||||
%D%/stmqspi.c \
|
||||
%D%/stellaris.c \
|
||||
%D%/stm32f1x.c \
|
||||
%D%/stm32f2x.c \
|
||||
@@ -83,6 +85,8 @@ NORHEADERS = \
|
||||
%D%/imp.h \
|
||||
%D%/non_cfi.h \
|
||||
%D%/ocl.h \
|
||||
%D%/sfdp.h \
|
||||
%D%/spi.h \
|
||||
%D%/stm32l4x.h \
|
||||
%D%/stmqspi.h \
|
||||
%D%/msp432.h
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user