flash/nor: add support for TI MSP432 devices
[openocd.git] / contrib / loaders / flash / msp432 / main_msp432e4x.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * Neither the name of Texas Instruments Incorporated nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 ******************************************************************************/
34
35 #include <stdint.h>
36 #include <stdbool.h>
37 #include "driverlib.h"
38
39 #include "MSP432E4_FlashLibIf.h"
40
41 /* Local prototypes */
42 void msp432_flash_init(void);
43 void msp432_flash_mass_erase(void);
44 void msp432_flash_sector_erase(void);
45 void msp432_flash_write(void);
46 void msp432_flash_continous_write(void);
47 void msp432_flash_exit(void);
48
49 int main(void)
50 {
51 /* Disable interrupts */
52 __asm(" cpsid i");
53
54 /* Halt watchdog */
55 SYSCTL->RCGCWD &= ~(SYSCTL_RCGCWD_R1 + SYSCTL_RCGCWD_R0);
56
57 while (1) {
58 switch (FLASH_LOADER->FLASH_FUNCTION) {
59 case FLASH_INIT:
60 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
61 msp432_flash_init();
62 FLASH_LOADER->FLASH_FUNCTION = 0;
63 break;
64 case FLASH_MASS_ERASE:
65 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
66 msp432_flash_mass_erase();
67 FLASH_LOADER->FLASH_FUNCTION = 0;
68 break;
69 case FLASH_SECTOR_ERASE:
70 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
71 msp432_flash_sector_erase();
72 FLASH_LOADER->FLASH_FUNCTION = 0;
73 break;
74 case FLASH_PROGRAM:
75 case FLASH_CONTINUOUS_PROGRAM:
76 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
77 msp432_flash_continous_write();
78 FLASH_LOADER->FLASH_FUNCTION = 0;
79 break;
80 case FLASH_EXIT:
81 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
82 msp432_flash_exit();
83 FLASH_LOADER->FLASH_FUNCTION = 0;
84 break;
85 case FLASH_NO_COMMAND:
86 break;
87 default:
88 FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND;
89 break;
90 }
91 }
92 }
93
94 /* Initialize flash */
95 void msp432_flash_init(void)
96 {
97 SCB->VTOR = 0x20000000;
98 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
99 }
100
101 /* Erase entire flash */
102 void msp432_flash_mass_erase(void)
103 {
104 bool success = false;
105
106 /* Clear the flash access and error interrupts. */
107 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
108 FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
109
110 /* Trigger mass erase */
111 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_MERASE;
112 while (FLASH_CTRL->FMC & FLASH_FMC_MERASE)
113 ;
114
115 /* Return an error if an access violation occurred. */
116 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
117 FLASH_FCRIS_ERRIS));
118 if (!success)
119 FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR;
120 else
121 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
122 }
123
124 /* Erase one flash sector */
125 void msp432_flash_sector_erase(void)
126 {
127 bool success = false;
128
129 /* Clear the flash access and error interrupts. */
130 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
131 FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
132
133 /* Set 16kB aligned flash page address to be erased (16kB block) */
134 FLASH_CTRL->FMA = FLASH_LOADER->DST_ADDRESS;
135 /* Trigger sector erase (erase flash page) */
136 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
137 while (FLASH_CTRL->FMC & FLASH_FMC_ERASE)
138 ;
139
140 /* Return an error if an access violation occurred. */
141 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
142 FLASH_FCRIS_ERRIS));
143
144 if (!success)
145 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
146 else
147 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
148 }
149
150 /* Write data to flash */
151 void msp432_flash_continous_write(void)
152 {
153 bool buffer1_in_use = false;
154 bool buffer2_in_use = false;
155 uint32_t *src_address = NULL;
156 bool success = true;
157 uint32_t i = 0;
158 uint32_t address = FLASH_LOADER->DST_ADDRESS;
159 uint32_t data_to_write = FLASH_LOADER->SRC_LENGTH;
160 int32_t write_package = 0;
161
162 /* Clear the flash access and error interrupts. */
163 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
164 FLASH_FCMISC_INVDMISC | FLASH_FCMISC_PROGMISC | FLASH_FCMISC_PMISC);
165 do {
166 if (data_to_write > SRC_LENGTH_MAX) {
167 write_package = SRC_LENGTH_MAX;
168 data_to_write -= write_package;
169 } else {
170 write_package = data_to_write;
171 data_to_write -= write_package;
172 }
173 while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) &&
174 !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY))
175 ;
176
177 if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) {
178 FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE;
179 src_address = (uint32_t *) RAM_LOADER_BUFFER1;
180 buffer1_in_use = true;
181 } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) {
182 FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE;
183 src_address = (uint32_t *) RAM_LOADER_BUFFER2;
184 buffer2_in_use = true;
185 }
186
187 /*
188 * The flash hardware can only write complete words to flash. If
189 * an unaligned address is passed in, we must do a read-modify-write
190 * on a word with enough bytes to align the rest of the buffer. And
191 * if less than a whole word remains at the end, we must also do a
192 * read-modify-write on a final word to finish up.
193 */
194 if (0 != (address & 0x3)) {
195 uint32_t head;
196 uint8_t *ui8head = (uint8_t *)&head;
197 uint8_t *buffer = (uint8_t *)src_address;
198
199 /* Get starting offset for data to write (will be 1 to 3) */
200 uint32_t head_offset = address & 0x03;
201
202 /* Get the aligned address to write this first word to */
203 uint32_t head_address = address & 0xfffffffc;
204
205 /* Retrieve what is already in flash at the head address */
206 head = *(uint32_t *)head_address;
207
208 /* Substitute in the new data to write */
209 while ((write_package > 0) && (head_offset < 4)) {
210 ui8head[head_offset] = *buffer;
211 head_offset++;
212 address++;
213 buffer++;
214 write_package--;
215 }
216 src_address = (uint32_t *)buffer;
217
218 FLASH_CTRL->FMD = head;
219 FLASH_CTRL->FMA = head_address;
220 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
221
222 /* Wait until the word has been programmed. */
223 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
224 ;
225
226 /* Return an error if an access violation occurred. */
227 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
228 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
229 }
230
231 /* Program a word at a time until aligned on 32-word boundary */
232 while ((write_package >= 4) && ((address & 0x7f) != 0) && success) {
233 FLASH_CTRL->FMD = *src_address++;
234 FLASH_CTRL->FMA = address;
235 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
236
237 /* Wait until the word has been programmed. */
238 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
239 ;
240
241 /* Prepare for next word to write */
242 write_package -= 4;
243 address += 4;
244
245 /* Return an error if an access violation occurred. */
246 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
247 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
248 }
249
250 /* Program data in 32-word blocks */
251 while ((write_package >= 32) && success) {
252 /* Loop over the words in this 32-word block. */
253 i = 0;
254 do {
255 FLASH_CTRL->FWBN[i] = *src_address++;
256 write_package -= 4;
257 i++;
258 } while ((write_package > 0) && (i < 32));
259 FLASH_CTRL->FMA = address;
260 FLASH_CTRL->FMC2 = FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF;
261
262 /* Wait until the write buffer has been programmed. */
263 while (FLASH_CTRL->FMC2 & FLASH_FMC2_WRBUF)
264 ;
265
266 /* Increment destination address by words written */
267 address += 128;
268
269 /* Return an error if an access violation occurred. */
270 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
271 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
272 }
273
274 /* Program a word at a time on left over data */
275 while ((write_package >= 4) && success) {
276 FLASH_CTRL->FMD = *src_address++;
277 FLASH_CTRL->FMA = address;
278 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
279
280 /* Wait until the word has been programmed. */
281 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
282 ;
283
284 /* Prepare for next word to write */
285 write_package -= 4;
286 address += 4;
287
288 /* Return an error if an access violation occurred. */
289 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
290 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
291 }
292
293 if ((write_package > 0) && success) {
294 uint32_t tail;
295 uint8_t *ui8tail = (uint8_t *)&tail;
296 uint8_t *buffer = (uint8_t *)src_address;
297
298 /* Set starting offset for data to write */
299 uint32_t tail_offset = 0;
300
301 /* Get the address to write this last word to */
302 uint32_t tail_address = address;
303
304 /* Retrieve what is already in flash at the tail address */
305 tail = *(uint32_t *)address;
306
307 /* Substitute in the new data to write */
308 while (write_package > 0) {
309 ui8tail[tail_offset] = *buffer;
310 tail_offset++;
311 address++;
312 buffer++;
313 write_package--;
314 }
315
316 FLASH_CTRL->FMD = tail;
317 FLASH_CTRL->FMA = tail_address;
318 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
319
320 /* Wait until the word has been programmed. */
321 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
322 ;
323
324 /* Return an error if an access violation occurred. */
325 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
326 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
327 }
328
329 if (buffer1_in_use) {
330 FLASH_LOADER->BUFFER1_STATUS_REGISTER &=
331 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
332 buffer1_in_use = false;
333 } else if (buffer2_in_use) {
334 FLASH_LOADER->BUFFER2_STATUS_REGISTER &=
335 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
336 buffer2_in_use = false;
337 }
338 } while (success && data_to_write);
339
340 if (!success)
341 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
342 else
343 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
344 }
345
346 /* Exit flash programming */
347 void msp432_flash_exit(void)
348 {
349 SCB->VTOR = 0x00000000;
350 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
351 }

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)