Added SPIFI flash driver, algorithms, and docs
[fw/openocd] / contrib / loaders / flash / lpcspifi_erase.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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21         .text
22         .syntax unified
23         .cpu cortex-m3
24         .thumb
25         .thumb_func
26
27 /*
28  * Params :
29  * r0 = start address, status (out)
30  * r1 = count
31  * r2 = erase command
32  * r3 = block size
33  */
34
35 #define SSP_BASE_HIGH                           0x4008
36 #define SSP_BASE_LOW                            0x3000
37 #define SSP_CR0_OFFSET                          0x00
38 #define SSP_CR1_OFFSET                          0x04
39 #define SSP_DATA_OFFSET                         0x08
40 #define SSP_CPSR_OFFSET                         0x10
41 #define SSP_SR_OFFSET                           0x0c
42
43 #define SSP_CLOCK_BASE_HIGH             0x4005
44 #define SSP_CLOCK_BASE_LOW                      0x0000
45 #define SSP_BRANCH_CLOCK_BASE_HIGH      0x4005
46 #define SSP_BRANCH_CLOCK_BASE_LOW       0x2000
47 #define SSP_BASE_CLOCK_OFFSET           0x94
48 #define SSP_BRANCH_CLOCK_OFFSET         0x700
49
50 #define IOCONFIG_BASE_HIGH                      0x4008
51 #define IOCONFIG_BASE_LOW                       0x6000
52 #define IOCONFIG_SCK_OFFSET                     0x18c
53 #define IOCONFIG_HOLD_OFFSET            0x190
54 #define IOCONFIG_WP_OFFSET                      0x194
55 #define IOCONFIG_MISO_OFFSET            0x198
56 #define IOCONFIG_MOSI_OFFSET            0x19c
57 #define IOCONFIG_CS_OFFSET                      0x1a0
58
59 #define IO_BASE_HIGH                            0x400f
60 #define IO_BASE_LOW                             0x4000
61 #define IO_CS_OFFSET                            0xab
62 #define IODIR_BASE_HIGH                         0x400f
63 #define IODIR_BASE_LOW                          0x6000
64 #define IO_CS_DIR_OFFSET                        0x14
65
66
67 setup: /* Initialize SSP pins and module */
68         mov.w   r10, #IOCONFIG_BASE_LOW
69         movt    r10, #IOCONFIG_BASE_HIGH
70         mov.w   r8, #0xea
71         str.w   r8, [r10, #IOCONFIG_SCK_OFFSET]         /* Configure SCK pin function */
72         mov.w   r8, #0x40
73         str.w   r8, [r10, #IOCONFIG_HOLD_OFFSET]        /* Configure /HOLD pin function */
74         mov.w   r8, #0x40
75         str.w   r8, [r10, #IOCONFIG_WP_OFFSET]          /* Configure /WP pin function */
76         mov.w   r8, #0xed
77         str.w   r8, [r10, #IOCONFIG_MISO_OFFSET]        /* Configure MISO pin function */
78         mov.w   r8, #0xed
79         str.w   r8, [r10, #IOCONFIG_MOSI_OFFSET]        /* Configure MOSI pin function */
80         mov.w   r8, #0x44
81         str.w   r8, [r10, #IOCONFIG_CS_OFFSET]          /* Configure CS pin function */
82
83         mov.w   r10, #IODIR_BASE_LOW
84         movt    r10, #IODIR_BASE_HIGH
85         mov.w   r8, #0x800
86         str     r8, [r10, #IO_CS_DIR_OFFSET]            /* Set CS as output */
87         mov.w   r10, #IO_BASE_LOW
88         movt    r10, #IO_BASE_HIGH
89         mov.w   r8, #0xff
90         str.w   r8, [r10, #IO_CS_OFFSET]                        /* Set CS high */
91
92         mov.w   r10, #SSP_CLOCK_BASE_LOW
93         movt    r10, #SSP_CLOCK_BASE_HIGH
94         mov.w   r8, #0x0000
95         movt    r8, #0x0100
96         str.w   r8, [r10, #SSP_BASE_CLOCK_OFFSET]       /* Configure SSP0 base clock (use 12 MHz IRC) */
97
98         mov.w   r10, #SSP_BRANCH_CLOCK_BASE_LOW
99         movt    r10, #SSP_BRANCH_CLOCK_BASE_HIGH
100         mov.w   r8, #0x01
101         str.w   r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
102
103         mov.w   r10, #SSP_BASE_LOW
104         movt    r10, #SSP_BASE_HIGH
105         mov.w   r8, #0x07
106         str.w   r8, [r10, #SSP_CR0_OFFSET]                      /* Set clock postscale */
107         mov.w   r8, #0x02
108         str.w   r8, [r10, #SSP_CPSR_OFFSET]             /* Set clock prescale */
109         str.w   r8, [r10, #SSP_CR1_OFFSET]                      /* Enable SSP in SPI mode */
110 write_enable:
111         bl              cs_down
112         mov.w   r9, #0x06               /* Send the write enable command */
113         bl              write_data
114         bl              cs_up
115
116         bl              cs_down
117         mov.w   r9, #0x05               /* Get status register */
118         bl              write_data
119         mov.w   r9, #0x00               /* Dummy data to clock in status */
120         bl              write_data
121         bl              cs_up
122
123         tst     r9, #0x02               /* If the WE bit isn't set, we have a problem. */
124         beq     error
125 erase:
126         bl              cs_down
127         mov.w   r9, r2                  /* Send the erase command */
128         bl              write_data
129 write_address:
130         lsr     r9, r0, #16     /* Send the current 24-bit write address, MSB first */
131         bl              write_data
132         lsr     r9, r0, #8
133         bl              write_data
134         mov.w   r9, r0
135         bl              write_data
136         bl              cs_up
137 wait_flash_busy:                        /* Wait for the flash to finish the previous erase */
138         bl              cs_down
139         mov.w   r9, #0x05               /* Get status register */
140         bl              write_data
141         mov.w   r9, #0x00               /* Dummy data to clock in status */
142         bl              write_data
143         bl              cs_up
144         tst     r9, #0x01               /* If it isn't done, keep waiting */
145         bne     wait_flash_busy
146
147         subs    r1, r1, #1                                      /* decrement count */
148         cbz             r1, exit                                        /* Exit if we have written everything */
149         add     r0, r3                                          /* Move the address up by the block size */
150         b               write_enable                            /* Start a new block erase */
151 write_data:                                                     /* Send/receive 1 byte of data over SSP */
152         mov.w   r10, #SSP_BASE_LOW
153         movt    r10, #SSP_BASE_HIGH
154         str.w   r9, [r10, #SSP_DATA_OFFSET]     /* Write supplied data to the SSP data reg */
155 wait_transmit:
156         ldr     r9, [r10, #SSP_SR_OFFSET]       /* Check SSP status */
157         tst     r9, #0x0010                                     /* Check if BSY bit is set */
158         bne     wait_transmit                           /* If still transmitting, keep waiting */
159         ldr     r9, [r10, #SSP_DATA_OFFSET]     /* Load received data */
160         bx              lr                                                      /* Exit subroutine */
161 cs_up:
162         mov.w   r8, #0xff
163         b               cs_write
164 cs_down:
165         mov.w   r8, #0x0000
166 cs_write:
167         mov.w   r10, #IO_BASE_LOW
168         movt    r10, #IO_BASE_HIGH
169         str.w   r8, [r10, #IO_CS_OFFSET]
170         bx              lr
171 error:
172         movs    r0, #0
173 exit:
174         bkpt    #0x00
175
176         .end