1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
4 * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
6 * Partially based on drivers/mtd/nand_ids.c from Linux. *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
31 static struct nand_ecclayout nand_oob_16
= {
33 .eccpos
= {0, 1, 2, 3, 6, 7},
40 static struct nand_ecclayout nand_oob_64
= {
43 40, 41, 42, 43, 44, 45, 46, 47,
44 48, 49, 50, 51, 52, 53, 54, 55,
45 56, 57, 58, 59, 60, 61, 62, 63
53 void nand_fileio_init(struct nand_fileio_state
*state
)
55 memset(state
, 0, sizeof(*state
));
56 state
->oob_format
= NAND_OOB_NONE
;
59 int nand_fileio_start(struct command_context
*cmd_ctx
,
60 struct nand_device
*nand
, const char *filename
, int filemode
,
61 struct nand_fileio_state
*state
)
63 if (state
->address
% nand
->page_size
) {
64 command_print(cmd_ctx
, "only page-aligned addresses are supported");
65 return ERROR_COMMAND_SYNTAX_ERROR
;
68 duration_start(&state
->bench
);
70 if (NULL
!= filename
) {
71 int retval
= fileio_open(&state
->fileio
, filename
, filemode
, FILEIO_BINARY
);
72 if (ERROR_OK
!= retval
) {
73 const char *msg
= (FILEIO_READ
== filemode
) ? "read" : "write";
74 command_print(cmd_ctx
, "failed to open '%s' for %s access",
78 state
->file_opened
= true;
81 if (!(state
->oob_format
& NAND_OOB_ONLY
)) {
82 state
->page_size
= nand
->page_size
;
83 state
->page
= malloc(nand
->page_size
);
86 if (state
->oob_format
& (NAND_OOB_RAW
| NAND_OOB_SW_ECC
| NAND_OOB_SW_ECC_KW
)) {
87 if (nand
->page_size
== 512) {
89 state
->eccpos
= nand_oob_16
.eccpos
;
90 } else if (nand
->page_size
== 2048) {
92 state
->eccpos
= nand_oob_64
.eccpos
;
94 state
->oob
= malloc(state
->oob_size
);
99 int nand_fileio_cleanup(struct nand_fileio_state
*state
)
101 if (state
->file_opened
)
102 fileio_close(&state
->fileio
);
114 int nand_fileio_finish(struct nand_fileio_state
*state
)
116 nand_fileio_cleanup(state
);
117 return duration_measure(&state
->bench
);
120 COMMAND_HELPER(nand_fileio_parse_args
, struct nand_fileio_state
*state
,
121 struct nand_device
**dev
, enum fileio_access filemode
,
122 bool need_size
, bool sw_ecc
)
124 nand_fileio_init(state
);
126 unsigned minargs
= need_size
? 4 : 3;
127 if (CMD_ARGC
< minargs
)
128 return ERROR_COMMAND_SYNTAX_ERROR
;
130 struct nand_device
*nand
;
131 int retval
= CALL_COMMAND_HANDLER(nand_command_get_device
, 0, &nand
);
132 if (ERROR_OK
!= retval
)
135 if (NULL
== nand
->device
) {
136 command_print(CMD_CTX
, "#%s: not probed", CMD_ARGV
[0]);
140 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[2], state
->address
);
142 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[3], state
->size
);
143 if (state
->size
% nand
->page_size
) {
144 command_print(CMD_CTX
, "only page-aligned sizes are supported");
145 return ERROR_COMMAND_SYNTAX_ERROR
;
149 if (CMD_ARGC
> minargs
) {
150 for (unsigned i
= minargs
; i
< CMD_ARGC
; i
++) {
151 if (!strcmp(CMD_ARGV
[i
], "oob_raw"))
152 state
->oob_format
|= NAND_OOB_RAW
;
153 else if (!strcmp(CMD_ARGV
[i
], "oob_only"))
154 state
->oob_format
|= NAND_OOB_RAW
| NAND_OOB_ONLY
;
155 else if (sw_ecc
&& !strcmp(CMD_ARGV
[i
], "oob_softecc"))
156 state
->oob_format
|= NAND_OOB_SW_ECC
;
157 else if (sw_ecc
&& !strcmp(CMD_ARGV
[i
], "oob_softecc_kw"))
158 state
->oob_format
|= NAND_OOB_SW_ECC_KW
;
160 command_print(CMD_CTX
, "unknown option: %s", CMD_ARGV
[i
]);
161 return ERROR_COMMAND_SYNTAX_ERROR
;
166 retval
= nand_fileio_start(CMD_CTX
, nand
, CMD_ARGV
[1], filemode
, state
);
167 if (ERROR_OK
!= retval
)
172 retval
= fileio_size(&state
->fileio
, &filesize
);
173 if (retval
!= ERROR_OK
)
175 state
->size
= filesize
;
184 * @returns If no error occurred, returns number of bytes consumed;
185 * otherwise, returns a negative error code.)
187 int nand_fileio_read(struct nand_device
*nand
, struct nand_fileio_state
*s
)
189 size_t total_read
= 0;
192 if (NULL
!= s
->page
) {
193 fileio_read(&s
->fileio
, s
->page_size
, s
->page
, &one_read
);
194 if (one_read
< s
->page_size
)
195 memset(s
->page
+ one_read
, 0xff, s
->page_size
- one_read
);
196 total_read
+= one_read
;
199 if (s
->oob_format
& NAND_OOB_SW_ECC
) {
201 memset(s
->oob
, 0xff, s
->oob_size
);
202 for (uint32_t i
= 0, j
= 0; i
< s
->page_size
; i
+= 256) {
203 nand_calculate_ecc(nand
, s
->page
+ i
, ecc
);
204 s
->oob
[s
->eccpos
[j
++]] = ecc
[0];
205 s
->oob
[s
->eccpos
[j
++]] = ecc
[1];
206 s
->oob
[s
->eccpos
[j
++]] = ecc
[2];
208 } else if (s
->oob_format
& NAND_OOB_SW_ECC_KW
) {
210 * In this case eccpos is not used as
211 * the ECC data is always stored contigously
212 * at the end of the OOB area. It consists
213 * of 10 bytes per 512-byte data block.
215 uint8_t *ecc
= s
->oob
+ s
->oob_size
- s
->page_size
/ 512 * 10;
216 memset(s
->oob
, 0xff, s
->oob_size
);
217 for (uint32_t i
= 0; i
< s
->page_size
; i
+= 512) {
218 nand_calculate_ecc_kw(nand
, s
->page
+ i
, ecc
);
221 } else if (NULL
!= s
->oob
) {
222 fileio_read(&s
->fileio
, s
->oob_size
, s
->oob
, &one_read
);
223 if (one_read
< s
->oob_size
)
224 memset(s
->oob
+ one_read
, 0xff, s
->oob_size
- one_read
);
225 total_read
+= one_read
;