1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2020 by Nuvoton Technology Corporation
5 * Mulin Chao <mlchao@nuvoton.com>
6 * Wealian Liao <WHLIAO@nuvoton.com>
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"
19 /* NPCX flash loader */
20 static const uint8_t npcx_algo[] = {
21 #include "../../../contrib/loaders/flash/npcx/npcx_algo.inc"
24 #define NPCX_FLASH_TIMEOUT_MS 8000
25 #define NPCX_FLASH_BASE_ADDR 0x64000000
28 enum npcx_flash_device_index {
35 struct npcx_flash_bank {
36 const char *family_name;
37 uint32_t sector_length;
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;
44 uint32_t algo_working_size;
49 struct npcx_flash_info {
55 static const struct npcx_flash_info flash_info[] = {
56 [NPCX_FLASH_256KB] = {
57 .name = "256KB Flash",
61 [NPCX_FLASH_512KB] = {
62 .name = "512KB Flash",
71 [NPCX_FLASH_UNKNOWN] = {
72 .name = "Unknown Flash",
77 static int npcx_init(struct flash_bank *bank)
79 struct target *target = bank->target;
80 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
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;
86 int retval = target_alloc_working_area(target, npcx_bank->algo_working_size,
87 &npcx_bank->working_area);
88 if (retval != ERROR_OK)
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;
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;
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;
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;
129 * At this point, the algorithm is running on the target and
130 * ready to receive commands and data to flash the target
136 static int npcx_quit(struct flash_bank *bank)
138 struct target *target = bank->target;
139 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
141 /* Regardless of the algo's status, attempt to halt the target */
142 (void)target_halt(target);
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);
148 target_free_working_area(target, npcx_bank->working_area);
149 npcx_bank->working_area = NULL;
154 static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
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);
160 int64_t start_ms = timeval_ms();
163 int retval = target_read_u32(target, status_addr, &status);
164 if (retval != ERROR_OK)
169 int64_t elapsed_ms = timeval_ms() - start_ms;
170 if (elapsed_ms > NPCX_FLASH_TIMEOUT_MS)
172 } while (status == NPCX_FLASH_LOADER_EXECUTE);
174 if (status != NPCX_FLASH_LOADER_WAIT) {
175 LOG_ERROR("%s: Flash operation failed, status=0x%" PRIx32,
176 npcx_bank->family_name,
184 static enum npcx_flash_device_index npcx_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
186 struct target *target = bank->target;
187 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
188 struct npcx_flash_params algo_params;
190 if (target->state != TARGET_HALTED) {
191 LOG_ERROR("Target not halted");
192 return ERROR_TARGET_NOT_HALTED;
195 int retval = npcx_init(bank);
196 if (retval != ERROR_OK)
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);
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);
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);
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);
222 /* Regardless of errors, try to close down algo */
223 (void)npcx_quit(bank);
228 static int npcx_get_flash(uint32_t flash_id)
230 for (uint32_t i = 0; i < ARRAY_SIZE(flash_info) - 1; i++) {
231 if (flash_info[i].id == flash_id)
235 return NPCX_FLASH_UNKNOWN;
238 static int npcx_probe(struct flash_bank *bank)
240 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
241 uint32_t sector_length = NPCX_FLASH_ERASE_SIZE;
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;
253 int retval = npcx_get_flash_id(bank, &flash_id);
254 if (retval != ERROR_OK)
257 npcx_bank->flash = npcx_get_flash(flash_id);
259 unsigned int num_sectors = flash_info[npcx_bank->flash].size / sector_length;
261 bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
262 if (!bank->sectors) {
263 LOG_ERROR("Out of memory");
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;
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;
281 /* We've successfully determined the stats on the flash bank */
282 npcx_bank->probed = true;
284 /* If we fall through to here, then all went well */
288 static int npcx_auto_probe(struct flash_bank *bank)
290 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
291 int retval = ERROR_OK;
293 if (!npcx_bank->probed)
294 retval = npcx_probe(bank);
299 FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command)
301 struct npcx_flash_bank *npcx_bank;
304 return ERROR_COMMAND_SYNTAX_ERROR;
306 npcx_bank = calloc(1, sizeof(struct npcx_flash_bank));
308 LOG_ERROR("Out of memory");
312 /* Initialize private flash information */
313 npcx_bank->family_name = "npcx";
314 npcx_bank->sector_length = NPCX_FLASH_ERASE_SIZE;
316 /* Finish initialization of bank */
317 bank->driver_priv = npcx_bank;
323 static int npcx_chip_erase(struct flash_bank *bank)
325 struct target *target = bank->target;
326 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
327 struct npcx_flash_params algo_params;
329 if (target->state != TARGET_HALTED) {
330 LOG_ERROR("Target not halted");
331 return ERROR_TARGET_NOT_HALTED;
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)
339 retval = npcx_init(bank);
340 if (retval != ERROR_OK)
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);
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);
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);
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);
364 /* Regardless of errors, try to close down algo */
365 (void)npcx_quit(bank);
370 static int npcx_erase(struct flash_bank *bank, unsigned int first,
373 struct target *target = bank->target;
374 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
375 struct npcx_flash_params algo_params;
377 if (target->state != TARGET_HALTED) {
378 LOG_ERROR("Target not halted");
379 return ERROR_TARGET_NOT_HALTED;
382 if ((first == 0) && (last == (bank->num_sectors - 1))) {
383 /* Request chip erase */
384 return npcx_chip_erase(bank);
387 uint32_t address = first * npcx_bank->sector_length;
388 uint32_t length = (last - first + 1) * npcx_bank->sector_length;
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)
395 retval = npcx_init(bank);
396 if (retval != ERROR_OK)
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);
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);
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);
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);
422 /* Regardless of errors, try to close down algo */
423 (void)npcx_quit(bank);
428 static int npcx_write(struct flash_bank *bank, const uint8_t *buffer,
429 uint32_t offset, uint32_t count)
431 struct target *target = bank->target;
432 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
433 struct npcx_flash_params algo_params;
435 if (target->state != TARGET_HALTED) {
436 LOG_ERROR("Target not halted");
437 return ERROR_TARGET_NOT_HALTED;
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)
445 retval = npcx_init(bank);
446 if (retval != ERROR_OK)
449 /* Initialize algorithm parameters to default values */
450 target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_PROGRAM);
452 uint32_t address = offset;
455 uint32_t size = (count > NPCX_FLASH_LOADER_BUFFER_SIZE) ?
456 NPCX_FLASH_LOADER_BUFFER_SIZE : count;
458 /* Put the data into buffer */
459 retval = target_write_buffer(target, npcx_bank->buffer_addr,
461 if (retval != ERROR_OK) {
462 LOG_ERROR("Unable to write data to target memory");
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);
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)
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)
484 /* Wait for flash write finish */
485 retval = npcx_wait_algo_done(bank, npcx_bank->params_addr);
486 if (retval != ERROR_OK)
494 /* Regardless of errors, try to close down algo */
495 (void)npcx_quit(bank);
500 static int npcx_info(struct flash_bank *bank, struct command_invocation *cmd)
502 struct npcx_flash_bank *npcx_bank = bank->driver_priv;
504 command_print_sameline(cmd, "%s flash: %s\n",
505 npcx_bank->family_name,
506 flash_info[npcx_bank->flash].name);
511 const struct flash_driver npcx_flash = {
513 .flash_bank_command = npcx_flash_bank_command,
516 .read = default_flash_read,
518 .auto_probe = npcx_auto_probe,
519 .erase_check = default_flash_blank_check,
521 .free_driver_priv = default_flash_free_driver_priv,