Flash, FRAM and EEPROM driver for STM32 QUAD-/OCTOSPI interface
[openocd.git] / contrib / loaders / flash / stmqspi / stmqspi_write.S
1 /***************************************************************************
2 * Copyright (C) 2016 - 2018 by Andreas Bolsch *
3 * andreas.bolsch@mni.thm.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 .text
20 .syntax unified
21 .cpu cortex-m0
22 .thumb
23 .thumb_func
24
25 /* Params:
26 * r0 - total count (bytes), remaining bytes (out, 0 means successful)
27 * r1 - flash page size
28 * r2 - address offset into flash
29 * r3 - QSPI io_base
30 * r8 - fifo start
31 * r9 - fifo end + 1
32
33 * Clobbered:
34 * r4 - rp
35 * r5 - address of QSPI_DR
36 * r7 - tmp
37 * r10 - single 0x0 / dual 0x1
38 */
39
40 #include "../../../../src/flash/nor/stmqspi.h"
41
42 .macro qspi_abort
43 movs r5, #(1<<SPI_ABORT) /* abort bit mask */
44 ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
45 orrs r7, r7, r5 /* set abort bit */
46 str r7, [r3, #QSPI_CR] /* store new CR register */
47 .endm
48
49 .macro wait_busy
50 0:
51 ldr r7, [r3, #QSPI_SR] /* load status */
52 lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
53 bcs 0b /* loop until BUSY cleared */
54 movs r7, #(1<<SPI_TCF) /* TCF bitmask */
55 str r7, [r3, #QSPI_FCR] /* clear TCF flag */
56 .endm
57
58 start:
59 subs r0, r0, #1 /* decrement count for DLR */
60 subs r1, r1, #1 /* page size mask and for DLR */
61 ldr r4, rp /* load rp */
62 ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */
63 lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
64 lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
65 mov r10, r7 /* save in r10 */
66 wip_loop:
67 qspi_abort /* start in clean state */
68 movs r5, #QSPI_DR /* load QSPI_DR address offset */
69 adds r5, r5, r3 /* address of QSPI_DR */
70 wait_busy
71 mov r7, r10 /* get dual bit */
72 str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
73 ldr r7, ccr_read_status /* CCR for status read */
74 str r7, [r3, #QSPI_CCR] /* initiate status read */
75 ldr r7, [r3, #QSPI_SR] /* wait for command startup */
76 ldrb r7, [r5] /* get first status register */
77 lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
78 bcs wip_loop /* then poll again */
79 mov r7, r10 /* get dual bit */
80 tst r7, r7 /* dual mode ? */
81 beq write_enable /* not dual, then ok */
82 ldrb r7, [r5] /* get second status register */
83 lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
84 bcs wip_loop /* then poll again */
85 write_enable:
86 tst r0, r0 /* test residual count */
87 bmi exit /* if negative, then finished */
88 wait_busy
89 ldr r7, ccr_write_enable /* CCR for write enable */
90 str r7, [r3, #QSPI_CCR] /* initiate write enable */
91 wait_busy
92 mov r7, r10 /* get dual bit */
93 str r7, [r3, #QSPI_DLR] /* one or two (for dual) bytes */
94 ldr r7, ccr_read_status /* CCR for status read */
95 str r7, [r3, #QSPI_CCR] /* initiate status read */
96 ldr r7, [r3, #QSPI_SR] /* wait for command startup */
97 ldrb r7, [r5] /* get first status register */
98 lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
99 bcc error /* write enabled, then error */
100 mov r7, r10 /* get dual bit */
101 tst r7, r7 /* dual mode ? */
102 beq start_write /* not dual, then ok */
103 ldrb r7, [r5] /* get second status register */
104 lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
105 bcc error /* write enabled, then error */
106 start_write:
107 wait_busy
108 mov r7, r2 /* get current start address */
109 orrs r7, r7, r1 /* end of current page */
110 subs r7, r7, r2 /* count-1 to end of page */
111 cmp r7, r0 /* if this count <= remaining */
112 bls write_dlr /* then write to end of page */
113 mov r7, r0 /* else write all remaining */
114 write_dlr:
115 str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */
116 ldr r7, ccr_page_write /* CCR for page write */
117 str r7, [r3, #QSPI_CCR] /* initiate transfer */
118 str r2, [r3, #QSPI_AR] /* store SPI start address */
119 ldr r7, [r3, #QSPI_SR] /* wait for command startup */
120 write_loop:
121 ldr r7, wp /* get wp */
122 cmp r7, #0 /* if wp equals 0 */
123 beq exit /* then abort */
124 cmp r4, r7 /* check if fifo empty */
125 beq write_loop /* wait until not empty */
126 ldrb r7, [r4, #0] /* read next byte */
127 strb r7, [r5] /* write next byte to DR */
128 adds r4, r4, #1 /* increment internal rp */
129 cmp r4, r9 /* internal rp beyond end? */
130 blo upd_write /* if no, then ok */
131 mov r4, r8 /* else wrap around */
132 upd_write:
133 adr r7, rp /* get address of rp */
134 str r4, [r7] /* store updated rp */
135 adds r2, r2, #1 /* increment address */
136 subs r0, r0, #1 /* decrement (count-1) */
137 bmi page_end /* stop if no data left */
138 tst r2, r1 /* page end ? */
139 bne write_loop /* if not, then next byte */
140 page_end:
141 ldr r7, [r3, #QSPI_SR] /* load status */
142 lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
143 bcc page_end /* loop until TCF set */
144 bal wip_loop /* then next page */
145
146 error:
147 movs r0, #0 /* return 0xFFFFFFFF */
148 subs r0, r0, #2 /* for error */
149 exit:
150 adds r0, r0, #1 /* increment count due to the -1 */
151 qspi_abort /* to idle state */
152
153 .align 2 /* align to word, bkpt is 4 words */
154 bkpt #0 /* before code end for exit_point */
155 .align 2 /* align to word */
156
157 .space 4 /* not used */
158 ccr_read_status:
159 .space 4 /* QSPI_CCR value for READ_STATUS command */
160 .space 4 /* not used */
161 .space 4 /* not used */
162
163 .space 4 /* not used */
164 ccr_write_enable:
165 .space 4 /* QSPI_CCR value for WRITE_ENABLE command */
166 .space 4 /* not used */
167 .space 4 /* not used */
168
169 .space 4 /* not used */
170 ccr_page_write:
171 .space 4 /* QSPI_CCR value for PAGE_PROG command */
172 .space 4 /* not used */
173 .space 4 /* not used */
174
175 .equ wp, . /* wp, uint32_t */
176 .equ rp, wp + 4 /* rp, uint32_t */
177 .equ buffer, rp + 4 /* buffer follows right away */

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)