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

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)