]> git.sur5r.net Git - openocd/blob - contrib/loaders/flash/mrvlqspi_write.S
flash/nor: add mrvlqspi flash controller driver
[openocd] / contrib / loaders / flash / mrvlqspi_write.S
1 /***************************************************************************
2  *   Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com>                *
3  *                                                                         *
4  *   Adapted from (contrib/loaders/flash/lpcspifi_write.S):                *
5  *   Copyright (C) 2012 by George Harris                                   *
6  *   george@luminairecoffee.com                                            *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  *   This program is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
16  *   GNU General Public License for more details.                          *
17  *                                                                         *
18  *   You should have received a copy of the GNU General Public License     *
19  *   along with this program; if not, write to the                         *
20  *   Free Software Foundation, Inc.,                                       *
21  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
22  ***************************************************************************/
23
24         .text
25         .syntax unified
26         .cpu cortex-m3
27         .thumb
28         .thumb_func
29
30 /*
31  * For compilation:
32  * arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c contrib/loaders/flash/mrvlqspi_write.S
33  * arm-none-eabi-objcopy -O binary mrvlqspi_write.o code.bin
34  * Copy code.bin into mrvlqspi flash driver
35  */
36
37 /*
38  * Params :
39  * r0 = workarea start, status (out)
40  * r1 = workarea end
41  * r2 = target address (offset from flash base)
42  * r3 = count (bytes)
43  * r4 = page size
44  * r5 = qspi base address
45  * Clobbered:
46  * r7 - rp
47  * r8 - wp, tmp
48  * r9 - send/receive data
49  * r10 - current page end address
50  */
51
52 #define CNTL    0x0
53 #define CONF    0x4
54 #define DOUT    0x8
55 #define DIN     0xc
56 #define INSTR   0x10
57 #define ADDR    0x14
58 #define RDMODE  0x18
59 #define HDRCNT  0x1c
60 #define DINCNT  0x20
61
62 #define SS_EN (1 << 0)
63 #define XFER_RDY (1 << 1)
64 #define RFIFO_EMPTY (1 << 4)
65 #define WFIFO_EMPTY (1 << 6)
66 #define WFIFO_FULL (1 << 7)
67 #define FIFO_FLUSH (1 << 9)
68 #define RW_EN (1 << 13)
69 #define XFER_STOP (1 << 14)
70 #define XFER_START (1 << 15)
71
72 #define INS_WRITE_ENABLE 0x06
73 #define INS_READ_STATUS 0x05
74 #define INS_PAGE_PROGRAM 0x02
75
76 init:
77         mov.w   r10, #0x00
78 find_next_page_boundary:
79         add     r10, r4         /* Increment to the next page */
80         cmp     r10, r2
81         /* If we have not reached the next page boundary after the target address, keep going */
82         bls     find_next_page_boundary
83 write_enable:
84         /* Flush read/write fifo's */
85         bl      flush_fifo
86
87         /* Instruction byte 1 */
88         movs    r8, #0x1
89         str     r8, [r5, #HDRCNT]
90
91         /* Set write enable instruction */
92         movs    r8, #INS_WRITE_ENABLE
93         str     r8, [r5, #INSTR]
94
95         movs    r9, #0x1
96         bl      start_tx
97         bl      stop_tx
98 page_program:
99         /* Instruction byte 1, Addr byte 3 */
100         movs    r8, #0x31
101         str     r8, [r5, #HDRCNT]
102         /* Todo: set addr and data pin to single */
103 write_address:
104         mov     r8, r2
105         str     r8, [r5, #ADDR]
106         /* Set page program instruction */
107         movs    r8, #INS_PAGE_PROGRAM
108         str     r8, [r5, #INSTR]
109         /* Start write transfer */
110         movs    r9, #0x1
111         bl      start_tx
112 wait_fifo:
113         ldr     r8, [r0]        /* read the write pointer */
114         cmp     r8, #0          /* if it's zero, we're gonzo */
115         beq     exit
116         ldr     r7, [r0, #4]    /* read the read pointer */
117         cmp     r7, r8          /* wait until they are not equal */
118         beq     wait_fifo
119 write:
120         ldrb    r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */
121         bl      write_data      /* send the byte to the flash chip */
122
123         cmp     r7, r1          /* wrap the read pointer if it is at the end */
124         it      cs
125         addcs   r7, r0, #8      /* skip loader args */
126         str     r7, [r0, #4]    /* store the new read pointer */
127         subs    r3, r3, #1      /* decrement count */
128         cmp     r3, #0          /* Exit if we have written everything */
129         beq     write_wait
130         add     r2, #1          /* Increment flash address by 1 */
131         cmp     r10, r2         /* See if we have reached the end of a page */
132         bne     wait_fifo       /* If not, keep writing bytes */
133 write_wait:
134         bl      stop_tx         /* Otherwise, end the command and keep going w/ the next page */
135         add     r10, r4         /* Move up the end-of-page address by the page size*/
136 check_flash_busy:               /* Wait for the flash to finish the previous page write */
137         /* Flush read/write fifo's */
138         bl      flush_fifo
139         /* Instruction byte 1 */
140         movs    r8, #0x1
141         str     r8, [r5, #HDRCNT]
142         /* Continuous data in of status register */
143         movs    r8, #0x0
144         str     r8, [r5, #DINCNT]
145         /* Set write enable instruction */
146         movs    r8, #INS_READ_STATUS
147         str     r8, [r5, #INSTR]
148         /* Start read transfer */
149         movs    r9, #0x0
150         bl      start_tx
151 wait_flash_busy:
152         bl      read_data
153         and.w   r9, r9, #0x1
154         cmp     r9, #0x0
155         bne.n   wait_flash_busy
156         bl      stop_tx
157         cmp     r3, #0
158         bne.n   write_enable    /* If it is done, start a new page write */
159         b       exit            /* All data written, exit */
160
161 write_data:                     /* Send/receive 1 byte of data over QSPI */
162         ldr     r8, [r5, #CNTL]
163         lsls    r8, r8, #24
164         bmi.n   write_data
165         str     r9, [r5, #DOUT]
166         bx      lr
167
168 read_data:                      /* Read 1 byte of data over QSPI */
169         ldr     r8, [r5, #CNTL]
170         lsls    r8, r8, #27
171         bmi.n   read_data
172         ldr     r9, [r5, #DIN]
173         bx      lr
174
175 flush_fifo:                     /* Flush read write fifos */
176         ldr     r8, [r5, #CONF]
177         orr.w   r8, r8, #FIFO_FLUSH
178         str     r8, [r5, #CONF]
179 flush_reset:
180         ldr     r8, [r5, #CONF]
181         lsls    r8, r8, #22
182         bmi.n   flush_reset
183         bx      lr
184
185 start_tx:
186         ldr     r8, [r5, #CNTL]
187         orr.w   r8, r8, #SS_EN
188         str     r8, [r5, #CNTL]
189 xfer_rdy:
190         ldr     r8, [r5, #CNTL]
191         lsls    r8, r8, #30
192         bpl.n   xfer_rdy
193         ldr     r8, [r5, #CONF]
194         bfi     r8, r9, #13, #1
195         orr.w   r8, r8, #XFER_START
196         str     r8, [r5, #CONF]
197         bx lr
198
199 stop_tx:
200         ldr     r8, [r5, #CNTL]
201         lsls    r8, r8, #30
202         bpl.n   stop_tx
203 wfifo_wait:
204         ldr     r8, [r5, #CNTL]
205         lsls    r8, r8, #25
206         bpl.n   wfifo_wait
207         ldr     r8, [r5, #CONF]
208         orr.w   r8, r8, #XFER_STOP
209         str     r8, [r5, #CONF]
210 xfer_start:
211         ldr     r8, [r5, #CONF]
212         lsls    r8, r8, #16
213         bmi.n   xfer_start
214 ss_disable:
215         # Disable SS_EN
216         ldr     r8, [r5, #CNTL]
217         bic.w   r8, r8, #SS_EN
218         str     r8, [r5, #CNTL]
219 wait:
220         ldr     r8, [r5, #CNTL]
221         lsls    r8, r8, #30
222         bpl.n   wait
223         bx      lr
224
225 error:
226         movs    r0, #0
227         str     r0, [r2, #4]    /* set rp = 0 on error */
228 exit:
229         mov     r0, r6
230         bkpt    #0x00
231
232         .end