stm32l4x: Fix stm32l4x dual bank support
[openocd.git] / src / flash / nor / cc26xx.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 "cc26xx.h"
24 #include <helper/binarybuffer.h>
25 #include <helper/time_support.h>
26 #include <target/algorithm.h>
27 #include <target/armv7m.h>
28 #include <target/image.h>
29
30 #define FLASH_TIMEOUT 8000
31
32 struct cc26xx_bank {
33 const char *family_name;
34 uint32_t icepick_id;
35 uint32_t user_id;
36 uint32_t device_type;
37 uint32_t sector_length;
38 bool probed;
39 struct working_area *working_area;
40 struct armv7m_algorithm armv7m_info;
41 const uint8_t *algo_code;
42 uint32_t algo_size;
43 uint32_t algo_working_size;
44 uint32_t buffer_addr[2];
45 uint32_t params_addr[2];
46 };
47
48 static int cc26xx_auto_probe(struct flash_bank *bank);
49
50 static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id)
51 {
52 uint32_t device_type = 0;
53
54 switch (icepick_id & ICEPICK_ID_MASK) {
55 case CC26X0_ICEPICK_ID:
56 device_type = CC26X0_TYPE;
57 break;
58 case CC26X1_ICEPICK_ID:
59 device_type = CC26X1_TYPE;
60 break;
61 case CC13X0_ICEPICK_ID:
62 device_type = CC13X0_TYPE;
63 break;
64 case CC13X2_CC26X2_ICEPICK_ID:
65 default:
66 if ((user_id & USER_ID_CC13_MASK) != 0)
67 device_type = CC13X2_TYPE;
68 else
69 device_type = CC26X2_TYPE;
70 break;
71 }
72
73 return device_type;
74 }
75
76 static uint32_t cc26xx_sector_length(uint32_t icepick_id)
77 {
78 uint32_t sector_length;
79
80 switch (icepick_id & ICEPICK_ID_MASK) {
81 case CC26X0_ICEPICK_ID:
82 case CC26X1_ICEPICK_ID:
83 case CC13X0_ICEPICK_ID:
84 /* Chameleon family device */
85 sector_length = CC26X0_SECTOR_LENGTH;
86 break;
87 case CC13X2_CC26X2_ICEPICK_ID:
88 default:
89 /* Agama family device */
90 sector_length = CC26X2_SECTOR_LENGTH;
91 break;
92 }
93
94 return sector_length;
95 }
96
97 static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
98 {
99 struct target *target = bank->target;
100 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
101
102 uint32_t status_addr = params_addr + CC26XX_STATUS_OFFSET;
103 uint32_t status = CC26XX_BUFFER_FULL;
104 long long start_ms;
105 long long elapsed_ms;
106
107 int retval = ERROR_OK;
108
109 start_ms = timeval_ms();
110 while (CC26XX_BUFFER_FULL == status) {
111 retval = target_read_u32(target, status_addr, &status);
112 if (ERROR_OK != retval)
113 return retval;
114
115 elapsed_ms = timeval_ms() - start_ms;
116 if (elapsed_ms > 500)
117 keep_alive();
118 if (elapsed_ms > FLASH_TIMEOUT)
119 break;
120 };
121
122 if (CC26XX_BUFFER_EMPTY != status) {
123 LOG_ERROR("%s: Flash operation failed", cc26xx_bank->family_name);
124 return ERROR_FAIL;
125 }
126
127 return ERROR_OK;
128 }
129
130 static int cc26xx_init(struct flash_bank *bank)
131 {
132 struct target *target = bank->target;
133 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
134
135 int retval;
136
137 /* Make sure we've probed the flash to get the device and size */
138 retval = cc26xx_auto_probe(bank);
139 if (ERROR_OK != retval)
140 return retval;
141
142 /* Check for working area to use for flash helper algorithm */
143 if (NULL != cc26xx_bank->working_area)
144 target_free_working_area(target, cc26xx_bank->working_area);
145 retval = target_alloc_working_area(target, cc26xx_bank->algo_working_size,
146 &cc26xx_bank->working_area);
147 if (ERROR_OK != retval)
148 return retval;
149
150 /* Confirm the defined working address is the area we need to use */
151 if (CC26XX_ALGO_BASE_ADDRESS != cc26xx_bank->working_area->address)
152 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
153
154 /* Write flash helper algorithm into target memory */
155 retval = target_write_buffer(target, CC26XX_ALGO_BASE_ADDRESS,
156 cc26xx_bank->algo_size, cc26xx_bank->algo_code);
157 if (ERROR_OK != retval) {
158 LOG_ERROR("%s: Failed to load flash helper algorithm",
159 cc26xx_bank->family_name);
160 target_free_working_area(target, cc26xx_bank->working_area);
161 return retval;
162 }
163
164 /* Initialize the ARMv7 specific info to run the algorithm */
165 cc26xx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
166 cc26xx_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
167
168 /* Begin executing the flash helper algorithm */
169 retval = target_start_algorithm(target, 0, NULL, 0, NULL,
170 CC26XX_ALGO_BASE_ADDRESS, 0, &cc26xx_bank->armv7m_info);
171 if (ERROR_OK != retval) {
172 LOG_ERROR("%s: Failed to start flash helper algorithm",
173 cc26xx_bank->family_name);
174 target_free_working_area(target, cc26xx_bank->working_area);
175 return retval;
176 }
177
178 /*
179 * At this point, the algorithm is running on the target and
180 * ready to receive commands and data to flash the target
181 */
182
183 return retval;
184 }
185
186 static int cc26xx_quit(struct flash_bank *bank)
187 {
188 struct target *target = bank->target;
189 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
190
191 int retval;
192
193 /* Regardless of the algo's status, attempt to halt the target */
194 (void)target_halt(target);
195
196 /* Now confirm target halted and clean up from flash helper algorithm */
197 retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT,
198 &cc26xx_bank->armv7m_info);
199
200 target_free_working_area(target, cc26xx_bank->working_area);
201 cc26xx_bank->working_area = NULL;
202
203 return retval;
204 }
205
206 static int cc26xx_mass_erase(struct flash_bank *bank)
207 {
208 struct target *target = bank->target;
209 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
210 struct cc26xx_algo_params algo_params;
211
212 int retval;
213
214 if (TARGET_HALTED != target->state) {
215 LOG_ERROR("Target not halted");
216 return ERROR_TARGET_NOT_HALTED;
217 }
218
219 retval = cc26xx_init(bank);
220 if (ERROR_OK != retval)
221 return retval;
222
223 /* Initialize algorithm parameters */
224 buf_set_u32(algo_params.address, 0, 32, 0);
225 buf_set_u32(algo_params.length, 0, 32, 4);
226 buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_ALL);
227 buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
228
229 /* Issue flash helper algorithm parameters for mass erase */
230 retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
231 sizeof(algo_params), (uint8_t *)&algo_params);
232
233 /* Wait for command to complete */
234 if (ERROR_OK == retval)
235 retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
236
237 /* Regardless of errors, try to close down algo */
238 (void)cc26xx_quit(bank);
239
240 return retval;
241 }
242
243 FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command)
244 {
245 struct cc26xx_bank *cc26xx_bank;
246
247 if (CMD_ARGC < 6)
248 return ERROR_COMMAND_SYNTAX_ERROR;
249
250 cc26xx_bank = malloc(sizeof(struct cc26xx_bank));
251 if (NULL == cc26xx_bank)
252 return ERROR_FAIL;
253
254 /* Initialize private flash information */
255 memset((void *)cc26xx_bank, 0x00, sizeof(struct cc26xx_bank));
256 cc26xx_bank->family_name = "cc26xx";
257 cc26xx_bank->device_type = CC26XX_NO_TYPE;
258 cc26xx_bank->sector_length = 0x1000;
259
260 /* Finish initialization of bank */
261 bank->driver_priv = cc26xx_bank;
262 bank->next = NULL;
263
264 return ERROR_OK;
265 }
266
267 static int cc26xx_erase(struct flash_bank *bank, int first, int last)
268 {
269 struct target *target = bank->target;
270 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
271 struct cc26xx_algo_params algo_params;
272
273 uint32_t address;
274 uint32_t length;
275 int retval;
276
277 if (TARGET_HALTED != target->state) {
278 LOG_ERROR("Target not halted");
279 return ERROR_TARGET_NOT_HALTED;
280 }
281
282 /* Do a mass erase if user requested all sectors of flash */
283 if ((first == 0) && (last == (bank->num_sectors - 1))) {
284 /* Request mass erase of flash */
285 return cc26xx_mass_erase(bank);
286 }
287
288 address = first * cc26xx_bank->sector_length;
289 length = (last - first + 1) * cc26xx_bank->sector_length;
290
291 retval = cc26xx_init(bank);
292 if (ERROR_OK != retval)
293 return retval;
294
295 /* Set up algorithm parameters for erase command */
296 buf_set_u32(algo_params.address, 0, 32, address);
297 buf_set_u32(algo_params.length, 0, 32, length);
298 buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_SECTORS);
299 buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
300
301 /* Issue flash helper algorithm parameters for erase */
302 retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
303 sizeof(algo_params), (uint8_t *)&algo_params);
304
305 /* If no error, wait for erase to finish */
306 if (ERROR_OK == retval)
307 retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
308
309 /* Regardless of errors, try to close down algo */
310 (void)cc26xx_quit(bank);
311
312 return retval;
313 }
314
315 static int cc26xx_protect(struct flash_bank *bank, int set, int first,
316 int last)
317 {
318 return ERROR_OK;
319 }
320
321 static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer,
322 uint32_t offset, uint32_t count)
323 {
324 struct target *target = bank->target;
325 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
326 struct cc26xx_algo_params algo_params[2];
327 uint32_t size = 0;
328 long long start_ms;
329 long long elapsed_ms;
330 uint32_t address;
331
332 uint32_t index;
333 int retval;
334
335 if (TARGET_HALTED != target->state) {
336 LOG_ERROR("Target not halted");
337 return ERROR_TARGET_NOT_HALTED;
338 }
339
340 retval = cc26xx_init(bank);
341 if (ERROR_OK != retval)
342 return retval;
343
344 /* Initialize algorithm parameters to default values */
345 buf_set_u32(algo_params[0].command, 0, 32, CC26XX_CMD_PROGRAM);
346 buf_set_u32(algo_params[1].command, 0, 32, CC26XX_CMD_PROGRAM);
347
348 /* Write requested data, ping-ponging between two buffers */
349 index = 0;
350 start_ms = timeval_ms();
351 address = bank->base + offset;
352 while (count > 0) {
353
354 if (count > cc26xx_bank->sector_length)
355 size = cc26xx_bank->sector_length;
356 else
357 size = count;
358
359 /* Put next block of data to flash into buffer */
360 retval = target_write_buffer(target, cc26xx_bank->buffer_addr[index],
361 size, buffer);
362 if (ERROR_OK != retval) {
363 LOG_ERROR("Unable to write data to target memory");
364 break;
365 }
366
367 /* Update algo parameters for next block */
368 buf_set_u32(algo_params[index].address, 0, 32, address);
369 buf_set_u32(algo_params[index].length, 0, 32, size);
370 buf_set_u32(algo_params[index].status, 0, 32, CC26XX_BUFFER_FULL);
371
372 /* Issue flash helper algorithm parameters for block write */
373 retval = target_write_buffer(target, cc26xx_bank->params_addr[index],
374 sizeof(algo_params[index]), (uint8_t *)&algo_params[index]);
375 if (ERROR_OK != retval)
376 break;
377
378 /* Wait for next ping pong buffer to be ready */
379 index ^= 1;
380 retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
381 if (ERROR_OK != retval)
382 break;
383
384 count -= size;
385 buffer += size;
386 address += size;
387
388 elapsed_ms = timeval_ms() - start_ms;
389 if (elapsed_ms > 500)
390 keep_alive();
391 }
392
393 /* If no error yet, wait for last buffer to finish */
394 if (ERROR_OK == retval) {
395 index ^= 1;
396 retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
397 }
398
399 /* Regardless of errors, try to close down algo */
400 (void)cc26xx_quit(bank);
401
402 return retval;
403 }
404
405 static int cc26xx_probe(struct flash_bank *bank)
406 {
407 struct target *target = bank->target;
408 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
409
410 uint32_t sector_length;
411 uint32_t value;
412 int num_sectors;
413 int max_sectors;
414
415 int retval;
416
417 retval = target_read_u32(target, FCFG1_ICEPICK_ID, &value);
418 if (ERROR_OK != retval)
419 return retval;
420 cc26xx_bank->icepick_id = value;
421
422 retval = target_read_u32(target, FCFG1_USER_ID, &value);
423 if (ERROR_OK != retval)
424 return retval;
425 cc26xx_bank->user_id = value;
426
427 cc26xx_bank->device_type = cc26xx_device_type(cc26xx_bank->icepick_id,
428 cc26xx_bank->user_id);
429
430 sector_length = cc26xx_sector_length(cc26xx_bank->icepick_id);
431
432 /* Set up appropriate flash helper algorithm */
433 switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) {
434 case CC26X0_ICEPICK_ID:
435 case CC26X1_ICEPICK_ID:
436 case CC13X0_ICEPICK_ID:
437 /* Chameleon family device */
438 cc26xx_bank->algo_code = cc26x0_algo;
439 cc26xx_bank->algo_size = sizeof(cc26x0_algo);
440 cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE;
441 cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0;
442 cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1;
443 cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0;
444 cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1;
445 max_sectors = CC26X0_MAX_SECTORS;
446 break;
447 case CC13X2_CC26X2_ICEPICK_ID:
448 default:
449 /* Agama family device */
450 cc26xx_bank->algo_code = cc26x2_algo;
451 cc26xx_bank->algo_size = sizeof(cc26x2_algo);
452 cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE;
453 cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0;
454 cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1;
455 cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0;
456 cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1;
457 max_sectors = CC26X2_MAX_SECTORS;
458 break;
459 }
460
461 retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value);
462 if (ERROR_OK != retval)
463 return retval;
464 num_sectors = value & 0xff;
465 if (num_sectors > max_sectors)
466 num_sectors = max_sectors;
467
468 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
469 if (NULL == bank->sectors)
470 return ERROR_FAIL;
471
472 bank->base = CC26XX_FLASH_BASE_ADDR;
473 bank->num_sectors = num_sectors;
474 bank->size = num_sectors * sector_length;
475 bank->write_start_alignment = 0;
476 bank->write_end_alignment = 0;
477 cc26xx_bank->sector_length = sector_length;
478
479 for (int i = 0; i < num_sectors; i++) {
480 bank->sectors[i].offset = i * sector_length;
481 bank->sectors[i].size = sector_length;
482 bank->sectors[i].is_erased = -1;
483 bank->sectors[i].is_protected = 0;
484 }
485
486 /* We've successfully determined the stats on the flash bank */
487 cc26xx_bank->probed = true;
488
489 /* If we fall through to here, then all went well */
490
491 return ERROR_OK;
492 }
493
494 static int cc26xx_auto_probe(struct flash_bank *bank)
495 {
496 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
497
498 int retval = ERROR_OK;
499
500 if (bank->bank_number != 0) {
501 /* Invalid bank number somehow */
502 return ERROR_FAIL;
503 }
504
505 if (!cc26xx_bank->probed)
506 retval = cc26xx_probe(bank);
507
508 return retval;
509 }
510
511 static int cc26xx_protect_check(struct flash_bank *bank)
512 {
513 return ERROR_OK;
514 }
515
516 static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size)
517 {
518 struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
519 int printed = 0;
520 const char *device;
521
522 switch (cc26xx_bank->device_type) {
523 case CC26X0_TYPE:
524 device = "CC26x0";
525 break;
526 case CC26X1_TYPE:
527 device = "CC26x1";
528 break;
529 case CC13X0_TYPE:
530 device = "CC13x0";
531 break;
532 case CC13X2_TYPE:
533 device = "CC13x2";
534 break;
535 case CC26X2_TYPE:
536 device = "CC26x2";
537 break;
538 case CC26XX_NO_TYPE:
539 default:
540 device = "Unrecognized";
541 break;
542 }
543
544 printed = snprintf(buf, buf_size,
545 "%s device: ICEPick ID 0x%08x, USER ID 0x%08x\n",
546 device, cc26xx_bank->icepick_id, cc26xx_bank->user_id);
547
548 if (printed >= buf_size)
549 return ERROR_BUF_TOO_SMALL;
550
551 return ERROR_OK;
552 }
553
554 struct flash_driver cc26xx_flash = {
555 .name = "cc26xx",
556 .flash_bank_command = cc26xx_flash_bank_command,
557 .erase = cc26xx_erase,
558 .protect = cc26xx_protect,
559 .write = cc26xx_write,
560 .read = default_flash_read,
561 .probe = cc26xx_probe,
562 .auto_probe = cc26xx_auto_probe,
563 .erase_check = default_flash_blank_check,
564 .protect_check = cc26xx_protect_check,
565 .info = cc26xx_info,
566 .free_driver_priv = default_flash_free_driver_priv,
567 };

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)