Flash, FRAM and EEPROM driver for STM32 QUAD-/OCTOSPI interface
[openocd.git] / contrib / loaders / flash / stmqspi / stmoctospi_write.S
1 /***************************************************************************
2 * Copyright (C) 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 - OCTOSPI io_base
30 * r8 - fifo start
31 * r9 - fifo end + 1
32
33 * Clobbered:
34 * r4 - rp
35 * r5 - address of OCTOSPI_DR
36 * r6 - address of OCTOSPI_CCR
37 * r7 - tmp
38 * r10 - single 0x0 / dual 0x1
39 */
40
41 #include "../../../../src/flash/nor/stmqspi.h"
42
43 #define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR)
44 #define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR)
45 #define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR)
46
47 .macro octospi_abort
48 movs r5, #(1<<SPI_ABORT) /* abort bit mask */
49 ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI CR register */
50 orrs r7, r7, r5 /* set abort bit */
51 str r7, [r3, #OCTOSPI_CR] /* store new CR register */
52 .endm
53
54 .macro wait_busy
55 0:
56 ldr r7, [r3, #OCTOSPI_SR] /* load status */
57 lsrs r7, r7, #(SPI_BUSY+1) /* shift BUSY into C */
58 bcs 0b /* loop until BUSY cleared */
59 movs r7, #(1<<SPI_TCF) /* TCF bitmask */
60 str r7, [r3, #OCTOSPI_FCR] /* clear TCF flag */
61 .endm
62
63 start:
64 subs r0, r0, #1 /* decrement count for DLR */
65 subs r1, r1, #1 /* page size mask and for DLR */
66 ldr r4, rp /* load rp */
67 ldr r7, [r3, #OCTOSPI_CR] /* get OCTOSPI_CR register */
68 lsls r7, r7, #(31-SPI_DUAL_FLASH) /* clear higher order bits */
69 lsrs r7, r7, #31 /* DUAL_FLASH bit into bit 0 */
70 mov r10, r7 /* save in r10 */
71 wip_loop:
72 octospi_abort /* start in clean state */
73 movs r5, #OCTOSPI_DR /* load OCTOSPI_DR address offset */
74 adds r5, r5, r3 /* address of OCTOSPI_DR */
75 movs r6, #OCTOSPI_CCR-OCTOSPI_DR /* load OCTOSPI_CCR address offset */
76 adds r6, r6, r5 /* address of OCTOSPI_CCR */
77 wait_busy
78 ldr r7, cr_read_status /* indirect read mode */
79 str r7, [r3, #OCTOSPI_CR] /* set mode */
80 mov r7, r10 /* get dual bit */
81 str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
82 ldr r7, ccr_read_status /* CCR for status read */
83 str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
84 ldr r7, tcr_read_status /* TCR for status read */
85 str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
86 ldr r7, ir_read_status /* IR for status read */
87 str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
88 movs r7, #0 /* dummy address */
89 str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
90 ldrb r7, [r5] /* get first status register */
91 lsrs r7, r7, #(SPIFLASH_BSY+1) /* if first flash busy, */
92 bcs wip_loop /* then poll again */
93 mov r7, r10 /* get dual bit */
94 tst r7, r7 /* dual mode ? */
95 beq write_enable /* not dual, then ok */
96 ldrb r7, [r5] /* get second status register */
97 lsrs r7, r7, #(SPIFLASH_BSY+1) /* if second flash busy, */
98 bcs wip_loop /* then poll again */
99 write_enable:
100 tst r0, r0 /* test residual count */
101 bmi exit /* if negative, then finished */
102 wait_busy
103 ldr r7, cr_write_enable /* indirect write mode */
104 str r7, [r3, #OCTOSPI_CR] /* set mode */
105 ldr r7, ccr_write_enable /* CCR for write enable */
106 str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate write enable */
107 ldr r7, tcr_write_enable /* TCR for write enable */
108 str r7, [r6, #OCTOSPI_TCR_CCR] /* write enable instruction */
109 ldr r7, ir_write_enable /* IR for write enable */
110 str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
111 movs r7, #0 /* silicon bug in L5? dummy write */
112 str r7, [r3, #OCTOSPI_AR] /* into AR resolves issue */
113 wait_busy
114 ldr r7, cr_read_status /* indirect read mode */
115 str r7, [r3, #OCTOSPI_CR] /* set mode */
116 mov r7, r10 /* get dual count */
117 str r7, [r3, #OCTOSPI_DLR] /* one or two (for dual) bytes */
118 ldr r7, ccr_read_status /* CCR for status read */
119 str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate status read */
120 ldr r7, tcr_read_status /* TCR for status read */
121 str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
122 ldr r7, ir_read_status /* IR for status read */
123 str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
124 movs r7, #0 /* dummy address */
125 str r7, [r3, #OCTOSPI_AR] /* into AR (for 8-line mode) */
126 ldrb r7, [r5] /* get first status register */
127 lsrs r7, r7, #(SPIFLASH_WE+1) /* if first flash not */
128 bcc error /* write enabled, then error */
129 mov r7, r10 /* get dual bit */
130 tst r7, r7 /* dual mode ? */
131 beq start_write /* not dual, then ok */
132 ldrb r7, [r5] /* get second status register */
133 lsrs r7, r7, #(SPIFLASH_WE+1) /* if second flash not */
134 bcc error /* write enabled, then error */
135 start_write:
136 wait_busy
137 ldr r7, cr_page_write /* indirect write mode */
138 str r7, [r3, #OCTOSPI_CR] /* set mode */
139 mov r7, r2 /* get current start address */
140 orrs r7, r7, r1 /* end of current page */
141 subs r7, r7, r2 /* count-1 to end of page */
142 cmp r7, r0 /* if this count <= remaining */
143 bls write_dlr /* then write to end of page */
144 mov r7, r0 /* else write all remaining */
145 write_dlr:
146 str r7, [r3, #OCTOSPI_DLR] /* size-1 in DLR register */
147 ldr r7, ccr_page_write /* CCR for page write */
148 str r7, [r6, #OCTOSPI_CCR_CCR] /* initiate transfer */
149 ldr r7, tcr_page_write /* TCR for page write */
150 str r7, [r6, #OCTOSPI_TCR_CCR] /* instruction */
151 ldr r7, ir_page_write /* IR for page write */
152 str r7, [r6, #OCTOSPI_IR_CCR] /* instruction */
153 str r2, [r3, #OCTOSPI_AR] /* store SPI start address */
154 write_loop:
155 ldr r7, wp /* get wp */
156 cmp r7, #0 /* if wp equals 0 */
157 beq exit /* then abort */
158 cmp r4, r7 /* check if fifo empty */
159 beq write_loop /* wait until not empty */
160 ldrb r7, [r4, #0] /* read next byte */
161 strb r7, [r5] /* write next byte to DR */
162 adds r4, r4, #1 /* increment internal rp */
163 cmp r4, r9 /* internal rp beyond end? */
164 blo upd_write /* if no, then ok */
165 mov r4, r8 /* else wrap around */
166 upd_write:
167 adr r7, rp /* get address of rp */
168 str r4, [r7] /* store updated rp */
169 adds r2, r2, #1 /* increment address */
170 subs r0, r0, #1 /* decrement (count-1) */
171 bmi page_end /* stop if no data left */
172 tst r2, r1 /* page end ? */
173 bne write_loop /* if not, then next byte */
174 page_end:
175 ldr r7, [r3, #OCTOSPI_SR] /* load status */
176 lsrs r7, r7, #(SPI_TCF+1) /* shift TCF into C */
177 bcc page_end /* loop until TCF set */
178 bal wip_loop /* then next page */
179
180 error:
181 movs r0, #0 /* return 0xFFFFFFFF */
182 subs r0, r0, #2 /* for error */
183 exit:
184 adds r0, r0, #1 /* increment count due to the -1 */
185 octospi_abort /* to idle state */
186 .align 2 /* align to word, bkpt is 4 words */
187 bkpt #0 /* before code end for exit_point */
188 .align 2 /* align to word */
189
190 cr_read_status:
191 .space 4 /* OCTOSPI_CR value for READ_STATUS command */
192 ccr_read_status:
193 .space 4 /* OCTOSPI_CCR value for READ_STATUS command */
194 tcr_read_status:
195 .space 4 /* OCTOSPI_TCR value for READ_STATUS command */
196 ir_read_status:
197 .space 4 /* OCTOSPI_IR value for READ_STATUS command */
198
199 cr_write_enable:
200 .space 4 /* OCTOSPI_CR value for WRITE_ENABLE command */
201 ccr_write_enable:
202 .space 4 /* OCTOSPI_CCR value for WRITE_ENABLE command */
203 tcr_write_enable:
204 .space 4 /* OCTOSPI_TCR value for WRITE_ENABLE command */
205 ir_write_enable:
206 .space 4 /* OCTOSPI_IR value for WRITE_ENABLE command */
207
208 cr_page_write:
209 .space 4 /* OCTOSPI_CR value for PAGE_PROG command */
210 ccr_page_write:
211 .space 4 /* OCTOSPI_CCR value for PAGE_PROG command */
212 tcr_page_write:
213 .space 4 /* OCTOSPI_TCR value for PAGE_PROG command */
214 ir_page_write:
215 .space 4 /* OCTOSPI_IR value for PAGE_PROG command */
216
217 .equ wp, . /* wp, uint32_t */
218 .equ rp, wp + 4 /* rp, uint32_t */
219 .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)