flash/nor/at91sam7: fix flash bank allocation
[openocd.git] / src / flash / nor / npcx.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /*
4 * Copyright (C) 2020 by Nuvoton Technology Corporation
5 * Mulin Chao <mlchao@nuvoton.com>
6 * Wealian Liao <WHLIAO@nuvoton.com>
7 * Luca Hung <YCHUNG0@nuvoton.com>
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include "imp.h"
15 #include <helper/binarybuffer.h>
16 #include <helper/time_support.h>
17 #include <target/armv7m.h>
18 #include "../../../contrib/loaders/flash/npcx/npcx_flash.h"
19
20 /* NPCX flash loader */
21 static const uint8_t npcx_algo[] = {
22 #include "../../../contrib/loaders/flash/npcx/npcx_algo.inc"
23 };
24
25 #define NPCX_FLASH_TIMEOUT_MS 8000
26
27 /* flash list */
28 enum npcx_flash_device_index {
29 NPCX_FLASH_256KB = 0,
30 NPCX_FLASH_512KB = 1,
31 NPCX_FLASH_1MB = 2,
32 NPCX_FLASH_UNKNOWN,
33 };
34
35 struct npcx_flash_bank {
36 uint32_t sector_length;
37 bool probed;
38 enum npcx_flash_device_index flash;
39 struct working_area *working_area;
40 struct armv7m_algorithm armv7m_info;
41 const uint8_t *algo_code;
42 uint32_t algo_size;
43 uint32_t algo_working_size;
44 uint32_t buffer_addr;
45 uint32_t params_addr;
46 uint32_t fiu_ver;
47 };
48
49 struct npcx_flash_info {
50 char *name;
51 uint32_t id;
52 uint32_t size;
53 };
54
55 static const struct npcx_flash_info flash_info[] = {
56 [NPCX_FLASH_256KB] = {
57 .name = "256KB Flash",
58 .id = 0xEF4012,
59 .size = 256 * 1024,
60 },
61 [NPCX_FLASH_512KB] = {
62 .name = "512KB Flash",
63 .id = 0xEF4013,
64 .size = 512 * 1024,
65 },
66 [NPCX_FLASH_1MB] = {
67 .name = "1MB Flash",
68 .id = 0xEF4014,
69 .size = 1024 * 1024,
70 },
71 [NPCX_FLASH_UNKNOWN] = {
72 .name = "Unknown Flash",
73 .size = 0xFFFFFFFF,
74 },
75 };
76
77 static int npcx_init(struct flash_bank *bank)
78 {
79 struct target *target = bank->target;
80 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
81
82 /* Check for working area to use for flash helper algorithm */
83 target_free_working_area(target, npcx_bank->working_area);
84 npcx_bank->working_area = NULL;
85
86 int retval = target_alloc_working_area(target, npcx_bank->algo_working_size,
87 &npcx_bank->working_area);
88 if (retval != ERROR_OK)
89 return retval;
90
91 /* Confirm the defined working address is the area we need to use */
92 if (npcx_bank->working_area->address != NPCX_FLASH_LOADER_WORKING_ADDR) {
93 LOG_TARGET_ERROR(target, "Invalid working address");
94 LOG_INFO("Hint: Use '-work-area-phys 0x%" PRIx32 "' in your target configuration",
95 NPCX_FLASH_LOADER_WORKING_ADDR);
96 target_free_working_area(target, npcx_bank->working_area);
97 npcx_bank->working_area = NULL;
98 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
99 }
100
101 /* Write flash helper algorithm into target memory */
102 retval = target_write_buffer(target, NPCX_FLASH_LOADER_PROGRAM_ADDR,
103 npcx_bank->algo_size, npcx_bank->algo_code);
104 if (retval != ERROR_OK) {
105 LOG_TARGET_ERROR(target, "Failed to load flash helper algorithm");
106 target_free_working_area(target, npcx_bank->working_area);
107 npcx_bank->working_area = NULL;
108 return retval;
109 }
110
111 /* Initialize the ARMv7 specific info to run the algorithm */
112 npcx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
113 npcx_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
114
115 /* Begin executing the flash helper algorithm */
116 retval = target_start_algorithm(target, 0, NULL, 0, NULL,
117 NPCX_FLASH_LOADER_PROGRAM_ADDR, 0,
118 &npcx_bank->armv7m_info);
119 if (retval != ERROR_OK) {
120 LOG_TARGET_ERROR(target, "Failed to start flash helper algorithm");
121 target_free_working_area(target, npcx_bank->working_area);
122 npcx_bank->working_area = NULL;
123 return retval;
124 }
125
126 /*
127 * At this point, the algorithm is running on the target and
128 * ready to receive commands and data to flash the target
129 */
130
131 return retval;
132 }
133
134 static int npcx_quit(struct flash_bank *bank)
135 {
136 struct target *target = bank->target;
137 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
138
139 /* Regardless of the algo's status, attempt to halt the target */
140 (void)target_halt(target);
141
142 /* Now confirm target halted and clean up from flash helper algorithm */
143 int retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
144 NPCX_FLASH_TIMEOUT_MS, &npcx_bank->armv7m_info);
145
146 target_free_working_area(target, npcx_bank->working_area);
147 npcx_bank->working_area = NULL;
148
149 return retval;
150 }
151
152 static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
153 {
154 struct target *target = bank->target;
155 uint32_t status_addr = params_addr + offsetof(struct npcx_flash_params, sync);
156 uint32_t status;
157 int64_t start_ms = timeval_ms();
158
159 do {
160 int retval = target_read_u32(target, status_addr, &status);
161 if (retval != ERROR_OK)
162 return retval;
163
164 keep_alive();
165
166 int64_t elapsed_ms = timeval_ms() - start_ms;
167 if (elapsed_ms > NPCX_FLASH_TIMEOUT_MS)
168 break;
169 } while (status == NPCX_FLASH_LOADER_EXECUTE);
170
171 if (status != NPCX_FLASH_LOADER_WAIT) {
172 LOG_TARGET_ERROR(target, "Flash operation failed, status (%0x" PRIX32 ") ", status);
173 return ERROR_FAIL;
174 }
175
176 return ERROR_OK;
177 }
178
179 static enum npcx_flash_device_index npcx_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
180 {
181 struct target *target = bank->target;
182 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
183 struct npcx_flash_params algo_params;
184
185 if (target->state != TARGET_HALTED) {
186 LOG_ERROR("Target not halted");
187 return ERROR_TARGET_NOT_HALTED;
188 }
189
190 int retval = npcx_init(bank);
191 if (retval != ERROR_OK)
192 return retval;
193
194 /* Set up algorithm parameters for get flash ID command */
195 target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver);
196 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_GET_FLASH_ID);
197 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
198
199 /* Issue flash helper algorithm parameters for get flash ID */
200 retval = target_write_buffer(target, npcx_bank->params_addr,
201 sizeof(algo_params), (uint8_t *)&algo_params);
202 if (retval != ERROR_OK) {
203 (void)npcx_quit(bank);
204 return retval;
205 }
206
207 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
208 retval = target_write_buffer(target, npcx_bank->params_addr,
209 sizeof(algo_params), (uint8_t *)&algo_params);
210
211 /* If no error, wait for finishing */
212 if (retval == ERROR_OK) {
213 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
214 if (retval == ERROR_OK)
215 target_read_u32(target, NPCX_FLASH_LOADER_BUFFER_ADDR, flash_id);
216 }
217
218 /* Regardless of errors, try to close down algo */
219 (void)npcx_quit(bank);
220
221 return retval;
222 }
223
224 static int npcx_get_flash(uint32_t flash_id)
225 {
226 for (uint32_t i = 0; i < ARRAY_SIZE(flash_info) - 1; i++) {
227 if (flash_info[i].id == flash_id)
228 return i;
229 }
230
231 return NPCX_FLASH_UNKNOWN;
232 }
233
234 static int npcx_probe(struct flash_bank *bank)
235 {
236 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
237 uint32_t sector_length = NPCX_FLASH_ERASE_SIZE;
238 uint32_t flash_id;
239
240 /* Set up appropriate flash helper algorithm */
241 npcx_bank->algo_code = npcx_algo;
242 npcx_bank->algo_size = sizeof(npcx_algo);
243 npcx_bank->algo_working_size = NPCX_FLASH_LOADER_PARAMS_SIZE +
244 NPCX_FLASH_LOADER_BUFFER_SIZE +
245 NPCX_FLASH_LOADER_PROGRAM_SIZE;
246 npcx_bank->buffer_addr = NPCX_FLASH_LOADER_BUFFER_ADDR;
247 npcx_bank->params_addr = NPCX_FLASH_LOADER_PARAMS_ADDR;
248
249
250 int retval = npcx_get_flash_id(bank, &flash_id);
251 if (retval != ERROR_OK)
252 return retval;
253
254 npcx_bank->flash = npcx_get_flash(flash_id);
255
256 unsigned int num_sectors = flash_info[npcx_bank->flash].size / sector_length;
257
258 bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
259 if (!bank->sectors) {
260 LOG_ERROR("Out of memory");
261 return ERROR_FAIL;
262 }
263
264 bank->num_sectors = num_sectors;
265 bank->size = num_sectors * sector_length;
266 bank->write_start_alignment = 0;
267 bank->write_end_alignment = 0;
268 npcx_bank->sector_length = sector_length;
269
270 for (unsigned int i = 0; i < num_sectors; i++) {
271 bank->sectors[i].offset = i * sector_length;
272 bank->sectors[i].size = sector_length;
273 bank->sectors[i].is_erased = -1;
274 bank->sectors[i].is_protected = 0;
275 }
276
277 /* We've successfully determined the stats on the flash bank */
278 npcx_bank->probed = true;
279
280 /* If we fall through to here, then all went well */
281 return ERROR_OK;
282 }
283
284 static int npcx_auto_probe(struct flash_bank *bank)
285 {
286 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
287 int retval = ERROR_OK;
288
289 if (!npcx_bank->probed)
290 retval = npcx_probe(bank);
291
292 return retval;
293 }
294
295 FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command)
296 {
297 struct npcx_flash_bank *npcx_bank;
298
299 if (CMD_ARGC < 6 || CMD_ARGC > 7)
300 return ERROR_COMMAND_SYNTAX_ERROR;
301
302 npcx_bank = calloc(1, sizeof(struct npcx_flash_bank));
303 if (!npcx_bank) {
304 LOG_ERROR("Out of memory");
305 return ERROR_FAIL;
306 }
307
308 const char *fiu;
309 if (CMD_ARGC == 6) {
310 LOG_WARNING("No FIU is selection, using default.");
311 npcx_bank->fiu_ver = NPCX_FIU_NPCX;
312 }
313
314 if (CMD_ARGC == 7) {
315 fiu = CMD_ARGV[6];
316 if (strcmp(fiu, "npcx.fiu") == 0) {
317 npcx_bank->fiu_ver = NPCX_FIU_NPCX;
318 } else if (strcmp(fiu, "npcx_v2.fiu") == 0) {
319 npcx_bank->fiu_ver = NPCX_FIU_NPCX_V2;
320 } else if (strcmp(fiu, "npck.fiu") == 0) {
321 npcx_bank->fiu_ver = NPCX_FIU_NPCK;
322 } else {
323 LOG_ERROR("%s is not a valid fiu", fiu);
324 free(npcx_bank);
325 return ERROR_TARGET_INVALID;
326 }
327 }
328
329 /* Initialize private flash information */
330 npcx_bank->sector_length = NPCX_FLASH_ERASE_SIZE;
331
332 /* Finish initialization of bank */
333 bank->driver_priv = npcx_bank;
334 bank->next = NULL;
335
336 return ERROR_OK;
337 }
338
339 static int npcx_chip_erase(struct flash_bank *bank)
340 {
341 struct target *target = bank->target;
342 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
343 struct npcx_flash_params algo_params;
344
345 if (target->state != TARGET_HALTED) {
346 LOG_ERROR("Target not halted");
347 return ERROR_TARGET_NOT_HALTED;
348 }
349
350 /* Make sure we've probed the flash to get the device and size */
351 int retval = npcx_auto_probe(bank);
352 if (retval != ERROR_OK)
353 return retval;
354
355 retval = npcx_init(bank);
356 if (retval != ERROR_OK)
357 return retval;
358
359 /* Set up algorithm parameters for chip erase command */
360 target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver);
361 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_ALL);
362 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
363
364 /* Set algorithm parameters */
365 retval = target_write_buffer(target, npcx_bank->params_addr,
366 sizeof(algo_params), (uint8_t *)&algo_params);
367 if (retval != ERROR_OK) {
368 (void)npcx_quit(bank);
369 return retval;
370 }
371
372 /* Issue flash helper algorithm parameters for chip erase */
373 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
374 retval = target_write_buffer(target, npcx_bank->params_addr,
375 sizeof(algo_params), (uint8_t *)&algo_params);
376
377 /* If no error, wait for chip erase finish */
378 if (retval == ERROR_OK)
379 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
380
381 /* Regardless of errors, try to close down algo */
382 (void)npcx_quit(bank);
383
384 return retval;
385 }
386
387 static int npcx_erase(struct flash_bank *bank, unsigned int first,
388 unsigned int last)
389 {
390 struct target *target = bank->target;
391 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
392 struct npcx_flash_params algo_params;
393
394 if (target->state != TARGET_HALTED) {
395 LOG_ERROR("Target not halted");
396 return ERROR_TARGET_NOT_HALTED;
397 }
398
399 if ((first == 0) && (last == (bank->num_sectors - 1))) {
400 /* Request chip erase */
401 return npcx_chip_erase(bank);
402 }
403
404 uint32_t address = first * npcx_bank->sector_length;
405 uint32_t length = (last - first + 1) * npcx_bank->sector_length;
406
407 /* Make sure we've probed the flash to get the device and size */
408 int retval = npcx_auto_probe(bank);
409 if (retval != ERROR_OK)
410 return retval;
411
412 retval = npcx_init(bank);
413 if (retval != ERROR_OK)
414 return retval;
415
416 /* Set up algorithm parameters for erase command */
417 target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver);
418 target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address);
419 target_buffer_set_u32(target, (uint8_t *)&algo_params.len, length);
420 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_SECTORS);
421 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
422
423 /* Set algorithm parameters */
424 retval = target_write_buffer(target, npcx_bank->params_addr,
425 sizeof(algo_params), (uint8_t *)&algo_params);
426 if (retval != ERROR_OK) {
427 (void)npcx_quit(bank);
428 return retval;
429 }
430
431 /* Issue flash helper algorithm parameters for erase */
432 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
433 retval = target_write_buffer(target, npcx_bank->params_addr,
434 sizeof(algo_params), (uint8_t *)&algo_params);
435
436 /* If no error, wait for erase to finish */
437 if (retval == ERROR_OK)
438 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
439
440 /* Regardless of errors, try to close down algo */
441 (void)npcx_quit(bank);
442
443 return retval;
444 }
445
446 static int npcx_write(struct flash_bank *bank, const uint8_t *buffer,
447 uint32_t offset, uint32_t count)
448 {
449 struct target *target = bank->target;
450 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
451 struct npcx_flash_params algo_params;
452
453 if (target->state != TARGET_HALTED) {
454 LOG_ERROR("Target not halted");
455 return ERROR_TARGET_NOT_HALTED;
456 }
457
458 /* Make sure we've probed the flash to get the device and size */
459 int retval = npcx_auto_probe(bank);
460 if (retval != ERROR_OK)
461 return retval;
462
463 retval = npcx_init(bank);
464 if (retval != ERROR_OK)
465 return retval;
466
467 /* Initialize algorithm parameters to default values */
468 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_PROGRAM);
469
470 uint32_t address = offset;
471
472 while (count > 0) {
473 uint32_t size = (count > NPCX_FLASH_LOADER_BUFFER_SIZE) ?
474 NPCX_FLASH_LOADER_BUFFER_SIZE : count;
475
476 /* Put the data into buffer */
477 retval = target_write_buffer(target, npcx_bank->buffer_addr,
478 size, buffer);
479 if (retval != ERROR_OK) {
480 LOG_ERROR("Unable to write data to target memory");
481 break;
482 }
483
484 /* Update algo parameters for flash write */
485 target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver);
486 target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address);
487 target_buffer_set_u32(target, (uint8_t *)&algo_params.len, size);
488 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
489
490 /* Set algorithm parameters */
491 retval = target_write_buffer(target, npcx_bank->params_addr,
492 sizeof(algo_params), (uint8_t *)&algo_params);
493 if (retval != ERROR_OK)
494 break;
495
496 /* Issue flash helper algorithm parameters for flash write */
497 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
498 retval = target_write_buffer(target, npcx_bank->params_addr,
499 sizeof(algo_params), (uint8_t *)&algo_params);
500 if (retval != ERROR_OK)
501 break;
502
503 /* Wait for flash write finish */
504 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
505 if (retval != ERROR_OK)
506 break;
507
508 count -= size;
509 buffer += size;
510 address += size;
511 }
512
513 /* Regardless of errors, try to close down algo */
514 (void)npcx_quit(bank);
515
516 return retval;
517 }
518
519 static int npcx_info(struct flash_bank *bank, struct command_invocation *cmd)
520 {
521 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
522
523 command_print_sameline(cmd, "%s flash: %s\n",
524 target_name(bank->target),
525 flash_info[npcx_bank->flash].name);
526
527 return ERROR_OK;
528 }
529
530 const struct flash_driver npcx_flash = {
531 .name = "npcx",
532 .flash_bank_command = npcx_flash_bank_command,
533 .erase = npcx_erase,
534 .write = npcx_write,
535 .read = default_flash_read,
536 .probe = npcx_probe,
537 .auto_probe = npcx_auto_probe,
538 .erase_check = default_flash_blank_check,
539 .info = npcx_info,
540 .free_driver_priv = default_flash_free_driver_priv,
541 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)