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

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)