aboutsummaryrefslogtreecommitdiff
path: root/contrib/loaders/flash/mrvlqspi_write.S
blob: 064192c9c1ff5f78a594cc9d96ba5f427d30ab59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/***************************************************************************
 *   Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com>                *
 *                                                                         *
 *   Adapted from (contrib/loaders/flash/lpcspifi_write.S):                *
 *   Copyright (C) 2012 by George Harris                                   *
 *   george@luminairecoffee.com                                            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
 ***************************************************************************/

	.text
	.syntax unified
	.cpu cortex-m3
	.thumb
	.thumb_func

/*
 * For compilation:
 * arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c contrib/loaders/flash/mrvlqspi_write.S
 * arm-none-eabi-objcopy -O binary mrvlqspi_write.o code.bin
 * Copy code.bin into mrvlqspi flash driver
 */

/*
 * Params :
 * r0 = workarea start, status (out)
 * r1 = workarea end
 * r2 = target address (offset from flash base)
 * r3 = count (bytes)
 * r4 = page size
 * r5 = qspi base address
 * Clobbered:
 * r7 - rp
 * r8 - wp, tmp
 * r9 - send/receive data
 * r10 - current page end address
 */

#define CNTL	0x0
#define CONF	0x4
#define DOUT	0x8
#define DIN	0xc
#define INSTR   0x10
#define ADDR    0x14
#define RDMODE  0x18
#define HDRCNT	0x1c
#define DINCNT  0x20

#define SS_EN (1 << 0)
#define XFER_RDY (1 << 1)
#define RFIFO_EMPTY (1 << 4)
#define WFIFO_EMPTY (1 << 6)
#define WFIFO_FULL (1 << 7)
#define FIFO_FLUSH (1 << 9)
#define RW_EN (1 << 13)
#define XFER_STOP (1 << 14)
#define XFER_START (1 << 15)

#define INS_WRITE_ENABLE 0x06
#define INS_READ_STATUS 0x05
#define INS_PAGE_PROGRAM 0x02

init:
	mov.w 	r10, #0x00
find_next_page_boundary:
	add 	r10, r4		/* Increment to the next page */
	cmp 	r10, r2
	/* If we have not reached the next page boundary after the target address, keep going */
	bls 	find_next_page_boundary
write_enable:
	/* Flush read/write fifo's */
	bl 	flush_fifo

	/* Instruction byte 1 */
	movs 	r8, #0x1
	str 	r8, [r5, #HDRCNT]

	/* Set write enable instruction */
	movs 	r8, #INS_WRITE_ENABLE
	str 	r8, [r5, #INSTR]

	movs	r9, #0x1
	bl	start_tx
	bl 	stop_tx
page_program:
	/* Instruction byte 1, Addr byte 3 */
	movs 	r8, #0x31
	str 	r8, [r5, #HDRCNT]
	/* Todo: set addr and data pin to single */
write_address:
	mov 	r8, r2
	str 	r8, [r5, #ADDR]
	/* Set page program instruction */
	movs 	r8, #INS_PAGE_PROGRAM
	str 	r8, [r5, #INSTR]
	/* Start write transfer */
	movs	r9, #0x1
	bl	start_tx
wait_fifo:
	ldr 	r8, [r0]  	/* read the write pointer */
	cmp 	r8, #0 		/* if it's zero, we're gonzo */
	beq 	exit
	ldr 	r7, [r0, #4] 	/* read the read pointer */
	cmp 	r7, r8 		/* wait until they are not equal */
	beq 	wait_fifo
write:
	ldrb 	r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */
	bl 	write_data 	/* send the byte to the flash chip */

	cmp 	r7, r1		/* wrap the read pointer if it is at the end */
	it  	cs
	addcs	r7, r0, #8	/* skip loader args */
	str 	r7, [r0, #4]	/* store the new read pointer */
	subs	r3, r3, #1	/* decrement count */
	cmp	r3, #0 		/* Exit if we have written everything */
	beq	write_wait
	add 	r2, #1 		/* Increment flash address by 1 */
	cmp 	r10, r2   	/* See if we have reached the end of a page */
	bne 	wait_fifo 	/* If not, keep writing bytes */
write_wait:
	bl 	stop_tx		/* Otherwise, end the command and keep going w/ the next page */
	add 	r10, r4 	/* Move up the end-of-page address by the page size*/
check_flash_busy:		/* Wait for the flash to finish the previous page write */
	/* Flush read/write fifo's */
	bl 	flush_fifo
	/* Instruction byte 1 */
	movs 	r8, #0x1
	str 	r8, [r5, #HDRCNT]
	/* Continuous data in of status register */
	movs	r8, #0x0
	str 	r8, [r5, #DINCNT]
	/* Set write enable instruction */
	movs 	r8, #INS_READ_STATUS
	str 	r8, [r5, #INSTR]
	/* Start read transfer */
	movs	r9, #0x0
	bl	start_tx
wait_flash_busy:
	bl 	read_data
	and.w	r9, r9, #0x1
	cmp	r9, #0x0
	bne.n	wait_flash_busy
	bl 	stop_tx
	cmp	r3, #0
	bne.n 	write_enable 	/* If it is done, start a new page write */
	b	exit		/* All data written, exit */

write_data: 			/* Send/receive 1 byte of data over QSPI */
	ldr	r8, [r5, #CNTL]
	lsls    r8, r8, #24
	bmi.n	write_data
	str 	r9, [r5, #DOUT]
	bx	lr

read_data:			/* Read 1 byte of data over QSPI */
	ldr	r8, [r5, #CNTL]
	lsls    r8, r8, #27
	bmi.n	read_data
	ldr	r9, [r5, #DIN]
	bx	lr

flush_fifo:			/* Flush read write fifos */
	ldr	r8, [r5, #CONF]
	orr.w   r8, r8, #FIFO_FLUSH
	str     r8, [r5, #CONF]
flush_reset:
	ldr	r8, [r5, #CONF]
	lsls    r8, r8, #22
	bmi.n	flush_reset
	bx	lr

start_tx:
	ldr	r8, [r5, #CNTL]
	orr.w	r8, r8, #SS_EN
	str	r8, [r5, #CNTL]
xfer_rdy:
	ldr	r8, [r5, #CNTL]
	lsls    r8, r8, #30
	bpl.n	xfer_rdy
	ldr	r8, [r5, #CONF]
	bfi	r8, r9, #13, #1
	orr.w	r8, r8, #XFER_START
	str	r8, [r5, #CONF]
	bx lr

stop_tx:
	ldr	r8, [r5, #CNTL]
	lsls    r8, r8, #30
	bpl.n	stop_tx
wfifo_wait:
	ldr	r8, [r5, #CNTL]
	lsls    r8, r8, #25
	bpl.n	wfifo_wait
	ldr	r8, [r5, #CONF]
	orr.w	r8, r8, #XFER_STOP
	str	r8, [r5, #CONF]
xfer_start:
	ldr	r8, [r5, #CONF]
	lsls	r8, r8, #16
	bmi.n 	xfer_start
ss_disable:
	# Disable SS_EN
	ldr	r8, [r5, #CNTL]
	bic.w	r8, r8, #SS_EN
	str	r8, [r5, #CNTL]
wait:
	ldr	r8, [r5, #CNTL]
	lsls    r8, r8, #30
	bpl.n	wait
	bx 	lr

error:
	movs	r0, #0
	str 	r0, [r2, #4]	/* set rp = 0 on error */
exit:
	mov 	r0, r6
	bkpt 	#0x00

	.end