1 /***************************************************************************
2 * Copyright (C) 2017 by Texas Instruments, Inc. *
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. *
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. *
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 ***************************************************************************/
24 #include <helper/binarybuffer.h>
25 #include <helper/time_support.h>
26 #include <target/algorithm.h>
27 #include <target/armv7m.h>
29 #define FLASH_TIMEOUT 5000
31 struct cc3220sf_bank {
33 struct armv7m_algorithm armv7m_info;
36 static int cc3220sf_mass_erase(struct flash_bank *bank)
38 struct target *target = bank->target;
44 int retval = ERROR_OK;
46 if (target->state != TARGET_HALTED) {
47 LOG_ERROR("Target not halted");
48 return ERROR_TARGET_NOT_HALTED;
51 /* Set starting address to erase to zero */
52 retval = target_write_u32(target, FMA_REGISTER_ADDR, 0);
53 if (retval != ERROR_OK)
56 /* Write the MERASE bit of the FMC register */
57 retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE);
58 if (retval != ERROR_OK)
61 /* Poll the MERASE bit until the mass erase is complete */
63 start_ms = timeval_ms();
65 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
66 if (retval != ERROR_OK)
69 if ((value & FMC_MERASE_BIT) == 0) {
70 /* Bit clears when mass erase is finished */
73 elapsed_ms = timeval_ms() - start_ms;
76 if (elapsed_ms > FLASH_TIMEOUT)
82 /* Mass erase timed out waiting for confirmation */
89 FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
91 struct cc3220sf_bank *cc3220sf_bank;
94 return ERROR_COMMAND_SYNTAX_ERROR;
96 cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
100 /* Initialize private flash information */
101 cc3220sf_bank->probed = false;
103 /* Finish initialization of flash bank */
104 bank->driver_priv = cc3220sf_bank;
110 static int cc3220sf_erase(struct flash_bank *bank, unsigned int first,
113 struct target *target = bank->target;
116 long long elapsed_ms;
120 int retval = ERROR_OK;
122 if (target->state != TARGET_HALTED) {
123 LOG_ERROR("Target not halted");
124 return ERROR_TARGET_NOT_HALTED;
127 /* Do a mass erase if user requested all sectors of flash */
128 if ((first == 0) && (last == (bank->num_sectors - 1))) {
129 /* Request mass erase of flash */
130 return cc3220sf_mass_erase(bank);
133 /* Erase requested sectors one by one */
134 for (unsigned int i = first; i <= last; i++) {
136 /* Determine address of sector to erase */
137 address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE;
139 /* Set starting address to erase */
140 retval = target_write_u32(target, FMA_REGISTER_ADDR, address);
141 if (retval != ERROR_OK)
144 /* Write the ERASE bit of the FMC register */
145 retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE);
146 if (retval != ERROR_OK)
149 /* Poll the ERASE bit until the erase is complete */
151 start_ms = timeval_ms();
153 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
154 if (retval != ERROR_OK)
157 if ((value & FMC_ERASE_BIT) == 0) {
158 /* Bit clears when mass erase is finished */
161 elapsed_ms = timeval_ms() - start_ms;
162 if (elapsed_ms > 500)
164 if (elapsed_ms > FLASH_TIMEOUT)
170 /* Sector erase timed out waiting for confirmation */
178 static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
179 uint32_t offset, uint32_t count)
181 struct target *target = bank->target;
182 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
183 struct working_area *algo_working_area;
184 struct working_area *buffer_working_area;
185 struct reg_param reg_params[3];
186 uint32_t algo_base_address;
187 uint32_t algo_buffer_address;
188 uint32_t algo_buffer_size;
194 int retval = ERROR_OK;
196 if (target->state != TARGET_HALTED) {
197 LOG_ERROR("Target not halted");
198 return ERROR_TARGET_NOT_HALTED;
201 /* Obtain working area to use for flash helper algorithm */
202 retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
204 if (retval != ERROR_OK)
207 /* Obtain working area to use for flash buffer */
208 retval = target_alloc_working_area(target,
209 target_get_working_area_avail(target), &buffer_working_area);
210 if (retval != ERROR_OK) {
211 target_free_working_area(target, algo_working_area);
215 algo_base_address = algo_working_area->address;
216 algo_buffer_address = buffer_working_area->address;
217 algo_buffer_size = buffer_working_area->size;
219 /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
220 /* (algo runs more efficiently if it operates on 32 words at a time) */
221 if (algo_buffer_size > 0x80)
222 algo_buffer_size &= ~0x7f;
224 /* Write flash helper algorithm into target memory */
225 retval = target_write_buffer(target, algo_base_address,
226 sizeof(cc3220sf_algo), cc3220sf_algo);
227 if (retval != ERROR_OK) {
228 target_free_working_area(target, algo_working_area);
229 target_free_working_area(target, buffer_working_area);
233 /* Initialize the ARMv7m specific info to run the algorithm */
234 cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
235 cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
237 /* Initialize register params for flash helper algorithm */
238 init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
239 init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
240 init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
242 /* Prepare to write to flash */
243 address = FLASH_BASE_ADDR + offset;
246 /* The flash hardware can only write complete words to flash. If
247 * an unaligned address is passed in, we must do a read-modify-write
248 * on a word with enough bytes to align the rest of the buffer. And
249 * if less than a whole word remains at the end, we must also do a
250 * read-modify-write on a final word to finish up.
253 /* Do one word write to align address on 32-bit boundary if needed */
254 if (0 != (address & 0x3)) {
257 /* Get starting offset for data to write (will be 1 to 3) */
258 uint32_t head_offset = address & 0x03;
260 /* Get the aligned address to write this first word to */
261 uint32_t head_address = address & 0xfffffffc;
263 /* Retrieve what is already in flash at the head address */
264 retval = target_read_buffer(target, head_address, sizeof(head), head);
266 if (retval == ERROR_OK) {
267 /* Substitute in the new data to write */
268 while ((remaining > 0) && (head_offset < 4)) {
269 head[head_offset] = *buffer;
277 if (retval == ERROR_OK) {
278 /* Helper parameters are passed in registers R0-R2 */
279 /* Set start of data buffer, address to write to, and word count */
280 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
281 buf_set_u32(reg_params[1].value, 0, 32, head_address);
282 buf_set_u32(reg_params[2].value, 0, 32, 1);
284 /* Write head value into buffer to flash */
285 retval = target_write_buffer(target, algo_buffer_address,
289 if (retval == ERROR_OK) {
290 /* Execute the flash helper algorithm */
291 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
292 algo_base_address, 0, FLASH_TIMEOUT,
293 &cc3220sf_bank->armv7m_info);
294 if (retval != ERROR_OK)
295 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
297 /* Check that the head value was written to flash */
298 result = buf_get_u32(reg_params[2].value, 0, 32);
301 LOG_ERROR("cc3220sf: Flash operation failed");
306 /* Check if there's data at end of buffer that isn't a full word */
307 uint32_t tail_count = remaining & 0x03;
308 /* Adjust remaining so it is a multiple of whole words */
309 remaining -= tail_count;
311 while ((retval == ERROR_OK) && (remaining > 0)) {
312 /* Set start of data buffer and address to write to */
313 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
314 buf_set_u32(reg_params[1].value, 0, 32, address);
316 /* Download data to write into memory buffer */
317 if (remaining >= algo_buffer_size) {
318 /* Fill up buffer with data to flash */
319 retval = target_write_buffer(target, algo_buffer_address,
320 algo_buffer_size, buffer);
321 if (retval != ERROR_OK)
324 /* Count to write is in 32-bit words */
325 words = algo_buffer_size / 4;
327 /* Bump variables to next data */
328 address += algo_buffer_size;
329 buffer += algo_buffer_size;
330 remaining -= algo_buffer_size;
332 /* Fill buffer with what's left of the data */
333 retval = target_write_buffer(target, algo_buffer_address,
335 if (retval != ERROR_OK)
338 /* Calculate the final word count to write */
339 words = remaining / 4;
340 if (0 != (remaining % 4))
343 /* Bump variables to any final data */
344 address += remaining;
349 /* Set number of words to write */
350 buf_set_u32(reg_params[2].value, 0, 32, words);
352 /* Execute the flash helper algorithm */
353 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
354 algo_base_address, 0, FLASH_TIMEOUT,
355 &cc3220sf_bank->armv7m_info);
356 if (retval != ERROR_OK) {
357 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
361 /* Check that all words were written to flash */
362 result = buf_get_u32(reg_params[2].value, 0, 32);
365 LOG_ERROR("cc3220sf: Flash operation failed");
372 /* Do one word write for any final bytes less than a full word */
373 if ((retval == ERROR_OK) && (tail_count != 0)) {
376 /* Set starting byte offset for data to write */
377 uint32_t tail_offset = 0;
379 /* Retrieve what is already in flash at the tail address */
380 retval = target_read_buffer(target, address, sizeof(tail), tail);
382 if (retval == ERROR_OK) {
383 /* Substitute in the new data to write */
384 while (tail_count > 0) {
385 tail[tail_offset] = *buffer;
392 if (retval == ERROR_OK) {
393 /* Set start of data buffer, address to write to, and word count */
394 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
395 buf_set_u32(reg_params[1].value, 0, 32, address);
396 buf_set_u32(reg_params[2].value, 0, 32, 1);
398 /* Write tail value into buffer to flash */
399 retval = target_write_buffer(target, algo_buffer_address,
403 if (retval == ERROR_OK) {
404 /* Execute the flash helper algorithm */
405 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
406 algo_base_address, 0, FLASH_TIMEOUT,
407 &cc3220sf_bank->armv7m_info);
408 if (retval != ERROR_OK)
409 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
411 /* Check that the tail was written to flash */
412 result = buf_get_u32(reg_params[2].value, 0, 32);
415 LOG_ERROR("cc3220sf: Flash operation failed");
421 destroy_reg_param(®_params[0]);
422 destroy_reg_param(®_params[1]);
423 destroy_reg_param(®_params[2]);
424 target_free_working_area(target, algo_working_area);
425 target_free_working_area(target, buffer_working_area);
430 static int cc3220sf_probe(struct flash_bank *bank)
432 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
436 unsigned int num_sectors;
438 base = FLASH_BASE_ADDR;
439 size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
440 num_sectors = FLASH_NUM_SECTORS;
444 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
450 bank->write_start_alignment = 0;
451 bank->write_end_alignment = 0;
452 bank->num_sectors = num_sectors;
454 for (unsigned int i = 0; i < num_sectors; i++) {
455 bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
456 bank->sectors[i].size = FLASH_SECTOR_SIZE;
457 bank->sectors[i].is_erased = -1;
458 bank->sectors[i].is_protected = 0;
461 /* We've successfully recorded the stats on this flash bank */
462 cc3220sf_bank->probed = true;
464 /* If we fall through to here, then all went well */
469 static int cc3220sf_auto_probe(struct flash_bank *bank)
471 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
473 int retval = ERROR_OK;
475 if (!cc3220sf_bank->probed)
476 retval = cc3220sf_probe(bank);
481 static int cc3220sf_info(struct flash_bank *bank, struct command_invocation *cmd)
483 command_print_sameline(cmd, "CC3220SF with 1MB internal flash\n");
487 const struct flash_driver cc3220sf_flash = {
489 .flash_bank_command = cc3220sf_flash_bank_command,
490 .erase = cc3220sf_erase,
491 .write = cc3220sf_write,
492 .read = default_flash_read,
493 .probe = cc3220sf_probe,
494 .auto_probe = cc3220sf_auto_probe,
495 .erase_check = default_flash_blank_check,
496 .info = cc3220sf_info,
497 .free_driver_priv = default_flash_free_driver_priv,