flash/nor/lpcspifi.c: fix bug that prevented clean reset after flash write
[openocd.git] / contrib / loaders / flash / lpcspifi_write.S
1 /***************************************************************************
2 * Copyright (C) 2012 by George Harris *
3 * george@luminairecoffee.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 .text
22 .syntax unified
23 .cpu cortex-m3
24 .thumb
25 .thumb_func
26
27 /*
28 * Params :
29 * r0 = workarea start, status (out)
30 * r1 = workarea end
31 * r2 = target address (offset from flash base)
32 * r3 = count (bytes)
33 * r4 = page size
34 * Clobbered:
35 * r7 - rp
36 * r8 - wp, tmp
37 * r9 - send/receive data
38 * r10 - temp
39 * r11 - current page end address
40 */
41
42 /*
43 * This code is embedded within: src/flash/nor/lpcspifi.c as a "C" array.
44 *
45 * To rebuild:
46 * arm-none-eabi-gcc -c lpcspifi_write.S
47 * arm-none-eabi-objcopy -O binary lpcspifi_write.o lpcspifi_write.bin
48 * xxd -c 8 -i lpcspifi_write.bin > lpcspifi_write.txt
49 *
50 * Then read and edit this result into the "C" source.
51 */
52
53 #define SSP_BASE_HIGH 0x4008
54 #define SSP_BASE_LOW 0x3000
55 #define SSP_CR0_OFFSET 0x00
56 #define SSP_CR1_OFFSET 0x04
57 #define SSP_DATA_OFFSET 0x08
58 #define SSP_CPSR_OFFSET 0x10
59 #define SSP_SR_OFFSET 0x0c
60
61 #define SSP_CLOCK_BASE_HIGH 0x4005
62 #define SSP_CLOCK_BASE_LOW 0x0000
63 #define SSP_BRANCH_CLOCK_BASE_HIGH 0x4005
64 #define SSP_BRANCH_CLOCK_BASE_LOW 0x2000
65 #define SSP_BASE_CLOCK_OFFSET 0x94
66 #define SSP_BRANCH_CLOCK_OFFSET 0x700
67
68 #define IOCONFIG_BASE_HIGH 0x4008
69 #define IOCONFIG_BASE_LOW 0x6000
70 #define IOCONFIG_SCK_OFFSET 0x18c
71 #define IOCONFIG_HOLD_OFFSET 0x190
72 #define IOCONFIG_WP_OFFSET 0x194
73 #define IOCONFIG_MISO_OFFSET 0x198
74 #define IOCONFIG_MOSI_OFFSET 0x19c
75 #define IOCONFIG_CS_OFFSET 0x1a0
76
77 #define IO_BASE_HIGH 0x400f
78 #define IO_BASE_LOW 0x4000
79 #define IO_CS_OFFSET 0xab
80 #define IODIR_BASE_HIGH 0x400f
81 #define IODIR_BASE_LOW 0x6000
82 #define IO_CS_DIR_OFFSET 0x14
83
84
85 setup: /* Initialize SSP pins and module */
86 mov.w r10, #IOCONFIG_BASE_LOW
87 movt r10, #IOCONFIG_BASE_HIGH
88 mov.w r8, #0xea
89 str.w r8, [r10, #IOCONFIG_SCK_OFFSET] /* Configure SCK pin function */
90 mov.w r8, #0x40
91 str.w r8, [r10, #IOCONFIG_HOLD_OFFSET] /* Configure /HOLD pin function */
92 mov.w r8, #0x40
93 str.w r8, [r10, #IOCONFIG_WP_OFFSET] /* Configure /WP pin function */
94 mov.w r8, #0xed
95 str.w r8, [r10, #IOCONFIG_MISO_OFFSET] /* Configure MISO pin function */
96 mov.w r8, #0xed
97 str.w r8, [r10, #IOCONFIG_MOSI_OFFSET] /* Configure MOSI pin function */
98 mov.w r8, #0x44
99 str.w r8, [r10, #IOCONFIG_CS_OFFSET] /* Configure CS pin function */
100
101 mov.w r10, #IODIR_BASE_LOW
102 movt r10, #IODIR_BASE_HIGH
103 mov.w r8, #0x800
104 str r8, [r10, #IO_CS_DIR_OFFSET] /* Set CS as output */
105 mov.w r10, #IO_BASE_LOW
106 movt r10, #IO_BASE_HIGH
107 mov.w r8, #0xff
108 str.w r8, [r10, #IO_CS_OFFSET] /* Set CS high */
109
110 mov.w r10, #SSP_CLOCK_BASE_LOW
111 movt r10, #SSP_CLOCK_BASE_HIGH
112 mov.w r8, #0x0000
113 movt r8, #0x0100
114 str.w r8, [r10, #SSP_BASE_CLOCK_OFFSET] /* Configure SSP0 base clock (use 12 MHz IRC) */
115
116 mov.w r10, #SSP_BRANCH_CLOCK_BASE_LOW
117 movt r10, #SSP_BRANCH_CLOCK_BASE_HIGH
118 mov.w r8, #0x01
119 str.w r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
120
121 mov.w r10, #SSP_BASE_LOW
122 movt r10, #SSP_BASE_HIGH
123 mov.w r8, #0x07
124 str.w r8, [r10, #SSP_CR0_OFFSET] /* Set clock postscale */
125 mov.w r8, #0x02
126 str.w r8, [r10, #SSP_CPSR_OFFSET] /* Set clock prescale */
127 str.w r8, [r10, #SSP_CR1_OFFSET] /* Enable SSP in SPI mode */
128
129 mov.w r11, #0x00
130 find_next_page_boundary:
131 add r11, r4 /* Increment to the next page */
132 cmp r11, r2
133 /* If we have not reached the next page boundary after the target address, keep going */
134 bls find_next_page_boundary
135 write_enable:
136 bl cs_down
137 mov.w r9, #0x06 /* Send the write enable command */
138 bl write_data
139 bl cs_up
140
141 bl cs_down
142 mov.w r9, #0x05 /* Get status register */
143 bl write_data
144 mov.w r9, #0x00 /* Dummy data to clock in status */
145 bl write_data
146 bl cs_up
147
148 tst r9, #0x02 /* If the WE bit isn't set, we have a problem. */
149 beq error
150 page_program:
151 bl cs_down
152 mov.w r9, #0x02 /* Send the page program command */
153 bl write_data
154 write_address:
155 lsr r9, r2, #16 /* Send the current 24-bit write address, MSB first */
156 bl write_data
157 lsr r9, r2, #8
158 bl write_data
159 mov.w r9, r2
160 bl write_data
161 wait_fifo:
162 ldr r8, [r0] /* read the write pointer */
163 cmp r8, #0 /* if it's zero, we're gonzo */
164 beq exit
165 ldr r7, [r0, #4] /* read the read pointer */
166 cmp r7, r8 /* wait until they are not equal */
167 beq wait_fifo
168 write:
169 ldrb r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */
170 bl write_data /* send the byte to the flash chip */
171
172 cmp r7, r1 /* wrap the read pointer if it is at the end */
173 it cs
174 addcs r7, r0, #8 /* skip loader args */
175 str r7, [r0, #4] /* store the new read pointer */
176 subs r3, r3, #1 /* decrement count */
177 cbz r3, exit /* Exit if we have written everything */
178
179 add r2, #1 /* Increment flash address by 1 */
180 cmp r11, r2 /* See if we have reached the end of a page */
181 bne wait_fifo /* If not, keep writing bytes */
182 bl cs_up /* Otherwise, end the command and keep going w/ the next page */
183 add r11, r4 /* Move up the end-of-page address by the page size*/
184 wait_flash_busy: /* Wait for the flash to finish the previous page write */
185 bl cs_down
186 mov.w r9, #0x05 /* Get status register */
187 bl write_data
188 mov.w r9, #0x00 /* Dummy data to clock in status */
189 bl write_data
190 bl cs_up
191 tst r9, #0x01 /* If it isn't done, keep waiting */
192 bne wait_flash_busy
193 b write_enable /* If it is done, start a new page write */
194 write_data: /* Send/receive 1 byte of data over SSP */
195 mov.w r10, #SSP_BASE_LOW
196 movt r10, #SSP_BASE_HIGH
197 str.w r9, [r10, #SSP_DATA_OFFSET] /* Write supplied data to the SSP data reg */
198 wait_transmit:
199 ldr r9, [r10, #SSP_SR_OFFSET] /* Check SSP status */
200 tst r9, #0x0010 /* Check if BSY bit is set */
201 bne wait_transmit /* If still transmitting, keep waiting */
202 ldr r9, [r10, #SSP_DATA_OFFSET] /* Load received data */
203 bx lr /* Exit subroutine */
204 cs_up:
205 mov.w r8, #0xff
206 b cs_write
207 cs_down:
208 mov.w r8, #0x0000
209 cs_write:
210 mov.w r10, #IO_BASE_LOW
211 movt r10, #IO_BASE_HIGH
212 str.w r8, [r10, #IO_CS_OFFSET]
213 bx lr
214 error:
215 movs r0, #0
216 str r0, [r2, #4] /* set rp = 0 on error */
217 exit:
218 bl cs_up /* end the command before returning */
219 mov r0, r6
220 bkpt #0x00
221
222 .end

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)