PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/blob/a780-blob/src/blob/flash.c

https://gitlab.com/openezx/openezx-svn
C | 627 lines | 422 code | 131 blank | 74 comment | 51 complexity | 164bf1a11dc31aa0f7807549d93bae9c MD5 | raw file
Possible License(s): GPL-2.0
  1. /*-------------------------------------------------------------------------
  2. * Filename: flash.c
  3. * Version: $Id: flash.c,v 1.11 2002/01/03 16:07:17 erikm Exp $
  4. * Copyright: Copyright (C) 1999, Jan-Derk Bakker
  5. * Author: Jan-Derk Bakker <J.D.Bakker@its.tudelft.nl>
  6. * Description: Flash I/O functions for blob
  7. * Created at: Mon Aug 23 20:00:00 1999
  8. * Modified by: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
  9. * Modified at: Sat Jan 15 19:16:34 2000
  10. *-----------------------------------------------------------------------*/
  11. /*
  12. * flash.c: Flash I/O functions for blob
  13. *
  14. * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
  15. * Copyright (C) 1999 Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
  16. *
  17. * This program is free software; you can redistribute it and/or modify
  18. * it under the terms of the GNU General Public License as published by
  19. * the Free Software Foundation; either version 2 of the License, or
  20. * (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  30. *
  31. */
  32. #ident "$Id: flash.c,v 1.11 2002/01/03 16:07:17 erikm Exp $"
  33. #ifdef HAVE_CONFIG_H
  34. # include <blob/config.h>
  35. #endif
  36. #include <blob/arch.h>
  37. #include <blob/errno.h>
  38. #include <blob/error.h>
  39. #include <blob/led.h>
  40. #include <blob/util.h>
  41. #include <blob/serial.h>
  42. #include <blob/flash.h>
  43. #include <blob/init.h>
  44. #include <blob/command.h>
  45. /* this is enough for a 16MB flash with 128kB blocks */
  46. #define NUM_FLASH_BLOCKS (128 * 3)
  47. typedef struct {
  48. u32 start;
  49. u32 size;
  50. int lockable;
  51. } flash_block_t;
  52. static flash_block_t flash_blocks[NUM_FLASH_BLOCKS];
  53. static int num_flash_blocks;
  54. flash_descriptor_t *flash_descriptors;
  55. flash_driver_t *flash_driver;
  56. /* dummy function for enable_vpp and disable_vpp */
  57. int flash_dummy_ok(void)
  58. {
  59. return 0;
  60. }
  61. /* initialise the flash blocks table */
  62. static void init_flash(void)
  63. {
  64. int i = 0;
  65. int j;
  66. u32 start = 0;
  67. #ifdef BLOB_DEBUG
  68. if(flash_descriptors == NULL) {
  69. printerrprefix();
  70. SerialOutputString("undefined flash_descriptors\n");
  71. return;
  72. }
  73. if(flash_driver == NULL) {
  74. printerrprefix();
  75. SerialOutputString("undefined flash_driver\n");
  76. return;
  77. }
  78. #endif
  79. /* fill out missing flash driver functions */
  80. if(flash_driver->enable_vpp == NULL)
  81. flash_driver->enable_vpp = flash_dummy_ok;
  82. if(flash_driver->disable_vpp == NULL)
  83. flash_driver->disable_vpp = flash_dummy_ok;
  84. /* initialise flash blocks table */
  85. num_flash_blocks = 0;
  86. while(flash_descriptors[i].size != 0) {
  87. #ifdef BLOB_DEBUG
  88. SerialOutputDec(flash_descriptors[i].num);
  89. SerialOutputString("x 0x");
  90. SerialOutputHex(flash_descriptors[i].size);
  91. SerialOutputString(", ");
  92. if(!flash_descriptors[i].lockable)
  93. SerialOutputString("not ");
  94. SerialOutputString("lockable\n");
  95. #endif
  96. for(j = 0; j < flash_descriptors[i].num; j++) {
  97. flash_blocks[num_flash_blocks].start = start;
  98. flash_blocks[num_flash_blocks].size =
  99. flash_descriptors[i].size;
  100. flash_blocks[num_flash_blocks].lockable =
  101. flash_descriptors[i].lockable;
  102. start += flash_descriptors[i].size;
  103. num_flash_blocks++;
  104. if(num_flash_blocks >= NUM_FLASH_BLOCKS) {
  105. printerrprefix();
  106. SerialOutputString("not enough flash_blocks\n");
  107. break;
  108. }
  109. }
  110. i++;
  111. }
  112. #ifdef BLOB_DEBUG
  113. SerialOutputString("Flash map:\n");
  114. for(i = 0; i < num_flash_blocks; i++) {
  115. SerialOutputString(" 0x");
  116. SerialOutputHex(flash_blocks[i].size);
  117. SerialOutputString(" @ 0x");
  118. SerialOutputHex(flash_blocks[i].start);
  119. SerialOutputString(" (");
  120. SerialOutputDec(flash_blocks[i].size / 1024);
  121. SerialOutputString(" kB), ");
  122. if(!flash_blocks[i].lockable)
  123. SerialOutputString("not ");
  124. SerialOutputString("lockable\n");
  125. }
  126. #endif
  127. }
  128. __initlist(init_flash, INIT_LEVEL_OTHER_STUFF + 1);
  129. int flash_erase_region(u32 *start, u32 nwords)
  130. {
  131. u32 *cur;
  132. u32 *end;
  133. int rv, i;
  134. cur = start;
  135. end = start + nwords;
  136. #if BLOB_DEBUG
  137. SerialOutputString(__FUNCTION__ "(): erasing 0x");
  138. SerialOutputHex(nwords);
  139. SerialOutputString(" (");
  140. SerialOutputDec(nwords);
  141. SerialOutputString(") words at 0x");
  142. SerialOutputHex((u32)start);
  143. serial_write('\n');
  144. #endif
  145. flash_driver->enable_vpp();
  146. i =0;
  147. while(cur < end) {
  148. SerialOutputString("erasing dirty block at 0x");
  149. SerialOutputHex((u32)cur);
  150. serial_write('\n');
  151. /* dirty block */
  152. rv = flash_driver->erase(cur);
  153. if(rv < 0) {
  154. printerrprefix();
  155. SerialOutputString("flash erase error at 0x");
  156. SerialOutputHex((u32)cur);
  157. serial_write('\n');
  158. flash_driver->disable_vpp();
  159. return rv;
  160. }
  161. cur += 0x20000/sizeof(*cur);
  162. printlcd(".");
  163. i++;
  164. if((i%20)==0)
  165. printlcd("\n");
  166. }
  167. printlcd("\n");
  168. flash_driver->disable_vpp();
  169. return 0;
  170. }
  171. #if 0
  172. /* Write a flash region with a minimum number of erase operations.
  173. *
  174. * Flash chips wear from erase operations (that's why flash lifetime
  175. * is specified in erase cycles), so we try to limit the number of
  176. * erase operations in this function. Luckily the flash helps us a
  177. * little bit with this, because it only allows you to change a '1'
  178. * bit into a '0' during a write operation. This means that 0xffff can
  179. * be changed into 0x1010, and 0x1010 into 0x0000, but 0x0000 can't be
  180. * changed into anything else anymore because there are no '1' bits
  181. * left.
  182. */
  183. int flash_write_region(u32 *dst, const u32 *src, u32 nwords)
  184. {
  185. int rv;
  186. u32 nerrors = 0;
  187. u32 i = 0;
  188. u32 nerase = 0;
  189. u32 nwrite = 0;
  190. u32 nscandown = 0;
  191. u32 nskip = 0;
  192. #if defined BLOB_DEBUG
  193. SerialOutputString(__FUNCTION__ "(): flashing 0x");
  194. SerialOutputHex(nwords);
  195. SerialOutputString(" (");
  196. SerialOutputDec(nwords);
  197. SerialOutputString(") words from 0x");
  198. SerialOutputHex((u32)src);
  199. SerialOutputString(" to 0x");
  200. SerialOutputHex((u32)dst);
  201. serial_write('\n');
  202. #endif
  203. flash_driver->enable_vpp();
  204. while(i < nwords) {
  205. /* nothing to write */
  206. if(dst[i] == src[i]) {
  207. i++;
  208. nskip++;
  209. continue;
  210. }
  211. /* different, so write to this location */
  212. rv = flash_driver->write(&dst[i], &src[i]);
  213. nwrite++;
  214. if(rv == 0) {
  215. i++;
  216. } else {
  217. nerrors++;
  218. SerialOutputString("erasing at 0x");
  219. SerialOutputHex((u32)&dst[i]);
  220. SerialOutputString("...");
  221. /* erase block at current location */
  222. rv = flash_driver->erase(&dst[i]);
  223. nerase++;
  224. if(rv < 0) {
  225. /* something is obviously wrong */
  226. SerialOutputString(" error\n");
  227. flash_driver->disable_vpp();
  228. return rv;
  229. }
  230. SerialOutputString(" scanning down...");
  231. /* scan down until we find the first
  232. non-erased location and restart writing
  233. again from that location */
  234. while((i > 0) &&
  235. ((dst[i] != src[i]) || (dst[i] == 0xffffffff))) {
  236. i--;
  237. nscandown++;
  238. }
  239. SerialOutputString(" resume writing at 0x");
  240. SerialOutputHex((u32)&dst[i]);
  241. serial_write('\n');
  242. }
  243. /* there is something seriously wrong if this is true */
  244. if(nerrors > 2 * nwords) {
  245. printerrprefix();
  246. SerialOutputString("too many flash errors, probably hardware error\n");
  247. flash_driver->disable_vpp();
  248. return -EFLASHPGM;
  249. }
  250. }
  251. #ifdef BLOB_DEBUG
  252. SerialOutputDec(nwords);
  253. SerialOutputString(" words source image\n");
  254. SerialOutputDec(nwrite);
  255. SerialOutputString(" words written to flash\n");
  256. SerialOutputDec(nskip);
  257. SerialOutputString(" words skipped\n");
  258. SerialOutputDec(nerase);
  259. SerialOutputString(" erase operations\n");
  260. SerialOutputDec(nscandown);
  261. SerialOutputString(" words scanned down\n");
  262. serial_write('\n');
  263. #endif
  264. flash_driver->disable_vpp();
  265. return 0;
  266. }
  267. #endif
  268. unsigned short flash_program_buf(volatile u16* addr, volatile u16* data, volatile int len)
  269. {
  270. volatile unsigned short *ROM;
  271. unsigned short stat = 0;
  272. int timeout = 0x50000;
  273. int i;
  274. volatile int tlen;
  275. volatile unsigned short *taddr,*tdata;
  276. tlen = len;
  277. ROM = (volatile unsigned short *)((unsigned long)addr);
  278. taddr=(volatile unsigned short *)((unsigned long)addr);
  279. tdata=(volatile unsigned short *)((unsigned long)data);
  280. // Clear any error conditions
  281. ROM[0] = 0x0050;
  282. while(len>0)
  283. {
  284. timeout=0x50000;
  285. ROM[0]=0x00E8;
  286. while(((stat=ROM[0])&0x0080)!=0x0080)
  287. {
  288. if(--timeout==0)
  289. {
  290. stat=*addr;
  291. printlcd("\ntimeout1\n");
  292. goto bad;
  293. }
  294. }
  295. ROM[0]=31;
  296. for(i=0;i<32;i++)
  297. {
  298. *addr=*data;
  299. addr++;
  300. data++;
  301. }
  302. len=len-64;
  303. ROM[0]=0x00D0;
  304. timeout=0x50000;
  305. while(((stat=ROM[0])&0x0080)!=0x0080)
  306. {
  307. if(--timeout==0)
  308. {
  309. stat=*addr;
  310. printlcd("\ntimeout2\n");
  311. goto bad;
  312. }
  313. }
  314. ROM[0]=0x00ff;
  315. }
  316. // ROM[0]=FLASH_Reset;
  317. stat = 0;
  318. while(tlen>0)
  319. {
  320. if(*taddr!=*tdata)
  321. {
  322. printlcd("\ncheck error\n");
  323. stat=tlen;
  324. break;
  325. }
  326. tlen-=2;
  327. taddr ++;
  328. tdata ++;
  329. }
  330. // Restore ROM to "normal" mode
  331. bad:
  332. ROM[0] = 0x00FF;
  333. return stat;
  334. }
  335. //
  336. // CAUTION! This code must be copied to RAM before execution. Therefore,
  337. // it must not contain any code which might be position dependent!
  338. //
  339. int flash_write_region(u16 *dst, u16 *src, u32 nwords)
  340. {
  341. unsigned long size;
  342. unsigned short stat=0;
  343. int i;
  344. i = 0;
  345. while(nwords>0)
  346. {
  347. size = nwords;
  348. if(size >= 0x20000)
  349. size = 0x20000;
  350. stat = flash_program_buf(dst, src, size);
  351. if(stat)
  352. {
  353. printlcd("!!!\n");
  354. return -EFLASHPGM;
  355. }
  356. printlcd(".");
  357. i++;
  358. if((i%20)==0)
  359. printlcd("\n");
  360. nwords -= size;
  361. dst += size/sizeof(*dst);
  362. src += size/sizeof(*src);
  363. }
  364. printlcd("\n");
  365. return stat;
  366. }
  367. /* given an address, return the flash block index number (or negative
  368. * error number otherwise
  369. */
  370. static int find_block(u32 address)
  371. {
  372. int i;
  373. for (i = 0; i < num_flash_blocks; i++) {
  374. u32 start = flash_blocks[i].start;
  375. int length = flash_blocks[i].size;
  376. u32 endIncl = start + length - 1;
  377. if (address >= start && address <= endIncl)
  378. return i;
  379. }
  380. return -ERANGE;
  381. }
  382. /* convert address range to range of flash blocks. returns 0 on
  383. * success or negative error number on failure.
  384. */
  385. static int address_range_to_block_range(u32 startAddress, int length,
  386. int *startBlock, int *endInclBlock)
  387. {
  388. int sb, eib;
  389. #ifdef FLASH_DEBUG
  390. SerialOutputString(__FUNCTION__ ": startAddress = 0x");
  391. SerialOutputHex(startAddress);
  392. SerialOutputString(", length = 0x");
  393. SerialOutputHex(length);
  394. SerialOutputString("\n");
  395. #endif
  396. sb = find_block(startAddress);
  397. eib = find_block(startAddress + length - 1);
  398. if(sb < 0)
  399. return sb;
  400. if(eib < 0)
  401. return eib;
  402. #ifdef FLASH_DEBUG
  403. SerialOutputString("sb: ");
  404. SerialOutputDec(sb);
  405. SerialOutputString(", eib: ");
  406. SerialOutputDec(eib);
  407. SerialOutputString("\n");
  408. #endif
  409. // would be nice to warn if sb isn't at the beginning of
  410. // its block or eib isn't at the very end of its block.
  411. *startBlock = sb;
  412. *endInclBlock = eib;
  413. return 0;
  414. }
  415. static int do_flash_lock(u32 *start, u32 nwords, int lock)
  416. {
  417. int sb, eib;
  418. int rv;
  419. int i;
  420. u32 *addr;
  421. #ifdef BLOB_DEBUG
  422. SerialOutputString(__FUNCTION__ "(): ");
  423. if(lock == 0)
  424. SerialOutputString("un");
  425. SerialOutputString("lock at 0x");
  426. SerialOutputHex((u32)start);
  427. SerialOutputString(", nwords = 0x");
  428. SerialOutputHex(nwords);
  429. serial_write('\n');
  430. #endif
  431. rv = address_range_to_block_range((u32) start, nwords * sizeof(u32),
  432. &sb, &eib);
  433. if(rv < 0)
  434. return rv;
  435. /* check if it is lockable at all */
  436. for(i = sb; i <= eib; i++) {
  437. if(!flash_blocks[i].lockable) {
  438. #ifdef BLOB_DEBUG
  439. printerrprefix();
  440. SerialOutputString("can't (un)lock unlockable blocks\n");
  441. #endif
  442. return -EFLASHPGM;
  443. }
  444. }
  445. flash_driver->enable_vpp();
  446. for(i = sb; i <= eib; i++) {
  447. addr = (u32 *)flash_blocks[i].start;
  448. if(lock)
  449. rv = flash_driver->lock_block(addr);
  450. else
  451. rv = flash_driver->unlock_block(addr);
  452. if(rv < 0) {
  453. flash_driver->disable_vpp();
  454. #ifdef BLOB_DEBUG
  455. printerrprefix();
  456. SerialOutputString("can't (un)lock block at 0x");
  457. SerialOutputHex((u32)addr);
  458. serial_write('\n');
  459. #endif
  460. return rv;
  461. }
  462. }
  463. flash_driver->disable_vpp();
  464. return 0;
  465. }
  466. int flash_lock_region(u32 *start, u32 nwords)
  467. {
  468. return do_flash_lock(start, nwords, 1);
  469. }
  470. int flash_unlock_region(u32 *start, u32 nwords)
  471. {
  472. return do_flash_lock(start, nwords, 0);
  473. }
  474. /* return number of blocks in the region locked, 0 if everything is
  475. * unlocked, or negative error number otherwise */
  476. int flash_query_region(u32 *start, u32 nwords)
  477. {
  478. int sb, eib, rv, i;
  479. int cnt = 0;
  480. u32 *addr;
  481. rv = address_range_to_block_range((u32) start, nwords * sizeof(u32),
  482. &sb, &eib);
  483. if(rv < 0)
  484. return rv;
  485. for(i = sb; i <= eib; i++) {
  486. addr = (u32 *)flash_blocks[i].start;
  487. if(flash_blocks[i].lockable) {
  488. rv = flash_driver->query_block_lock(addr);
  489. if(rv < 0)
  490. return rv;
  491. if(rv > 0)
  492. cnt++;
  493. }
  494. }
  495. return cnt;
  496. }