flash/nor: Add support for TI CC3220SF internal flash
[openocd.git] / 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 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)