M480 BSP  V3.05.001
The Board Support Package for M480 Series
spim.c
Go to the documentation of this file.
1 /**************************************************************************/
10 #include <stdio.h>
11 #include <string.h>
12 #include "NuMicro.h"
13 
14 
31 #define ENABLE_DEBUG 0
32 
33 #if ENABLE_DEBUG
34 #define SPIM_DBGMSG printf
35 #else
36 #define SPIM_DBGMSG(...) do { } while (0) /* disable debug */
37 #endif
38 
39 static volatile uint8_t g_Supported_List[] =
40 {
41  MFGID_WINBOND,
42  MFGID_MXIC,
43  MFGID_EON,
44  MFGID_ISSI,
45  MFGID_SPANSION
46 };
47 
48 static void N_delay(int n);
49 static void SwitchNBitOutput(uint32_t u32NBit);
50 static void SwitchNBitInput(uint32_t u32NBit);
51 static void spim_write(uint8_t pu8TxBuf[], uint32_t u32NTx);
52 static void spim_read(uint8_t pu8RxBuf[], uint32_t u32NRx);
53 static void SPIM_WriteStatusRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit);
54 static void SPIM_ReadStatusRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
55 static void SPIM_ReadStatusRegister2(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
56 static void SPIM_WriteStatusRegister2(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit);
57 static void SPIM_ReadStatusRegister3(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
58 static void SPIM_ReadSecurityRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
59 static int spim_is_write_done(uint32_t u32NBit);
60 static int spim_wait_write_done(uint32_t u32NBit);
61 static void spim_set_write_enable(int isEn, uint32_t u32NBit);
62 static void spim_enable_spansion_quad_mode(int isEn);
63 static void spim_eon_set_qpi_mode(int isEn);
64 static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit);
65 static void SPIM_WriteInPageDataByIo(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
66  uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int isSync);
67 static void SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
68  uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync);
69 
70 
71 static void N_delay(int n)
72 {
73  while (n-- > 0)
74  {
75  __NOP();
76  }
77 }
78 
79 static void SwitchNBitOutput(uint32_t u32NBit)
80 {
81  switch (u32NBit)
82  {
83  case 1UL:
84  SPIM_ENABLE_SING_OUTPUT_MODE(); /* 1-bit, Output. */
85  break;
86 
87  case 2UL:
88  SPIM_ENABLE_DUAL_OUTPUT_MODE(); /* 2-bit, Output. */
89  break;
90 
91  case 4UL:
92  SPIM_ENABLE_QUAD_OUTPUT_MODE(); /* 4-bit, Output. */
93  break;
94 
95  default:
96  break;
97  }
98 }
99 
100 static void SwitchNBitInput(uint32_t u32NBit)
101 {
102  switch (u32NBit)
103  {
104  case 1UL:
105  SPIM_ENABLE_SING_INPUT_MODE(); /* 1-bit, Input. */
106  break;
107 
108  case 2UL:
109  SPIM_ENABLE_DUAL_INPUT_MODE(); /* 2-bit, Input. */
110  break;
111 
112  case 4UL:
113  SPIM_ENABLE_QUAD_INPUT_MODE(); /* 4-bit, Input. */
114  break;
115 
116  default:
117  break;
118  }
119 }
120 
121 
128 static void spim_write(uint8_t pu8TxBuf[], uint32_t u32NTx)
129 {
130  uint32_t buf_idx = 0UL;
131 
132  while (u32NTx)
133  {
134  uint32_t dataNum = 0UL, dataNum2;
135 
136  if (u32NTx >= 16UL)
137  {
138  dataNum = 4UL;
139  }
140  else if (u32NTx >= 12UL)
141  {
142  dataNum = 3UL;
143  }
144  else if (u32NTx >= 8UL)
145  {
146  dataNum = 2UL;
147  }
148  else if (u32NTx >= 4UL)
149  {
150  dataNum = 1UL;
151  }
152 
153  dataNum2 = dataNum;
154  while (dataNum2)
155  {
156  uint32_t tmp;
157 
158  memcpy(&tmp, &pu8TxBuf[buf_idx], 4U);
159  buf_idx += 4UL;
160  u32NTx -= 4UL;
161 
162  dataNum2 --;
163  /* *((__O uint32_t *) &SPIM->TX0 + dataNum2) = tmp; */
164  SPIM->TX[dataNum2] = tmp;
165  }
166 
167  if (dataNum)
168  {
169  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
170  SPIM_SET_DATA_WIDTH(32UL);
171  SPIM_SET_DATA_NUM(dataNum);
172  SPIM_SET_GO();
173  SPIM_WAIT_FREE();
174  }
175 
176  if (u32NTx && (u32NTx < 4UL))
177  {
178  uint32_t rnm, tmp;
179 
180  rnm = u32NTx;
181  memcpy(&tmp, &pu8TxBuf[buf_idx], u32NTx);
182  buf_idx += u32NTx;
183  u32NTx = 0UL;
184  SPIM->TX[0] = tmp;
185 
186  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
187  SPIM_SET_DATA_WIDTH(rnm * 8UL);
188  SPIM_SET_DATA_NUM(1UL);
189  SPIM_SET_GO();
190  SPIM_WAIT_FREE();
191  }
192  }
193 }
194 
201 static void spim_read(uint8_t pu8RxBuf[], uint32_t u32NRx)
202 {
203  uint32_t buf_idx = 0UL;
204 
205  while (u32NRx)
206  {
207  uint32_t dataNum = 0UL; /* number of words */
208 
209  if (u32NRx >= 16UL)
210  {
211  dataNum = 4UL;
212  }
213  else if (u32NRx >= 12UL)
214  {
215  dataNum = 3UL;
216  }
217  else if (u32NRx >= 8UL)
218  {
219  dataNum = 2UL;
220  }
221  else if (u32NRx >= 4UL)
222  {
223  dataNum = 1UL;
224  }
225 
226  if (dataNum)
227  {
228  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
229  SPIM_SET_DATA_WIDTH(32UL);
230  SPIM_SET_DATA_NUM(dataNum);
231  SPIM_SET_GO();
232  SPIM_WAIT_FREE();
233  }
234 
235  while (dataNum)
236  {
237  uint32_t tmp;
238 
239  tmp = SPIM->RX[dataNum-1UL];
240  memcpy(&pu8RxBuf[buf_idx], &tmp, 4U);
241  buf_idx += 4UL;
242  dataNum --;
243  u32NRx -= 4UL;
244  }
245 
246  if (u32NRx && (u32NRx < 4UL))
247  {
248  uint32_t tmp;
249 
250  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
251  SPIM_SET_DATA_WIDTH(u32NRx * 8UL);
252  SPIM_SET_DATA_NUM(1UL);
253  SPIM_SET_GO();
254  SPIM_WAIT_FREE();
255 
256  tmp = SPIM->RX[0];
257  memcpy(&pu8RxBuf[buf_idx], &tmp, u32NRx);
258  buf_idx += u32NRx;
259  u32NRx = 0UL;
260  }
261  }
262 }
263 
271 static void SPIM_ReadStatusRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
272 {
273  uint8_t cmdBuf[] = {OPCODE_RDSR}; /* 1-byte Read Status Register #1 command. */
274 
275  SPIM_SET_SS_EN(1); /* CS activated. */
276  SwitchNBitOutput(u32NBit);
277  spim_write(cmdBuf, sizeof (cmdBuf));
278  SwitchNBitInput(u32NBit);
279  spim_read(dataBuf, u32NRx);
280  SPIM_SET_SS_EN(0); /* CS deactivated. */
281 }
282 
290 static void SPIM_WriteStatusRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
291 {
292  uint8_t cmdBuf[] = {OPCODE_WRSR, 0x00U}; /* 1-byte Write Status Register #1 command + 1-byte data. */
293 
294  cmdBuf[1] = dataBuf[0];
295  SPIM_SET_SS_EN(1); /* CS activated. */
296  SwitchNBitOutput(u32NBit);
297  spim_write(cmdBuf, sizeof (cmdBuf));
298  SPIM_SET_SS_EN(0); /* CS deactivated. */
299 }
300 
308 static void SPIM_ReadStatusRegister2(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
309 {
310  uint8_t cmdBuf[] = {OPCODE_RDSR2}; /* 1-byte Read Status Register #1 command. */
311 
312  SPIM_SET_SS_EN(1); /* CS activated. */
313  SwitchNBitOutput(u32NBit);
314  spim_write(cmdBuf, sizeof (cmdBuf));
315  SwitchNBitInput(u32NBit);
316  spim_read(dataBuf, u32NRx);
317  SPIM_SET_SS_EN(0); /* CS deactivated. */
318 }
319 
328 static void SPIM_WriteStatusRegister2(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
329 {
330  uint8_t cmdBuf[3] = {OPCODE_WRSR, 0U, 0U};
331 
332  cmdBuf[1] = dataBuf[0];
333  cmdBuf[2] = dataBuf[1];
334 
335  SPIM_SET_SS_EN(1); /* CS activated. */
336  SwitchNBitOutput(u32NBit);
337  spim_write(cmdBuf, sizeof (cmdBuf));
338  SPIM_SET_SS_EN(0); /* CS deactivated. */
339 }
340 
341 #if 0 /* not used */
342 
349 static void SPIM_WriteStatusRegister3(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
350 {
351  uint8_t cmdBuf[] = {OPCODE_WRSR3, 0x00U}; /* 1-byte Write Status Register #2 command + 1-byte data. */
352  cmdBuf[1] = dataBuf[0];
353 
354  SPIM_SET_SS_EN(1); /* CS activated. */
355  SwitchNBitOutput(u32NBit);
356  spim_write(cmdBuf, sizeof (cmdBuf));
357  SPIM_SET_SS_EN(0); /* CS deactivated. */
358 }
359 #endif
360 
368 static void SPIM_ReadStatusRegister3(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
369 {
370  uint8_t cmdBuf[] = {OPCODE_RDSR3}; /* 1-byte Read Status Register #1 command. */
371 
372  SPIM_SET_SS_EN(1); /* CS activated. */
373  SwitchNBitOutput(u32NBit);
374  spim_write(cmdBuf, sizeof (cmdBuf));
375  SwitchNBitInput(u32NBit);
376  spim_read(dataBuf, u32NRx);
377  SPIM_SET_SS_EN(0); /* CS deactivated. */
378 }
379 
380 #if 0 /* not used */
381 
388 static void SPIM_WriteSecurityRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
389 {
390  uint8_t cmdBuf[] = {OPCODE_WRSCUR, 0x00U}; /* 1-byte Write Status Register #2 command + 1-byte data. */
391  cmdBuf[1] = dataBuf[0];
392 
393  SPIM_SET_SS_EN(1); /* CS activated. */
394  SwitchNBitOutput(u32NBit);
395  spim_write(cmdBuf, sizeof (cmdBuf));
396  SPIM_SET_SS_EN(0); /* CS deactivated. */
397 }
398 #endif
399 
407 static void SPIM_ReadSecurityRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
408 {
409  uint8_t cmdBuf[] = {OPCODE_RDSCUR}; /* 1-byte Read Status Register #1 command. */
410 
411  SPIM_SET_SS_EN(1); /* CS activated. */
412  SwitchNBitOutput(u32NBit);
413  spim_write(cmdBuf, sizeof (cmdBuf));
414  SwitchNBitInput(u32NBit);
415  spim_read(dataBuf, u32NRx);
416  SPIM_SET_SS_EN(0); /* CS deactivated. */
417 }
418 
423 static int spim_is_write_done(uint32_t u32NBit)
424 {
425  uint8_t status[1];
426  SPIM_ReadStatusRegister(status, sizeof (status), u32NBit);
427  return ! (status[0] & SR_WIP);
428 }
429 
435 static int spim_wait_write_done(uint32_t u32NBit)
436 {
437  uint32_t count;
438  int ret = -1;
439 
440  for (count = 0UL; count < SystemCoreClock/1000UL; count++)
441  {
442  if (spim_is_write_done(u32NBit))
443  {
444  ret = 0;
445  break;
446  }
447  }
448  if (ret != 0)
449  {
450  SPIM_DBGMSG("spim_wait_write_done time-out!!\n");
451  }
452  return ret;
453 }
454 
461 static void spim_set_write_enable(int isEn, uint32_t u32NBit)
462 {
463  uint8_t cmdBuf[] = {0U}; /* 1-byte Write Enable command. */
464  cmdBuf[0] = isEn ? OPCODE_WREN : OPCODE_WRDI;
465 
466  SPIM_SET_SS_EN(1); /* CS activated. */
467  SwitchNBitOutput(u32NBit);
468  spim_write(cmdBuf, sizeof (cmdBuf));
469  SPIM_SET_SS_EN(0); /* CS deactivated. */
470 }
471 
479 uint32_t SPIM_GetSClkFreq(void)
480 {
481  uint32_t clkDiv = SPIM_GET_CLOCK_DIVIDER();
482 
483  return clkDiv ? SystemCoreClock / (clkDiv * 2U) : SystemCoreClock;
484 }
485 
492 int SPIM_InitFlash(int clrWP)
493 {
494  uint8_t idBuf[3];
495  uint8_t cmdBuf[1];
496  uint32_t i;
497  int32_t ret = -1;
498 
500 
501  /*
502  * Because not sure in SPI or QPI mode, do QPI reset and then SPI reset.
503  */
504  /* QPI Reset Enable */
505  cmdBuf[0] = OPCODE_RSTEN;
506  SPIM_SET_SS_EN(1); /* CS activated. */
507  SPIM_ENABLE_QUAD_OUTPUT_MODE(); /* 1-bit, Output. */
508  spim_write(cmdBuf, sizeof (cmdBuf));
509  SPIM_SET_SS_EN(0); /* CS deactivated. */
510 
511  /* QPI Reset */
512  cmdBuf[0] = OPCODE_RST;
513  SPIM_SET_SS_EN(1); /* CS activated. */
514  SPIM_ENABLE_QUAD_OUTPUT_MODE(); /* 1-bit, Output. */
515  spim_write(cmdBuf, sizeof (cmdBuf));
516  SPIM_SET_SS_EN(0); /* CS deactivated. */
517 
518  /* SPI ResetEnable */
519  cmdBuf[0] = OPCODE_RSTEN;
520  SPIM_SET_SS_EN(1); /* CS activated. */
521  SPIM_ENABLE_SING_OUTPUT_MODE(); /* 1-bit, Output. */
522  spim_write(cmdBuf, sizeof (cmdBuf));
523  SPIM_SET_SS_EN(0); /* CS deactivated. */
524 
525  /* SPI Reset */
526  cmdBuf[0] = OPCODE_RST;
527  SPIM_SET_SS_EN(1); /* CS activated. */
528  SPIM_ENABLE_SING_OUTPUT_MODE(); /* 1-bit, Output. */
529  spim_write(cmdBuf, sizeof (cmdBuf));
530  SPIM_SET_SS_EN(0); /* CS deactivated. */
531 
532  if (clrWP)
533  {
534  uint8_t dataBuf[] = {0x00U};
535 
536  spim_set_write_enable(1, 1UL); /* Clear Block Protect. */
537  SPIM_WriteStatusRegister(dataBuf, sizeof (dataBuf), 1U);
538  spim_wait_write_done(1UL);
539  }
540 
541  SPIM_ReadJedecId(idBuf, sizeof (idBuf), 1UL);
542 
543  /* printf("ID: 0x%x, 0x%x, px%x\n", idBuf[0], idBuf[1], idBuf[2]); */
544 
545  for (i = 0UL; i < sizeof(g_Supported_List)/sizeof(g_Supported_List[0]); i++)
546  {
547  if (idBuf[0] == g_Supported_List[i])
548  {
549  ret = 0;
550  }
551  }
552  if (ret != 0)
553  {
554  SPIM_DBGMSG("Flash initialize failed!! 0x%x\n", idBuf[0]);
555  }
556  return ret;
557 }
558 
566 void SPIM_ReadJedecId(uint8_t idBuf[], uint32_t u32NRx, uint32_t u32NBit)
567 {
568  uint8_t cmdBuf[] = { OPCODE_RDID }; /* 1-byte JEDEC ID command. */
569 
570  SPIM_SET_SS_EN(1); /* CS activated. */
571  SwitchNBitOutput(u32NBit);
572  spim_write(cmdBuf, sizeof (cmdBuf));
573  SwitchNBitInput(u32NBit);
574  spim_read(idBuf, u32NRx);
575  SPIM_SET_SS_EN(0); /* CS deactivated. */
576 }
577 
580 static void spim_enable_spansion_quad_mode(int isEn)
581 {
582  uint8_t cmdBuf[3];
583  uint8_t dataBuf[1], status1;
584 
585  cmdBuf[0] = 0x5U; /* Read Status Register-1 */
586 
587  SPIM_SET_SS_EN(1);
588  SwitchNBitOutput(1UL);
589  spim_write(cmdBuf, sizeof (cmdBuf));
590  SwitchNBitInput(1UL);
591  spim_read(dataBuf, sizeof (dataBuf));
592  SPIM_SET_SS_EN(0);
593  /* SPIM_DBGMSG("SR1 = 0x%x\n", dataBuf[0]); */
594 
595  status1 = dataBuf[0];
596 
597  cmdBuf[0] = 0x35U; /* Read Configuration Register-1 */
598 
599  SPIM_SET_SS_EN(1);
600  SwitchNBitOutput(1UL);
601  spim_write(cmdBuf, sizeof (cmdBuf));
602  SwitchNBitInput(1UL);
603  spim_read(dataBuf, sizeof (dataBuf));
604  SPIM_SET_SS_EN(0);
605  /* SPIM_DBGMSG("CR1 = 0x%x\n", dataBuf[0]); */
606 
607  spim_set_write_enable(1, 1UL);
608 
609  cmdBuf[0] = 0x1U; /* Write register */
610  cmdBuf[1] = status1;
611 
612  if (isEn)
613  {
614  cmdBuf[2] = dataBuf[0] | 0x2U; /* set QUAD */
615  }
616  else
617  {
618  cmdBuf[2] = dataBuf[0] & ~0x2U; /* clear QUAD */
619  }
620 
621  SPIM_SET_SS_EN(1);
622  SwitchNBitOutput(1UL);
623  spim_write(cmdBuf, 3UL);
624  SPIM_SET_SS_EN(0);
625 
626  spim_set_write_enable(0, 1UL);
627 
628 
629  cmdBuf[0] = 0x35U; /* Read Configuration Register-1 */
630 
631  SPIM_SET_SS_EN(1);
632  SwitchNBitOutput(1UL);
633  spim_write(cmdBuf, sizeof (cmdBuf));
634  SwitchNBitInput(1UL);
635  spim_read(dataBuf, sizeof (dataBuf));
636  SPIM_SET_SS_EN(0);
637 
638  /* SPIM_DBGMSG("CR1 = 0x%x\n", dataBuf[0]); */
639  N_delay(10000);
640 }
641 
650 void SPIM_SetQuadEnable(int isEn, uint32_t u32NBit)
651 {
652  uint8_t idBuf[3];
653  uint8_t dataBuf[2];
654 
655  SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
656 
657  SPIM_DBGMSG("SPIM_SetQuadEnable - Flash ID is 0x%x\n", idBuf[0]);
658 
659  switch (idBuf[0])
660  {
661  case MFGID_WINBOND: /* Winbond SPI flash */
662  SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
663  SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
664  SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
665  if (isEn)
666  {
667  dataBuf[1] |= SR2_QE;
668  }
669  else
670  {
671  dataBuf[1] &= ~SR2_QE;
672  }
673 
674  spim_set_write_enable(1, u32NBit); /* Write Enable. */
675  SPIM_WriteStatusRegister2(dataBuf, sizeof (dataBuf), u32NBit);
676  spim_wait_write_done(u32NBit);
677 
678  SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
679  SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
680  SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
681  break;
682 
683  case MFGID_MXIC: /* MXIC SPI flash. */
684  case MFGID_EON:
685  case MFGID_ISSI: /* ISSI SPI flash. */
686  spim_set_write_enable(1, u32NBit); /* Write Enable. */
687  dataBuf[0] = isEn ? SR_QE : 0U;
688  SPIM_WriteStatusRegister(dataBuf, sizeof (dataBuf), u32NBit);
689  spim_wait_write_done(u32NBit);
690  break;
691 
692  case MFGID_SPANSION:
693  spim_enable_spansion_quad_mode(isEn);
694  break;
695 
696  default:
697  break;
698  }
699 }
700 
706 static void spim_eon_set_qpi_mode(int isEn)
707 {
708  uint8_t cmdBuf[1]; /* 1-byte command. */
709 
710  uint8_t status[1];
711  SPIM_ReadStatusRegister(status, sizeof (status), 1UL);
712  SPIM_DBGMSG("Status: 0x%x\n", status[0]);
713 
714  if (isEn) /* Assume in SPI mode. */
715  {
716  cmdBuf[0] = OPCODE_ENQPI;
717 
718  SPIM_SET_SS_EN(1); /* CS activated. */
719  SwitchNBitOutput(1UL);
720  spim_write(cmdBuf, sizeof (cmdBuf));
721  SPIM_SET_SS_EN(0); /* CS deactivated. */
722  }
723  else /* Assume in QPI mode. */
724  {
725  cmdBuf[0] = OPCODE_EXQPI;
726 
727  SPIM_SET_SS_EN(1); /* CS activated. */
728  SwitchNBitOutput(4UL);
729  spim_write(cmdBuf, sizeof (cmdBuf));
730  SPIM_SET_SS_EN(0); /* CS deactivated. */
731  }
732 
733  SPIM_ReadStatusRegister(status, sizeof (status), 1UL);
734  SPIM_DBGMSG("Status: 0x%x\n", status[0]);
735 }
736 
737 
738 static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit)
739 {
740  uint8_t cmdBuf[2];
741  uint8_t dataBuf[1];
742 
743  cmdBuf[0] = OPCODE_BRRD;
744  SPIM_SET_SS_EN(1); /* CS activated. */
745  SwitchNBitOutput(u32NBit);
746  spim_write(cmdBuf, 1UL);
747  SwitchNBitInput(1UL);
748  spim_read(dataBuf, 1UL);
749  SPIM_SET_SS_EN(0); /* CS deactivated. */
750 
751  SPIM_DBGMSG("Bank Address register= 0x%x\n", dataBuf[0]);
752 
753  cmdBuf[0] = OPCODE_BRWR;
754 
755  if (isEn)
756  {
757  cmdBuf[1] = dataBuf[0] | 0x80U; /* set EXTADD */
758  }
759  else
760  {
761  cmdBuf[1] = dataBuf[0] & ~0x80U; /* clear EXTADD */
762  }
763 
764  SPIM_SET_SS_EN(1); /* CS activated. */
765  SwitchNBitOutput(1UL);
766  spim_write(cmdBuf, 2UL);
767  SPIM_SET_SS_EN(0); /* CS deactivated. */
768 }
769 
777 int SPIM_Is4ByteModeEnable(uint32_t u32NBit)
778 {
779  int isEn = 0;
780  int isSupt = 0;
781  uint8_t idBuf[3];
782  uint8_t dataBuf[1];
783 
784  SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
785 
786  /* Based on Flash size, check if 4-byte address mode is supported. */
787  switch (idBuf[0])
788  {
789  case MFGID_WINBOND:
790  case MFGID_MXIC:
791  case MFGID_EON:
792  isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
793  break;
794 
795  case MFGID_ISSI:
796  isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
797  break;
798 
799  default:
800  break;
801  }
802 
803  if (isSupt != 0)
804  {
805  if (idBuf[0] == MFGID_WINBOND)
806  {
807  /* Winbond SPI flash. */
808  SPIM_ReadStatusRegister3(dataBuf, sizeof (dataBuf), u32NBit);
809  isEn = !! (dataBuf[0] & SR3_ADR);
810  }
811  else if ((idBuf[0] == MFGID_MXIC) || (idBuf[0] ==MFGID_EON))
812  {
813  /* MXIC/EON SPI flash. */
814  SPIM_ReadSecurityRegister(dataBuf, sizeof (dataBuf), u32NBit);
815  isEn = !! (dataBuf[0] & SCUR_4BYTE);
816  }
817  }
818 
819  return isEn;
820 }
821 
832 int SPIM_Enable_4Bytes_Mode(int isEn, uint32_t u32NBit)
833 {
834  int isSupt = 0L, ret = -1;
835  uint8_t idBuf[3];
836  uint8_t cmdBuf[1]; /* 1-byte Enter/Exit 4-Byte Mode command. */
837 
838  SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
839 
840  /* Based on Flash size, check if 4-byte address mode is supported. */
841  switch (idBuf[0])
842  {
843  case MFGID_WINBOND:
844  case MFGID_MXIC:
845  case MFGID_EON:
846  isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
847  break;
848 
849  case MFGID_ISSI:
850  isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
851  break;
852 
853  case MFGID_SPANSION:
854  SPIM_SPANSION_4Bytes_Enable(isEn, u32NBit);
855  isSupt = 1L;
856  ret = 0L;
857  break;
858 
859  default:
860  break;
861  }
862 
863  if ((isSupt) && (idBuf[0] != MFGID_SPANSION))
864  {
865  cmdBuf[0] = isEn ? OPCODE_EN4B : OPCODE_EX4B;
866 
867  SPIM_SET_SS_EN(1); /* CS activated. */
868  SwitchNBitOutput(u32NBit);
869  spim_write(cmdBuf, sizeof (cmdBuf));
870  SPIM_SET_SS_EN(0); /* CS deactivated. */
871 
872  /*
873  * FIXME: Per test, 4BYTE Indicator bit doesn't set after EN4B, which
874  * doesn't match spec(MX25L25635E), so skip the check below.
875  */
876  if (idBuf[0] != MFGID_MXIC)
877  {
878  if (isEn)
879  {
880  while (! SPIM_Is4ByteModeEnable(u32NBit)) { }
881  }
882  else
883  {
884  while (SPIM_Is4ByteModeEnable(u32NBit)) { }
885  }
886  }
887  ret = 0;
888  }
889  return ret;
890 }
891 
892 
893 void SPIM_WinbondUnlock(uint32_t u32NBit)
894 {
895  uint8_t idBuf[3];
896  uint8_t dataBuf[4];
897 
898  SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
899 
900  if ((idBuf[0] != MFGID_WINBOND) || (idBuf[1] != 0x40) || (idBuf[2] != 0x16))
901  {
902  SPIM_DBGMSG("SPIM_WinbondUnlock - Not W25Q32, do nothing.\n");
903  return;
904  }
905 
906  SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
907  SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
908  SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
909  dataBuf[1] &= ~0x40; /* clear Status Register-1 SEC bit */
910 
911  spim_set_write_enable(1, u32NBit); /* Write Enable. */
912  SPIM_WriteStatusRegister2(dataBuf, sizeof (dataBuf), u32NBit);
913  spim_wait_write_done(u32NBit);
914 
915  SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
916  SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
917  SPIM_DBGMSG("Status Register (after unlock): 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
918 }
919 
926 void SPIM_ChipErase(uint32_t u32NBit, int isSync)
927 {
928  uint8_t cmdBuf[] = { OPCODE_CHIP_ERASE }; /* 1-byte Chip Erase command. */
929 
930  spim_set_write_enable(1, u32NBit); /* Write Enable. */
931 
932  SPIM_SET_SS_EN(1); /* CS activated. */
933  SwitchNBitOutput(u32NBit);
934  spim_write(cmdBuf, sizeof (cmdBuf));
935  SPIM_SET_SS_EN(0); /* CS deactivated. */
936 
937  if (isSync)
938  {
939  spim_wait_write_done(u32NBit);
940  }
941 }
942 
943 
953 void SPIM_EraseBlock(uint32_t u32Addr, int is4ByteAddr, uint8_t u8ErsCmd, uint32_t u32NBit, int isSync)
954 {
955  uint8_t cmdBuf[16];
956  uint32_t buf_idx = 0UL;
957 
958  spim_set_write_enable(1, u32NBit); /* Write Enable. */
959 
960  cmdBuf[buf_idx++] = u8ErsCmd;
961 
962  if (is4ByteAddr)
963  {
964  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
965  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
966  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
967  cmdBuf[buf_idx++] = (uint8_t) (u32Addr & 0xFFUL);
968  }
969  else
970  {
971  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
972  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
973  cmdBuf[buf_idx++] = (uint8_t) (u32Addr & 0xFFUL);
974  }
975 
976  SPIM_SET_SS_EN(1); /* CS activated. */
977  SwitchNBitOutput(u32NBit);
978  spim_write(cmdBuf, buf_idx);
979  SPIM_SET_SS_EN(0); /* CS deactivated. */
980 
981  if (isSync)
982  {
983  spim_wait_write_done(u32NBit);
984  }
985 }
986 
987 
1003 static void SPIM_WriteInPageDataByIo(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1004  uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int isSync)
1005 {
1006  uint8_t cmdBuf[16];
1007  uint32_t buf_idx;
1008 
1009  spim_set_write_enable(1, u32NBitCmd); /* Write Enable. */
1010 
1011  SPIM_SET_SS_EN(1); /* CS activated. */
1012 
1013  SwitchNBitOutput(u32NBitCmd);
1014  cmdBuf[0] = wrCmd;
1015  spim_write(cmdBuf, 1UL); /* Write out command. */
1016 
1017  buf_idx = 0UL;
1018  if (is4ByteAddr)
1019  {
1020  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1021  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1022  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1023  cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1024  }
1025  else
1026  {
1027  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1028  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1029  cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1030  }
1031 
1032  SwitchNBitOutput(u32NBitAddr);
1033  spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
1034 
1035  SwitchNBitOutput(u32NBitDat);
1036  spim_write(pu8TxBuf, u32NTx); /* Write out data. */
1037 
1038  SPIM_SET_SS_EN(0); /* CS deactivated. */
1039 
1040  if (isSync)
1041  {
1042  spim_wait_write_done(u32NBitCmd);
1043  }
1044 }
1045 
1056 static void SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
1057  uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync)
1058 {
1059  if ((wrCmd == CMD_QUAD_PAGE_PROGRAM_WINBOND) ||
1060  (wrCmd == CMD_QUAD_PAGE_PROGRAM_MXIC))
1061  {
1062  SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
1063  }
1064  else if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1065  {
1066  SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
1067  spim_eon_set_qpi_mode(1); /* Enter QPI mode. */
1068  }
1069 
1070  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEWRITE);/* Switch to Page Write mode. */
1071  SPIM_SET_SPIM_MODE(wrCmd); /* SPIM mode. */
1072  SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
1073 
1074  SPIM->SRAMADDR = (uint32_t) pu8TxBuf; /* SRAM u32Address. */
1075  SPIM->DMACNT = u32NTx; /* Transfer length. */
1076  SPIM->FADDR = u32Addr; /* Flash u32Address.*/
1077  SPIM_SET_GO(); /* Go. */
1078 
1079  if (isSync)
1080  {
1081  SPIM_WAIT_FREE();
1082  }
1083 
1084  if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1085  {
1086  spim_eon_set_qpi_mode(0); /* Exit QPI mode. */
1087  }
1088 }
1089 
1104 void SPIM_IO_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1105  uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat)
1106 {
1107  uint32_t pageOffset, toWr;
1108  uint32_t buf_idx = 0UL;
1109 
1110  pageOffset = u32Addr % 256UL;
1111 
1112  if ((pageOffset + u32NTx) <= 256UL) /* Do all the bytes fit onto one page ? */
1113  {
1114  SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, u32NTx, &pu8TxBuf[buf_idx],
1115  wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1116  }
1117  else
1118  {
1119  toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
1120 
1121  SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1122  wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1123  u32Addr += toWr; /* Advance indicator. */
1124  u32NTx -= toWr;
1125  buf_idx += toWr;
1126 
1127  while (u32NTx)
1128  {
1129  toWr = 256UL;
1130  if (toWr > u32NTx)
1131  {
1132  toWr = u32NTx;
1133  }
1134 
1135  SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1136  wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1137  u32Addr += toWr; /* Advance indicator. */
1138  u32NTx -= toWr;
1139  buf_idx += toWr;
1140  }
1141  }
1142 }
1143 
1157 void SPIM_IO_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[], uint8_t rdCmd,
1158  uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int u32NDummy)
1159 {
1160  uint8_t cmdBuf[16];
1161  uint32_t buf_idx;
1162 
1163  SPIM_SET_SS_EN(1); /* CS activated. */
1164 
1165  cmdBuf[0] = rdCmd;
1166  SwitchNBitOutput(u32NBitCmd);
1167  spim_write(cmdBuf, 1UL); /* Write out command. */
1168 
1169  buf_idx = 0UL;
1170  if (is4ByteAddr)
1171  {
1172  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1173  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1174  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1175  cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1176  }
1177  else
1178  {
1179  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1180  cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1181  cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1182  }
1183  SwitchNBitOutput(u32NBitAddr);
1184  spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
1185 
1186  buf_idx = 0UL;
1187  while (u32NDummy --)
1188  {
1189  cmdBuf[buf_idx++] = 0x00U;
1190  }
1191 
1192  /* Same bit mode as above. */
1193  spim_write(cmdBuf, buf_idx); /* Write out dummy bytes. */
1194 
1195  SwitchNBitInput(u32NBitDat);
1196  spim_read(pu8RxBuf, u32NRx); /* Read back data. */
1197 
1198  SPIM_SET_SS_EN(0); /* CS deactivated. */
1199 }
1200 
1210 void SPIM_DMA_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint32_t wrCmd)
1211 {
1212  uint32_t pageOffset, toWr;
1213  uint32_t buf_idx = 0UL;
1214 
1215  pageOffset = u32Addr % 256UL;
1216 
1217  if ((pageOffset + u32NTx) <= 256UL)
1218  {
1219  /* Do all the bytes fit onto one page ? */
1220  SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, u32NTx, pu8TxBuf, wrCmd, 1);
1221  }
1222  else
1223  {
1224  toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
1225 
1226  SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1227 
1228  u32Addr += toWr; /* Advance indicator. */
1229  u32NTx -= toWr;
1230  buf_idx += toWr;
1231 
1232  while (u32NTx)
1233  {
1234  toWr = 256UL;
1235  if (toWr > u32NTx)
1236  {
1237  toWr = u32NTx;
1238  }
1239 
1240  SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1241 
1242  u32Addr += toWr; /* Advance indicator. */
1243  u32NTx -= toWr;
1244  buf_idx += toWr;
1245  }
1246  }
1247 }
1248 
1259 void SPIM_DMA_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[],
1260  uint32_t u32RdCmd, int isSync)
1261 {
1262  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEREAD); /* Switch to Page Read mode. */
1263  SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
1264  SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
1265 
1266  SPIM->SRAMADDR = (uint32_t) pu8RxBuf; /* SRAM u32Address. */
1267  SPIM->DMACNT = u32NRx; /* Transfer length. */
1268  SPIM->FADDR = u32Addr; /* Flash u32Address.*/
1269  SPIM_SET_GO(); /* Go. */
1270 
1271  if (isSync)
1272  {
1273  SPIM_WAIT_FREE(); /* Wait for DMA done. */
1274  }
1275 }
1276 
1284 void SPIM_EnterDirectMapMode(int is4ByteAddr, uint32_t u32RdCmd, uint32_t u32IdleIntvl)
1285 {
1286  SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-byte u32Address. */
1287  SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
1288  SPIM_SET_IDL_INTVL(u32IdleIntvl); /* Idle interval. */
1289  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_DIRECTMAP); /* Switch to Direct Map mode. */
1290 }
1291 
1297 {
1298  SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch back to Normal mode. */
1299 }
1300 
1301  /* end of group SPIM_EXPORTED_FUNCTIONS */
1303  /* end of group SPIM_Driver */
1305  /* end of group Standard_Driver */
1307 
1308 /*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/
#define CMD_QUAD_PAGE_PROGRAM_MXIC
Definition: spim.h:55
void SPIM_EnterDirectMapMode(int is4ByteAddr, uint32_t u32RdCmd, uint32_t u32IdleIntvl)
Enter Direct Map mode.
Definition: spim.c:1284
#define SPIM_SET_DATA_NUM(x)
Definition: spim.h:229
static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit)
Definition: spim.c:738
#define SPIM_WAIT_FREE()
Definition: spim.h:357
#define SPIM_SET_4BYTE_ADDR_EN(x)
Definition: spim.h:177
#define SPIM_GET_CLOCK_DIVIDER()
Definition: spim.h:458
#define SPIM_CTL0_OPMODE_PAGEREAD
Definition: spim.h:49
void SPIM_IO_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd, uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat)
Write data to SPI Flash by sending commands manually (I/O mode).
Definition: spim.c:1104
NuMicro peripheral access layer header file.
#define SPIM_ENABLE_SING_INPUT_MODE()
Definition: spim.h:245
#define SPIM_SET_SS_EN(x)
Definition: spim.h:408
#define SPIM_SET_IDL_INTVL(x)
Definition: spim.h:433
void SPIM_ExitDirectMapMode(void)
Exit Direct Map mode.
Definition: spim.c:1296
#define SPIM_ENABLE_DUAL_OUTPUT_MODE()
Definition: spim.h:272
uint32_t SystemCoreClock
Definition: system_M480.c:21
#define SPIM_CTL0_OPMODE_IO
Definition: spim.h:47
#define SPIM_ENABLE_QUAD_INPUT_MODE()
Definition: spim.h:281
#define SPIM_SET_OPMODE(x)
Definition: spim.h:315
int SPIM_InitFlash(int clrWP)
Initialize SPIM flash.
Definition: spim.c:492
int SPIM_Is4ByteModeEnable(uint32_t u32NBit)
int SPIM_Enable_4Bytes_Mode(int isEn, uint32_t u32NBit)
Enter/Exit 4-byte address mode.
Definition: spim.c:832
void SPIM_DMA_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint32_t wrCmd)
Write data to SPI Flash by Page Write mode.
Definition: spim.c:1210
#define SPIM_CTL0_OPMODE_PAGEWRITE
Definition: spim.h:48
#define SPIM_SET_SPIM_MODE(x)
Definition: spim.h:330
void SPIM_SetQuadEnable(int isEn, uint32_t u32NBit)
Set Quad Enable/disable.
Definition: spim.c:650
void SPIM_ChipErase(uint32_t u32NBit, int isSync)
Erase whole chip.
Definition: spim.c:926
#define SPIM_ENABLE_SING_OUTPUT_MODE()
Definition: spim.h:254
#define SPIM_SET_GO()
Definition: spim.h:345
static void spim_eon_set_qpi_mode(int isEn)
Enter/exit QPI mode.
Definition: spim.c:706
#define CMD_QUAD_PAGE_PROGRAM_WINBOND
Definition: spim.h:54
#define CMD_QUAD_PAGE_PROGRAM_EON
Definition: spim.h:56
#define SPIM_CTL0_OPMODE_DIRECTMAP
Definition: spim.h:50
void SPIM_DMA_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[], uint32_t u32RdCmd, int isSync)
Read data from SPI Flash by Page Read mode.
Definition: spim.c:1259
void SPIM_IO_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[], uint8_t rdCmd, uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int u32NDummy)
Read data from SPI Flash by sending commands manually (I/O mode).
Definition: spim.c:1157
void SPIM_EraseBlock(uint32_t u32Addr, int is4ByteAddr, uint8_t u8ErsCmd, uint32_t u32NBit, int isSync)
Erase one block.
Definition: spim.c:953
uint32_t SPIM_GetSClkFreq(void)
Get SPIM serial clock.
Definition: spim.c:479
void SPIM_WinbondUnlock(uint32_t u32NBit)
Definition: spim.c:893
#define SPIM
Definition: M480.h:448
#define SPIM_ENABLE_DUAL_INPUT_MODE()
Definition: spim.h:263
#define SPIM_SET_SS_ACTLVL(x)
Definition: spim.h:424
void SPIM_ReadJedecId(uint8_t idBuf[], uint32_t u32NRx, uint32_t u32NBit)
Issue JEDEC ID command.
Definition: spim.c:566
#define SPIM_ENABLE_QUAD_OUTPUT_MODE()
Definition: spim.h:290
#define SPIM_SET_DATA_WIDTH(x)
Definition: spim.h:213