openocd: src/flash: replace the GPL-2.0-or-later license tag
[openocd.git] / 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 };

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)