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> *
8 * Partially based on drivers/mtd/nand_ids.c from Linux. *
9 ***************************************************************************/
18 static struct nand_ecclayout nand_oob_16
= {
20 .eccpos
= {0, 1, 2, 3, 6, 7},
27 static struct nand_ecclayout nand_oob_64
= {
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
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
);
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",
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) {
76 state
->eccpos
= nand_oob_16
.eccpos
;
77 } else if (nand
->page_size
== 2048) {
79 state
->eccpos
= nand_oob_64
.eccpos
;
81 state
->oob
= malloc(state
->oob_size
);
86 int nand_fileio_cleanup(struct nand_fileio_state
*state
)
88 if (state
->file_opened
)
89 fileio_close(state
->fileio
);
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 int 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
)
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
);
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 int 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
;
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
)
156 retval
= fileio_size(state
->fileio
, &filesize
);
157 if (retval
!= ERROR_OK
)
159 state
->size
= filesize
;
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;
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
) {
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
);
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
;