flash/nor: add support for Nuvoton NPCX series flash
[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 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 };