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