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
,