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

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)