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