ec999e24a30ad48ba14519391f875f80a14b4fb7
[fw/openocd] / 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 };