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