flash/nor/at91samd: Use 32-bit register writes for ST-Link compat
[fw/openocd] / src / flash / nor / cc3220sf.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2017 by Texas Instruments, Inc.                         *
5  ***************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "imp.h"
12 #include "cc3220sf.h"
13 #include <helper/binarybuffer.h>
14 #include <helper/time_support.h>
15 #include <target/algorithm.h>
16 #include <target/armv7m.h>
17
18 #define FLASH_TIMEOUT 5000
19
20 struct cc3220sf_bank {
21         bool probed;
22         struct armv7m_algorithm armv7m_info;
23 };
24
25 /* Flash helper algorithm for CC3220SF */
26 static const uint8_t cc3220sf_algo[] = {
27 #include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc"
28 };
29
30 static int cc3220sf_mass_erase(struct flash_bank *bank)
31 {
32         struct target *target = bank->target;
33         bool done;
34         long long start_ms;
35         long long elapsed_ms;
36         uint32_t value;
37
38         int retval = ERROR_OK;
39
40         if (target->state != TARGET_HALTED) {
41                 LOG_ERROR("Target not halted");
42                 return ERROR_TARGET_NOT_HALTED;
43         }
44
45         /* Set starting address to erase to zero */
46         retval = target_write_u32(target, FMA_REGISTER_ADDR, 0);
47         if (retval != ERROR_OK)
48                 return retval;
49
50         /* Write the MERASE bit of the FMC register */
51         retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE);
52         if (retval != ERROR_OK)
53                 return retval;
54
55         /* Poll the MERASE bit until the mass erase is complete */
56         done = false;
57         start_ms = timeval_ms();
58         while (!done) {
59                 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
60                 if (retval != ERROR_OK)
61                         return retval;
62
63                 if ((value & FMC_MERASE_BIT) == 0) {
64                         /* Bit clears when mass erase is finished */
65                         done = true;
66                 } else {
67                         elapsed_ms = timeval_ms() - start_ms;
68                         if (elapsed_ms > 500)
69                                 keep_alive();
70                         if (elapsed_ms > FLASH_TIMEOUT)
71                                 break;
72                 }
73         }
74
75         if (!done) {
76                 /* Mass erase timed out waiting for confirmation */
77                 return ERROR_FAIL;
78         }
79
80         return retval;
81 }
82
83 FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
84 {
85         struct cc3220sf_bank *cc3220sf_bank;
86
87         if (CMD_ARGC < 6)
88                 return ERROR_COMMAND_SYNTAX_ERROR;
89
90         cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
91         if (!cc3220sf_bank)
92                 return ERROR_FAIL;
93
94         /* Initialize private flash information */
95         cc3220sf_bank->probed = false;
96
97         /* Finish initialization of flash bank */
98         bank->driver_priv = cc3220sf_bank;
99         bank->next = NULL;
100
101         return ERROR_OK;
102 }
103
104 static int cc3220sf_erase(struct flash_bank *bank, unsigned int first,
105                 unsigned int last)
106 {
107         struct target *target = bank->target;
108         bool done;
109         long long start_ms;
110         long long elapsed_ms;
111         uint32_t address;
112         uint32_t value;
113
114         int retval = ERROR_OK;
115
116         if (target->state != TARGET_HALTED) {
117                 LOG_ERROR("Target not halted");
118                 return ERROR_TARGET_NOT_HALTED;
119         }
120
121         /* Do a mass erase if user requested all sectors of flash */
122         if ((first == 0) && (last == (bank->num_sectors - 1))) {
123                 /* Request mass erase of flash */
124                 return cc3220sf_mass_erase(bank);
125         }
126
127         /* Erase requested sectors one by one */
128         for (unsigned int i = first; i <= last; i++) {
129
130                 /* Determine address of sector to erase */
131                 address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE;
132
133                 /* Set starting address to erase */
134                 retval = target_write_u32(target, FMA_REGISTER_ADDR, address);
135                 if (retval != ERROR_OK)
136                         return retval;
137
138                 /* Write the ERASE bit of the FMC register */
139                 retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE);
140                 if (retval != ERROR_OK)
141                         return retval;
142
143                 /* Poll the ERASE bit until the erase is complete */
144                 done = false;
145                 start_ms = timeval_ms();
146                 while (!done) {
147                         retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
148                         if (retval != ERROR_OK)
149                                 return retval;
150
151                         if ((value & FMC_ERASE_BIT) == 0) {
152                                 /* Bit clears when mass erase is finished */
153                                 done = true;
154                         } else {
155                                 elapsed_ms = timeval_ms() - start_ms;
156                                 if (elapsed_ms > 500)
157                                         keep_alive();
158                                 if (elapsed_ms > FLASH_TIMEOUT)
159                                         break;
160                         }
161                 }
162
163                 if (!done) {
164                         /* Sector erase timed out waiting for confirmation */
165                         return ERROR_FAIL;
166                 }
167         }
168
169         return retval;
170 }
171
172 static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
173         uint32_t offset, uint32_t count)
174 {
175         struct target *target = bank->target;
176         struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
177         struct working_area *algo_working_area;
178         struct working_area *buffer_working_area;
179         struct reg_param reg_params[3];
180         uint32_t algo_base_address;
181         uint32_t algo_buffer_address;
182         uint32_t algo_buffer_size;
183         uint32_t address;
184         uint32_t remaining;
185         uint32_t words;
186         uint32_t result;
187
188         int retval = ERROR_OK;
189
190         if (target->state != TARGET_HALTED) {
191                 LOG_ERROR("Target not halted");
192                 return ERROR_TARGET_NOT_HALTED;
193         }
194
195         /* Obtain working area to use for flash helper algorithm */
196         retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
197                                 &algo_working_area);
198         if (retval != ERROR_OK)
199                 return retval;
200
201         /* Obtain working area to use for flash buffer */
202         retval = target_alloc_working_area(target,
203                                 target_get_working_area_avail(target), &buffer_working_area);
204         if (retval != ERROR_OK) {
205                 target_free_working_area(target, algo_working_area);
206                 return retval;
207         }
208
209         algo_base_address = algo_working_area->address;
210         algo_buffer_address = buffer_working_area->address;
211         algo_buffer_size = buffer_working_area->size;
212
213         /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
214         /* (algo runs more efficiently if it operates on 32 words at a time) */
215         if (algo_buffer_size > 0x80)
216                 algo_buffer_size &= ~0x7f;
217
218         /* Write flash helper algorithm into target memory */
219         retval = target_write_buffer(target, algo_base_address,
220                                 sizeof(cc3220sf_algo), cc3220sf_algo);
221         if (retval != ERROR_OK) {
222                 target_free_working_area(target, algo_working_area);
223                 target_free_working_area(target, buffer_working_area);
224                 return retval;
225         }
226
227         /* Initialize the ARMv7m specific info to run the algorithm */
228         cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
229         cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
230
231         /* Initialize register params for flash helper algorithm */
232         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
233         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
234         init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
235
236         /* Prepare to write to flash */
237         address = FLASH_BASE_ADDR + offset;
238         remaining = count;
239
240         /* The flash hardware can only write complete words to flash. If
241          * an unaligned address is passed in, we must do a read-modify-write
242          * on a word with enough bytes to align the rest of the buffer. And
243          * if less than a whole word remains at the end, we must also do a
244          * read-modify-write on a final word to finish up.
245          */
246
247         /* Do one word write to align address on 32-bit boundary if needed */
248         if (0 != (address & 0x3)) {
249                 uint8_t head[4];
250
251                 /* Get starting offset for data to write (will be 1 to 3) */
252                 uint32_t head_offset = address & 0x03;
253
254                 /* Get the aligned address to write this first word to */
255                 uint32_t head_address = address & 0xfffffffc;
256
257                 /* Retrieve what is already in flash at the head address */
258                 retval = target_read_buffer(target, head_address, sizeof(head), head);
259
260                 if (retval == ERROR_OK) {
261                         /* Substitute in the new data to write */
262                         while ((remaining > 0) && (head_offset < 4)) {
263                                 head[head_offset] = *buffer;
264                                 head_offset++;
265                                 address++;
266                                 buffer++;
267                                 remaining--;
268                         }
269                 }
270
271                 if (retval == ERROR_OK) {
272                         /* Helper parameters are passed in registers R0-R2 */
273                         /* Set start of data buffer, address to write to, and word count */
274                         buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
275                         buf_set_u32(reg_params[1].value, 0, 32, head_address);
276                         buf_set_u32(reg_params[2].value, 0, 32, 1);
277
278                         /* Write head value into buffer to flash */
279                         retval = target_write_buffer(target, algo_buffer_address,
280                                                 sizeof(head), head);
281                 }
282
283                 if (retval == ERROR_OK) {
284                         /* Execute the flash helper algorithm */
285                         retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
286                                                 algo_base_address, 0, FLASH_TIMEOUT,
287                                                 &cc3220sf_bank->armv7m_info);
288                         if (retval != ERROR_OK)
289                                 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
290
291                         /* Check that the head value was written to flash */
292                         result = buf_get_u32(reg_params[2].value, 0, 32);
293                         if (result != 0) {
294                                 retval = ERROR_FAIL;
295                                 LOG_ERROR("cc3220sf: Flash operation failed");
296                         }
297                 }
298         }
299
300         /* Check if there's data at end of buffer that isn't a full word */
301         uint32_t tail_count = remaining & 0x03;
302         /* Adjust remaining so it is a multiple of whole words */
303         remaining -= tail_count;
304
305         while ((retval == ERROR_OK) && (remaining > 0)) {
306                 /* Set start of data buffer and address to write to */
307                 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
308                 buf_set_u32(reg_params[1].value, 0, 32, address);
309
310                 /* Download data to write into memory buffer */
311                 if (remaining >= algo_buffer_size) {
312                         /* Fill up buffer with data to flash */
313                         retval = target_write_buffer(target, algo_buffer_address,
314                                                 algo_buffer_size, buffer);
315                         if (retval != ERROR_OK)
316                                 break;
317
318                         /* Count to write is in 32-bit words */
319                         words = algo_buffer_size / 4;
320
321                         /* Bump variables to next data */
322                         address += algo_buffer_size;
323                         buffer += algo_buffer_size;
324                         remaining -= algo_buffer_size;
325                 } else {
326                         /* Fill buffer with what's left of the data */
327                         retval = target_write_buffer(target, algo_buffer_address,
328                                                 remaining, buffer);
329                         if (retval != ERROR_OK)
330                                 break;
331
332                         /* Calculate the final word count to write */
333                         words = remaining / 4;
334                         if (0 != (remaining % 4))
335                                 words++;
336
337                         /* Bump variables to any final data */
338                         address += remaining;
339                         buffer += remaining;
340                         remaining = 0;
341                 }
342
343                 /* Set number of words to write */
344                 buf_set_u32(reg_params[2].value, 0, 32, words);
345
346                 /* Execute the flash helper algorithm */
347                 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
348                                         algo_base_address, 0, FLASH_TIMEOUT,
349                                         &cc3220sf_bank->armv7m_info);
350                 if (retval != ERROR_OK) {
351                         LOG_ERROR("cc3220sf: Flash algorithm failed to run");
352                         break;
353                 }
354
355                 /* Check that all words were written to flash */
356                 result = buf_get_u32(reg_params[2].value, 0, 32);
357                 if (result != 0) {
358                         retval = ERROR_FAIL;
359                         LOG_ERROR("cc3220sf: Flash operation failed");
360                         break;
361                 }
362
363                 keep_alive();
364         }
365
366         /* Do one word write for any final bytes less than a full word */
367         if ((retval == ERROR_OK) && (tail_count != 0)) {
368                 uint8_t tail[4];
369
370                 /* Set starting byte offset for data to write */
371                 uint32_t tail_offset = 0;
372
373                 /* Retrieve what is already in flash at the tail address */
374                 retval = target_read_buffer(target, address, sizeof(tail), tail);
375
376                 if (retval == ERROR_OK) {
377                         /* Substitute in the new data to write */
378                         while (tail_count > 0) {
379                                 tail[tail_offset] = *buffer;
380                                 tail_offset++;
381                                 buffer++;
382                                 tail_count--;
383                         }
384                 }
385
386                 if (retval == ERROR_OK) {
387                         /* Set start of data buffer, address to write to, and word count */
388                         buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
389                         buf_set_u32(reg_params[1].value, 0, 32, address);
390                         buf_set_u32(reg_params[2].value, 0, 32, 1);
391
392                         /* Write tail value into buffer to flash */
393                         retval = target_write_buffer(target, algo_buffer_address,
394                                                 sizeof(tail), tail);
395                 }
396
397                 if (retval == ERROR_OK) {
398                         /* Execute the flash helper algorithm */
399                         retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
400                                                 algo_base_address, 0, FLASH_TIMEOUT,
401                                                 &cc3220sf_bank->armv7m_info);
402                         if (retval != ERROR_OK)
403                                 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
404
405                         /* Check that the tail was written to flash */
406                         result = buf_get_u32(reg_params[2].value, 0, 32);
407                         if (result != 0) {
408                                 retval = ERROR_FAIL;
409                                 LOG_ERROR("cc3220sf: Flash operation failed");
410                         }
411                 }
412         }
413
414         /* Free resources  */
415         destroy_reg_param(&reg_params[0]);
416         destroy_reg_param(&reg_params[1]);
417         destroy_reg_param(&reg_params[2]);
418         target_free_working_area(target, algo_working_area);
419         target_free_working_area(target, buffer_working_area);
420
421         return retval;
422 }
423
424 static int cc3220sf_probe(struct flash_bank *bank)
425 {
426         struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
427
428         uint32_t base;
429         uint32_t size;
430         unsigned int num_sectors;
431
432         base = FLASH_BASE_ADDR;
433         size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
434         num_sectors = FLASH_NUM_SECTORS;
435
436         free(bank->sectors);
437
438         bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
439         if (!bank->sectors)
440                 return ERROR_FAIL;
441
442         bank->base = base;
443         bank->size = size;
444         bank->write_start_alignment = 0;
445         bank->write_end_alignment = 0;
446         bank->num_sectors = num_sectors;
447
448         for (unsigned int i = 0; i < num_sectors; i++) {
449                 bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
450                 bank->sectors[i].size = FLASH_SECTOR_SIZE;
451                 bank->sectors[i].is_erased = -1;
452                 bank->sectors[i].is_protected = 0;
453         }
454
455         /* We've successfully recorded the stats on this flash bank */
456         cc3220sf_bank->probed = true;
457
458         /* If we fall through to here, then all went well */
459
460         return ERROR_OK;
461 }
462
463 static int cc3220sf_auto_probe(struct flash_bank *bank)
464 {
465         struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
466
467         int retval = ERROR_OK;
468
469         if (!cc3220sf_bank->probed)
470                 retval = cc3220sf_probe(bank);
471
472         return retval;
473 }
474
475 static int cc3220sf_info(struct flash_bank *bank, struct command_invocation *cmd)
476 {
477         command_print_sameline(cmd, "CC3220SF with 1MB internal flash\n");
478         return ERROR_OK;
479 }
480
481 const struct flash_driver cc3220sf_flash = {
482         .name = "cc3220sf",
483         .flash_bank_command = cc3220sf_flash_bank_command,
484         .erase = cc3220sf_erase,
485         .write = cc3220sf_write,
486         .read = default_flash_read,
487         .probe = cc3220sf_probe,
488         .auto_probe = cc3220sf_auto_probe,
489         .erase_check = default_flash_blank_check,
490         .info = cc3220sf_info,
491         .free_driver_priv = default_flash_free_driver_priv,
492 };