contrib: replace the BSD-3-Clause license tag
[fw/openocd] / contrib / loaders / flash / msp432 / main_msp432e4x.c
1 /* SPDX-License-Identifier: BSD-3-Clause */
2
3 /******************************************************************************
4 *
5 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
6 *
7 ******************************************************************************/
8
9 #include <stdint.h>
10 #include <stdbool.h>
11 #include "driverlib.h"
12
13 #include "MSP432E4_FlashLibIf.h"
14
15 /* Local prototypes */
16 void msp432_flash_init(void);
17 void msp432_flash_mass_erase(void);
18 void msp432_flash_sector_erase(void);
19 void msp432_flash_write(void);
20 void msp432_flash_continous_write(void);
21 void msp432_flash_exit(void);
22
23 int main(void)
24 {
25         /* Disable interrupts */
26         __asm("  cpsid i");
27
28         /* Halt watchdog */
29         SYSCTL->RCGCWD &= ~(SYSCTL_RCGCWD_R1 + SYSCTL_RCGCWD_R0);
30
31         while (1) {
32                 switch (FLASH_LOADER->FLASH_FUNCTION) {
33                         case FLASH_INIT:
34                                 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
35                                 msp432_flash_init();
36                                 FLASH_LOADER->FLASH_FUNCTION = 0;
37                                 break;
38                         case FLASH_MASS_ERASE:
39                                 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
40                                 msp432_flash_mass_erase();
41                                 FLASH_LOADER->FLASH_FUNCTION = 0;
42                                 break;
43                         case FLASH_SECTOR_ERASE:
44                                 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
45                                 msp432_flash_sector_erase();
46                                 FLASH_LOADER->FLASH_FUNCTION = 0;
47                                 break;
48                         case FLASH_PROGRAM:
49                         case FLASH_CONTINUOUS_PROGRAM:
50                                 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
51                                 msp432_flash_continous_write();
52                                 FLASH_LOADER->FLASH_FUNCTION = 0;
53                                 break;
54                         case FLASH_EXIT:
55                                 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
56                                 msp432_flash_exit();
57                                 FLASH_LOADER->FLASH_FUNCTION = 0;
58                                 break;
59                         case FLASH_NO_COMMAND:
60                                 break;
61                         default:
62                                 FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND;
63                                 break;
64                 }
65         }
66 }
67
68 /* Initialize flash */
69 void msp432_flash_init(void)
70 {
71         SCB->VTOR = 0x20000000;
72         FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
73 }
74
75 /* Erase entire flash */
76 void msp432_flash_mass_erase(void)
77 {
78         bool success = false;
79
80         /* Clear the flash access and error interrupts. */
81         FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
82                                                   FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
83
84         /* Trigger mass erase */
85         FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_MERASE;
86         while (FLASH_CTRL->FMC & FLASH_FMC_MERASE)
87                 ;
88
89         /* Return an error if an access violation occurred. */
90         success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
91                                 FLASH_FCRIS_ERRIS));
92         if (!success)
93                 FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR;
94         else
95                 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
96 }
97
98 /* Erase one flash sector */
99 void msp432_flash_sector_erase(void)
100 {
101         bool success = false;
102
103         /* Clear the flash access and error interrupts. */
104         FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
105                                                   FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
106
107         /* Set 16kB aligned flash page address to be erased (16kB block) */
108         FLASH_CTRL->FMA = FLASH_LOADER->DST_ADDRESS;
109         /* Trigger sector erase (erase flash page) */
110         FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
111         while (FLASH_CTRL->FMC & FLASH_FMC_ERASE)
112                 ;
113
114         /* Return an error if an access violation occurred. */
115         success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
116                                 FLASH_FCRIS_ERRIS));
117
118         if (!success)
119                 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
120         else
121                 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
122 }
123
124 /* Write data to flash */
125 void msp432_flash_continous_write(void)
126 {
127         bool buffer1_in_use = false;
128         bool buffer2_in_use = false;
129         uint32_t *src_address = NULL;
130         bool success = true;
131         uint32_t i = 0;
132         uint32_t address = FLASH_LOADER->DST_ADDRESS;
133         uint32_t data_to_write = FLASH_LOADER->SRC_LENGTH;
134         int32_t write_package = 0;
135
136         /* Clear the flash access and error interrupts. */
137         FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
138                 FLASH_FCMISC_INVDMISC | FLASH_FCMISC_PROGMISC | FLASH_FCMISC_PMISC);
139         do {
140                 if (data_to_write > SRC_LENGTH_MAX) {
141                         write_package = SRC_LENGTH_MAX;
142                         data_to_write -= write_package;
143                 } else {
144                         write_package = data_to_write;
145                         data_to_write -= write_package;
146                 }
147                 while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) &&
148                         !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY))
149                         ;
150
151                 if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) {
152                         FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE;
153                         src_address  = (uint32_t *) RAM_LOADER_BUFFER1;
154                         buffer1_in_use = true;
155                 } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) {
156                         FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE;
157                         src_address  = (uint32_t *) RAM_LOADER_BUFFER2;
158                         buffer2_in_use = true;
159                 }
160
161                 /*
162                  * The flash hardware can only write complete words to flash. If
163                  * an unaligned address is passed in, we must do a read-modify-write
164                  * on a word with enough bytes to align the rest of the buffer. And
165                  * if less than a whole word remains at the end, we must also do a
166                  * read-modify-write on a final word to finish up.
167                  */
168                 if (0 != (address & 0x3)) {
169                         uint32_t head;
170                         uint8_t *ui8head = (uint8_t *)&head;
171                         uint8_t *buffer = (uint8_t *)src_address;
172
173                         /* Get starting offset for data to write (will be 1 to 3) */
174                         uint32_t head_offset = address & 0x03;
175
176                         /* Get the aligned address to write this first word to */
177                         uint32_t head_address = address & 0xfffffffc;
178
179                         /* Retrieve what is already in flash at the head address */
180                         head = *(uint32_t *)head_address;
181
182                         /* Substitute in the new data to write */
183                         while ((write_package > 0) && (head_offset < 4)) {
184                                 ui8head[head_offset] = *buffer;
185                                 head_offset++;
186                                 address++;
187                                 buffer++;
188                                 write_package--;
189                         }
190                         src_address = (uint32_t *)buffer;
191
192                         FLASH_CTRL->FMD = head;
193                         FLASH_CTRL->FMA = head_address;
194                         FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
195
196                         /* Wait until the word has been programmed. */
197                         while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
198                                 ;
199
200                         /* Return an error if an access violation occurred. */
201                         success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
202                                 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
203                 }
204
205                 /* Program a word at a time until aligned on 32-word boundary */
206                 while ((write_package >= 4) && ((address & 0x7f) != 0) && success) {
207                         FLASH_CTRL->FMD = *src_address++;
208                         FLASH_CTRL->FMA = address;
209                         FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
210
211                         /* Wait until the word has been programmed. */
212                         while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
213                                 ;
214
215                         /* Prepare for next word to write */
216                         write_package -= 4;
217                         address += 4;
218
219                         /* Return an error if an access violation occurred. */
220                         success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
221                                 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
222                 }
223
224                 /* Program data in 32-word blocks */
225                 while ((write_package >= 32) && success) {
226                         /* Loop over the words in this 32-word block. */
227                         i = 0;
228                         do {
229                                 FLASH_CTRL->FWBN[i] = *src_address++;
230                                 write_package -= 4;
231                                 i++;
232                         } while ((write_package > 0) && (i < 32));
233                         FLASH_CTRL->FMA = address;
234                         FLASH_CTRL->FMC2 = FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF;
235
236                         /* Wait until the write buffer has been programmed. */
237                         while (FLASH_CTRL->FMC2 & FLASH_FMC2_WRBUF)
238                                 ;
239
240                         /* Increment destination address by words written */
241                         address += 128;
242
243                         /* Return an error if an access violation occurred. */
244                         success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
245                                 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
246                 }
247
248                 /* Program a word at a time on left over data */
249                 while ((write_package >= 4) && success) {
250                         FLASH_CTRL->FMD = *src_address++;
251                         FLASH_CTRL->FMA = address;
252                         FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
253
254                         /* Wait until the word has been programmed. */
255                         while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
256                                 ;
257
258                         /* Prepare for next word to write */
259                         write_package -= 4;
260                         address += 4;
261
262                         /* Return an error if an access violation occurred. */
263                         success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
264                                 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
265                 }
266
267                 if ((write_package > 0) && success) {
268                         uint32_t tail;
269                         uint8_t *ui8tail = (uint8_t *)&tail;
270                         uint8_t *buffer = (uint8_t *)src_address;
271
272                         /* Set starting offset for data to write */
273                         uint32_t tail_offset = 0;
274
275                         /* Get the address to write this last word to */
276                         uint32_t tail_address = address;
277
278                         /* Retrieve what is already in flash at the tail address */
279                         tail = *(uint32_t *)address;
280
281                         /* Substitute in the new data to write */
282                         while (write_package > 0) {
283                                 ui8tail[tail_offset] = *buffer;
284                                 tail_offset++;
285                                 address++;
286                                 buffer++;
287                                 write_package--;
288                         }
289
290                         FLASH_CTRL->FMD = tail;
291                         FLASH_CTRL->FMA = tail_address;
292                         FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
293
294                         /* Wait until the word has been programmed. */
295                         while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
296                                 ;
297
298                         /* Return an error if an access violation occurred. */
299                         success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
300                                 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
301                 }
302
303                 if (buffer1_in_use) {
304                         FLASH_LOADER->BUFFER1_STATUS_REGISTER &=
305                                 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
306                         buffer1_in_use = false;
307                 } else if (buffer2_in_use) {
308                         FLASH_LOADER->BUFFER2_STATUS_REGISTER &=
309                                 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
310                         buffer2_in_use = false;
311                 }
312         } while (success && data_to_write);
313
314         if (!success)
315                 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
316         else
317                 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
318 }
319
320 /* Exit flash programming */
321 void msp432_flash_exit(void)
322 {
323         SCB->VTOR = 0x00000000;
324         FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
325 }