jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / contrib / loaders / flash / lpcspifi_write.S
blob476e143aa4121c82428b185955de3b8aab73a29b
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4  *   Copyright (C) 2012 by George Harris                                   *
5  *   george@luminairecoffee.com                                            *
6  ***************************************************************************/
8         .text
9         .syntax unified
10         .cpu cortex-m3
11         .thumb
12         .thumb_func
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  */
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  */
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
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
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
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
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 */
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 */
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) */
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 */
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 */
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
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
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 */
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 */
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
209         .end