1 /***************************************************************************
2 * Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com> *
4 * Adapted from (contrib/loaders/flash/lpcspifi_write.S): *
5 * Copyright (C) 2012 by George Harris *
6 * george@luminairecoffee.com *
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. *
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. *
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 ***************************************************************************/
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
39 * r0 = workarea start, status (out)
41 * r2 = target address (offset from flash base)
44 * r5 = qspi base address
48 * r9 - send/receive data
49 * r10 - current page end address
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)
72 #define INS_WRITE_ENABLE 0x06
73 #define INS_READ_STATUS 0x05
74 #define INS_PAGE_PROGRAM 0x02
78 find_next_page_boundary:
79 add r10, r4 /* Increment to the next page */
81 /* If we have not reached the next page boundary after the target address, keep going */
82 bls find_next_page_boundary
84 /* Flush read/write fifo's */
87 /* Instruction byte 1 */
91 /* Set write enable instruction */
92 movs r8, #INS_WRITE_ENABLE
99 /* Instruction byte 1, Addr byte 3 */
101 str r8, [r5, #HDRCNT]
102 /* Todo: set addr and data pin to single */
106 /* Set page program instruction */
107 movs r8, #INS_PAGE_PROGRAM
109 /* Start write transfer */
113 ldr r8, [r0] /* read the write pointer */
114 cmp r8, #0 /* if it's zero, we're gonzo */
116 ldr r7, [r0, #4] /* read the read pointer */
117 cmp r7, r8 /* wait until they are not equal */
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 */
123 cmp r7, r1 /* wrap the read pointer if it is at the end */
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 */
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 */
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 */
139 /* Instruction byte 1 */
141 str r8, [r5, #HDRCNT]
142 /* Continuous data in of status register */
144 str r8, [r5, #DINCNT]
145 /* Set write enable instruction */
146 movs r8, #INS_READ_STATUS
148 /* Start read transfer */
155 bne.n wait_flash_busy
158 bne.n write_enable /* If it is done, start a new page write */
159 b exit /* All data written, exit */
161 write_data: /* Send/receive 1 byte of data over QSPI */
168 read_data: /* Read 1 byte of data over QSPI */
175 flush_fifo: /* Flush read write fifos */
177 orr.w r8, r8, #FIFO_FLUSH
195 orr.w r8, r8, #XFER_START
208 orr.w r8, r8, #XFER_STOP
227 str r0, [r2, #4] /* set rp = 0 on error */