You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

251 lines
6.9 KiB

  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> *
  5. * *
  6. * Partially based on drivers/mtd/nand_ids.c from Linux. *
  7. * *
  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. *
  12. * *
  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. *
  17. * *
  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. ***************************************************************************/
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "core.h"
  27. #include "fileio.h"
  28. static struct nand_ecclayout nand_oob_16 = {
  29. .eccbytes = 6,
  30. .eccpos = {0, 1, 2, 3, 6, 7},
  31. .oobfree = {
  32. {.offset = 8,
  33. . length = 8}}
  34. };
  35. static struct nand_ecclayout nand_oob_64 = {
  36. .eccbytes = 24,
  37. .eccpos = {
  38. 40, 41, 42, 43, 44, 45, 46, 47,
  39. 48, 49, 50, 51, 52, 53, 54, 55,
  40. 56, 57, 58, 59, 60, 61, 62, 63},
  41. .oobfree = {
  42. {.offset = 2,
  43. .length = 38}}
  44. };
  45. void nand_fileio_init(struct nand_fileio_state *state)
  46. {
  47. memset(state, 0, sizeof(*state));
  48. state->oob_format = NAND_OOB_NONE;
  49. }
  50. int nand_fileio_start(struct command_context *cmd_ctx,
  51. struct nand_device *nand, const char *filename, int filemode,
  52. struct nand_fileio_state *state)
  53. {
  54. if (state->address % nand->page_size)
  55. {
  56. command_print(cmd_ctx, "only page-aligned addresses are supported");
  57. return ERROR_COMMAND_SYNTAX_ERROR;
  58. }
  59. duration_start(&state->bench);
  60. if (NULL != filename)
  61. {
  62. int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY);
  63. if (ERROR_OK != retval)
  64. {
  65. const char *msg = (FILEIO_READ == filemode) ? "read" : "write";
  66. command_print(cmd_ctx, "failed to open '%s' for %s access",
  67. filename, msg);
  68. return retval;
  69. }
  70. state->file_opened = true;
  71. }
  72. if (!(state->oob_format & NAND_OOB_ONLY))
  73. {
  74. state->page_size = nand->page_size;
  75. state->page = malloc(nand->page_size);
  76. }
  77. if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW))
  78. {
  79. if (nand->page_size == 512)
  80. {
  81. state->oob_size = 16;
  82. state->eccpos = nand_oob_16.eccpos;
  83. }
  84. else if (nand->page_size == 2048)
  85. {
  86. state->oob_size = 64;
  87. state->eccpos = nand_oob_64.eccpos;
  88. }
  89. state->oob = malloc(state->oob_size);
  90. }
  91. return ERROR_OK;
  92. }
  93. int nand_fileio_cleanup(struct nand_fileio_state *state)
  94. {
  95. if (state->file_opened)
  96. fileio_close(&state->fileio);
  97. if (state->oob)
  98. {
  99. free(state->oob);
  100. state->oob = NULL;
  101. }
  102. if (state->page)
  103. {
  104. free(state->page);
  105. state->page = NULL;
  106. }
  107. return ERROR_OK;
  108. }
  109. int nand_fileio_finish(struct nand_fileio_state *state)
  110. {
  111. nand_fileio_cleanup(state);
  112. return duration_measure(&state->bench);
  113. }
  114. COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
  115. struct nand_device **dev, enum fileio_access filemode,
  116. bool need_size, bool sw_ecc)
  117. {
  118. nand_fileio_init(state);
  119. unsigned minargs = need_size ? 4 : 3;
  120. if (CMD_ARGC < minargs)
  121. return ERROR_COMMAND_SYNTAX_ERROR;
  122. struct nand_device *nand;
  123. int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand);
  124. if (ERROR_OK != retval)
  125. return retval;
  126. if (NULL == nand->device)
  127. {
  128. command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
  129. return ERROR_OK;
  130. }
  131. COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address);
  132. if (need_size)
  133. {
  134. COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size);
  135. if (state->size % nand->page_size)
  136. {
  137. command_print(CMD_CTX, "only page-aligned sizes are supported");
  138. return ERROR_COMMAND_SYNTAX_ERROR;
  139. }
  140. }
  141. if (CMD_ARGC > minargs)
  142. {
  143. for (unsigned i = minargs; i < CMD_ARGC; i++)
  144. {
  145. if (!strcmp(CMD_ARGV[i], "oob_raw"))
  146. state->oob_format |= NAND_OOB_RAW;
  147. else if (!strcmp(CMD_ARGV[i], "oob_only"))
  148. state->oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
  149. else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc"))
  150. state->oob_format |= NAND_OOB_SW_ECC;
  151. else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw"))
  152. state->oob_format |= NAND_OOB_SW_ECC_KW;
  153. else
  154. {
  155. command_print(CMD_CTX, "unknown option: %s", CMD_ARGV[i]);
  156. return ERROR_COMMAND_SYNTAX_ERROR;
  157. }
  158. }
  159. }
  160. retval = nand_fileio_start(CMD_CTX, nand, CMD_ARGV[1], filemode, state);
  161. if (ERROR_OK != retval)
  162. return retval;
  163. if (!need_size)
  164. {
  165. int filesize;
  166. retval = fileio_size(&state->fileio, &filesize);
  167. if (retval != ERROR_OK)
  168. return retval;
  169. state->size = filesize;
  170. }
  171. *dev = nand;
  172. return ERROR_OK;
  173. }
  174. /**
  175. * @returns If no error occurred, returns number of bytes consumed;
  176. * otherwise, returns a negative error code.)
  177. */
  178. int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
  179. {
  180. size_t total_read = 0;
  181. size_t one_read;
  182. if (NULL != s->page)
  183. {
  184. fileio_read(&s->fileio, s->page_size, s->page, &one_read);
  185. if (one_read < s->page_size)
  186. memset(s->page + one_read, 0xff, s->page_size - one_read);
  187. total_read += one_read;
  188. }
  189. if (s->oob_format & NAND_OOB_SW_ECC)
  190. {
  191. uint8_t ecc[3];
  192. memset(s->oob, 0xff, s->oob_size);
  193. for (uint32_t i = 0, j = 0; i < s->page_size; i += 256)
  194. {
  195. nand_calculate_ecc(nand, s->page + i, ecc);
  196. s->oob[s->eccpos[j++]] = ecc[0];
  197. s->oob[s->eccpos[j++]] = ecc[1];
  198. s->oob[s->eccpos[j++]] = ecc[2];
  199. }
  200. }
  201. else if (s->oob_format & NAND_OOB_SW_ECC_KW)
  202. {
  203. /*
  204. * In this case eccpos is not used as
  205. * the ECC data is always stored contigously
  206. * at the end of the OOB area. It consists
  207. * of 10 bytes per 512-byte data block.
  208. */
  209. uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10;
  210. memset(s->oob, 0xff, s->oob_size);
  211. for (uint32_t i = 0; i < s->page_size; i += 512)
  212. {
  213. nand_calculate_ecc_kw(nand, s->page + i, ecc);
  214. ecc += 10;
  215. }
  216. }
  217. else if (NULL != s->oob)
  218. {
  219. fileio_read(&s->fileio, s->oob_size, s->oob, &one_read);
  220. if (one_read < s->oob_size)
  221. memset(s->oob + one_read, 0xff, s->oob_size - one_read);
  222. total_read += one_read;
  223. }
  224. return total_read;
  225. }