23540ac606e9d293596cb9dc5656675b6c3d3b88
[fw/openocd] / 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 }