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