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