contrib: replace the GPLv2-or-later license tag
[fw/openocd] / 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 */