1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com> *
6 * Adapted from (contrib/loaders/flash/lpcspifi_write.S): *
7 * Copyright (C) 2012 by George Harris *
8 * george@luminairecoffee.com *
9 ***************************************************************************/
19 * arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c contrib/loaders/flash/mrvlqspi_write.S
20 * arm-none-eabi-objcopy -O binary mrvlqspi_write.o code.bin
21 * Copy code.bin into mrvlqspi flash driver
26 * r0 = workarea start, status (out)
28 * r2 = target address (offset from flash base)
31 * r5 = qspi base address
35 * r9 - send/receive data
36 * r10 - current page end address
49 #define SS_EN (1 << 0)
50 #define XFER_RDY (1 << 1)
51 #define RFIFO_EMPTY (1 << 4)
52 #define WFIFO_EMPTY (1 << 6)
53 #define WFIFO_FULL (1 << 7)
54 #define FIFO_FLUSH (1 << 9)
55 #define RW_EN (1 << 13)
56 #define XFER_STOP (1 << 14)
57 #define XFER_START (1 << 15)
59 #define INS_WRITE_ENABLE 0x06
60 #define INS_READ_STATUS 0x05
61 #define INS_PAGE_PROGRAM 0x02
65 find_next_page_boundary:
66 add r10, r4 /* Increment to the next page */
68 /* If we have not reached the next page boundary after the target address, keep going */
69 bls find_next_page_boundary
71 /* Flush read/write fifos */
74 /* Instruction byte 1 */
78 /* Set write enable instruction */
79 movs r8, #INS_WRITE_ENABLE
86 /* Instruction byte 1, Addr byte 3 */
89 /* Todo: set addr and data pin to single */
93 /* Set page program instruction */
94 movs r8, #INS_PAGE_PROGRAM
96 /* Start write transfer */
100 ldr r8, [r0] /* read the write pointer */
101 cmp r8, #0 /* if it's zero, we're gonzo */
103 ldr r7, [r0, #4] /* read the read pointer */
104 cmp r7, r8 /* wait until they are not equal */
107 ldrb r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */
108 bl write_data /* send the byte to the flash chip */
110 cmp r7, r1 /* wrap the read pointer if it is at the end */
112 addcs r7, r0, #8 /* skip loader args */
113 str r7, [r0, #4] /* store the new read pointer */
114 subs r3, r3, #1 /* decrement count */
115 cmp r3, #0 /* Exit if we have written everything */
117 add r2, #1 /* Increment flash address by 1 */
118 cmp r10, r2 /* See if we have reached the end of a page */
119 bne wait_fifo /* If not, keep writing bytes */
121 bl stop_tx /* Otherwise, end the command and keep going w/ the next page */
122 add r10, r4 /* Move up the end-of-page address by the page size*/
123 check_flash_busy: /* Wait for the flash to finish the previous page write */
124 /* Flush read/write fifos */
126 /* Instruction byte 1 */
128 str r8, [r5, #HDRCNT]
129 /* Continuous data in of status register */
131 str r8, [r5, #DINCNT]
132 /* Set write enable instruction */
133 movs r8, #INS_READ_STATUS
135 /* Start read transfer */
142 bne.n wait_flash_busy
145 bne.n write_enable /* If it is done, start a new page write */
146 b exit /* All data written, exit */
148 write_data: /* Send/receive 1 byte of data over QSPI */
155 read_data: /* Read 1 byte of data over QSPI */
162 flush_fifo: /* Flush read write fifos */
164 orr.w r8, r8, #FIFO_FLUSH
182 orr.w r8, r8, #XFER_START
195 orr.w r8, r8, #XFER_STOP
214 str r0, [r2, #4] /* set rp = 0 on error */