cfi_mtd.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * (C) Copyright 2008 Semihalf
  3. *
  4. * Written by: Piotr Ziecik <kosmo@semihalf.com>
  5. *
  6. * See file CREDITS for list of people who contributed to this
  7. * project.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of
  12. * the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22. * MA 02111-1307 USA
  23. *
  24. */
  25. #include <common.h>
  26. #include <flash.h>
  27. #include <malloc.h>
  28. #include <asm/errno.h>
  29. #include <linux/mtd/mtd.h>
  30. #include <linux/mtd/concat.h>
  31. #include <mtd/cfi_flash.h>
  32. static struct mtd_info cfi_mtd_info[CFI_MAX_FLASH_BANKS];
  33. static char cfi_mtd_names[CFI_MAX_FLASH_BANKS][16];
  34. #ifdef CONFIG_MTD_CONCAT
  35. static char c_mtd_name[16];
  36. #endif
  37. static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
  38. {
  39. flash_info_t *fi = mtd->priv;
  40. size_t a_start = fi->start[0] + instr->addr;
  41. size_t a_end = a_start + instr->len;
  42. int s_first = -1;
  43. int s_last = -1;
  44. int error, sect;
  45. for (sect = 0; sect < fi->sector_count; sect++) {
  46. if (a_start == fi->start[sect])
  47. s_first = sect;
  48. if (sect < fi->sector_count - 1) {
  49. if (a_end == fi->start[sect + 1]) {
  50. s_last = sect;
  51. break;
  52. }
  53. } else {
  54. s_last = sect;
  55. break;
  56. }
  57. }
  58. if (s_first >= 0 && s_first <= s_last) {
  59. instr->state = MTD_ERASING;
  60. flash_set_verbose(0);
  61. error = flash_erase(fi, s_first, s_last);
  62. flash_set_verbose(1);
  63. if (error) {
  64. instr->state = MTD_ERASE_FAILED;
  65. return -EIO;
  66. }
  67. instr->state = MTD_ERASE_DONE;
  68. mtd_erase_callback(instr);
  69. return 0;
  70. }
  71. return -EINVAL;
  72. }
  73. static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
  74. size_t *retlen, u_char *buf)
  75. {
  76. flash_info_t *fi = mtd->priv;
  77. u_char *f = (u_char*)(fi->start[0]) + from;
  78. memcpy(buf, f, len);
  79. *retlen = len;
  80. return 0;
  81. }
  82. static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
  83. size_t *retlen, const u_char *buf)
  84. {
  85. flash_info_t *fi = mtd->priv;
  86. u_long t = fi->start[0] + to;
  87. int error;
  88. flash_set_verbose(0);
  89. error = write_buff(fi, (u_char*)buf, t, len);
  90. flash_set_verbose(1);
  91. if (!error) {
  92. *retlen = len;
  93. return 0;
  94. }
  95. return -EIO;
  96. }
  97. static void cfi_mtd_sync(struct mtd_info *mtd)
  98. {
  99. /*
  100. * This function should wait until all pending operations
  101. * finish. However this driver is fully synchronous, so
  102. * this function returns immediately
  103. */
  104. }
  105. static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
  106. {
  107. flash_info_t *fi = mtd->priv;
  108. flash_set_verbose(0);
  109. flash_protect(FLAG_PROTECT_SET, fi->start[0] + ofs,
  110. fi->start[0] + ofs + len - 1, fi);
  111. flash_set_verbose(1);
  112. return 0;
  113. }
  114. static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
  115. {
  116. flash_info_t *fi = mtd->priv;
  117. flash_set_verbose(0);
  118. flash_protect(FLAG_PROTECT_CLEAR, fi->start[0] + ofs,
  119. fi->start[0] + ofs + len - 1, fi);
  120. flash_set_verbose(1);
  121. return 0;
  122. }
  123. static int cfi_mtd_set_erasesize(struct mtd_info *mtd, flash_info_t *fi)
  124. {
  125. int sect_size = 0;
  126. int sect_size_old = 0;
  127. int sect;
  128. int regions = 0;
  129. int numblocks = 0;
  130. ulong offset;
  131. ulong base_addr;
  132. /*
  133. * First detect the number of eraseregions so that we can allocate
  134. * the array of eraseregions correctly
  135. */
  136. for (sect = 0; sect < fi->sector_count; sect++) {
  137. if (sect_size_old != flash_sector_size(fi, sect))
  138. regions++;
  139. sect_size_old = flash_sector_size(fi, sect);
  140. }
  141. switch (regions) {
  142. case 0:
  143. return 1;
  144. case 1: /* flash has uniform erase size */
  145. mtd->numeraseregions = 0;
  146. mtd->erasesize = sect_size_old;
  147. return 0;
  148. }
  149. mtd->numeraseregions = regions;
  150. mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info) * regions);
  151. /*
  152. * Now detect the largest sector and fill the eraseregions
  153. */
  154. regions = 0;
  155. base_addr = offset = fi->start[0];
  156. sect_size_old = flash_sector_size(fi, 0);
  157. for (sect = 0; sect < fi->sector_count; sect++) {
  158. if (sect_size_old != flash_sector_size(fi, sect)) {
  159. mtd->eraseregions[regions].offset = offset - base_addr;
  160. mtd->eraseregions[regions].erasesize = sect_size_old;
  161. mtd->eraseregions[regions].numblocks = numblocks;
  162. /* Now start counting the next eraseregions */
  163. numblocks = 0;
  164. regions++;
  165. offset = fi->start[sect];
  166. }
  167. numblocks++;
  168. /*
  169. * Select the largest sector size as erasesize (e.g. for UBI)
  170. */
  171. if (flash_sector_size(fi, sect) > sect_size)
  172. sect_size = flash_sector_size(fi, sect);
  173. sect_size_old = flash_sector_size(fi, sect);
  174. }
  175. /*
  176. * Set the last region
  177. */
  178. mtd->eraseregions[regions].offset = offset - base_addr;
  179. mtd->eraseregions[regions].erasesize = sect_size_old;
  180. mtd->eraseregions[regions].numblocks = numblocks;
  181. mtd->erasesize = sect_size;
  182. return 0;
  183. }
  184. int cfi_mtd_init(void)
  185. {
  186. struct mtd_info *mtd;
  187. flash_info_t *fi;
  188. int error, i;
  189. int devices_found = 0;
  190. struct mtd_info *mtd_list[CONFIG_SYS_MAX_FLASH_BANKS];
  191. for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
  192. fi = &flash_info[i];
  193. mtd = &cfi_mtd_info[i];
  194. memset(mtd, 0, sizeof(struct mtd_info));
  195. error = cfi_mtd_set_erasesize(mtd, fi);
  196. if (error)
  197. continue;
  198. sprintf(cfi_mtd_names[i], "nor%d", i);
  199. mtd->name = cfi_mtd_names[i];
  200. mtd->type = MTD_NORFLASH;
  201. mtd->flags = MTD_CAP_NORFLASH;
  202. mtd->size = fi->size;
  203. mtd->writesize = 1;
  204. mtd->erase = cfi_mtd_erase;
  205. mtd->read = cfi_mtd_read;
  206. mtd->write = cfi_mtd_write;
  207. mtd->sync = cfi_mtd_sync;
  208. mtd->lock = cfi_mtd_lock;
  209. mtd->unlock = cfi_mtd_unlock;
  210. mtd->priv = fi;
  211. if (add_mtd_device(mtd))
  212. return -ENOMEM;
  213. mtd_list[devices_found++] = mtd;
  214. }
  215. #ifdef CONFIG_MTD_CONCAT
  216. if (devices_found > 1) {
  217. /*
  218. * We detected multiple devices. Concatenate them together.
  219. */
  220. sprintf(c_mtd_name, "nor%d", devices_found);
  221. mtd = mtd_concat_create(mtd_list, devices_found, c_mtd_name);
  222. if (mtd == NULL)
  223. return -ENXIO;
  224. if (add_mtd_device(mtd))
  225. return -ENOMEM;
  226. }
  227. #endif /* CONFIG_MTD_CONCAT */
  228. return 0;
  229. }