update files to correct FSF address
[openocd.git] / contrib / loaders / flash / lpcspifi_write.S
blobd47129769659744e4c8c81d7f705b15387bc9880
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  ***************************************************************************/
21         .text
22         .syntax unified
23         .cpu cortex-m3
24         .thumb
25         .thumb_func
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  */
42 #define SSP_BASE_HIGH                           0x4008
43 #define SSP_BASE_LOW                            0x3000
44 #define SSP_CR0_OFFSET                          0x00
45 #define SSP_CR1_OFFSET                          0x04
46 #define SSP_DATA_OFFSET                         0x08
47 #define SSP_CPSR_OFFSET                         0x10
48 #define SSP_SR_OFFSET                           0x0c
50 #define SSP_CLOCK_BASE_HIGH             0x4005
51 #define SSP_CLOCK_BASE_LOW                      0x0000
52 #define SSP_BRANCH_CLOCK_BASE_HIGH      0x4005
53 #define SSP_BRANCH_CLOCK_BASE_LOW       0x2000
54 #define SSP_BASE_CLOCK_OFFSET           0x94
55 #define SSP_BRANCH_CLOCK_OFFSET         0x700
57 #define IOCONFIG_BASE_HIGH                      0x4008
58 #define IOCONFIG_BASE_LOW                       0x6000
59 #define IOCONFIG_SCK_OFFSET                     0x18c
60 #define IOCONFIG_HOLD_OFFSET            0x190
61 #define IOCONFIG_WP_OFFSET                      0x194
62 #define IOCONFIG_MISO_OFFSET            0x198
63 #define IOCONFIG_MOSI_OFFSET            0x19c
64 #define IOCONFIG_CS_OFFSET                      0x1a0
66 #define IO_BASE_HIGH                            0x400f
67 #define IO_BASE_LOW                             0x4000
68 #define IO_CS_OFFSET                            0xab
69 #define IODIR_BASE_HIGH                         0x400f
70 #define IODIR_BASE_LOW                          0x6000
71 #define IO_CS_DIR_OFFSET                        0x14
74 setup: /* Initialize SSP pins and module */
75         mov.w   r10, #IOCONFIG_BASE_LOW
76         movt    r10, #IOCONFIG_BASE_HIGH
77         mov.w   r8, #0xea
78         str.w   r8, [r10, #IOCONFIG_SCK_OFFSET]         /* Configure SCK pin function */
79         mov.w   r8, #0x40
80         str.w   r8, [r10, #IOCONFIG_HOLD_OFFSET]        /* Configure /HOLD pin function */
81         mov.w   r8, #0x40
82         str.w   r8, [r10, #IOCONFIG_WP_OFFSET]          /* Configure /WP pin function */
83         mov.w   r8, #0xed
84         str.w   r8, [r10, #IOCONFIG_MISO_OFFSET]        /* Configure MISO pin function */
85         mov.w   r8, #0xed
86         str.w   r8, [r10, #IOCONFIG_MOSI_OFFSET]        /* Configure MOSI pin function */
87         mov.w   r8, #0x44
88         str.w   r8, [r10, #IOCONFIG_CS_OFFSET]          /* Configure CS pin function */
90         mov.w   r10, #IODIR_BASE_LOW
91         movt    r10, #IODIR_BASE_HIGH
92         mov.w   r8, #0x800
93         str     r8, [r10, #IO_CS_DIR_OFFSET]            /* Set CS as output */
94         mov.w   r10, #IO_BASE_LOW
95         movt    r10, #IO_BASE_HIGH
96         mov.w   r8, #0xff
97         str.w   r8, [r10, #IO_CS_OFFSET]                        /* Set CS high */
99         mov.w   r10, #SSP_CLOCK_BASE_LOW
100         movt    r10, #SSP_CLOCK_BASE_HIGH
101         mov.w   r8, #0x0000
102         movt    r8, #0x0100
103         str.w   r8, [r10, #SSP_BASE_CLOCK_OFFSET]       /* Configure SSP0 base clock (use 12 MHz IRC) */
105         mov.w   r10, #SSP_BRANCH_CLOCK_BASE_LOW
106         movt    r10, #SSP_BRANCH_CLOCK_BASE_HIGH
107         mov.w   r8, #0x01
108         str.w   r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
110         mov.w   r10, #SSP_BASE_LOW
111         movt    r10, #SSP_BASE_HIGH
112         mov.w   r8, #0x07
113         str.w   r8, [r10, #SSP_CR0_OFFSET]                      /* Set clock postscale */
114         mov.w   r8, #0x02
115         str.w   r8, [r10, #SSP_CPSR_OFFSET]             /* Set clock prescale */
116         str.w   r8, [r10, #SSP_CR1_OFFSET]                      /* Enable SSP in SPI mode */
118         mov.w   r11, #0x00
119 find_next_page_boundary:
120         add     r11, r4                 /* Increment to the next page */
121         cmp     r11, r2
122         /* If we have not reached the next page boundary after the target address, keep going */
123         bls     find_next_page_boundary
124 write_enable:
125         bl              cs_down
126         mov.w   r9, #0x06               /* Send the write enable command */
127         bl              write_data
128         bl              cs_up
130         bl              cs_down
131         mov.w   r9, #0x05               /* Get status register */
132         bl              write_data
133         mov.w   r9, #0x00               /* Dummy data to clock in status */
134         bl              write_data
135         bl              cs_up
137         tst     r9, #0x02               /* If the WE bit isn't set, we have a problem. */
138         beq     error
139 page_program:
140         bl              cs_down
141         mov.w   r9, #0x02               /* Send the page program command */
142         bl              write_data
143 write_address:
144         lsr     r9, r2, #16     /* Send the current 24-bit write address, MSB first */
145         bl              write_data
146         lsr     r9, r2, #8
147         bl              write_data
148         mov.w   r9, r2
149         bl              write_data
150 wait_fifo:
151         ldr     r8, [r0]                /* read the write pointer */
152         cmp     r8, #0                  /* if it's zero, we're gonzo */
153         beq     exit
154         ldr     r7, [r0, #4]    /* read the read pointer */
155         cmp     r7, r8                  /* wait until they are not equal */
156         beq     wait_fifo
157 write:
158         ldrb    r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */
159         bl              write_data              /* send the byte to the flash chip */
161         cmp     r7, r1                  /* wrap the read pointer if it is at the end */
162         it      cs
163         addcs   r7, r0, #8              /* skip loader args */
164         str     r7, [r0, #4]    /* store the new read pointer */
165         subs    r3, r3, #1              /* decrement count */
166         cbz             r3, exit                /* Exit if we have written everything */
168         add     r2, #1                  /* Increment flash address by 1 */
169         cmp     r11, r2                 /* See if we have reached the end of a page */
170         bne     wait_fifo               /* If not, keep writing bytes */
171         bl              cs_up                   /* Otherwise, end the command and keep going w/ the next page */
172         add     r11, r4                 /* Move up the end-of-page address by the page size*/
173 wait_flash_busy:                        /* Wait for the flash to finish the previous page write */
174         bl              cs_down
175         mov.w   r9, #0x05                                       /* Get status register */
176         bl              write_data
177         mov.w   r9, #0x00                                       /* Dummy data to clock in status */
178         bl              write_data
179         bl              cs_up
180         tst     r9, #0x01                                       /* If it isn't done, keep waiting */
181         bne     wait_flash_busy
182         b               write_enable                            /* If it is done, start a new page write */
183 write_data:                                                     /* Send/receive 1 byte of data over SSP */
184         mov.w   r10, #SSP_BASE_LOW
185         movt    r10, #SSP_BASE_HIGH
186         str.w   r9, [r10, #SSP_DATA_OFFSET]     /* Write supplied data to the SSP data reg */
187 wait_transmit:
188         ldr     r9, [r10, #SSP_SR_OFFSET]       /* Check SSP status */
189         tst     r9, #0x0010                                     /* Check if BSY bit is set */
190         bne     wait_transmit                           /* If still transmitting, keep waiting */
191         ldr     r9, [r10, #SSP_DATA_OFFSET]     /* Load received data */
192         bx              lr                                                      /* Exit subroutine */
193 cs_up:
194         mov.w   r8, #0xff
195         b               cs_write
196 cs_down:
197         mov.w   r8, #0x0000
198 cs_write:
199         mov.w   r10, #IO_BASE_LOW
200         movt    r10, #IO_BASE_HIGH
201         str.w   r8, [r10, #IO_CS_OFFSET]
202         bx              lr
203 error:
204         movs    r0, #0
205         str     r0, [r2, #4]    /* set rp = 0 on error */
206 exit:
207         mov     r0, r6
208         bkpt    #0x00
210         .end