SpiBooter.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. #include <string.h>
  2. #include "typedef.h"
  3. #include "amt630h.h"
  4. #include "UartPrint.h"
  5. #include "timer.h"
  6. #include "spi.h"
  7. #include "cp15.h"
  8. #include "sysinfo.h"
  9. #include "crc32.h"
  10. #include "gpio.h"
  11. #define SPI_CS_GPIO 32
  12. #define SPI_RXFIFO_FULL (1<<4)
  13. #define SPI_RXFIFO_NOTEMPTY (1<<3)
  14. #define SPI_TXFIFO_EMPTY (1<<2)
  15. #define SPI_TXFIFO_NOTFULL (1<<1)
  16. #define SPIFLASH_BUSY (1<<0)
  17. static void SetCSGpioEnable(int enable)
  18. {
  19. gpio_direction_output(SPI_CS_GPIO, !enable);
  20. }
  21. static void SetSpiDataMode(unsigned int bitMode)
  22. {
  23. unsigned int val = 0;
  24. (void)val;
  25. while((rSPI_SR & SPI_BUSY));
  26. rSPI_SSIENR = 0;
  27. val = rSPI_CTLR0;
  28. val &=~(0x1f<<16);
  29. val |=((bitMode-1)<<16);
  30. rSPI_CTLR0 = val;
  31. rSPI_SSIENR = 1;
  32. }
  33. static void SpiEmptyRxFIFO(void)
  34. {
  35. INT32 data = 0;
  36. (void)data;
  37. while(rSPI_SR & SPI_RXFIFO_NOTEMPTY)
  38. data = rSPI_DR;
  39. }
  40. static UINT8 SpiReadSta(void)
  41. {
  42. UINT8 status;
  43. SetSpiDataMode(8);
  44. SetCSGpioEnable(1);
  45. rSPI_DR = SPI_READ_STATUS;
  46. rSPI_DR = 0;
  47. while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
  48. status = rSPI_DR;
  49. while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
  50. status = rSPI_DR;
  51. //PrintVariableValueHex("status:", status);
  52. while(rSPI_SR & SPIFLASH_BUSY);
  53. SetCSGpioEnable(0);
  54. SetSpiDataMode(32);
  55. return status;
  56. }
  57. static void SpiReadPage(UINT32 pagenum, UINT32 *buf)
  58. {
  59. UINT32 addr;
  60. UINT32 val = 0;
  61. INT32 i;
  62. UINT8 tmpaddr[3];
  63. (void)val;
  64. addr = pagenum*BYTESPERPAGE;
  65. tmpaddr[0] = addr;
  66. tmpaddr[1] = addr>>8;
  67. tmpaddr[2] = addr>>16;
  68. SpiEmptyRxFIFO();
  69. SetCSGpioEnable(1);
  70. rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_READ_DATA;
  71. for(i=0;i<WORDSPERPAGE;i++)
  72. {
  73. while(!(rSPI_SR & SPI_TXFIFO_NOTFULL));
  74. rSPI_DR = 0;
  75. }
  76. while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
  77. val = rSPI_DR;
  78. for(i = 0; i < WORDSPERPAGE; i++)
  79. {
  80. while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
  81. *buf++ = rSPI_DR;
  82. }
  83. while(rSPI_SR & SPIFLASH_BUSY);
  84. SetCSGpioEnable(0);
  85. }
  86. void SpiSelectPad()
  87. {
  88. UINT32 val;
  89. val = rSYS_PAD_CTRL02;
  90. val &= ~0xfff;
  91. val |= (0x1<<10)|(0x1 << 8)|(0x1 << 6)|(0x1 << 4)| (0x1 << 2);
  92. rSYS_PAD_CTRL02 = val;
  93. val = rSYS_SSP_CLK_CFG;
  94. val &= ~((0x1<<31)|(0x1<<30));
  95. val |= (0x1<<31)|(0x1<<30);
  96. rSYS_SSP_CLK_CFG = val;
  97. //cs inactive first
  98. SetCSGpioEnable(0);
  99. }
  100. void Reset(void)
  101. {
  102. SetSpiDataMode(8);
  103. rSPI_DR = 0x66;
  104. while((SpiReadSta() & SPI_BUSY));
  105. // while(!(SpiReadSta() & SPIFLASH_WRITEENABLE));
  106. rSPI_DR = 0x99;
  107. while((SpiReadSta() & SPI_BUSY));
  108. // while(!(SpiReadSta() & SPIFLASH_WRITEENABLE));
  109. SetSpiDataMode(32);
  110. }
  111. void SpiInit()
  112. {
  113. unsigned int val;
  114. val = rSYS_SOFT_RST;
  115. val &= ~(0x1<<8);
  116. rSYS_SOFT_RST = val;
  117. udelay(10);
  118. val |= (0x1<<8);
  119. rSYS_SOFT_RST = val;
  120. rSPI_SSIENR = 0;
  121. rSPI_CTLR0 = 0;
  122. rSPI_CTLR0 |=(0<<21)|(0x1f<<16)|(0x0<<12)|(0x0<<8)|(0x0<<4);
  123. // rSPI_CTLR1 = 63;
  124. rSPI_BAUDR = 4;//42;//16;//2;
  125. rSPI_SER = 1;
  126. rSPI_SSIENR = 1;
  127. // Reset();
  128. }
  129. static void SpiReadDeviceId(UINT8 *mfid, UINT8 *devid)
  130. {
  131. UINT8 val[6];
  132. int i;
  133. SetSpiDataMode(8);
  134. SetCSGpioEnable(1);
  135. rSPI_DR = SPI_MF_DEVICE_ID;
  136. rSPI_DR = 0;
  137. rSPI_DR = 0;
  138. rSPI_DR = 0;
  139. rSPI_DR = 0;
  140. rSPI_DR = 0;
  141. for (i = 0; i < 6; i++)
  142. {
  143. while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
  144. val[i] = rSPI_DR;
  145. }
  146. *mfid = val[4];
  147. *devid = val[5];
  148. while(rSPI_SR & SPIFLASH_BUSY);
  149. SetCSGpioEnable(0);
  150. SetSpiDataMode(32);
  151. }
  152. static void SpiReadJedecId(UINT8 *mfid, UINT8 *memid, UINT8 *capid)
  153. {
  154. UINT8 val[4];
  155. int i;
  156. SetSpiDataMode(8);
  157. SetCSGpioEnable(1);
  158. rSPI_DR = SPI_READ_JEDEC_ID;
  159. rSPI_DR = 0;
  160. rSPI_DR = 0;
  161. rSPI_DR = 0;
  162. for (i = 0; i < 4; i++)
  163. {
  164. while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
  165. val[i] = rSPI_DR;
  166. }
  167. *mfid = val[1];
  168. *memid = val[2];
  169. *capid = val[3];
  170. while(rSPI_SR & SPIFLASH_BUSY);
  171. SetCSGpioEnable(0);
  172. SetSpiDataMode(32);
  173. }
  174. void SpiReadId(void)
  175. {
  176. UINT8 mfid,devid,memid,capid;
  177. SpiReadDeviceId(&mfid,&devid);
  178. SpiReadJedecId(&mfid,&memid,&capid);
  179. PrintVariableValueHex("ManufacturerID: ", mfid);
  180. PrintVariableValueHex("DeviceID: ", devid);
  181. PrintVariableValueHex("Memory Type ID: ", memid);
  182. PrintVariableValueHex("Capacity ID: ", capid);
  183. }
  184. #define SPI_READ_MAXLEN BYTESPERPAGE
  185. static void SpiLoadStepldr(void (*readfunc)(UINT32, UINT32 *))
  186. {
  187. unsigned int i = 0;
  188. UINT32 *buf = (UINT32*)STEPLDR_ENTRY;
  189. UINT32 offset;
  190. UINT32 size;
  191. UINT32 nPageCount;
  192. UINT32 nPageStart;
  193. if (ReadSysInfo()) {
  194. SendUartString("read sysinfo fail, try to load stepldr part a.\n");
  195. offset = STEPLDRA_OFFSET;
  196. size = STEPLDR_MAX_SIZE;
  197. } else {
  198. SysInfo *sysinfo = GetSysInfo();
  199. offset = sysinfo->stepldr_offset;
  200. size = sysinfo->stepldr_size;
  201. }
  202. PrintVariableValueHex("stepldr offset: ", offset);
  203. nPageCount = (size + BYTESPERPAGE - 1) / BYTESPERPAGE;
  204. nPageStart = offset / BYTESPERPAGE;
  205. for(i = nPageStart; i < nPageStart + nPageCount; i++)
  206. {
  207. readfunc(i, buf);
  208. buf += BYTESPERPAGE/4;
  209. }
  210. #ifdef MMU_ENABLE
  211. CP15_clean_dcache_for_dma(STEPLDR_ENTRY, STEPLDR_ENTRY + size);
  212. #endif
  213. }
  214. static void SpiWriteEnable(void)
  215. {
  216. SetSpiDataMode(8);
  217. SetCSGpioEnable(1);
  218. rSPI_DR = SPI_WRITE_ENABLE;
  219. while(rSPI_SR & SPIFLASH_BUSY);
  220. SetCSGpioEnable(0);
  221. while((SpiReadSta() & SPI_BUSY));
  222. while(!(SpiReadSta() & SPIFLASH_WRITEENABLE));
  223. SetSpiDataMode(32);
  224. }
  225. static void SpiEraseSector(UINT32 sectorNum)
  226. {
  227. UINT32 addr;
  228. UINT8 tmpaddr[3];
  229. addr = BYTESPERSECTOR*sectorNum;
  230. tmpaddr[0] = addr;
  231. tmpaddr[1] = addr>>8;
  232. tmpaddr[2] = addr>>16;
  233. SpiWriteEnable();
  234. SetCSGpioEnable(1);
  235. rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_SECTOR_ERASE;
  236. while(rSPI_SR & SPIFLASH_BUSY);
  237. SetCSGpioEnable(0);
  238. while((SpiReadSta() & SPIFLASH_WRITEENABLE));
  239. }
  240. static void SpiEraseBlock(UINT32 blockNum)
  241. {
  242. UINT32 addr;
  243. UINT8 tmpaddr[3];
  244. addr = BYTESPERBLOCK*blockNum;
  245. tmpaddr[0] = addr;
  246. tmpaddr[1] = addr>>8;
  247. tmpaddr[2] = addr>>16;
  248. SpiWriteEnable();
  249. SetCSGpioEnable(1);
  250. rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_BLOCK_ERASE;
  251. while(rSPI_SR & SPIFLASH_BUSY);
  252. SetCSGpioEnable(0);
  253. while((SpiReadSta() & SPIFLASH_WRITEENABLE));
  254. }
  255. static void SpiWritePage(UINT32 pagenum, UINT32 *buf)
  256. {
  257. UINT32 addr;
  258. UINT32 val = 0;;
  259. INT32 i;
  260. UINT8 tmpaddr[3];
  261. (void)val;
  262. addr = pagenum*BYTESPERPAGE;
  263. tmpaddr[0] = addr;
  264. tmpaddr[1] = addr>>8;
  265. tmpaddr[2] = addr>>16;
  266. SpiWriteEnable();
  267. SetCSGpioEnable(1);
  268. rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_PAGE_PROGRAM;
  269. for(i=0;i<WORDSPERPAGE;i++)
  270. {
  271. while(!(rSPI_SR & SPI_TXFIFO_NOTFULL));
  272. rSPI_DR = *buf++;
  273. }
  274. while(rSPI_SR & SPIFLASH_BUSY);
  275. SetCSGpioEnable(0);
  276. while(SpiReadSta() & SPI_BUSY);
  277. }
  278. void bootFromSPI(void)
  279. {
  280. void (*funPtr)(void);
  281. SpiLoadStepldr(SpiReadPage);
  282. funPtr = (void (*)(void))STEPLDR_ENTRY;
  283. funPtr();
  284. }
  285. static unsigned int pagecheck[WORDSPERPAGE];
  286. /* offset is at least align to SECOTR_SIZE */
  287. static int SpiNorBurnPage(int pagenum, unsigned int *buf)
  288. {
  289. int timeout = 3;
  290. unsigned int *tmp = (unsigned int *)buf;
  291. int i;
  292. retry:
  293. SpiWritePage(pagenum, buf);
  294. SpiReadPage(pagenum, pagecheck);
  295. for (i = 0; i < WORDSPERPAGE; i++) {
  296. if (tmp[i] != pagecheck[i]) {
  297. if (timeout-- > 0) {
  298. PrintVariableValueHex("write: ", tmp[i]);
  299. PrintVariableValueHex("read: ", pagecheck[i]);
  300. SendUartString("burn check data fail, retry...\r\n");
  301. goto retry;
  302. } else {
  303. SendUartString("burn error!\r\n");
  304. return -1;
  305. }
  306. }
  307. }
  308. return 0;
  309. }
  310. /* offset is at least align to SECOTR_SIZE */
  311. int SpiNorBurn(void *buf, unsigned int offset, unsigned int size)
  312. {
  313. int i, j;
  314. int secstart, secnum;
  315. int blkstart, blknum;
  316. int pagestart, pageburned;
  317. int remain = size;
  318. unsigned int *pbuf = (unsigned int *)buf;
  319. pagestart = offset / BYTESPERPAGE;
  320. pageburned = 0;
  321. while (remain > 0) {
  322. unsigned int tmp = offset & (BYTESPERBLOCK - 1);
  323. if (tmp) {
  324. tmp = (BYTESPERBLOCK - tmp) / BYTESPERSECTOR;
  325. secnum = (remain + BYTESPERSECTOR - 1) / BYTESPERSECTOR;
  326. secnum = min(tmp, secnum);
  327. secstart = offset / BYTESPERSECTOR;
  328. for (i = 0; i < secnum; i++) {
  329. SpiEraseSector(secstart + i);
  330. for (j = 0; j < PAGESPERSECTORS; j++) {
  331. if (SpiNorBurnPage(pagestart + j, pbuf))
  332. return -1;
  333. pbuf += WORDSPERPAGE;
  334. pageburned++;
  335. remain -= BYTESPERPAGE;
  336. if (remain <= 0) goto finish;
  337. }
  338. pagestart += PAGESPERSECTORS;
  339. }
  340. offset += secnum * BYTESPERSECTOR;
  341. } else {
  342. blkstart = offset / BYTESPERBLOCK;
  343. blknum = remain / BYTESPERBLOCK;
  344. for (i = 0; i < blknum; i++) {
  345. SpiEraseBlock(blkstart + i);
  346. for (j = 0; j < PAGESPERSECTORS * SECTORSPERBLOCK; j++) {
  347. if (SpiNorBurnPage(pagestart + j, pbuf))
  348. return -1;
  349. pbuf += WORDSPERPAGE;
  350. pageburned++;
  351. remain -= BYTESPERPAGE;
  352. if (remain <= 0) goto finish;
  353. }
  354. pagestart += PAGESPERSECTORS * SECTORSPERBLOCK;
  355. }
  356. offset += blknum * BYTESPERBLOCK;
  357. if (remain > 0) {
  358. secstart = offset / BYTESPERSECTOR;
  359. secnum = (remain + BYTESPERSECTOR - 1) / BYTESPERSECTOR;
  360. for (i = 0; i < secnum; i++) {
  361. SpiEraseSector(secstart + i);
  362. for (j = 0; j < PAGESPERSECTORS; j++) {
  363. if (SpiNorBurnPage(pagestart + j, pbuf))
  364. return -1;
  365. pbuf += WORDSPERPAGE;
  366. pageburned++;
  367. remain -= BYTESPERPAGE;
  368. if (remain <= 0) goto finish;
  369. }
  370. pagestart += PAGESPERSECTORS;
  371. }
  372. offset += secnum * BYTESPERSECTOR;
  373. }
  374. }
  375. }
  376. finish:
  377. return 0;
  378. }
  379. int SpiReadSysInfo(SysInfo *info)
  380. {
  381. UINT32 *buf = (UINT32*)IMAGE_ENTRY;
  382. int pagestart;
  383. int pagenum;
  384. UINT32 checksum;
  385. UINT32 calc_checksum;
  386. int i;
  387. pagestart = SYSINFOA_OFFSET / BYTESPERPAGE;
  388. pagenum = (sizeof(SysInfo) + BYTESPERPAGE - 1) / BYTESPERPAGE;
  389. for(i = pagestart; i < pagestart + pagenum; i++)
  390. {
  391. SpiReadPage(i, buf);
  392. buf += BYTESPERPAGE/4;
  393. }
  394. checksum = *(UINT32*)(IMAGE_ENTRY + sizeof(SysInfo) - 4);
  395. calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, sizeof(SysInfo) - 4, 0xffffffff);
  396. if (calc_checksum == checksum) {
  397. memcpy(info, (void*)IMAGE_ENTRY, sizeof(SysInfo));
  398. return 0;
  399. }
  400. buf = (UINT32*)IMAGE_ENTRY;
  401. pagestart = SYSINFOB_OFFSET / BYTESPERPAGE;
  402. for(i = pagestart; i < pagestart + pagenum; i++)
  403. {
  404. SpiReadPage(i, buf);
  405. buf += BYTESPERPAGE/4;
  406. }
  407. checksum = *(UINT32*)(IMAGE_ENTRY + sizeof(SysInfo) - 4);
  408. calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, sizeof(SysInfo) - 4, 0xffffffff);
  409. if (calc_checksum == checksum) {
  410. memcpy(info, (void*)IMAGE_ENTRY, sizeof(SysInfo));
  411. return 0;
  412. }
  413. return -1;
  414. }
  415. void SpiWriteSysInfo(SysInfo *info)
  416. {
  417. SpiNorBurn(info, SYSINFOB_OFFSET, sizeof(SysInfo));
  418. SpiNorBurn(info, SYSINFOA_OFFSET, sizeof(SysInfo));
  419. }