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