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

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)