flash/nor/at91samd: set usage for command "set-security"
[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_write(struct flash_bank *bank, const uint8_t *buffer,
177 uint32_t offset, uint32_t count)
178 {
179 struct target *target = bank->target;
180 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
181 struct working_area *algo_working_area;
182 struct working_area *buffer_working_area;
183 struct reg_param reg_params[3];
184 uint32_t algo_base_address;
185 uint32_t algo_buffer_address;
186 uint32_t algo_buffer_size;
187 uint32_t address;
188 uint32_t remaining;
189 uint32_t words;
190 uint32_t result;
191
192 int retval = ERROR_OK;
193
194 if (TARGET_HALTED != target->state) {
195 LOG_ERROR("Target not halted");
196 return ERROR_TARGET_NOT_HALTED;
197 }
198
199 /* Obtain working area to use for flash helper algorithm */
200 retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
201 &algo_working_area);
202 if (ERROR_OK != retval)
203 return retval;
204
205 /* Obtain working area to use for flash buffer */
206 retval = target_alloc_working_area(target,
207 target_get_working_area_avail(target), &buffer_working_area);
208 if (ERROR_OK != retval) {
209 target_free_working_area(target, algo_working_area);
210 return retval;
211 }
212
213 algo_base_address = algo_working_area->address;
214 algo_buffer_address = buffer_working_area->address;
215 algo_buffer_size = buffer_working_area->size;
216
217 /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
218 /* (algo runs more efficiently if it operates on 32 words at a time) */
219 if (algo_buffer_size > 0x80)
220 algo_buffer_size &= ~0x7f;
221
222 /* Write flash helper algorithm into target memory */
223 retval = target_write_buffer(target, algo_base_address,
224 sizeof(cc3220sf_algo), cc3220sf_algo);
225 if (ERROR_OK != retval) {
226 target_free_working_area(target, algo_working_area);
227 target_free_working_area(target, buffer_working_area);
228 return retval;
229 }
230
231 /* Initialize the ARMv7m specific info to run the algorithm */
232 cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
233 cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
234
235 /* Initialize register params for flash helper algorithm */
236 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
237 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
238 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
239
240 /* Prepare to write to flash */
241 address = FLASH_BASE_ADDR + offset;
242 remaining = count;
243
244 /* The flash hardware can only write complete words to flash. If
245 * an unaligned address is passed in, we must do a read-modify-write
246 * on a word with enough bytes to align the rest of the buffer. And
247 * if less than a whole word remains at the end, we must also do a
248 * read-modify-write on a final word to finish up.
249 */
250
251 /* Do one word write to align address on 32-bit boundary if needed */
252 if (0 != (address & 0x3)) {
253 uint8_t head[4];
254
255 /* Get starting offset for data to write (will be 1 to 3) */
256 uint32_t head_offset = address & 0x03;
257
258 /* Get the aligned address to write this first word to */
259 uint32_t head_address = address & 0xfffffffc;
260
261 /* Retrieve what is already in flash at the head address */
262 retval = target_read_buffer(target, head_address, sizeof(head), head);
263
264 if (ERROR_OK == retval) {
265 /* Substitute in the new data to write */
266 while ((remaining > 0) && (head_offset < 4)) {
267 head[head_offset] = *buffer;
268 head_offset++;
269 address++;
270 buffer++;
271 remaining--;
272 }
273 }
274
275 if (ERROR_OK == retval) {
276 /* Helper parameters are passed in registers R0-R2 */
277 /* Set start of data buffer, address to write to, and word count */
278 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
279 buf_set_u32(reg_params[1].value, 0, 32, head_address);
280 buf_set_u32(reg_params[2].value, 0, 32, 1);
281
282 /* Write head value into buffer to flash */
283 retval = target_write_buffer(target, algo_buffer_address,
284 sizeof(head), head);
285 }
286
287 if (ERROR_OK == retval) {
288 /* Execute the flash helper algorithm */
289 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
290 algo_base_address, 0, FLASH_TIMEOUT,
291 &cc3220sf_bank->armv7m_info);
292 if (ERROR_OK != retval)
293 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
294
295 /* Check that the head value was written to flash */
296 result = buf_get_u32(reg_params[2].value, 0, 32);
297 if (0 != result) {
298 retval = ERROR_FAIL;
299 LOG_ERROR("cc3220sf: Flash operation failed");
300 }
301 }
302 }
303
304 /* Check if there's data at end of buffer that isn't a full word */
305 uint32_t tail_count = remaining & 0x03;
306 /* Adjust remaining so it is a multiple of whole words */
307 remaining -= tail_count;
308
309 while ((ERROR_OK == retval) && (remaining > 0)) {
310 /* Set start of data buffer and address to write to */
311 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
312 buf_set_u32(reg_params[1].value, 0, 32, address);
313
314 /* Download data to write into memory buffer */
315 if (remaining >= algo_buffer_size) {
316 /* Fill up buffer with data to flash */
317 retval = target_write_buffer(target, algo_buffer_address,
318 algo_buffer_size, buffer);
319 if (ERROR_OK != retval)
320 break;
321
322 /* Count to write is in 32-bit words */
323 words = algo_buffer_size / 4;
324
325 /* Bump variables to next data */
326 address += algo_buffer_size;
327 buffer += algo_buffer_size;
328 remaining -= algo_buffer_size;
329 } else {
330 /* Fill buffer with what's left of the data */
331 retval = target_write_buffer(target, algo_buffer_address,
332 remaining, buffer);
333 if (ERROR_OK != retval)
334 break;
335
336 /* Calculate the final word count to write */
337 words = remaining / 4;
338 if (0 != (remaining % 4))
339 words++;
340
341 /* Bump variables to any final data */
342 address += remaining;
343 buffer += remaining;
344 remaining = 0;
345 }
346
347 /* Set number of words to write */
348 buf_set_u32(reg_params[2].value, 0, 32, words);
349
350 /* Execute the flash helper algorithm */
351 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
352 algo_base_address, 0, FLASH_TIMEOUT,
353 &cc3220sf_bank->armv7m_info);
354 if (ERROR_OK != retval) {
355 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
356 break;
357 }
358
359 /* Check that all words were written to flash */
360 result = buf_get_u32(reg_params[2].value, 0, 32);
361 if (0 != result) {
362 retval = ERROR_FAIL;
363 LOG_ERROR("cc3220sf: Flash operation failed");
364 break;
365 }
366 }
367
368 /* Do one word write for any final bytes less than a full word */
369 if ((ERROR_OK == retval) && (0 != tail_count)) {
370 uint8_t tail[4];
371
372 /* Set starting byte offset for data to write */
373 uint32_t tail_offset = 0;
374
375 /* Retrieve what is already in flash at the tail address */
376 retval = target_read_buffer(target, address, sizeof(tail), tail);
377
378 if (ERROR_OK == retval) {
379 /* Substitute in the new data to write */
380 while (tail_count > 0) {
381 tail[tail_offset] = *buffer;
382 tail_offset++;
383 buffer++;
384 tail_count--;
385 }
386 }
387
388 if (ERROR_OK == retval) {
389 /* Set start of data buffer, address to write to, and word count */
390 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
391 buf_set_u32(reg_params[1].value, 0, 32, address);
392 buf_set_u32(reg_params[2].value, 0, 32, 1);
393
394 /* Write tail value into buffer to flash */
395 retval = target_write_buffer(target, algo_buffer_address,
396 sizeof(tail), tail);
397 }
398
399 if (ERROR_OK == retval) {
400 /* Execute the flash helper algorithm */
401 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
402 algo_base_address, 0, FLASH_TIMEOUT,
403 &cc3220sf_bank->armv7m_info);
404 if (ERROR_OK != retval)
405 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
406
407 /* Check that the tail was written to flash */
408 result = buf_get_u32(reg_params[2].value, 0, 32);
409 if (0 != result) {
410 retval = ERROR_FAIL;
411 LOG_ERROR("cc3220sf: Flash operation failed");
412 }
413 }
414 }
415
416 /* Free resources */
417 destroy_reg_param(&reg_params[0]);
418 destroy_reg_param(&reg_params[1]);
419 destroy_reg_param(&reg_params[2]);
420 target_free_working_area(target, algo_working_area);
421 target_free_working_area(target, buffer_working_area);
422
423 return retval;
424 }
425
426 static int cc3220sf_probe(struct flash_bank *bank)
427 {
428 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
429
430 uint32_t base;
431 uint32_t size;
432 int num_sectors;
433
434 base = FLASH_BASE_ADDR;
435 size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
436 num_sectors = FLASH_NUM_SECTORS;
437
438 if (NULL != bank->sectors) {
439 free(bank->sectors);
440 bank->sectors = NULL;
441 }
442
443 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
444 if (NULL == bank->sectors)
445 return ERROR_FAIL;
446
447 bank->base = base;
448 bank->size = size;
449 bank->write_start_alignment = 0;
450 bank->write_end_alignment = 0;
451 bank->num_sectors = num_sectors;
452
453 for (int i = 0; i < num_sectors; i++) {
454 bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
455 bank->sectors[i].size = FLASH_SECTOR_SIZE;
456 bank->sectors[i].is_erased = -1;
457 bank->sectors[i].is_protected = 0;
458 }
459
460 /* We've successfully recorded the stats on this flash bank */
461 cc3220sf_bank->probed = true;
462
463 /* If we fall through to here, then all went well */
464
465 return ERROR_OK;
466 }
467
468 static int cc3220sf_auto_probe(struct flash_bank *bank)
469 {
470 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
471
472 int retval = ERROR_OK;
473
474 if (!cc3220sf_bank->probed)
475 retval = cc3220sf_probe(bank);
476
477 return retval;
478 }
479
480 static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
481 {
482 int printed;
483
484 printed = snprintf(buf, buf_size, "CC3220SF with 1MB internal flash\n");
485
486 if (printed >= buf_size)
487 return ERROR_BUF_TOO_SMALL;
488
489 return ERROR_OK;
490 }
491
492 const struct flash_driver cc3220sf_flash = {
493 .name = "cc3220sf",
494 .flash_bank_command = cc3220sf_flash_bank_command,
495 .erase = cc3220sf_erase,
496 .write = cc3220sf_write,
497 .read = default_flash_read,
498 .probe = cc3220sf_probe,
499 .auto_probe = cc3220sf_auto_probe,
500 .erase_check = default_flash_blank_check,
501 .info = cc3220sf_info,
502 .free_driver_priv = default_flash_free_driver_priv,
503 };

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)