1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2017 by Texas Instruments, Inc. *
5 ***************************************************************************/
13 #include <helper/binarybuffer.h>
14 #include <helper/time_support.h>
15 #include <target/algorithm.h>
16 #include <target/armv7m.h>
18 #define FLASH_TIMEOUT 5000
20 struct cc3220sf_bank
{
22 struct armv7m_algorithm armv7m_info
;
25 /* Flash helper algorithm for CC3220SF */
26 static const uint8_t cc3220sf_algo
[] = {
27 #include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc"
30 static int cc3220sf_mass_erase(struct flash_bank
*bank
)
32 struct target
*target
= bank
->target
;
38 int retval
= ERROR_OK
;
40 if (target
->state
!= TARGET_HALTED
) {
41 LOG_ERROR("Target not halted");
42 return ERROR_TARGET_NOT_HALTED
;
45 /* Set starting address to erase to zero */
46 retval
= target_write_u32(target
, FMA_REGISTER_ADDR
, 0);
47 if (retval
!= ERROR_OK
)
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
)
55 /* Poll the MERASE bit until the mass erase is complete */
57 start_ms
= timeval_ms();
59 retval
= target_read_u32(target
, FMC_REGISTER_ADDR
, &value
);
60 if (retval
!= ERROR_OK
)
63 if ((value
& FMC_MERASE_BIT
) == 0) {
64 /* Bit clears when mass erase is finished */
67 elapsed_ms
= timeval_ms() - start_ms
;
70 if (elapsed_ms
> FLASH_TIMEOUT
)
76 /* Mass erase timed out waiting for confirmation */
83 FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command
)
85 struct cc3220sf_bank
*cc3220sf_bank
;
88 return ERROR_COMMAND_SYNTAX_ERROR
;
90 cc3220sf_bank
= malloc(sizeof(struct cc3220sf_bank
));
94 /* Initialize private flash information */
95 cc3220sf_bank
->probed
= false;
97 /* Finish initialization of flash bank */
98 bank
->driver_priv
= cc3220sf_bank
;
103 static int cc3220sf_erase(struct flash_bank
*bank
, unsigned int first
,
106 struct target
*target
= bank
->target
;
109 long long elapsed_ms
;
113 int retval
= ERROR_OK
;
115 if (target
->state
!= TARGET_HALTED
) {
116 LOG_ERROR("Target not halted");
117 return ERROR_TARGET_NOT_HALTED
;
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
);
126 /* Erase requested sectors one by one */
127 for (unsigned int i
= first
; i
<= last
; i
++) {
129 /* Determine address of sector to erase */
130 address
= FLASH_BASE_ADDR
+ i
* FLASH_SECTOR_SIZE
;
132 /* Set starting address to erase */
133 retval
= target_write_u32(target
, FMA_REGISTER_ADDR
, address
);
134 if (retval
!= ERROR_OK
)
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
)
142 /* Poll the ERASE bit until the erase is complete */
144 start_ms
= timeval_ms();
146 retval
= target_read_u32(target
, FMC_REGISTER_ADDR
, &value
);
147 if (retval
!= ERROR_OK
)
150 if ((value
& FMC_ERASE_BIT
) == 0) {
151 /* Bit clears when mass erase is finished */
154 elapsed_ms
= timeval_ms() - start_ms
;
155 if (elapsed_ms
> 500)
157 if (elapsed_ms
> FLASH_TIMEOUT
)
163 /* Sector erase timed out waiting for confirmation */
171 static int cc3220sf_write(struct flash_bank
*bank
, const uint8_t *buffer
,
172 uint32_t offset
, uint32_t count
)
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
;
187 int retval
= ERROR_OK
;
189 if (target
->state
!= TARGET_HALTED
) {
190 LOG_ERROR("Target not halted");
191 return ERROR_TARGET_NOT_HALTED
;
194 /* Obtain working area to use for flash helper algorithm */
195 retval
= target_alloc_working_area(target
, sizeof(cc3220sf_algo
),
197 if (retval
!= ERROR_OK
)
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
);
208 algo_base_address
= algo_working_area
->address
;
209 algo_buffer_address
= buffer_working_area
->address
;
210 algo_buffer_size
= buffer_working_area
->size
;
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;
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
);
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
;
230 /* Initialize register params for flash helper algorithm */
231 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
232 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
233 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
235 /* Prepare to write to flash */
236 address
= FLASH_BASE_ADDR
+ offset
;
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.
246 /* Do one word write to align address on 32-bit boundary if needed */
247 if (0 != (address
& 0x3)) {
250 /* Get starting offset for data to write (will be 1 to 3) */
251 uint32_t head_offset
= address
& 0x03;
253 /* Get the aligned address to write this first word to */
254 uint32_t head_address
= address
& 0xfffffffc;
256 /* Retrieve what is already in flash at the head address */
257 retval
= target_read_buffer(target
, head_address
, sizeof(head
), head
);
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
;
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);
277 /* Write head value into buffer to flash */
278 retval
= target_write_buffer(target
, algo_buffer_address
,
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");
290 /* Check that the head value was written to flash */
291 result
= buf_get_u32(reg_params
[2].value
, 0, 32);
294 LOG_ERROR("cc3220sf: Flash operation failed");
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
;
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
);
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
)
317 /* Count to write is in 32-bit words */
318 words
= algo_buffer_size
/ 4;
320 /* Bump variables to next data */
321 address
+= algo_buffer_size
;
322 buffer
+= algo_buffer_size
;
323 remaining
-= algo_buffer_size
;
325 /* Fill buffer with what's left of the data */
326 retval
= target_write_buffer(target
, algo_buffer_address
,
328 if (retval
!= ERROR_OK
)
331 /* Calculate the final word count to write */
332 words
= remaining
/ 4;
333 if (0 != (remaining
% 4))
336 /* Bump variables to any final data */
337 address
+= remaining
;
342 /* Set number of words to write */
343 buf_set_u32(reg_params
[2].value
, 0, 32, words
);
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");
354 /* Check that all words were written to flash */
355 result
= buf_get_u32(reg_params
[2].value
, 0, 32);
358 LOG_ERROR("cc3220sf: Flash operation failed");
365 /* Do one word write for any final bytes less than a full word */
366 if ((retval
== ERROR_OK
) && (tail_count
!= 0)) {
369 /* Set starting byte offset for data to write */
370 uint32_t tail_offset
= 0;
372 /* Retrieve what is already in flash at the tail address */
373 retval
= target_read_buffer(target
, address
, sizeof(tail
), tail
);
375 if (retval
== ERROR_OK
) {
376 /* Substitute in the new data to write */
377 while (tail_count
> 0) {
378 tail
[tail_offset
] = *buffer
;
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);
391 /* Write tail value into buffer to flash */
392 retval
= target_write_buffer(target
, algo_buffer_address
,
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");
404 /* Check that the tail was written to flash */
405 result
= buf_get_u32(reg_params
[2].value
, 0, 32);
408 LOG_ERROR("cc3220sf: Flash operation failed");
414 destroy_reg_param(®_params
[0]);
415 destroy_reg_param(®_params
[1]);
416 destroy_reg_param(®_params
[2]);
417 target_free_working_area(target
, algo_working_area
);
418 target_free_working_area(target
, buffer_working_area
);
423 static int cc3220sf_probe(struct flash_bank
*bank
)
425 struct cc3220sf_bank
*cc3220sf_bank
= bank
->driver_priv
;
429 unsigned int num_sectors
;
431 base
= FLASH_BASE_ADDR
;
432 size
= FLASH_NUM_SECTORS
* FLASH_SECTOR_SIZE
;
433 num_sectors
= FLASH_NUM_SECTORS
;
437 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_sectors
);
443 bank
->write_start_alignment
= 0;
444 bank
->write_end_alignment
= 0;
445 bank
->num_sectors
= num_sectors
;
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;
454 /* We've successfully recorded the stats on this flash bank */
455 cc3220sf_bank
->probed
= true;
457 /* If we fall through to here, then all went well */
462 static int cc3220sf_auto_probe(struct flash_bank
*bank
)
464 struct cc3220sf_bank
*cc3220sf_bank
= bank
->driver_priv
;
466 int retval
= ERROR_OK
;
468 if (!cc3220sf_bank
->probed
)
469 retval
= cc3220sf_probe(bank
);
474 static int cc3220sf_info(struct flash_bank
*bank
, struct command_invocation
*cmd
)
476 command_print_sameline(cmd
, "CC3220SF with 1MB internal flash\n");
480 const struct flash_driver cc3220sf_flash
= {
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
,
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)