1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2016 - 2018 by Andreas Bolsch *
5 * andreas.bolsch@mni.thm.de *
6 ***************************************************************************/
15 * r0 - total count (bytes), remaining bytes (out, 0 means successful)
16 * r1 - flash page size
17 * r2 - address offset into flash
24 * r5 - address of QSPI_DR
26 * r10 - single 0x0 / dual 0x1
29 #include "../../../../src/flash/nor/stmqspi.h"
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 */
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 */
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 */
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 */
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 */
75 tst r0, r0 /* test residual count */
76 bmi exit /* if negative, then finished */
78 ldr r7, ccr_write_enable /* CCR for write enable */
79 str r7, [r3, #QSPI_CCR] /* initiate write enable */
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 */
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 */
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 */
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 */
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 */
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 */
136 movs r0, #0 /* return 0xFFFFFFFF */
137 subs r0, r0, #2 /* for error */
139 adds r0, r0, #1 /* increment count due to the -1 */
140 qspi_abort /* to idle state */
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 */
146 .space 4 /* not used */
148 .space 4 /* QSPI_CCR value for READ_STATUS command */
149 .space 4 /* not used */
150 .space 4 /* not used */
152 .space 4 /* not used */
154 .space 4 /* QSPI_CCR value for WRITE_ENABLE command */
155 .space 4 /* not used */
156 .space 4 /* not used */
158 .space 4 /* not used */
160 .space 4 /* QSPI_CCR value for PAGE_PROG command */
161 .space 4 /* not used */
162 .space 4 /* not used */
164 .equ wp, . /* wp, uint32_t */
165 .equ rp, wp + 4 /* rp, uint32_t */
166 .equ buffer, rp + 4 /* buffer follows right away */