flash/nor: consolidate flash protect/protect_check
[openocd.git] / src / flash / nor / cc3220sf.c
1 /***************************************************************************
2 * Copyright (C) 2017 by Texas Instruments, Inc. *
3 * *
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. *
8 * *
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. *
13 * *
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 ***************************************************************************/
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "imp.h"
23 #include "cc3220sf.h"
24 #include <helper/time_support.h>
25 #include <target/algorithm.h>
26 #include <target/armv7m.h>
27
28 #define FLASH_TIMEOUT 5000
29
30 struct cc3220sf_bank {
31 bool probed;
32 struct armv7m_algorithm armv7m_info;
33 };
34
35 static int cc3220sf_mass_erase(struct flash_bank *bank)
36 {
37 struct target *target = bank->target;
38 bool done;
39 long long start_ms;
40 long long elapsed_ms;
41 uint32_t value;
42
43 int retval = ERROR_OK;
44
45 if (TARGET_HALTED != target->state) {
46 LOG_ERROR("Target not halted");
47 return ERROR_TARGET_NOT_HALTED;
48 }
49
50 /* Set starting address to erase to zero */
51 retval = target_write_u32(target, FMA_REGISTER_ADDR, 0);
52 if (ERROR_OK != retval)
53 return retval;
54
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)
58 return retval;
59
60 /* Poll the MERASE bit until the mass erase is complete */
61 done = false;
62 start_ms = timeval_ms();
63 while (!done) {
64 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
65 if (ERROR_OK != retval)
66 return retval;
67
68 if ((value & FMC_MERASE_BIT) == 0) {
69 /* Bit clears when mass erase is finished */
70 done = true;
71 } else {
72 elapsed_ms = timeval_ms() - start_ms;
73 if (elapsed_ms > 500)
74 keep_alive();
75 if (elapsed_ms > FLASH_TIMEOUT)
76 break;
77 }
78 }
79
80 if (!done) {
81 /* Mass erase timed out waiting for confirmation */
82 return ERROR_FAIL;
83 }
84
85 return retval;
86 }
87
88 FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
89 {
90 struct cc3220sf_bank *cc3220sf_bank;
91
92 if (CMD_ARGC < 6)
93 return ERROR_COMMAND_SYNTAX_ERROR;
94
95 cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
96 if (NULL == cc3220sf_bank)
97 return ERROR_FAIL;
98
99 /* Initialize private flash information */
100 cc3220sf_bank->probed = false;
101
102 /* Finish initialization of flash bank */
103 bank->driver_priv = cc3220sf_bank;
104 bank->next = NULL;
105
106 return ERROR_OK;
107 }
108
109 static int cc3220sf_erase(struct flash_bank *bank, int first, int last)
110 {
111 struct target *target = bank->target;
112 bool done;
113 long long start_ms;
114 long long elapsed_ms;
115 uint32_t address;
116 uint32_t value;
117
118 int retval = ERROR_OK;
119
120 if (TARGET_HALTED != target->state) {
121 LOG_ERROR("Target not halted");
122 return ERROR_TARGET_NOT_HALTED;
123 }
124
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);
129 }
130
131 /* Erase requested sectors one by one */
132 for (int i = first; i <= last; i++) {
133
134 /* Determine address of sector to erase */
135 address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE;
136
137 /* Set starting address to erase */
138 retval = target_write_u32(target, FMA_REGISTER_ADDR, address);
139 if (ERROR_OK != retval)
140 return retval;
141
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)
145 return retval;
146
147 /* Poll the ERASE bit until the erase is complete */
148 done = false;
149 start_ms = timeval_ms();
150 while (!done) {
151 retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
152 if (ERROR_OK != retval)
153 return retval;
154
155 if ((value & FMC_ERASE_BIT) == 0) {
156 /* Bit clears when mass erase is finished */
157 done = true;
158 } else {
159 elapsed_ms = timeval_ms() - start_ms;
160 if (elapsed_ms > 500)
161 keep_alive();
162 if (elapsed_ms > FLASH_TIMEOUT)
163 break;
164 }
165 }
166
167 if (!done) {
168 /* Sector erase timed out waiting for confirmation */
169 return ERROR_FAIL;
170 }
171 }
172
173 return retval;
174 }
175
176 static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
177 uint32_t offset, uint32_t count)
178 {
179 struct target *target = bank->target;
180 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
181 struct working_area *algo_working_area;
182 struct working_area *buffer_working_area;
183 struct reg_param reg_params[3];
184 uint32_t algo_base_address;
185 uint32_t algo_buffer_address;
186 uint32_t algo_buffer_size;
187 uint32_t address;
188 uint32_t remaining;
189 uint32_t words;
190 uint32_t result;
191
192 int retval = ERROR_OK;
193
194 if (TARGET_HALTED != target->state) {
195 LOG_ERROR("Target not halted");
196 return ERROR_TARGET_NOT_HALTED;
197 }
198
199 /* Obtain working area to use for flash helper algorithm */
200 retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
201 &algo_working_area);
202 if (ERROR_OK != retval)
203 return retval;
204
205 /* Obtain working area to use for flash buffer */
206 retval = target_alloc_working_area(target,
207 target_get_working_area_avail(target), &buffer_working_area);
208 if (ERROR_OK != retval) {
209 target_free_working_area(target, algo_working_area);
210 return retval;
211 }
212
213 algo_base_address = algo_working_area->address;
214 algo_buffer_address = buffer_working_area->address;
215 algo_buffer_size = buffer_working_area->size;
216
217 /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
218 /* (algo runs more efficiently if it operates on 32 words at a time) */
219 if (algo_buffer_size > 0x80)
220 algo_buffer_size &= ~0x7f;
221
222 /* Write flash helper algorithm into target memory */
223 retval = target_write_buffer(target, algo_base_address,
224 sizeof(cc3220sf_algo), cc3220sf_algo);
225 if (ERROR_OK != retval) {
226 target_free_working_area(target, algo_working_area);
227 target_free_working_area(target, buffer_working_area);
228 return retval;
229 }
230
231 /* Initialize the ARMv7m specific info to run the algorithm */
232 cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
233 cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
234
235 /* Initialize register params for flash helper algorithm */
236 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
237 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
238 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
239
240 /* Prepare to write to flash */
241 address = FLASH_BASE_ADDR + offset;
242 remaining = count;
243
244 /* The flash hardware can only write complete words to flash. If
245 * an unaligned address is passed in, we must do a read-modify-write
246 * on a word with enough bytes to align the rest of the buffer. And
247 * if less than a whole word remains at the end, we must also do a
248 * read-modify-write on a final word to finish up.
249 */
250
251 /* Do one word write to align address on 32-bit boundary if needed */
252 if (0 != (address & 0x3)) {
253 uint8_t head[4];
254
255 /* Get starting offset for data to write (will be 1 to 3) */
256 uint32_t head_offset = address & 0x03;
257
258 /* Get the aligned address to write this first word to */
259 uint32_t head_address = address & 0xfffffffc;
260
261 /* Retrieve what is already in flash at the head address */
262 retval = target_read_buffer(target, head_address, sizeof(head), head);
263
264 if (ERROR_OK == retval) {
265 /* Substitute in the new data to write */
266 while ((remaining > 0) && (head_offset < 4)) {
267 head[head_offset] = *buffer;
268 head_offset++;
269 address++;
270 buffer++;
271 remaining--;
272 }
273 }
274
275 if (ERROR_OK == retval) {
276 /* Helper parameters are passed in registers R0-R2 */
277 /* Set start of data buffer, address to write to, and word count */
278 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
279 buf_set_u32(reg_params[1].value, 0, 32, head_address);
280 buf_set_u32(reg_params[2].value, 0, 32, 1);
281
282 /* Write head value into buffer to flash */
283 retval = target_write_buffer(target, algo_buffer_address,
284 sizeof(head), head);
285 }
286
287 if (ERROR_OK == retval) {
288 /* Execute the flash helper algorithm */
289 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
290 algo_base_address, 0, FLASH_TIMEOUT,
291 &cc3220sf_bank->armv7m_info);
292 if (ERROR_OK != retval)
293 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
294
295 /* Check that the head value was written to flash */
296 result = buf_get_u32(reg_params[2].value, 0, 32);
297 if (0 != result) {
298 retval = ERROR_FAIL;
299 LOG_ERROR("cc3220sf: Flash operation failed");
300 }
301 }
302 }
303
304 /* Check if there's data at end of buffer that isn't a full word */
305 uint32_t tail_count = remaining & 0x03;
306 /* Adjust remaining so it is a multiple of whole words */
307 remaining -= tail_count;
308
309 while ((ERROR_OK == retval) && (remaining > 0)) {
310 /* Set start of data buffer and address to write to */
311 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
312 buf_set_u32(reg_params[1].value, 0, 32, address);
313
314 /* Download data to write into memory buffer */
315 if (remaining >= algo_buffer_size) {
316 /* Fill up buffer with data to flash */
317 retval = target_write_buffer(target, algo_buffer_address,
318 algo_buffer_size, buffer);
319 if (ERROR_OK != retval)
320 break;
321
322 /* Count to write is in 32-bit words */
323 words = algo_buffer_size / 4;
324
325 /* Bump variables to next data */
326 address += algo_buffer_size;
327 buffer += algo_buffer_size;
328 remaining -= algo_buffer_size;
329 } else {
330 /* Fill buffer with what's left of the data */
331 retval = target_write_buffer(target, algo_buffer_address,
332 remaining, buffer);
333 if (ERROR_OK != retval)
334 break;
335
336 /* Calculate the final word count to write */
337 words = remaining / 4;
338 if (0 != (remaining % 4))
339 words++;
340
341 /* Bump variables to any final data */
342 address += remaining;
343 buffer += remaining;
344 remaining = 0;
345 }
346
347 /* Set number of words to write */
348 buf_set_u32(reg_params[2].value, 0, 32, words);
349
350 /* Execute the flash helper algorithm */
351 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
352 algo_base_address, 0, FLASH_TIMEOUT,
353 &cc3220sf_bank->armv7m_info);
354 if (ERROR_OK != retval) {
355 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
356 break;
357 }
358
359 /* Check that all words were written to flash */
360 result = buf_get_u32(reg_params[2].value, 0, 32);
361 if (0 != result) {
362 retval = ERROR_FAIL;
363 LOG_ERROR("cc3220sf: Flash operation failed");
364 break;
365 }
366 }
367
368 /* Do one word write for any final bytes less than a full word */
369 if ((ERROR_OK == retval) && (0 != tail_count)) {
370 uint8_t tail[4];
371
372 /* Set starting byte offset for data to write */
373 uint32_t tail_offset = 0;
374
375 /* Retrieve what is already in flash at the tail address */
376 retval = target_read_buffer(target, address, sizeof(tail), tail);
377
378 if (ERROR_OK == retval) {
379 /* Substitute in the new data to write */
380 while (tail_count > 0) {
381 tail[tail_offset] = *buffer;
382 tail_offset++;
383 buffer++;
384 tail_count--;
385 }
386 }
387
388 if (ERROR_OK == retval) {
389 /* Set start of data buffer, address to write to, and word count */
390 buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
391 buf_set_u32(reg_params[1].value, 0, 32, address);
392 buf_set_u32(reg_params[2].value, 0, 32, 1);
393
394 /* Write tail value into buffer to flash */
395 retval = target_write_buffer(target, algo_buffer_address,
396 sizeof(tail), tail);
397 }
398
399 if (ERROR_OK == retval) {
400 /* Execute the flash helper algorithm */
401 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
402 algo_base_address, 0, FLASH_TIMEOUT,
403 &cc3220sf_bank->armv7m_info);
404 if (ERROR_OK != retval)
405 LOG_ERROR("cc3220sf: Flash algorithm failed to run");
406
407 /* Check that the tail was written to flash */
408 result = buf_get_u32(reg_params[2].value, 0, 32);
409 if (0 != result) {
410 retval = ERROR_FAIL;
411 LOG_ERROR("cc3220sf: Flash operation failed");
412 }
413 }
414 }
415
416 /* Free resources */
417 destroy_reg_param(&reg_params[0]);
418 destroy_reg_param(&reg_params[1]);
419 destroy_reg_param(&reg_params[2]);
420 target_free_working_area(target, algo_working_area);
421 target_free_working_area(target, buffer_working_area);
422
423 return retval;
424 }
425
426 static int cc3220sf_probe(struct flash_bank *bank)
427 {
428 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
429
430 uint32_t base;
431 uint32_t size;
432 int num_sectors;
433 int bank_id;
434
435 bank_id = bank->bank_number;
436
437 if (0 == bank_id) {
438 base = FLASH_BASE_ADDR;
439 size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
440 num_sectors = FLASH_NUM_SECTORS;
441 } else {
442 /* Invalid bank number somehow */
443 return ERROR_FAIL;
444 }
445
446 if (NULL != bank->sectors) {
447 free(bank->sectors);
448 bank->sectors = NULL;
449 }
450
451 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
452 if (NULL == bank->sectors)
453 return ERROR_FAIL;
454
455 bank->base = base;
456 bank->size = size;
457 bank->write_start_alignment = 0;
458 bank->write_end_alignment = 0;
459 bank->num_sectors = num_sectors;
460
461 for (int i = 0; i < num_sectors; i++) {
462 bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
463 bank->sectors[i].size = FLASH_SECTOR_SIZE;
464 bank->sectors[i].is_erased = -1;
465 bank->sectors[i].is_protected = 0;
466 }
467
468 /* We've successfully recorded the stats on this flash bank */
469 cc3220sf_bank->probed = true;
470
471 /* If we fall through to here, then all went well */
472
473 return ERROR_OK;
474 }
475
476 static int cc3220sf_auto_probe(struct flash_bank *bank)
477 {
478 struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
479
480 int retval = ERROR_OK;
481
482 if (0 != bank->bank_number) {
483 /* Invalid bank number somehow */
484 return ERROR_FAIL;
485 }
486
487 if (!cc3220sf_bank->probed)
488 retval = cc3220sf_probe(bank);
489
490 return retval;
491 }
492
493 static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
494 {
495 int printed;
496
497 printed = snprintf(buf, buf_size, "CC3220SF with 1MB internal flash\n");
498
499 if (printed >= buf_size)
500 return ERROR_BUF_TOO_SMALL;
501
502 return ERROR_OK;
503 }
504
505 struct flash_driver cc3220sf_flash = {
506 .name = "cc3220sf",
507 .flash_bank_command = cc3220sf_flash_bank_command,
508 .erase = cc3220sf_erase,
509 .write = cc3220sf_write,
510 .read = default_flash_read,
511 .probe = cc3220sf_probe,
512 .auto_probe = cc3220sf_auto_probe,
513 .erase_check = default_flash_blank_check,
514 .info = cc3220sf_info,
515 .free_driver_priv = default_flash_free_driver_priv,
516 };