target/xtensa: avoid IHI for writes to non-executable memory
[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
335 return ERROR_OK;
336 }
337
338 static int npcx_chip_erase(struct flash_bank *bank)
339 {
340 struct target *target = bank->target;
341 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
342 struct npcx_flash_params algo_params;
343
344 if (target->state != TARGET_HALTED) {
345 LOG_ERROR("Target not halted");
346 return ERROR_TARGET_NOT_HALTED;
347 }
348
349 /* Make sure we've probed the flash to get the device and size */
350 int retval = npcx_auto_probe(bank);
351 if (retval != ERROR_OK)
352 return retval;
353
354 retval = npcx_init(bank);
355 if (retval != ERROR_OK)
356 return retval;
357
358 /* Set up algorithm parameters for chip erase command */
359 target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver);
360 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_ALL);
361 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
362
363 /* Set algorithm parameters */
364 retval = target_write_buffer(target, npcx_bank->params_addr,
365 sizeof(algo_params), (uint8_t *)&algo_params);
366 if (retval != ERROR_OK) {
367 (void)npcx_quit(bank);
368 return retval;
369 }
370
371 /* Issue flash helper algorithm parameters for chip erase */
372 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
373 retval = target_write_buffer(target, npcx_bank->params_addr,
374 sizeof(algo_params), (uint8_t *)&algo_params);
375
376 /* If no error, wait for chip erase finish */
377 if (retval == ERROR_OK)
378 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
379
380 /* Regardless of errors, try to close down algo */
381 (void)npcx_quit(bank);
382
383 return retval;
384 }
385
386 static int npcx_erase(struct flash_bank *bank, unsigned int first,
387 unsigned int last)
388 {
389 struct target *target = bank->target;
390 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
391 struct npcx_flash_params algo_params;
392
393 if (target->state != TARGET_HALTED) {
394 LOG_ERROR("Target not halted");
395 return ERROR_TARGET_NOT_HALTED;
396 }
397
398 if ((first == 0) && (last == (bank->num_sectors - 1))) {
399 /* Request chip erase */
400 return npcx_chip_erase(bank);
401 }
402
403 uint32_t address = first * npcx_bank->sector_length;
404 uint32_t length = (last - first + 1) * npcx_bank->sector_length;
405
406 /* Make sure we've probed the flash to get the device and size */
407 int retval = npcx_auto_probe(bank);
408 if (retval != ERROR_OK)
409 return retval;
410
411 retval = npcx_init(bank);
412 if (retval != ERROR_OK)
413 return retval;
414
415 /* Set up algorithm parameters for erase command */
416 target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver);
417 target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address);
418 target_buffer_set_u32(target, (uint8_t *)&algo_params.len, length);
419 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_SECTORS);
420 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
421
422 /* Set algorithm parameters */
423 retval = target_write_buffer(target, npcx_bank->params_addr,
424 sizeof(algo_params), (uint8_t *)&algo_params);
425 if (retval != ERROR_OK) {
426 (void)npcx_quit(bank);
427 return retval;
428 }
429
430 /* Issue flash helper algorithm parameters for erase */
431 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
432 retval = target_write_buffer(target, npcx_bank->params_addr,
433 sizeof(algo_params), (uint8_t *)&algo_params);
434
435 /* If no error, wait for erase to finish */
436 if (retval == ERROR_OK)
437 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
438
439 /* Regardless of errors, try to close down algo */
440 (void)npcx_quit(bank);
441
442 return retval;
443 }
444
445 static int npcx_write(struct flash_bank *bank, const uint8_t *buffer,
446 uint32_t offset, uint32_t count)
447 {
448 struct target *target = bank->target;
449 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
450 struct npcx_flash_params algo_params;
451
452 if (target->state != TARGET_HALTED) {
453 LOG_ERROR("Target not halted");
454 return ERROR_TARGET_NOT_HALTED;
455 }
456
457 /* Make sure we've probed the flash to get the device and size */
458 int retval = npcx_auto_probe(bank);
459 if (retval != ERROR_OK)
460 return retval;
461
462 retval = npcx_init(bank);
463 if (retval != ERROR_OK)
464 return retval;
465
466 /* Initialize algorithm parameters to default values */
467 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_PROGRAM);
468
469 uint32_t address = offset;
470
471 while (count > 0) {
472 uint32_t size = (count > NPCX_FLASH_LOADER_BUFFER_SIZE) ?
473 NPCX_FLASH_LOADER_BUFFER_SIZE : count;
474
475 /* Put the data into buffer */
476 retval = target_write_buffer(target, npcx_bank->buffer_addr,
477 size, buffer);
478 if (retval != ERROR_OK) {
479 LOG_ERROR("Unable to write data to target memory");
480 break;
481 }
482
483 /* Update algo parameters for flash write */
484 target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver);
485 target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address);
486 target_buffer_set_u32(target, (uint8_t *)&algo_params.len, size);
487 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
488
489 /* Set algorithm parameters */
490 retval = target_write_buffer(target, npcx_bank->params_addr,
491 sizeof(algo_params), (uint8_t *)&algo_params);
492 if (retval != ERROR_OK)
493 break;
494
495 /* Issue flash helper algorithm parameters for flash write */
496 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
497 retval = target_write_buffer(target, npcx_bank->params_addr,
498 sizeof(algo_params), (uint8_t *)&algo_params);
499 if (retval != ERROR_OK)
500 break;
501
502 /* Wait for flash write finish */
503 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
504 if (retval != ERROR_OK)
505 break;
506
507 count -= size;
508 buffer += size;
509 address += size;
510 }
511
512 /* Regardless of errors, try to close down algo */
513 (void)npcx_quit(bank);
514
515 return retval;
516 }
517
518 static int npcx_info(struct flash_bank *bank, struct command_invocation *cmd)
519 {
520 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
521
522 command_print_sameline(cmd, "%s flash: %s\n",
523 target_name(bank->target),
524 flash_info[npcx_bank->flash].name);
525
526 return ERROR_OK;
527 }
528
529 const struct flash_driver npcx_flash = {
530 .name = "npcx",
531 .flash_bank_command = npcx_flash_bank_command,
532 .erase = npcx_erase,
533 .write = npcx_write,
534 .read = default_flash_read,
535 .probe = npcx_probe,
536 .auto_probe = npcx_auto_probe,
537 .erase_check = default_flash_blank_check,
538 .info = npcx_info,
539 .free_driver_priv = default_flash_free_driver_priv,
540 };

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)