openocd: src/flash: replace the GPL-2.0-or-later license tag
[openocd.git] / src / flash / nand / fileio.c
blob2bfbd698304ceda6d3ec09a52744f7a3fa7240b4
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
5 * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
6 * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
7 * *
8 * Partially based on drivers/mtd/nand_ids.c from Linux. *
9 ***************************************************************************/
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
15 #include "core.h"
16 #include "fileio.h"
18 static struct nand_ecclayout nand_oob_16 = {
19 .eccbytes = 6,
20 .eccpos = {0, 1, 2, 3, 6, 7},
21 .oobfree = {
22 {.offset = 8,
23 .length = 8}
27 static struct nand_ecclayout nand_oob_64 = {
28 .eccbytes = 24,
29 .eccpos = {
30 40, 41, 42, 43, 44, 45, 46, 47,
31 48, 49, 50, 51, 52, 53, 54, 55,
32 56, 57, 58, 59, 60, 61, 62, 63
34 .oobfree = {
35 {.offset = 2,
36 .length = 38}
40 void nand_fileio_init(struct nand_fileio_state *state)
42 memset(state, 0, sizeof(*state));
43 state->oob_format = NAND_OOB_NONE;
46 int nand_fileio_start(struct command_invocation *cmd,
47 struct nand_device *nand, const char *filename, int filemode,
48 struct nand_fileio_state *state)
50 if (state->address % nand->page_size) {
51 command_print(cmd, "only page-aligned addresses are supported");
52 return ERROR_COMMAND_SYNTAX_ERROR;
55 duration_start(&state->bench);
57 if (filename) {
58 int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY);
59 if (retval != ERROR_OK) {
60 const char *msg = (filemode == FILEIO_READ) ? "read" : "write";
61 command_print(cmd, "failed to open '%s' for %s access",
62 filename, msg);
63 return retval;
65 state->file_opened = true;
68 if (!(state->oob_format & NAND_OOB_ONLY)) {
69 state->page_size = nand->page_size;
70 state->page = malloc(nand->page_size);
73 if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW)) {
74 if (nand->page_size == 512) {
75 state->oob_size = 16;
76 state->eccpos = nand_oob_16.eccpos;
77 } else if (nand->page_size == 2048) {
78 state->oob_size = 64;
79 state->eccpos = nand_oob_64.eccpos;
81 state->oob = malloc(state->oob_size);
84 return ERROR_OK;
86 int nand_fileio_cleanup(struct nand_fileio_state *state)
88 if (state->file_opened)
89 fileio_close(state->fileio);
91 free(state->oob);
92 state->oob = NULL;
94 free(state->page);
95 state->page = NULL;
96 return ERROR_OK;
98 int nand_fileio_finish(struct nand_fileio_state *state)
100 nand_fileio_cleanup(state);
101 return duration_measure(&state->bench);
104 COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
105 struct nand_device **dev, enum fileio_access filemode,
106 bool need_size, bool sw_ecc)
108 nand_fileio_init(state);
110 unsigned minargs = need_size ? 4 : 3;
111 if (minargs > CMD_ARGC)
112 return ERROR_COMMAND_SYNTAX_ERROR;
114 struct nand_device *nand;
115 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand);
116 if (retval != ERROR_OK)
117 return retval;
119 if (!nand->device) {
120 command_print(CMD, "#%s: not probed", CMD_ARGV[0]);
121 return ERROR_NAND_DEVICE_NOT_PROBED;
124 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address);
125 if (need_size) {
126 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size);
127 if (state->size % nand->page_size) {
128 command_print(CMD, "only page-aligned sizes are supported");
129 return ERROR_COMMAND_SYNTAX_ERROR;
133 if (minargs < CMD_ARGC) {
134 for (unsigned i = minargs; i < CMD_ARGC; i++) {
135 if (!strcmp(CMD_ARGV[i], "oob_raw"))
136 state->oob_format |= NAND_OOB_RAW;
137 else if (!strcmp(CMD_ARGV[i], "oob_only"))
138 state->oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
139 else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc"))
140 state->oob_format |= NAND_OOB_SW_ECC;
141 else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw"))
142 state->oob_format |= NAND_OOB_SW_ECC_KW;
143 else {
144 command_print(CMD, "unknown option: %s", CMD_ARGV[i]);
145 return ERROR_COMMAND_SYNTAX_ERROR;
150 retval = nand_fileio_start(CMD, nand, CMD_ARGV[1], filemode, state);
151 if (retval != ERROR_OK)
152 return retval;
154 if (!need_size) {
155 size_t filesize;
156 retval = fileio_size(state->fileio, &filesize);
157 if (retval != ERROR_OK)
158 return retval;
159 state->size = filesize;
162 *dev = nand;
164 return ERROR_OK;
168 * @returns If no error occurred, returns number of bytes consumed;
169 * otherwise, returns a negative error code.)
171 int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
173 size_t total_read = 0;
174 size_t one_read;
176 if (s->page) {
177 fileio_read(s->fileio, s->page_size, s->page, &one_read);
178 if (one_read < s->page_size)
179 memset(s->page + one_read, 0xff, s->page_size - one_read);
180 total_read += one_read;
183 if (s->oob_format & NAND_OOB_SW_ECC) {
184 uint8_t ecc[3];
185 memset(s->oob, 0xff, s->oob_size);
186 for (uint32_t i = 0, j = 0; i < s->page_size; i += 256) {
187 nand_calculate_ecc(nand, s->page + i, ecc);
188 s->oob[s->eccpos[j++]] = ecc[0];
189 s->oob[s->eccpos[j++]] = ecc[1];
190 s->oob[s->eccpos[j++]] = ecc[2];
192 } else if (s->oob_format & NAND_OOB_SW_ECC_KW) {
194 * In this case eccpos is not used as
195 * the ECC data is always stored contiguously
196 * at the end of the OOB area. It consists
197 * of 10 bytes per 512-byte data block.
199 uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10;
200 memset(s->oob, 0xff, s->oob_size);
201 for (uint32_t i = 0; i < s->page_size; i += 512) {
202 nand_calculate_ecc_kw(nand, s->page + i, ecc);
203 ecc += 10;
205 } else if (s->oob) {
206 fileio_read(s->fileio, s->oob_size, s->oob, &one_read);
207 if (one_read < s->oob_size)
208 memset(s->oob + one_read, 0xff, s->oob_size - one_read);
209 total_read += one_read;
211 return total_read;