OpenOCD
flash/nand/fileio.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
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  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include "core.h"
16 #include "fileio.h"
17 
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}
24  }
25 };
26 
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
33  },
34  .oobfree = {
35  {.offset = 2,
36  .length = 38}
37  }
38 };
39 
41 {
42  memset(state, 0, sizeof(*state));
43  state->oob_format = NAND_OOB_NONE;
44 }
45 
47  struct nand_device *nand, const char *filename, int filemode,
48  struct nand_fileio_state *state)
49 {
50  if (state->address % nand->page_size) {
51  command_print(cmd, "only page-aligned addresses are supported");
53  }
54 
55  duration_start(&state->bench);
56 
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;
64  }
65  state->file_opened = true;
66  }
67 
68  if (!(state->oob_format & NAND_OOB_ONLY)) {
69  state->page_size = nand->page_size;
70  state->page = malloc(nand->page_size);
71  }
72 
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;
80  }
81  state->oob = malloc(state->oob_size);
82  }
83 
84  return ERROR_OK;
85 }
87 {
88  if (state->file_opened)
89  fileio_close(state->fileio);
90 
91  free(state->oob);
92  state->oob = NULL;
93 
94  free(state->page);
95  state->page = NULL;
96  return ERROR_OK;
97 }
99 {
101  return duration_measure(&state->bench);
102 }
103 
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)
107 {
109 
110  unsigned int minargs = need_size ? 4 : 3;
111  if (minargs > CMD_ARGC)
113 
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;
118 
119  if (!nand->device) {
120  command_print(CMD, "#%s: not probed", CMD_ARGV[0]);
122  }
123 
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");
130  }
131  }
132 
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;
143  else {
144  command_print(CMD, "unknown option: %s", CMD_ARGV[i]);
146  }
147  }
148  }
149 
150  retval = nand_fileio_start(CMD, nand, CMD_ARGV[1], filemode, state);
151  if (retval != ERROR_OK)
152  return retval;
153 
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;
160  }
161 
162  *dev = nand;
163 
164  return ERROR_OK;
165 }
166 
171 int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
172 {
173  size_t total_read = 0;
174  size_t one_read;
175 
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;
181  }
182 
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];
191  }
192  } else if (s->oob_format & NAND_OOB_SW_ECC_KW) {
193  /*
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.
198  */
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;
204  }
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;
210  }
211  return total_read;
212 }
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:443
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:141
#define CALL_COMMAND_HANDLER(name, extra ...)
Use this to macro to call a command helper (or a nested handler).
Definition: command.h:118
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define COMMAND_PARSE_NUMBER(type, in, out)
parses the string in into out as a type, or prints a command error and passes the error code to the c...
Definition: command.h:442
ecc
Definition: davinci.c:22
int nand_fileio_cleanup(struct nand_fileio_state *state)
int nand_fileio_start(struct command_invocation *cmd, struct nand_device *nand, const char *filename, int filemode, struct nand_fileio_state *state)
void nand_fileio_init(struct nand_fileio_state *state)
static struct nand_ecclayout nand_oob_16
static struct nand_ecclayout nand_oob_64
int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
int nand_fileio_finish(struct nand_fileio_state *state)
COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, struct nand_device **dev, enum fileio_access filemode, bool need_size, bool sw_ecc)
int fileio_read(struct fileio *fileio, size_t size, void *buffer, size_t *size_read)
int fileio_close(struct fileio *fileio)
int fileio_size(struct fileio *fileio, size_t *size)
FIX!!!!
int fileio_open(struct fileio **fileio, const char *url, enum fileio_access access_type, enum fileio_type type)
fileio_access
Definition: helper/fileio.h:26
@ FILEIO_READ
Definition: helper/fileio.h:28
@ FILEIO_BINARY
Definition: helper/fileio.h:23
#define ERROR_OK
Definition: log.h:164
int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code)
Definition: ecc_kw.c:93
#define ERROR_NAND_DEVICE_NOT_PROBED
Definition: nand/core.h:220
int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code)
Definition: ecc.c:48
@ NAND_OOB_NONE
Definition: nand/core.h:171
@ NAND_OOB_SW_ECC_KW
Definition: nand/core.h:177
@ NAND_OOB_ONLY
Definition: nand/core.h:174
@ NAND_OOB_SW_ECC
Definition: nand/core.h:175
@ NAND_OOB_RAW
Definition: nand/core.h:172
Upper level NOR flash interfaces.
When run_command is called, a new instance will be created on the stack, filled with the proper value...
Definition: command.h:76
int page_size
Definition: nand/core.h:56
struct nand_info * device
Definition: nand/core.h:53
int eccpos[64]
Definition: nand/core.h:42
enum oob_formats oob_format
struct fileio * fileio
int duration_measure(struct duration *duration)
Update the duration->elapsed field to finish the duration measurement.
Definition: time_support.c:74
int duration_start(struct duration *duration)
Update the duration->start field to start the duration measurement.
Definition: time_support.c:69
#define NULL
Definition: usb.h:16
uint8_t cmd
Definition: vdebug.c:1
uint8_t state[4]
Definition: vdebug.c:21