cmd_flash.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. * (C) Copyright 2000
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (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 Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. /*
  24. * FLASH support
  25. */
  26. #include <common.h>
  27. #include <command.h>
  28. #include <cmd_boot.h>
  29. #include <flash.h>
  30. #ifdef CONFIG_HAS_DATAFLASH
  31. #include <dataflash.h>
  32. #endif
  33. #if (CONFIG_COMMANDS & CFG_CMD_FLASH)
  34. extern flash_info_t flash_info[]; /* info for FLASH chips */
  35. /*
  36. * The user interface starts numbering for Flash banks with 1
  37. * for historical reasons.
  38. */
  39. /*
  40. * this routine looks for an abbreviated flash range specification.
  41. * the syntax is B:SF[-SL], where B is the bank number, SF is the first
  42. * sector to erase, and SL is the last sector to erase (defaults to SF).
  43. * bank numbers start at 1 to be consistent with other specs, sector numbers
  44. * start at zero.
  45. *
  46. * returns: 1 - correct spec; *pinfo, *psf and *psl are
  47. * set appropriately
  48. * 0 - doesn't look like an abbreviated spec
  49. * -1 - looks like an abbreviated spec, but got
  50. * a parsing error, a number out of range,
  51. * or an invalid flash bank.
  52. */
  53. static int
  54. abbrev_spec(char *str, flash_info_t **pinfo, int *psf, int *psl)
  55. {
  56. flash_info_t *fp;
  57. int bank, first, last;
  58. char *p, *ep;
  59. if ((p = strchr(str, ':')) == NULL)
  60. return 0;
  61. *p++ = '\0';
  62. bank = simple_strtoul(str, &ep, 10);
  63. if (ep == str || *ep != '\0' ||
  64. bank < 1 || bank > CFG_MAX_FLASH_BANKS ||
  65. (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
  66. return -1;
  67. str = p;
  68. if ((p = strchr(str, '-')) != NULL)
  69. *p++ = '\0';
  70. first = simple_strtoul(str, &ep, 10);
  71. if (ep == str || *ep != '\0' || first >= fp->sector_count)
  72. return -1;
  73. if (p != NULL) {
  74. last = simple_strtoul(p, &ep, 10);
  75. if (ep == p || *ep != '\0' ||
  76. last < first || last >= fp->sector_count)
  77. return -1;
  78. }
  79. else
  80. last = first;
  81. *pinfo = fp;
  82. *psf = first;
  83. *psl = last;
  84. return 1;
  85. }
  86. int do_flinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  87. {
  88. ulong bank;
  89. #ifdef CONFIG_HAS_DATAFLASH
  90. dataflash_print_info();
  91. #endif
  92. if (argc == 1) { /* print info for all FLASH banks */
  93. for (bank=0; bank <CFG_MAX_FLASH_BANKS; ++bank) {
  94. printf ("\nBank # %ld: ", bank+1);
  95. flash_print_info (&flash_info[bank]);
  96. }
  97. return 0;
  98. }
  99. bank = simple_strtoul(argv[1], NULL, 16);
  100. if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
  101. printf ("Only FLASH Banks # 1 ... # %d supported\n",
  102. CFG_MAX_FLASH_BANKS);
  103. return 1;
  104. }
  105. printf ("\nBank # %ld: ", bank);
  106. flash_print_info (&flash_info[bank-1]);
  107. return 0;
  108. }
  109. int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  110. {
  111. flash_info_t *info;
  112. ulong bank, addr_first, addr_last;
  113. int n, sect_first, sect_last;
  114. int rcode = 0;
  115. if (argc < 2) {
  116. printf ("Usage:\n%s\n", cmdtp->usage);
  117. return 1;
  118. }
  119. if (strcmp(argv[1], "all") == 0) {
  120. for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
  121. printf ("Erase Flash Bank # %ld ", bank);
  122. info = &flash_info[bank-1];
  123. rcode = flash_erase (info, 0, info->sector_count-1);
  124. }
  125. return rcode;
  126. }
  127. if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
  128. if (n < 0) {
  129. printf("Bad sector specification\n");
  130. return 1;
  131. }
  132. printf ("Erase Flash Sectors %d-%d in Bank # %d ",
  133. sect_first, sect_last, (info-flash_info)+1);
  134. rcode = flash_erase(info, sect_first, sect_last);
  135. return rcode;
  136. }
  137. if (argc != 3) {
  138. printf ("Usage:\n%s\n", cmdtp->usage);
  139. return 1;
  140. }
  141. if (strcmp(argv[1], "bank") == 0) {
  142. bank = simple_strtoul(argv[2], NULL, 16);
  143. if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
  144. printf ("Only FLASH Banks # 1 ... # %d supported\n",
  145. CFG_MAX_FLASH_BANKS);
  146. return 1;
  147. }
  148. printf ("Erase Flash Bank # %ld ", bank);
  149. info = &flash_info[bank-1];
  150. rcode = flash_erase (info, 0, info->sector_count-1);
  151. return rcode;
  152. }
  153. addr_first = simple_strtoul(argv[1], NULL, 16);
  154. addr_last = simple_strtoul(argv[2], NULL, 16);
  155. if (addr_first >= addr_last) {
  156. printf ("Usage:\n%s\n", cmdtp->usage);
  157. return 1;
  158. }
  159. printf ("Erase Flash from 0x%08lx to 0x%08lx ", addr_first, addr_last);
  160. rcode = flash_sect_erase(addr_first, addr_last);
  161. return rcode;
  162. }
  163. int flash_sect_erase (ulong addr_first, ulong addr_last)
  164. {
  165. flash_info_t *info;
  166. ulong bank;
  167. int s_first, s_last;
  168. int erased;
  169. int rcode = 0;
  170. erased = 0;
  171. for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
  172. ulong b_end;
  173. int sect;
  174. if (info->flash_id == FLASH_UNKNOWN) {
  175. continue;
  176. }
  177. b_end = info->start[0] + info->size - 1; /* bank end addr */
  178. s_first = -1; /* first sector to erase */
  179. s_last = -1; /* last sector to erase */
  180. for (sect=0; sect < info->sector_count; ++sect) {
  181. ulong end; /* last address in current sect */
  182. short s_end;
  183. s_end = info->sector_count - 1;
  184. end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
  185. if (addr_first > end)
  186. continue;
  187. if (addr_last < info->start[sect])
  188. continue;
  189. if (addr_first == info->start[sect]) {
  190. s_first = sect;
  191. }
  192. if (addr_last == end) {
  193. s_last = sect;
  194. }
  195. }
  196. if (s_first>=0 && s_first<=s_last) {
  197. erased += s_last - s_first + 1;
  198. rcode = flash_erase (info, s_first, s_last);
  199. }
  200. }
  201. if (erased) {
  202. printf ("Erased %d sectors\n", erased);
  203. } else {
  204. printf ("Error: start and/or end address"
  205. " not on sector boundary\n");
  206. rcode = 1;
  207. }
  208. return rcode;
  209. }
  210. int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  211. {
  212. flash_info_t *info;
  213. ulong bank, addr_first, addr_last;
  214. int i, p, n, sect_first, sect_last;
  215. int rcode = 0;
  216. if (argc < 3) {
  217. printf ("Usage:\n%s\n", cmdtp->usage);
  218. return 1;
  219. }
  220. if (strcmp(argv[1], "off") == 0)
  221. p = 0;
  222. else if (strcmp(argv[1], "on") == 0)
  223. p = 1;
  224. else {
  225. printf ("Usage:\n%s\n", cmdtp->usage);
  226. return 1;
  227. }
  228. if (strcmp(argv[2], "all") == 0) {
  229. for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
  230. info = &flash_info[bank-1];
  231. if (info->flash_id == FLASH_UNKNOWN) {
  232. continue;
  233. }
  234. printf ("%sProtect Flash Bank # %ld\n",
  235. p ? "" : "Un-", bank);
  236. for (i=0; i<info->sector_count; ++i) {
  237. #if defined(CFG_FLASH_PROTECTION)
  238. if (flash_real_protect(info, i, p))
  239. rcode = 1;
  240. putc ('.');
  241. #else
  242. info->protect[i] = p;
  243. #endif /* CFG_FLASH_PROTECTION */
  244. }
  245. }
  246. #if defined(CFG_FLASH_PROTECTION)
  247. if (!rcode) puts (" done\n");
  248. #endif /* CFG_FLASH_PROTECTION */
  249. return rcode;
  250. }
  251. if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
  252. if (n < 0) {
  253. printf("Bad sector specification\n");
  254. return 1;
  255. }
  256. printf("%sProtect Flash Sectors %d-%d in Bank # %d\n",
  257. p ? "" : "Un-", sect_first, sect_last,
  258. (info-flash_info)+1);
  259. for (i = sect_first; i <= sect_last; i++) {
  260. #if defined(CFG_FLASH_PROTECTION)
  261. if (flash_real_protect(info, i, p))
  262. rcode = 1;
  263. putc ('.');
  264. #else
  265. info->protect[i] = p;
  266. #endif /* CFG_FLASH_PROTECTION */
  267. }
  268. #if defined(CFG_FLASH_PROTECTION)
  269. if (!rcode) puts (" done\n");
  270. #endif /* CFG_FLASH_PROTECTION */
  271. return rcode;
  272. }
  273. if (argc != 4) {
  274. printf ("Usage:\n%s\n", cmdtp->usage);
  275. return 1;
  276. }
  277. if (strcmp(argv[2], "bank") == 0) {
  278. bank = simple_strtoul(argv[3], NULL, 16);
  279. if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
  280. printf ("Only FLASH Banks # 1 ... # %d supported\n",
  281. CFG_MAX_FLASH_BANKS);
  282. return 1;
  283. }
  284. printf ("%sProtect Flash Bank # %ld\n",
  285. p ? "" : "Un-", bank);
  286. info = &flash_info[bank-1];
  287. if (info->flash_id == FLASH_UNKNOWN) {
  288. printf ("missing or unknown FLASH type\n");
  289. return 1;
  290. }
  291. for (i=0; i<info->sector_count; ++i) {
  292. #if defined(CFG_FLASH_PROTECTION)
  293. if (flash_real_protect(info, i, p))
  294. rcode = 1;
  295. putc ('.');
  296. #else
  297. info->protect[i] = p;
  298. #endif /* CFG_FLASH_PROTECTION */
  299. }
  300. #if defined(CFG_FLASH_PROTECTION)
  301. if (!rcode) puts (" done\n");
  302. #endif /* CFG_FLASH_PROTECTION */
  303. return rcode;
  304. }
  305. addr_first = simple_strtoul(argv[2], NULL, 16);
  306. addr_last = simple_strtoul(argv[3], NULL, 16);
  307. if (addr_first >= addr_last) {
  308. printf ("Usage:\n%s\n", cmdtp->usage);
  309. return 1;
  310. }
  311. rcode = flash_sect_protect (p, addr_first, addr_last);
  312. return rcode;
  313. }
  314. int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
  315. {
  316. flash_info_t *info;
  317. ulong bank;
  318. int s_first, s_last;
  319. int protected, i;
  320. int rcode = 0;
  321. protected = 0;
  322. for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
  323. ulong b_end;
  324. int sect;
  325. if (info->flash_id == FLASH_UNKNOWN) {
  326. continue;
  327. }
  328. b_end = info->start[0] + info->size - 1; /* bank end addr */
  329. s_first = -1; /* first sector to erase */
  330. s_last = -1; /* last sector to erase */
  331. for (sect=0; sect < info->sector_count; ++sect) {
  332. ulong end; /* last address in current sect */
  333. short s_end;
  334. s_end = info->sector_count - 1;
  335. end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
  336. if (addr_first > end)
  337. continue;
  338. if (addr_last < info->start[sect])
  339. continue;
  340. if (addr_first == info->start[sect]) {
  341. s_first = sect;
  342. }
  343. if (addr_last == end) {
  344. s_last = sect;
  345. }
  346. }
  347. if (s_first>=0 && s_first<=s_last) {
  348. protected += s_last - s_first + 1;
  349. for (i=s_first; i<=s_last; ++i) {
  350. #if defined(CFG_FLASH_PROTECTION)
  351. if (flash_real_protect(info, i, p))
  352. rcode = 1;
  353. putc ('.');
  354. #else
  355. info->protect[i] = p;
  356. #endif /* CFG_FLASH_PROTECTION */
  357. }
  358. }
  359. #if defined(CFG_FLASH_PROTECTION)
  360. if (!rcode) putc ('\n');
  361. #endif /* CFG_FLASH_PROTECTION */
  362. }
  363. if (protected) {
  364. printf ("%sProtected %d sectors\n",
  365. p ? "" : "Un-", protected);
  366. } else {
  367. printf ("Error: start and/or end address"
  368. " not on sector boundary\n");
  369. rcode = 1;
  370. }
  371. return rcode;
  372. }
  373. #endif /* CFG_CMD_FLASH */