flash/nor: move variable's declaration in C file
[openocd.git] / src / flash / nor / cc3220sf.c
blob6493d6c830da588cf01186340df77604a39ade61
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2017 by Texas Instruments, Inc. *
5 ***************************************************************************/
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
11 #include "imp.h"
12 #include "cc3220sf.h"
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 {
21 bool probed;
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;
33 bool done;
34 long long start_ms;
35 long long elapsed_ms;
36 uint32_t value;
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)
48 return retval;
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)
53 return retval;
55 /* Poll the MERASE bit until the mass erase is complete */
56 done = false;
57 start_ms = timeval_ms();
58 while (!done) {
59 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
60 if (retval != ERROR_OK)
61 return retval;
63 if ((value & FMC_MERASE_BIT) == 0) {
64 /* Bit clears when mass erase is finished */
65 done = true;
66 } else {
67 elapsed_ms = timeval_ms() - start_ms;
68 if (elapsed_ms > 500)
69 keep_alive();
70 if (elapsed_ms > FLASH_TIMEOUT)
71 break;
75 if (!done) {
76 /* Mass erase timed out waiting for confirmation */
77 return ERROR_FAIL;
80 return retval;
83 FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
85 struct cc3220sf_bank *cc3220sf_bank;
87 if (CMD_ARGC < 6)
88 return ERROR_COMMAND_SYNTAX_ERROR;
90 cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
91 if (!cc3220sf_bank)
92 return ERROR_FAIL;
94 /* Initialize private flash information */
95 cc3220sf_bank->probed = false;
97 /* Finish initialization of flash bank */
98 bank->driver_priv = cc3220sf_bank;
99 bank->next = NULL;
101 return ERROR_OK;
104 static int cc3220sf_erase(struct flash_bank *bank, unsigned int first,
105 unsigned int last)
107 struct target *target = bank->target;
108 bool done;
109 long long start_ms;
110 long long elapsed_ms;
111 uint32_t address;
112 uint32_t value;
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)
136 return retval;
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)
141 return retval;
143 /* Poll the ERASE bit until the erase is complete */
144 done = false;
145 start_ms = timeval_ms();
146 while (!done) {
147 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
148 if (retval != ERROR_OK)
149 return retval;
151 if ((value & FMC_ERASE_BIT) == 0) {
152 /* Bit clears when mass erase is finished */
153 done = true;
154 } else {
155 elapsed_ms = timeval_ms() - start_ms;
156 if (elapsed_ms > 500)
157 keep_alive();
158 if (elapsed_ms > FLASH_TIMEOUT)
159 break;
163 if (!done) {
164 /* Sector erase timed out waiting for confirmation */
165 return ERROR_FAIL;
169 return retval;
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;
183 uint32_t address;
184 uint32_t remaining;
185 uint32_t words;
186 uint32_t result;
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),
197 &algo_working_area);
198 if (retval != ERROR_OK)
199 return retval;
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);
206 return retval;
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);
224 return retval;
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(&reg_params[0], "r0", 32, PARAM_OUT);
233 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
234 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
236 /* Prepare to write to flash */
237 address = FLASH_BASE_ADDR + offset;
238 remaining = count;
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)) {
249 uint8_t head[4];
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;
264 head_offset++;
265 address++;
266 buffer++;
267 remaining--;
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,
280 sizeof(head), head);
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);
293 if (result != 0) {
294 retval = ERROR_FAIL;
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)
316 break;
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;
325 } else {
326 /* Fill buffer with what's left of the data */
327 retval = target_write_buffer(target, algo_buffer_address,
328 remaining, buffer);
329 if (retval != ERROR_OK)
330 break;
332 /* Calculate the final word count to write */
333 words = remaining / 4;
334 if (0 != (remaining % 4))
335 words++;
337 /* Bump variables to any final data */
338 address += remaining;
339 buffer += remaining;
340 remaining = 0;
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");
352 break;
355 /* Check that all words were written to flash */
356 result = buf_get_u32(reg_params[2].value, 0, 32);
357 if (result != 0) {
358 retval = ERROR_FAIL;
359 LOG_ERROR("cc3220sf: Flash operation failed");
360 break;
363 keep_alive();
366 /* Do one word write for any final bytes less than a full word */
367 if ((retval == ERROR_OK) && (tail_count != 0)) {
368 uint8_t tail[4];
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;
380 tail_offset++;
381 buffer++;
382 tail_count--;
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,
394 sizeof(tail), tail);
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);
407 if (result != 0) {
408 retval = ERROR_FAIL;
409 LOG_ERROR("cc3220sf: Flash operation failed");
414 /* Free resources */
415 destroy_reg_param(&reg_params[0]);
416 destroy_reg_param(&reg_params[1]);
417 destroy_reg_param(&reg_params[2]);
418 target_free_working_area(target, algo_working_area);
419 target_free_working_area(target, buffer_working_area);
421 return retval;
424 static int cc3220sf_probe(struct flash_bank *bank)
426 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
428 uint32_t base;
429 uint32_t size;
430 unsigned int num_sectors;
432 base = FLASH_BASE_ADDR;
433 size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
434 num_sectors = FLASH_NUM_SECTORS;
436 free(bank->sectors);
438 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
439 if (!bank->sectors)
440 return ERROR_FAIL;
442 bank->base = base;
443 bank->size = size;
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 */
460 return ERROR_OK;
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);
472 return retval;
475 static int cc3220sf_info(struct flash_bank *bank, struct command_invocation *cmd)
477 command_print_sameline(cmd, "CC3220SF with 1MB internal flash\n");
478 return ERROR_OK;
481 const struct flash_driver cc3220sf_flash = {
482 .name = "cc3220sf",
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,