jtag: linuxgpiod: drop extra parenthesis
[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 */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "imp.h"
14 #include <helper/binarybuffer.h>
15 #include <helper/time_support.h>
16 #include <target/armv7m.h>
17 #include "../../../contrib/loaders/flash/npcx/npcx_flash.h"
18
19 /* NPCX flash loader */
20 static const uint8_t npcx_algo[] = {
21 #include "../../../contrib/loaders/flash/npcx/npcx_algo.inc"
22 };
23
24 #define NPCX_FLASH_TIMEOUT_MS 8000
25 #define NPCX_FLASH_BASE_ADDR 0x64000000
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 const char *family_name;
37 uint32_t sector_length;
38 bool probed;
39 enum npcx_flash_device_index flash;
40 struct working_area *working_area;
41 struct armv7m_algorithm armv7m_info;
42 const uint8_t *algo_code;
43 uint32_t algo_size;
44 uint32_t algo_working_size;
45 uint32_t buffer_addr;
46 uint32_t params_addr;
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_ERROR("%s: Invalid working address", npcx_bank->family_name);
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_ERROR("%s: Failed to load flash helper algorithm",
106 npcx_bank->family_name);
107 target_free_working_area(target, npcx_bank->working_area);
108 npcx_bank->working_area = NULL;
109 return retval;
110 }
111
112 /* Initialize the ARMv7 specific info to run the algorithm */
113 npcx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
114 npcx_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
115
116 /* Begin executing the flash helper algorithm */
117 retval = target_start_algorithm(target, 0, NULL, 0, NULL,
118 NPCX_FLASH_LOADER_PROGRAM_ADDR, 0,
119 &npcx_bank->armv7m_info);
120 if (retval != ERROR_OK) {
121 LOG_ERROR("%s: Failed to start flash helper algorithm",
122 npcx_bank->family_name);
123 target_free_working_area(target, npcx_bank->working_area);
124 npcx_bank->working_area = NULL;
125 return retval;
126 }
127
128 /*
129 * At this point, the algorithm is running on the target and
130 * ready to receive commands and data to flash the target
131 */
132
133 return retval;
134 }
135
136 static int npcx_quit(struct flash_bank *bank)
137 {
138 struct target *target = bank->target;
139 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
140
141 /* Regardless of the algo's status, attempt to halt the target */
142 (void)target_halt(target);
143
144 /* Now confirm target halted and clean up from flash helper algorithm */
145 int retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
146 NPCX_FLASH_TIMEOUT_MS, &npcx_bank->armv7m_info);
147
148 target_free_working_area(target, npcx_bank->working_area);
149 npcx_bank->working_area = NULL;
150
151 return retval;
152 }
153
154 static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
155 {
156 struct target *target = bank->target;
157 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
158 uint32_t status_addr = params_addr + offsetof(struct npcx_flash_params, sync);
159 uint32_t status;
160 int64_t start_ms = timeval_ms();
161
162 do {
163 int retval = target_read_u32(target, status_addr, &status);
164 if (retval != ERROR_OK)
165 return retval;
166
167 keep_alive();
168
169 int64_t elapsed_ms = timeval_ms() - start_ms;
170 if (elapsed_ms > NPCX_FLASH_TIMEOUT_MS)
171 break;
172 } while (status == NPCX_FLASH_LOADER_EXECUTE);
173
174 if (status != NPCX_FLASH_LOADER_WAIT) {
175 LOG_ERROR("%s: Flash operation failed, status=0x%" PRIx32,
176 npcx_bank->family_name,
177 status);
178 return ERROR_FAIL;
179 }
180
181 return ERROR_OK;
182 }
183
184 static enum npcx_flash_device_index npcx_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
185 {
186 struct target *target = bank->target;
187 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
188 struct npcx_flash_params algo_params;
189
190 if (target->state != TARGET_HALTED) {
191 LOG_ERROR("Target not halted");
192 return ERROR_TARGET_NOT_HALTED;
193 }
194
195 int retval = npcx_init(bank);
196 if (retval != ERROR_OK)
197 return retval;
198
199 /* Set up algorithm parameters for get flash ID command */
200 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_GET_FLASH_ID);
201 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
202
203 /* Issue flash helper algorithm parameters for get flash ID */
204 retval = target_write_buffer(target, npcx_bank->params_addr,
205 sizeof(algo_params), (uint8_t *)&algo_params);
206 if (retval != ERROR_OK) {
207 (void)npcx_quit(bank);
208 return retval;
209 }
210
211 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
212 retval = target_write_buffer(target, npcx_bank->params_addr,
213 sizeof(algo_params), (uint8_t *)&algo_params);
214
215 /* If no error, wait for finishing */
216 if (retval == ERROR_OK) {
217 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
218 if (retval == ERROR_OK)
219 target_read_u32(target, NPCX_FLASH_LOADER_BUFFER_ADDR, flash_id);
220 }
221
222 /* Regardless of errors, try to close down algo */
223 (void)npcx_quit(bank);
224
225 return retval;
226 }
227
228 static int npcx_get_flash(uint32_t flash_id)
229 {
230 for (uint32_t i = 0; i < ARRAY_SIZE(flash_info) - 1; i++) {
231 if (flash_info[i].id == flash_id)
232 return i;
233 }
234
235 return NPCX_FLASH_UNKNOWN;
236 }
237
238 static int npcx_probe(struct flash_bank *bank)
239 {
240 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
241 uint32_t sector_length = NPCX_FLASH_ERASE_SIZE;
242 uint32_t flash_id;
243
244 /* Set up appropriate flash helper algorithm */
245 npcx_bank->algo_code = npcx_algo;
246 npcx_bank->algo_size = sizeof(npcx_algo);
247 npcx_bank->algo_working_size = NPCX_FLASH_LOADER_PARAMS_SIZE +
248 NPCX_FLASH_LOADER_BUFFER_SIZE +
249 NPCX_FLASH_LOADER_PROGRAM_SIZE;
250 npcx_bank->buffer_addr = NPCX_FLASH_LOADER_BUFFER_ADDR;
251 npcx_bank->params_addr = NPCX_FLASH_LOADER_PARAMS_ADDR;
252
253 int retval = npcx_get_flash_id(bank, &flash_id);
254 if (retval != ERROR_OK)
255 return retval;
256
257 npcx_bank->flash = npcx_get_flash(flash_id);
258
259 unsigned int num_sectors = flash_info[npcx_bank->flash].size / sector_length;
260
261 bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
262 if (!bank->sectors) {
263 LOG_ERROR("Out of memory");
264 return ERROR_FAIL;
265 }
266
267 bank->base = NPCX_FLASH_BASE_ADDR;
268 bank->num_sectors = num_sectors;
269 bank->size = num_sectors * sector_length;
270 bank->write_start_alignment = 0;
271 bank->write_end_alignment = 0;
272 npcx_bank->sector_length = sector_length;
273
274 for (unsigned int i = 0; i < num_sectors; i++) {
275 bank->sectors[i].offset = i * sector_length;
276 bank->sectors[i].size = sector_length;
277 bank->sectors[i].is_erased = -1;
278 bank->sectors[i].is_protected = 0;
279 }
280
281 /* We've successfully determined the stats on the flash bank */
282 npcx_bank->probed = true;
283
284 /* If we fall through to here, then all went well */
285 return ERROR_OK;
286 }
287
288 static int npcx_auto_probe(struct flash_bank *bank)
289 {
290 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
291 int retval = ERROR_OK;
292
293 if (!npcx_bank->probed)
294 retval = npcx_probe(bank);
295
296 return retval;
297 }
298
299 FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command)
300 {
301 struct npcx_flash_bank *npcx_bank;
302
303 if (CMD_ARGC < 6)
304 return ERROR_COMMAND_SYNTAX_ERROR;
305
306 npcx_bank = calloc(1, sizeof(struct npcx_flash_bank));
307 if (!npcx_bank) {
308 LOG_ERROR("Out of memory");
309 return ERROR_FAIL;
310 }
311
312 /* Initialize private flash information */
313 npcx_bank->family_name = "npcx";
314 npcx_bank->sector_length = NPCX_FLASH_ERASE_SIZE;
315
316 /* Finish initialization of bank */
317 bank->driver_priv = npcx_bank;
318 bank->next = NULL;
319
320 return ERROR_OK;
321 }
322
323 static int npcx_chip_erase(struct flash_bank *bank)
324 {
325 struct target *target = bank->target;
326 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
327 struct npcx_flash_params algo_params;
328
329 if (target->state != TARGET_HALTED) {
330 LOG_ERROR("Target not halted");
331 return ERROR_TARGET_NOT_HALTED;
332 }
333
334 /* Make sure we've probed the flash to get the device and size */
335 int retval = npcx_auto_probe(bank);
336 if (retval != ERROR_OK)
337 return retval;
338
339 retval = npcx_init(bank);
340 if (retval != ERROR_OK)
341 return retval;
342
343 /* Set up algorithm parameters for chip erase command */
344 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_ALL);
345 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
346
347 /* Set algorithm parameters */
348 retval = target_write_buffer(target, npcx_bank->params_addr,
349 sizeof(algo_params), (uint8_t *)&algo_params);
350 if (retval != ERROR_OK) {
351 (void)npcx_quit(bank);
352 return retval;
353 }
354
355 /* Issue flash helper algorithm parameters for chip erase */
356 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
357 retval = target_write_buffer(target, npcx_bank->params_addr,
358 sizeof(algo_params), (uint8_t *)&algo_params);
359
360 /* If no error, wait for chip erase finish */
361 if (retval == ERROR_OK)
362 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
363
364 /* Regardless of errors, try to close down algo */
365 (void)npcx_quit(bank);
366
367 return retval;
368 }
369
370 static int npcx_erase(struct flash_bank *bank, unsigned int first,
371 unsigned int last)
372 {
373 struct target *target = bank->target;
374 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
375 struct npcx_flash_params algo_params;
376
377 if (target->state != TARGET_HALTED) {
378 LOG_ERROR("Target not halted");
379 return ERROR_TARGET_NOT_HALTED;
380 }
381
382 if ((first == 0) && (last == (bank->num_sectors - 1))) {
383 /* Request chip erase */
384 return npcx_chip_erase(bank);
385 }
386
387 uint32_t address = first * npcx_bank->sector_length;
388 uint32_t length = (last - first + 1) * npcx_bank->sector_length;
389
390 /* Make sure we've probed the flash to get the device and size */
391 int retval = npcx_auto_probe(bank);
392 if (retval != ERROR_OK)
393 return retval;
394
395 retval = npcx_init(bank);
396 if (retval != ERROR_OK)
397 return retval;
398
399 /* Set up algorithm parameters for erase command */
400 target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address);
401 target_buffer_set_u32(target, (uint8_t *)&algo_params.len, length);
402 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_SECTORS);
403 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
404
405 /* Set algorithm parameters */
406 retval = target_write_buffer(target, npcx_bank->params_addr,
407 sizeof(algo_params), (uint8_t *)&algo_params);
408 if (retval != ERROR_OK) {
409 (void)npcx_quit(bank);
410 return retval;
411 }
412
413 /* Issue flash helper algorithm parameters for erase */
414 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
415 retval = target_write_buffer(target, npcx_bank->params_addr,
416 sizeof(algo_params), (uint8_t *)&algo_params);
417
418 /* If no error, wait for erase to finish */
419 if (retval == ERROR_OK)
420 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
421
422 /* Regardless of errors, try to close down algo */
423 (void)npcx_quit(bank);
424
425 return retval;
426 }
427
428 static int npcx_write(struct flash_bank *bank, const uint8_t *buffer,
429 uint32_t offset, uint32_t count)
430 {
431 struct target *target = bank->target;
432 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
433 struct npcx_flash_params algo_params;
434
435 if (target->state != TARGET_HALTED) {
436 LOG_ERROR("Target not halted");
437 return ERROR_TARGET_NOT_HALTED;
438 }
439
440 /* Make sure we've probed the flash to get the device and size */
441 int retval = npcx_auto_probe(bank);
442 if (retval != ERROR_OK)
443 return retval;
444
445 retval = npcx_init(bank);
446 if (retval != ERROR_OK)
447 return retval;
448
449 /* Initialize algorithm parameters to default values */
450 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_PROGRAM);
451
452 uint32_t address = offset;
453
454 while (count > 0) {
455 uint32_t size = (count > NPCX_FLASH_LOADER_BUFFER_SIZE) ?
456 NPCX_FLASH_LOADER_BUFFER_SIZE : count;
457
458 /* Put the data into buffer */
459 retval = target_write_buffer(target, npcx_bank->buffer_addr,
460 size, buffer);
461 if (retval != ERROR_OK) {
462 LOG_ERROR("Unable to write data to target memory");
463 break;
464 }
465
466 /* Update algo parameters for flash write */
467 target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address);
468 target_buffer_set_u32(target, (uint8_t *)&algo_params.len, size);
469 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT);
470
471 /* Set algorithm parameters */
472 retval = target_write_buffer(target, npcx_bank->params_addr,
473 sizeof(algo_params), (uint8_t *)&algo_params);
474 if (retval != ERROR_OK)
475 break;
476
477 /* Issue flash helper algorithm parameters for flash write */
478 target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE);
479 retval = target_write_buffer(target, npcx_bank->params_addr,
480 sizeof(algo_params), (uint8_t *)&algo_params);
481 if (retval != ERROR_OK)
482 break;
483
484 /* Wait for flash write finish */
485 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
486 if (retval != ERROR_OK)
487 break;
488
489 count -= size;
490 buffer += size;
491 address += size;
492 }
493
494 /* Regardless of errors, try to close down algo */
495 (void)npcx_quit(bank);
496
497 return retval;
498 }
499
500 static int npcx_info(struct flash_bank *bank, struct command_invocation *cmd)
501 {
502 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
503
504 command_print_sameline(cmd, "%s flash: %s\n",
505 npcx_bank->family_name,
506 flash_info[npcx_bank->flash].name);
507
508 return ERROR_OK;
509 }
510
511 const struct flash_driver npcx_flash = {
512 .name = "npcx",
513 .flash_bank_command = npcx_flash_bank_command,
514 .erase = npcx_erase,
515 .write = npcx_write,
516 .read = default_flash_read,
517 .probe = npcx_probe,
518 .auto_probe = npcx_auto_probe,
519 .erase_check = default_flash_blank_check,
520 .info = npcx_info,
521 .free_driver_priv = default_flash_free_driver_priv,
522 };

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)