dfu_nand.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * dfu_nand.c -- DFU for NAND routines.
  3. *
  4. * Copyright (C) 2012-2013 Texas Instruments, Inc.
  5. *
  6. * Based on dfu_mmc.c which is:
  7. * Copyright (C) 2012 Samsung Electronics
  8. * author: Lukasz Majewski <l.majewski@samsung.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. #include <common.h>
  25. #include <malloc.h>
  26. #include <errno.h>
  27. #include <div64.h>
  28. #include <dfu.h>
  29. #include <linux/mtd/mtd.h>
  30. #include <jffs2/load_kernel.h>
  31. #include <nand.h>
  32. enum dfu_nand_op {
  33. DFU_OP_READ = 1,
  34. DFU_OP_WRITE,
  35. };
  36. static int nand_block_op(enum dfu_nand_op op, struct dfu_entity *dfu,
  37. u64 offset, void *buf, long *len)
  38. {
  39. loff_t start, lim;
  40. size_t count, actual;
  41. int ret;
  42. nand_info_t *nand;
  43. /* if buf == NULL return total size of the area */
  44. if (buf == NULL) {
  45. *len = dfu->data.nand.size;
  46. return 0;
  47. }
  48. start = dfu->data.nand.start + offset + dfu->bad_skip;
  49. lim = dfu->data.nand.start + dfu->data.nand.size - start;
  50. count = *len;
  51. if (nand_curr_device < 0 ||
  52. nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
  53. !nand_info[nand_curr_device].name) {
  54. printf("%s: invalid nand device\n", __func__);
  55. return -1;
  56. }
  57. nand = &nand_info[nand_curr_device];
  58. if (op == DFU_OP_READ) {
  59. ret = nand_read_skip_bad(nand, start, &count, &actual,
  60. lim, buf);
  61. } else {
  62. nand_erase_options_t opts;
  63. memset(&opts, 0, sizeof(opts));
  64. opts.offset = start;
  65. opts.length = count;
  66. opts.spread = 1;
  67. opts.quiet = 1;
  68. opts.lim = lim;
  69. /* first erase */
  70. ret = nand_erase_opts(nand, &opts);
  71. if (ret)
  72. return ret;
  73. /* then write */
  74. ret = nand_write_skip_bad(nand, start, &count, &actual,
  75. lim, buf, 0);
  76. }
  77. if (ret != 0) {
  78. printf("%s: nand_%s_skip_bad call failed at %llx!\n",
  79. __func__, op == DFU_OP_READ ? "read" : "write",
  80. start);
  81. return ret;
  82. }
  83. /*
  84. * Find out where we stopped writing data. This can be deeper into
  85. * the NAND than we expected due to having to skip bad blocks. So
  86. * we must take this into account for the next write, if any.
  87. */
  88. if (actual > count)
  89. dfu->bad_skip += actual - count;
  90. return ret;
  91. }
  92. static inline int nand_block_write(struct dfu_entity *dfu,
  93. u64 offset, void *buf, long *len)
  94. {
  95. return nand_block_op(DFU_OP_WRITE, dfu, offset, buf, len);
  96. }
  97. static inline int nand_block_read(struct dfu_entity *dfu,
  98. u64 offset, void *buf, long *len)
  99. {
  100. return nand_block_op(DFU_OP_READ, dfu, offset, buf, len);
  101. }
  102. static int dfu_write_medium_nand(struct dfu_entity *dfu,
  103. u64 offset, void *buf, long *len)
  104. {
  105. int ret = -1;
  106. switch (dfu->layout) {
  107. case DFU_RAW_ADDR:
  108. ret = nand_block_write(dfu, offset, buf, len);
  109. break;
  110. default:
  111. printf("%s: Layout (%s) not (yet) supported!\n", __func__,
  112. dfu_get_layout(dfu->layout));
  113. }
  114. return ret;
  115. }
  116. static int dfu_read_medium_nand(struct dfu_entity *dfu, u64 offset, void *buf,
  117. long *len)
  118. {
  119. int ret = -1;
  120. switch (dfu->layout) {
  121. case DFU_RAW_ADDR:
  122. ret = nand_block_read(dfu, offset, buf, len);
  123. break;
  124. default:
  125. printf("%s: Layout (%s) not (yet) supported!\n", __func__,
  126. dfu_get_layout(dfu->layout));
  127. }
  128. return ret;
  129. }
  130. int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
  131. {
  132. char *st;
  133. int ret, dev, part;
  134. dfu->dev_type = DFU_DEV_NAND;
  135. st = strsep(&s, " ");
  136. if (!strcmp(st, "raw")) {
  137. dfu->layout = DFU_RAW_ADDR;
  138. dfu->data.nand.start = simple_strtoul(s, &s, 16);
  139. s++;
  140. dfu->data.nand.size = simple_strtoul(s, &s, 16);
  141. } else if (!strcmp(st, "part")) {
  142. char mtd_id[32];
  143. struct mtd_device *mtd_dev;
  144. u8 part_num;
  145. struct part_info *pi;
  146. dfu->layout = DFU_RAW_ADDR;
  147. dev = simple_strtoul(s, &s, 10);
  148. s++;
  149. part = simple_strtoul(s, &s, 10);
  150. sprintf(mtd_id, "%s%d,%d", "nand", dev, part - 1);
  151. printf("using id '%s'\n", mtd_id);
  152. mtdparts_init();
  153. ret = find_dev_and_part(mtd_id, &mtd_dev, &part_num, &pi);
  154. if (ret != 0) {
  155. printf("Could not locate '%s'\n", mtd_id);
  156. return -1;
  157. }
  158. dfu->data.nand.start = pi->offset;
  159. dfu->data.nand.size = pi->size;
  160. } else {
  161. printf("%s: Memory layout (%s) not supported!\n", __func__, st);
  162. return -1;
  163. }
  164. dfu->read_medium = dfu_read_medium_nand;
  165. dfu->write_medium = dfu_write_medium_nand;
  166. /* initial state */
  167. dfu->inited = 0;
  168. return 0;
  169. }