cmd_flash.c 10 KB

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