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/time_support.h>
25 #include <target/algorithm.h>
26 #include <target/armv7m.h>
28 #define FLASH_TIMEOUT 5000
30 struct cc3220sf_bank {
32 struct armv7m_algorithm armv7m_info;
35 static int cc3220sf_mass_erase(struct flash_bank *bank)
37 struct target *target = bank->target;
43 int retval = ERROR_OK;
45 if (TARGET_HALTED != target->state) {
46 LOG_ERROR("Target not halted");
47 return ERROR_TARGET_NOT_HALTED;
50 /* Set starting address to erase to zero */
51 retval = target_write_u32(target, FMA_REGISTER_ADDR, 0);
52 if (ERROR_OK != retval)
55 /* Write the MERASE bit of the FMC register */
56 retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE);
57 if (ERROR_OK != retval)
60 /* Poll the MERASE bit until the mass erase is complete */
62 start_ms = timeval_ms();
64 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
65 if (ERROR_OK != retval)
68 if ((value & FMC_MERASE_BIT) == 0) {
69 /* Bit clears when mass erase is finished */
72 elapsed_ms = timeval_ms() - start_ms;
75 if (elapsed_ms > FLASH_TIMEOUT)
81 /* Mass erase timed out waiting for confirmation */
88 FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
90 struct cc3220sf_bank *cc3220sf_bank;
93 return ERROR_COMMAND_SYNTAX_ERROR;
95 cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
96 if (NULL == cc3220sf_bank)
99 /* Initialize private flash information */
100 cc3220sf_bank->probed = false;
102 /* Finish initialization of flash bank */
103 bank->driver_priv = cc3220sf_bank;
109 static int cc3220sf_erase(struct flash_bank *bank, int first, int last)
111 struct target *target = bank->target;
114 long long elapsed_ms;
118 int retval = ERROR_OK;
120 if (TARGET_HALTED != target->state) {
121 LOG_ERROR("Target not halted");
122 return ERROR_TARGET_NOT_HALTED;
125 /* Do a mass erase if user requested all sectors of flash */
126 if ((first == 0) && (last == (bank->num_sectors - 1))) {
127 /* Request mass erase of flash */
128 return cc3220sf_mass_erase(bank);
131 /* Erase requested sectors one by one */
132 for (int i = first; i <= last; i++) {
134 /* Determine address of sector to erase */
135 address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE;
137 /* Set starting address to erase */
138 retval = target_write_u32(target, FMA_REGISTER_ADDR, address);
139 if (ERROR_OK != retval)
142 /* Write the ERASE bit of the FMC register */
143 retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE);
144 if (ERROR_OK != retval)
147 /* Poll the ERASE bit until the erase is complete */
149 start_ms = timeval_ms();
151 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
152 if (ERROR_OK != retval)
155 if ((value & FMC_ERASE_BIT) == 0) {
156 /* Bit clears when mass erase is finished */
159 elapsed_ms = timeval_ms() - start_ms;
160 if (elapsed_ms > 500)
162 if (elapsed_ms > FLASH_TIMEOUT)
168 /* Sector erase timed out waiting for confirmation */
176 static int cc3220sf_protect(struct flash_bank *bank, int set, int first,
182 static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
183 uint32_t offset, uint32_t count)
185 struct target *target = bank->target;
186 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
187 struct working_area *algo_working_area;
188 struct working_area *buffer_working_area;
189 struct reg_param reg_params[3];
190 uint32_t algo_base_address;
191 uint32_t algo_buffer_address;
192 uint32_t algo_buffer_size;
198 int retval = ERROR_OK;
200 if (TARGET_HALTED != target->state) {
201 LOG_ERROR("Target not halted");
202 return ERROR_TARGET_NOT_HALTED;
205 /* Obtain working area to use for flash helper algorithm */
206 retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
208 if (ERROR_OK != retval)
211 /* Obtain working area to use for flash buffer */
212 retval = target_alloc_working_area(target,
213 target_get_working_area_avail(target), &buffer_working_area);
214 if (ERROR_OK != retval) {
215 target_free_working_area(target, algo_working_area);
219 algo_base_address = algo_working_area->address;
220 algo_buffer_address = buffer_working_area->address;
221 algo_buffer_size = buffer_working_area->size;
223 /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
224 /* (algo runs more efficiently if it operates on 32 words at a time) */
225 if (algo_buffer_size > 0x80)
226 algo_buffer_size &= ~0x7f;
228 /* Write flash helper algorithm into target memory */
229 retval = target_write_buffer(target, algo_base_address,
230 sizeof(cc3220sf_algo), cc3220sf_algo);
231 if (ERROR_OK != retval) {
232 target_free_working_area(target, algo_working_area);
233 target_free_working_area(target, buffer_working_area);
237 /* Initialize the ARMv7m specific info to run the algorithm */
238 cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
239 cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
241 /* Initialize register params for flash helper algorithm */
242 init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
243 init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
244 init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
246 /* Prepare to write to flash */
247 address = FLASH_BASE_ADDR + offset;
250 /* The flash hardware can only write complete words to flash. If
251 * an unaligned address is passed in, we must do a read-modify-write
252 * on a word with enough bytes to align the rest of the buffer. And
253 * if less than a whole word remains at the end, we must also do a
254 * read-modify-write on a final word to finish up.
257 /* Do one word write to align address on 32-bit boundary if needed */
258 if (0 != (address & 0x3)) {
261 /* Get starting offset for data to write (will be 1 to 3) */
262 uint32_t head_offset = address & 0x03;
264 /* Get the aligned address to write this first word to */
265 uint32_t head_address = address & 0xfffffffc;
267 /* Retrieve what is already in flash at the head address */
268 retval = target_read_buffer(target, head_address, sizeof(head), head);
270 if (ERROR_OK == retval) {
271 /* Substitute in the new data to write */
272 while ((remaining > 0) && (head_offset < 4)) {
273 head[head_offset] = *buffer;
281 if (ERROR_OK == retval) {
282 /* Helper parameters are passed in registers R0-R2 */
283 /* Set start of data buffer, address to write to, and word count */
284 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
285 buf_set_u32(reg_params[1].value, 0, 32, head_address);
286 buf_set_u32(reg_params[2].value, 0, 32, 1);
288 /* Write head value into buffer to flash */
289 retval = target_write_buffer(target, algo_buffer_address,
293 if (ERROR_OK == retval) {
294 /* Execute the flash helper algorithm */
295 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
296 algo_base_address, 0, FLASH_TIMEOUT,
297 &cc3220sf_bank->armv7m_info);
298 if (ERROR_OK != retval)
299 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
301 /* Check that the head value was written to flash */
302 result = buf_get_u32(reg_params[2].value, 0, 32);
305 LOG_ERROR("cc3220sf: Flash operation failed");
310 /* Check if there's data at end of buffer that isn't a full word */
311 uint32_t tail_count = remaining & 0x03;
312 /* Adjust remaining so it is a multiple of whole words */
313 remaining -= tail_count;
315 while ((ERROR_OK == retval) && (remaining > 0)) {
316 /* Set start of data buffer and address to write to */
317 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
318 buf_set_u32(reg_params[1].value, 0, 32, address);
320 /* Download data to write into memory buffer */
321 if (remaining >= algo_buffer_size) {
322 /* Fill up buffer with data to flash */
323 retval = target_write_buffer(target, algo_buffer_address,
324 algo_buffer_size, buffer);
325 if (ERROR_OK != retval)
328 /* Count to write is in 32-bit words */
329 words = algo_buffer_size / 4;
331 /* Bump variables to next data */
332 address += algo_buffer_size;
333 buffer += algo_buffer_size;
334 remaining -= algo_buffer_size;
336 /* Fill buffer with what's left of the data */
337 retval = target_write_buffer(target, algo_buffer_address,
339 if (ERROR_OK != retval)
342 /* Calculate the final word count to write */
343 words = remaining / 4;
344 if (0 != (remaining % 4))
347 /* Bump variables to any final data */
348 address += remaining;
353 /* Set number of words to write */
354 buf_set_u32(reg_params[2].value, 0, 32, words);
356 /* Execute the flash helper algorithm */
357 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
358 algo_base_address, 0, FLASH_TIMEOUT,
359 &cc3220sf_bank->armv7m_info);
360 if (ERROR_OK != retval) {
361 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
365 /* Check that all words were written to flash */
366 result = buf_get_u32(reg_params[2].value, 0, 32);
369 LOG_ERROR("cc3220sf: Flash operation failed");
374 /* Do one word write for any final bytes less than a full word */
375 if ((ERROR_OK == retval) && (0 != tail_count)) {
378 /* Set starting byte offset for data to write */
379 uint32_t tail_offset = 0;
381 /* Retrieve what is already in flash at the tail address */
382 retval = target_read_buffer(target, address, sizeof(tail), tail);
384 if (ERROR_OK == retval) {
385 /* Substitute in the new data to write */
386 while (tail_count > 0) {
387 tail[tail_offset] = *buffer;
394 if (ERROR_OK == retval) {
395 /* Set start of data buffer, address to write to, and word count */
396 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
397 buf_set_u32(reg_params[1].value, 0, 32, address);
398 buf_set_u32(reg_params[2].value, 0, 32, 1);
400 /* Write tail value into buffer to flash */
401 retval = target_write_buffer(target, algo_buffer_address,
405 if (ERROR_OK == retval) {
406 /* Execute the flash helper algorithm */
407 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
408 algo_base_address, 0, FLASH_TIMEOUT,
409 &cc3220sf_bank->armv7m_info);
410 if (ERROR_OK != retval)
411 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
413 /* Check that the tail was written to flash */
414 result = buf_get_u32(reg_params[2].value, 0, 32);
417 LOG_ERROR("cc3220sf: Flash operation failed");
423 destroy_reg_param(®_params[0]);
424 destroy_reg_param(®_params[1]);
425 destroy_reg_param(®_params[2]);
426 target_free_working_area(target, algo_working_area);
427 target_free_working_area(target, buffer_working_area);
432 static int cc3220sf_probe(struct flash_bank *bank)
434 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
441 bank_id = bank->bank_number;
444 base = FLASH_BASE_ADDR;
445 size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
446 num_sectors = FLASH_NUM_SECTORS;
448 /* Invalid bank number somehow */
452 if (NULL != bank->sectors) {
454 bank->sectors = NULL;
457 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
458 if (NULL == bank->sectors)
463 bank->write_start_alignment = 0;
464 bank->write_end_alignment = 0;
465 bank->num_sectors = num_sectors;
467 for (int i = 0; i < num_sectors; i++) {
468 bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
469 bank->sectors[i].size = FLASH_SECTOR_SIZE;
470 bank->sectors[i].is_erased = -1;
471 bank->sectors[i].is_protected = 0;
474 /* We've successfully recorded the stats on this flash bank */
475 cc3220sf_bank->probed = true;
477 /* If we fall through to here, then all went well */
482 static int cc3220sf_auto_probe(struct flash_bank *bank)
484 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
486 int retval = ERROR_OK;
488 if (0 != bank->bank_number) {
489 /* Invalid bank number somehow */
493 if (!cc3220sf_bank->probed)
494 retval = cc3220sf_probe(bank);
499 static int cc3220sf_protect_check(struct flash_bank *bank)
504 static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
508 printed = snprintf(buf, buf_size, "CC3220SF with 1MB internal flash\n");
510 if (printed >= buf_size)
511 return ERROR_BUF_TOO_SMALL;
516 struct flash_driver cc3220sf_flash = {
518 .flash_bank_command = cc3220sf_flash_bank_command,
519 .erase = cc3220sf_erase,
520 .protect = cc3220sf_protect,
521 .write = cc3220sf_write,
522 .read = default_flash_read,
523 .probe = cc3220sf_probe,
524 .auto_probe = cc3220sf_auto_probe,
525 .erase_check = default_flash_blank_check,
526 .protect_check = cc3220sf_protect_check,
527 .info = cc3220sf_info,
528 .free_driver_priv = default_flash_free_driver_priv,