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
;
104 static int cc3220sf_erase(struct flash_bank
*bank
, unsigned int first
,
107 struct target
*target
= bank
->target
;
110 long long elapsed_ms
;
114 int retval
= ERROR_OK
;
116 if (target
->state
!= TARGET_HALTED
) {
117 LOG_ERROR("Target not halted");
118 return ERROR_TARGET_NOT_HALTED
;
121 /* Do a mass erase if user requested all sectors of flash */
122 if ((first
== 0) && (last
== (bank
->num_sectors
- 1))) {
123 /* Request mass erase of flash */
124 return cc3220sf_mass_erase(bank
);
127 /* Erase requested sectors one by one */
128 for (unsigned int i
= first
; i
<= last
; i
++) {
130 /* Determine address of sector to erase */
131 address
= FLASH_BASE_ADDR
+ i
* FLASH_SECTOR_SIZE
;
133 /* Set starting address to erase */
134 retval
= target_write_u32(target
, FMA_REGISTER_ADDR
, address
);
135 if (retval
!= ERROR_OK
)
138 /* Write the ERASE bit of the FMC register */
139 retval
= target_write_u32(target
, FMC_REGISTER_ADDR
, FMC_ERASE_VALUE
);
140 if (retval
!= ERROR_OK
)
143 /* Poll the ERASE bit until the erase is complete */
145 start_ms
= timeval_ms();
147 retval
= target_read_u32(target
, FMC_REGISTER_ADDR
, &value
);
148 if (retval
!= ERROR_OK
)
151 if ((value
& FMC_ERASE_BIT
) == 0) {
152 /* Bit clears when mass erase is finished */
155 elapsed_ms
= timeval_ms() - start_ms
;
156 if (elapsed_ms
> 500)
158 if (elapsed_ms
> FLASH_TIMEOUT
)
164 /* Sector erase timed out waiting for confirmation */
172 static int cc3220sf_write(struct flash_bank
*bank
, const uint8_t *buffer
,
173 uint32_t offset
, uint32_t count
)
175 struct target
*target
= bank
->target
;
176 struct cc3220sf_bank
*cc3220sf_bank
= bank
->driver_priv
;
177 struct working_area
*algo_working_area
;
178 struct working_area
*buffer_working_area
;
179 struct reg_param reg_params
[3];
180 uint32_t algo_base_address
;
181 uint32_t algo_buffer_address
;
182 uint32_t algo_buffer_size
;
188 int retval
= ERROR_OK
;
190 if (target
->state
!= TARGET_HALTED
) {
191 LOG_ERROR("Target not halted");
192 return ERROR_TARGET_NOT_HALTED
;
195 /* Obtain working area to use for flash helper algorithm */
196 retval
= target_alloc_working_area(target
, sizeof(cc3220sf_algo
),
198 if (retval
!= ERROR_OK
)
201 /* Obtain working area to use for flash buffer */
202 retval
= target_alloc_working_area(target
,
203 target_get_working_area_avail(target
), &buffer_working_area
);
204 if (retval
!= ERROR_OK
) {
205 target_free_working_area(target
, algo_working_area
);
209 algo_base_address
= algo_working_area
->address
;
210 algo_buffer_address
= buffer_working_area
->address
;
211 algo_buffer_size
= buffer_working_area
->size
;
213 /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
214 /* (algo runs more efficiently if it operates on 32 words at a time) */
215 if (algo_buffer_size
> 0x80)
216 algo_buffer_size
&= ~0x7f;
218 /* Write flash helper algorithm into target memory */
219 retval
= target_write_buffer(target
, algo_base_address
,
220 sizeof(cc3220sf_algo
), cc3220sf_algo
);
221 if (retval
!= ERROR_OK
) {
222 target_free_working_area(target
, algo_working_area
);
223 target_free_working_area(target
, buffer_working_area
);
227 /* Initialize the ARMv7m specific info to run the algorithm */
228 cc3220sf_bank
->armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
229 cc3220sf_bank
->armv7m_info
.core_mode
= ARM_MODE_THREAD
;
231 /* Initialize register params for flash helper algorithm */
232 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
233 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
234 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
236 /* Prepare to write to flash */
237 address
= FLASH_BASE_ADDR
+ offset
;
240 /* The flash hardware can only write complete words to flash. If
241 * an unaligned address is passed in, we must do a read-modify-write
242 * on a word with enough bytes to align the rest of the buffer. And
243 * if less than a whole word remains at the end, we must also do a
244 * read-modify-write on a final word to finish up.
247 /* Do one word write to align address on 32-bit boundary if needed */
248 if (0 != (address
& 0x3)) {
251 /* Get starting offset for data to write (will be 1 to 3) */
252 uint32_t head_offset
= address
& 0x03;
254 /* Get the aligned address to write this first word to */
255 uint32_t head_address
= address
& 0xfffffffc;
257 /* Retrieve what is already in flash at the head address */
258 retval
= target_read_buffer(target
, head_address
, sizeof(head
), head
);
260 if (retval
== ERROR_OK
) {
261 /* Substitute in the new data to write */
262 while ((remaining
> 0) && (head_offset
< 4)) {
263 head
[head_offset
] = *buffer
;
271 if (retval
== ERROR_OK
) {
272 /* Helper parameters are passed in registers R0-R2 */
273 /* Set start of data buffer, address to write to, and word count */
274 buf_set_u32(reg_params
[0].value
, 0, 32, algo_buffer_address
);
275 buf_set_u32(reg_params
[1].value
, 0, 32, head_address
);
276 buf_set_u32(reg_params
[2].value
, 0, 32, 1);
278 /* Write head value into buffer to flash */
279 retval
= target_write_buffer(target
, algo_buffer_address
,
283 if (retval
== ERROR_OK
) {
284 /* Execute the flash helper algorithm */
285 retval
= target_run_algorithm(target
, 0, NULL
, 3, reg_params
,
286 algo_base_address
, 0, FLASH_TIMEOUT
,
287 &cc3220sf_bank
->armv7m_info
);
288 if (retval
!= ERROR_OK
)
289 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
291 /* Check that the head value was written to flash */
292 result
= buf_get_u32(reg_params
[2].value
, 0, 32);
295 LOG_ERROR("cc3220sf: Flash operation failed");
300 /* Check if there's data at end of buffer that isn't a full word */
301 uint32_t tail_count
= remaining
& 0x03;
302 /* Adjust remaining so it is a multiple of whole words */
303 remaining
-= tail_count
;
305 while ((retval
== ERROR_OK
) && (remaining
> 0)) {
306 /* Set start of data buffer and address to write to */
307 buf_set_u32(reg_params
[0].value
, 0, 32, algo_buffer_address
);
308 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
310 /* Download data to write into memory buffer */
311 if (remaining
>= algo_buffer_size
) {
312 /* Fill up buffer with data to flash */
313 retval
= target_write_buffer(target
, algo_buffer_address
,
314 algo_buffer_size
, buffer
);
315 if (retval
!= ERROR_OK
)
318 /* Count to write is in 32-bit words */
319 words
= algo_buffer_size
/ 4;
321 /* Bump variables to next data */
322 address
+= algo_buffer_size
;
323 buffer
+= algo_buffer_size
;
324 remaining
-= algo_buffer_size
;
326 /* Fill buffer with what's left of the data */
327 retval
= target_write_buffer(target
, algo_buffer_address
,
329 if (retval
!= ERROR_OK
)
332 /* Calculate the final word count to write */
333 words
= remaining
/ 4;
334 if (0 != (remaining
% 4))
337 /* Bump variables to any final data */
338 address
+= remaining
;
343 /* Set number of words to write */
344 buf_set_u32(reg_params
[2].value
, 0, 32, words
);
346 /* Execute the flash helper algorithm */
347 retval
= target_run_algorithm(target
, 0, NULL
, 3, reg_params
,
348 algo_base_address
, 0, FLASH_TIMEOUT
,
349 &cc3220sf_bank
->armv7m_info
);
350 if (retval
!= ERROR_OK
) {
351 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
355 /* Check that all words were written to flash */
356 result
= buf_get_u32(reg_params
[2].value
, 0, 32);
359 LOG_ERROR("cc3220sf: Flash operation failed");
366 /* Do one word write for any final bytes less than a full word */
367 if ((retval
== ERROR_OK
) && (tail_count
!= 0)) {
370 /* Set starting byte offset for data to write */
371 uint32_t tail_offset
= 0;
373 /* Retrieve what is already in flash at the tail address */
374 retval
= target_read_buffer(target
, address
, sizeof(tail
), tail
);
376 if (retval
== ERROR_OK
) {
377 /* Substitute in the new data to write */
378 while (tail_count
> 0) {
379 tail
[tail_offset
] = *buffer
;
386 if (retval
== ERROR_OK
) {
387 /* Set start of data buffer, address to write to, and word count */
388 buf_set_u32(reg_params
[0].value
, 0, 32, algo_buffer_address
);
389 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
390 buf_set_u32(reg_params
[2].value
, 0, 32, 1);
392 /* Write tail value into buffer to flash */
393 retval
= target_write_buffer(target
, algo_buffer_address
,
397 if (retval
== ERROR_OK
) {
398 /* Execute the flash helper algorithm */
399 retval
= target_run_algorithm(target
, 0, NULL
, 3, reg_params
,
400 algo_base_address
, 0, FLASH_TIMEOUT
,
401 &cc3220sf_bank
->armv7m_info
);
402 if (retval
!= ERROR_OK
)
403 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
405 /* Check that the tail was written to flash */
406 result
= buf_get_u32(reg_params
[2].value
, 0, 32);
409 LOG_ERROR("cc3220sf: Flash operation failed");
415 destroy_reg_param(®_params
[0]);
416 destroy_reg_param(®_params
[1]);
417 destroy_reg_param(®_params
[2]);
418 target_free_working_area(target
, algo_working_area
);
419 target_free_working_area(target
, buffer_working_area
);
424 static int cc3220sf_probe(struct flash_bank
*bank
)
426 struct cc3220sf_bank
*cc3220sf_bank
= bank
->driver_priv
;
430 unsigned int num_sectors
;
432 base
= FLASH_BASE_ADDR
;
433 size
= FLASH_NUM_SECTORS
* FLASH_SECTOR_SIZE
;
434 num_sectors
= FLASH_NUM_SECTORS
;
438 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_sectors
);
444 bank
->write_start_alignment
= 0;
445 bank
->write_end_alignment
= 0;
446 bank
->num_sectors
= num_sectors
;
448 for (unsigned int i
= 0; i
< num_sectors
; i
++) {
449 bank
->sectors
[i
].offset
= i
* FLASH_SECTOR_SIZE
;
450 bank
->sectors
[i
].size
= FLASH_SECTOR_SIZE
;
451 bank
->sectors
[i
].is_erased
= -1;
452 bank
->sectors
[i
].is_protected
= 0;
455 /* We've successfully recorded the stats on this flash bank */
456 cc3220sf_bank
->probed
= true;
458 /* If we fall through to here, then all went well */
463 static int cc3220sf_auto_probe(struct flash_bank
*bank
)
465 struct cc3220sf_bank
*cc3220sf_bank
= bank
->driver_priv
;
467 int retval
= ERROR_OK
;
469 if (!cc3220sf_bank
->probed
)
470 retval
= cc3220sf_probe(bank
);
475 static int cc3220sf_info(struct flash_bank
*bank
, struct command_invocation
*cmd
)
477 command_print_sameline(cmd
, "CC3220SF with 1MB internal flash\n");
481 const struct flash_driver cc3220sf_flash
= {
483 .flash_bank_command
= cc3220sf_flash_bank_command
,
484 .erase
= cc3220sf_erase
,
485 .write
= cc3220sf_write
,
486 .read
= default_flash_read
,
487 .probe
= cc3220sf_probe
,
488 .auto_probe
= cc3220sf_auto_probe
,
489 .erase_check
= default_flash_blank_check
,
490 .info
= cc3220sf_info
,
491 .free_driver_priv
= default_flash_free_driver_priv
,