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

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)