M480 BSP V3.0.7000
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
39static volatile uint8_t g_Supported_List[] =
40{
41 MFGID_WINBOND,
42 MFGID_MXIC,
43 MFGID_EON,
44 MFGID_ISSI,
45 MFGID_SPANSION
46};
47
48static void N_delay(int n);
49static void SwitchNBitOutput(uint32_t u32NBit);
50static void SwitchNBitInput(uint32_t u32NBit);
51static void spim_write(uint8_t pu8TxBuf[], uint32_t u32NTx);
52static void spim_read(uint8_t pu8RxBuf[], uint32_t u32NRx);
53static void SPIM_WriteStatusRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit);
54static void SPIM_ReadStatusRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
55static void SPIM_ReadStatusRegister2(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
56static void SPIM_WriteStatusRegister2(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit);
57static void SPIM_ReadStatusRegister3(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
58static void SPIM_ReadSecurityRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
59static int spim_is_write_done(uint32_t u32NBit);
60static int spim_wait_write_done(uint32_t u32NBit);
61static void spim_set_write_enable(int isEn, uint32_t u32NBit);
62static void spim_enable_spansion_quad_mode(int isEn);
63static void spim_eon_set_qpi_mode(int isEn);
64static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit);
65static 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);
67static void SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
68 uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync);
69
70
71static void N_delay(int n)
72{
73 while (n-- > 0)
74 {
75 __NOP();
76 }
77}
78
79static 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
100static 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
128static 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. */
171 SPIM_SET_DATA_NUM(dataNum);
172 SPIM_SET_GO();
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);
189 SPIM_SET_GO();
191 }
192 }
193}
194
201static 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. */
230 SPIM_SET_DATA_NUM(dataNum);
231 SPIM_SET_GO();
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);
253 SPIM_SET_GO();
255
256 tmp = SPIM->RX[0];
257 memcpy(&pu8RxBuf[buf_idx], &tmp, u32NRx);
258 buf_idx += u32NRx;
259 u32NRx = 0UL;
260 }
261 }
262}
263
271static 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
290static 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
308static 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
328static 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 */
349static 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
368static 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 */
388static 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
407static 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
423static 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
435static int spim_wait_write_done(uint32_t u32NBit)
436{
437 uint32_t count;
438 int ret = -1;
439
440 for (count = 0UL; count < SystemCoreClock / 10UL; 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
461static 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
479uint32_t SPIM_GetSClkFreq(void)
480{
481 uint32_t clkDiv = SPIM_GET_CLOCK_DIVIDER();
482
483 return clkDiv ? SystemCoreClock / (clkDiv * 2U) : SystemCoreClock;
484}
485
492int 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
566void 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
580static 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
588 SwitchNBitOutput(1UL);
589 spim_write(cmdBuf, sizeof (cmdBuf));
590 SwitchNBitInput(1UL);
591 spim_read(dataBuf, sizeof (dataBuf));
593 /* SPIM_DBGMSG("SR1 = 0x%x\n", dataBuf[0]); */
594
595 status1 = dataBuf[0];
596
597 cmdBuf[0] = 0x35U; /* Read Configuration Register-1 */
598
600 SwitchNBitOutput(1UL);
601 spim_write(cmdBuf, sizeof (cmdBuf));
602 SwitchNBitInput(1UL);
603 spim_read(dataBuf, sizeof (dataBuf));
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
622 SwitchNBitOutput(1UL);
623 spim_write(cmdBuf, 3UL);
625
626 spim_set_write_enable(0, 1UL);
627
628
629 cmdBuf[0] = 0x35U; /* Read Configuration Register-1 */
630
632 SwitchNBitOutput(1UL);
633 spim_write(cmdBuf, sizeof (cmdBuf));
634 SwitchNBitInput(1UL);
635 spim_read(dataBuf, sizeof (dataBuf));
637
638 /* SPIM_DBGMSG("CR1 = 0x%x\n", dataBuf[0]); */
639 N_delay(10000);
640}
641
650void 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 if (dataBuf[1] & SR2_QE)
668 return;
669 else
670 dataBuf[1] |= SR2_QE;
671 }
672 else
673 {
674 if ((dataBuf[1] & SR2_QE) == 0)
675 return;
676 else
677 dataBuf[1] &= ~SR2_QE;
678 }
679
680 spim_set_write_enable(1, u32NBit); /* Write Enable. */
681 SPIM_WriteStatusRegister2(dataBuf, sizeof (dataBuf), u32NBit);
682 spim_wait_write_done(u32NBit);
683
684 SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
685 SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
686 SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
687 break;
688
689 case MFGID_MXIC: /* MXIC SPI flash. */
690 case MFGID_EON:
691 case MFGID_ISSI: /* ISSI SPI flash. */
692 spim_set_write_enable(1, u32NBit); /* Write Enable. */
693 dataBuf[0] = isEn ? SR_QE : 0U;
694 SPIM_WriteStatusRegister(dataBuf, sizeof (dataBuf), u32NBit);
695 spim_wait_write_done(u32NBit);
696 break;
697
698 case MFGID_SPANSION:
699 spim_enable_spansion_quad_mode(isEn);
700 break;
701
702 default:
703 break;
704 }
705}
706
712static void spim_eon_set_qpi_mode(int isEn)
713{
714 uint8_t cmdBuf[1]; /* 1-byte command. */
715
716 uint8_t status[1];
717 SPIM_ReadStatusRegister(status, sizeof (status), 1UL);
718 SPIM_DBGMSG("Status: 0x%x\n", status[0]);
719
720 if (isEn) /* Assume in SPI mode. */
721 {
722 cmdBuf[0] = OPCODE_ENQPI;
723
724 SPIM_SET_SS_EN(1); /* CS activated. */
725 SwitchNBitOutput(1UL);
726 spim_write(cmdBuf, sizeof (cmdBuf));
727 SPIM_SET_SS_EN(0); /* CS deactivated. */
728 }
729 else /* Assume in QPI mode. */
730 {
731 cmdBuf[0] = OPCODE_EXQPI;
732
733 SPIM_SET_SS_EN(1); /* CS activated. */
734 SwitchNBitOutput(4UL);
735 spim_write(cmdBuf, sizeof (cmdBuf));
736 SPIM_SET_SS_EN(0); /* CS deactivated. */
737 }
738
739 SPIM_ReadStatusRegister(status, sizeof (status), 1UL);
740 SPIM_DBGMSG("Status: 0x%x\n", status[0]);
741}
742
743
744static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit)
745{
746 uint8_t cmdBuf[2];
747 uint8_t dataBuf[1];
748
749 cmdBuf[0] = OPCODE_BRRD;
750 SPIM_SET_SS_EN(1); /* CS activated. */
751 SwitchNBitOutput(u32NBit);
752 spim_write(cmdBuf, 1UL);
753 SwitchNBitInput(1UL);
754 spim_read(dataBuf, 1UL);
755 SPIM_SET_SS_EN(0); /* CS deactivated. */
756
757 SPIM_DBGMSG("Bank Address register= 0x%x\n", dataBuf[0]);
758
759 cmdBuf[0] = OPCODE_BRWR;
760
761 if (isEn)
762 {
763 cmdBuf[1] = dataBuf[0] | 0x80U; /* set EXTADD */
764 }
765 else
766 {
767 cmdBuf[1] = dataBuf[0] & ~0x80U; /* clear EXTADD */
768 }
769
770 SPIM_SET_SS_EN(1); /* CS activated. */
771 SwitchNBitOutput(1UL);
772 spim_write(cmdBuf, 2UL);
773 SPIM_SET_SS_EN(0); /* CS deactivated. */
774}
775
783int SPIM_Is4ByteModeEnable(uint32_t u32NBit)
784{
785 int isEn = 0;
786 int isSupt = 0;
787 uint8_t idBuf[3];
788 uint8_t dataBuf[1];
789
790 SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
791
792 /* Based on Flash size, check if 4-byte address mode is supported. */
793 switch (idBuf[0])
794 {
795 case MFGID_WINBOND:
796 case MFGID_MXIC:
797 case MFGID_EON:
798 isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
799 break;
800
801 case MFGID_ISSI:
802 isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
803 break;
804
805 default:
806 break;
807 }
808
809 if (isSupt != 0)
810 {
811 if (idBuf[0] == MFGID_WINBOND)
812 {
813 /* Winbond SPI flash. */
814 SPIM_ReadStatusRegister3(dataBuf, sizeof (dataBuf), u32NBit);
815 isEn = !! (dataBuf[0] & SR3_ADR);
816 }
817 else if ((idBuf[0] == MFGID_MXIC) || (idBuf[0] ==MFGID_EON))
818 {
819 /* MXIC/EON SPI flash. */
820 SPIM_ReadSecurityRegister(dataBuf, sizeof (dataBuf), u32NBit);
821 isEn = !! (dataBuf[0] & SCUR_4BYTE);
822 }
823 }
824
825 return isEn;
826}
827
838int SPIM_Enable_4Bytes_Mode(int isEn, uint32_t u32NBit)
839{
840 int isSupt = 0L, ret = -1;
841 uint8_t idBuf[3];
842 uint8_t cmdBuf[1]; /* 1-byte Enter/Exit 4-Byte Mode command. */
843 int32_t tout;
844
845 SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
846
847 /* Based on Flash size, check if 4-byte address mode is supported. */
848 switch (idBuf[0])
849 {
850 case MFGID_WINBOND:
851 case MFGID_MXIC:
852 case MFGID_EON:
853 isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
854 break;
855
856 case MFGID_ISSI:
857 isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
858 break;
859
860 case MFGID_SPANSION:
861 SPIM_SPANSION_4Bytes_Enable(isEn, u32NBit);
862 isSupt = 1L;
863 ret = 0L;
864 break;
865
866 default:
867 break;
868 }
869
870 if ((isSupt) && (idBuf[0] != MFGID_SPANSION))
871 {
872 cmdBuf[0] = isEn ? OPCODE_EN4B : OPCODE_EX4B;
873
874 SPIM_SET_SS_EN(1); /* CS activated. */
875 SwitchNBitOutput(u32NBit);
876 spim_write(cmdBuf, sizeof (cmdBuf));
877 SPIM_SET_SS_EN(0); /* CS deactivated. */
878
879 /*
880 * FIXME: Per test, 4BYTE Indicator bit doesn't set after EN4B, which
881 * doesn't match spec(MX25L25635E), so skip the check below.
882 */
883 ret = 0;
884 if (idBuf[0] != MFGID_MXIC)
885 {
886 /*
887 * About over 100 instrucsions executed, just want to give
888 * a time-out about 1 seconds to avoid infinite loop
889 */
890 tout = (SystemCoreClock)/100;
891
892 if (isEn)
893 {
894 while ((tout-- > 0) && !SPIM_Is4ByteModeEnable(u32NBit)) { }
895 }
896 else
897 {
898 while ((tout-- > 0) && SPIM_Is4ByteModeEnable(u32NBit)) { }
899 }
900 if (tout <= 0)
901 ret = -1;
902 }
903 }
904 return ret;
905}
906
907
908void SPIM_WinbondUnlock(uint32_t u32NBit)
909{
910 uint8_t idBuf[3];
911 uint8_t dataBuf[4];
912
913 SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
914
915 if ((idBuf[0] != MFGID_WINBOND) || (idBuf[1] != 0x40) || (idBuf[2] != 0x16))
916 {
917 SPIM_DBGMSG("SPIM_WinbondUnlock - Not W25Q32, do nothing.\n");
918 return;
919 }
920
921 SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
922 SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
923 SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
924 dataBuf[1] &= ~0x40; /* clear Status Register-1 SEC bit */
925
926 spim_set_write_enable(1, u32NBit); /* Write Enable. */
927 SPIM_WriteStatusRegister2(dataBuf, sizeof (dataBuf), u32NBit);
928 spim_wait_write_done(u32NBit);
929
930 SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
931 SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
932 SPIM_DBGMSG("Status Register (after unlock): 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
933}
934
941void SPIM_ChipErase(uint32_t u32NBit, int isSync)
942{
943 uint8_t cmdBuf[] = { OPCODE_CHIP_ERASE }; /* 1-byte Chip Erase command. */
944
945 spim_set_write_enable(1, u32NBit); /* Write Enable. */
946
947 SPIM_SET_SS_EN(1); /* CS activated. */
948 SwitchNBitOutput(u32NBit);
949 spim_write(cmdBuf, sizeof (cmdBuf));
950 SPIM_SET_SS_EN(0); /* CS deactivated. */
951
952 if (isSync)
953 {
954 spim_wait_write_done(u32NBit);
955 }
956}
957
958
968void SPIM_EraseBlock(uint32_t u32Addr, int is4ByteAddr, uint8_t u8ErsCmd, uint32_t u32NBit, int isSync)
969{
970 uint8_t cmdBuf[16];
971 uint32_t buf_idx = 0UL;
972
973 spim_set_write_enable(1, u32NBit); /* Write Enable. */
974
975 cmdBuf[buf_idx++] = u8ErsCmd;
976
977 if (is4ByteAddr)
978 {
979 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
980 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
981 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
982 cmdBuf[buf_idx++] = (uint8_t) (u32Addr & 0xFFUL);
983 }
984 else
985 {
986 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
987 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
988 cmdBuf[buf_idx++] = (uint8_t) (u32Addr & 0xFFUL);
989 }
990
991 SPIM_SET_SS_EN(1); /* CS activated. */
992 SwitchNBitOutput(u32NBit);
993 spim_write(cmdBuf, buf_idx);
994 SPIM_SET_SS_EN(0); /* CS deactivated. */
995
996 if (isSync)
997 {
998 spim_wait_write_done(u32NBit);
999 }
1000}
1001
1002
1018static void SPIM_WriteInPageDataByIo(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1019 uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int isSync)
1020{
1021 uint8_t cmdBuf[16];
1022 uint32_t buf_idx;
1023
1024 spim_set_write_enable(1, u32NBitCmd); /* Write Enable. */
1025
1026 SPIM_SET_SS_EN(1); /* CS activated. */
1027
1028 SwitchNBitOutput(u32NBitCmd);
1029 cmdBuf[0] = wrCmd;
1030 spim_write(cmdBuf, 1UL); /* Write out command. */
1031
1032 buf_idx = 0UL;
1033 if (is4ByteAddr)
1034 {
1035 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1036 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1037 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1038 cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1039 }
1040 else
1041 {
1042 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1043 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1044 cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1045 }
1046
1047 SwitchNBitOutput(u32NBitAddr);
1048 spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
1049
1050 SwitchNBitOutput(u32NBitDat);
1051 spim_write(pu8TxBuf, u32NTx); /* Write out data. */
1052
1053 SPIM_SET_SS_EN(0); /* CS deactivated. */
1054
1055 if (isSync)
1056 {
1057 spim_wait_write_done(u32NBitCmd);
1058 }
1059}
1060
1071static void SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
1072 uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync)
1073{
1074 if ((wrCmd == CMD_QUAD_PAGE_PROGRAM_WINBOND) ||
1075 (wrCmd == CMD_QUAD_PAGE_PROGRAM_MXIC))
1076 {
1077 SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
1078 }
1079 else if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1080 {
1081 SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
1082 spim_eon_set_qpi_mode(1); /* Enter QPI mode. */
1083 }
1084
1085 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEWRITE);/* Switch to Page Write mode. */
1086 SPIM_SET_SPIM_MODE(wrCmd); /* SPIM mode. */
1087 SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
1088
1089 SPIM->SRAMADDR = (uint32_t) pu8TxBuf; /* SRAM u32Address. */
1090 SPIM->DMACNT = u32NTx; /* Transfer length. */
1091 SPIM->FADDR = u32Addr; /* Flash u32Address.*/
1092 SPIM_SET_GO(); /* Go. */
1093
1094 if (isSync)
1095 {
1097 }
1098
1099 if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1100 {
1101 spim_eon_set_qpi_mode(0); /* Exit QPI mode. */
1102 }
1103}
1104
1119void SPIM_IO_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1120 uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat)
1121{
1122 uint32_t pageOffset, toWr;
1123 uint32_t buf_idx = 0UL;
1124
1125 pageOffset = u32Addr % 256UL;
1126
1127 if ((pageOffset + u32NTx) <= 256UL) /* Do all the bytes fit onto one page ? */
1128 {
1129 SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, u32NTx, &pu8TxBuf[buf_idx],
1130 wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1131 }
1132 else
1133 {
1134 toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
1135
1136 SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1137 wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1138 u32Addr += toWr; /* Advance indicator. */
1139 u32NTx -= toWr;
1140 buf_idx += toWr;
1141
1142 while (u32NTx)
1143 {
1144 toWr = 256UL;
1145 if (toWr > u32NTx)
1146 {
1147 toWr = u32NTx;
1148 }
1149
1150 SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1151 wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1152 u32Addr += toWr; /* Advance indicator. */
1153 u32NTx -= toWr;
1154 buf_idx += toWr;
1155 }
1156 }
1157}
1158
1172void SPIM_IO_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[], uint8_t rdCmd,
1173 uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int u32NDummy)
1174{
1175 uint8_t cmdBuf[16];
1176 uint32_t buf_idx;
1177
1178 SPIM_SET_SS_EN(1); /* CS activated. */
1179
1180 cmdBuf[0] = rdCmd;
1181 SwitchNBitOutput(u32NBitCmd);
1182 spim_write(cmdBuf, 1UL); /* Write out command. */
1183
1184 buf_idx = 0UL;
1185 if (is4ByteAddr)
1186 {
1187 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1188 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1189 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1190 cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1191 }
1192 else
1193 {
1194 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1195 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1196 cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1197 }
1198 SwitchNBitOutput(u32NBitAddr);
1199 spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
1200
1201 buf_idx = 0UL;
1202 while (u32NDummy --)
1203 {
1204 cmdBuf[buf_idx++] = 0x00U;
1205 }
1206
1207 /* Same bit mode as above. */
1208 spim_write(cmdBuf, buf_idx); /* Write out dummy bytes. */
1209
1210 SwitchNBitInput(u32NBitDat);
1211 spim_read(pu8RxBuf, u32NRx); /* Read back data. */
1212
1213 SPIM_SET_SS_EN(0); /* CS deactivated. */
1214}
1215
1225void SPIM_DMA_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint32_t wrCmd)
1226{
1227 uint32_t pageOffset, toWr;
1228 uint32_t buf_idx = 0UL;
1229
1230 pageOffset = u32Addr % 256UL;
1231
1232 if ((pageOffset + u32NTx) <= 256UL)
1233 {
1234 /* Do all the bytes fit onto one page ? */
1235 SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, u32NTx, pu8TxBuf, wrCmd, 1);
1236 }
1237 else
1238 {
1239 toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
1240
1241 SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1242
1243 u32Addr += toWr; /* Advance indicator. */
1244 u32NTx -= toWr;
1245 buf_idx += toWr;
1246
1247 while (u32NTx)
1248 {
1249 toWr = 256UL;
1250 if (toWr > u32NTx)
1251 {
1252 toWr = u32NTx;
1253 }
1254
1255 SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1256
1257 u32Addr += toWr; /* Advance indicator. */
1258 u32NTx -= toWr;
1259 buf_idx += toWr;
1260 }
1261 }
1262}
1263
1274void SPIM_DMA_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[],
1275 uint32_t u32RdCmd, int isSync)
1276{
1277 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEREAD); /* Switch to Page Read mode. */
1278 SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
1279 SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
1280
1281 SPIM->SRAMADDR = (uint32_t) pu8RxBuf; /* SRAM u32Address. */
1282 SPIM->DMACNT = u32NRx; /* Transfer length. */
1283 SPIM->FADDR = u32Addr; /* Flash u32Address.*/
1284 SPIM_SET_GO(); /* Go. */
1285
1286 if (isSync)
1287 {
1288 SPIM_WAIT_FREE(); /* Wait for DMA done. */
1289 }
1290}
1291
1299void SPIM_EnterDirectMapMode(int is4ByteAddr, uint32_t u32RdCmd, uint32_t u32IdleIntvl)
1300{
1301 SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-byte u32Address. */
1302 SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
1303 SPIM_SET_IDL_INTVL(u32IdleIntvl); /* Idle interval. */
1304 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_DIRECTMAP); /* Switch to Direct Map mode. */
1305}
1306
1312{
1313 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch back to Normal mode. */
1314}
1315
1316 /* end of group SPIM_EXPORTED_FUNCTIONS */
1318 /* end of group SPIM_Driver */
1320 /* end of group Standard_Driver */
1322
1323/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/
NuMicro peripheral access layer header file.
#define SPIM
Definition: M480.h:448
#define SPIM_CTL0_OPMODE_PAGEWRITE
Definition: spim.h:48
#define CMD_QUAD_PAGE_PROGRAM_EON
Definition: spim.h:56
#define CMD_QUAD_PAGE_PROGRAM_WINBOND
Definition: spim.h:54
#define CMD_QUAD_PAGE_PROGRAM_MXIC
Definition: spim.h:55
#define SPIM_CTL0_OPMODE_IO
Definition: spim.h:47
#define SPIM_CTL0_OPMODE_DIRECTMAP
Definition: spim.h:50
#define SPIM_CTL0_OPMODE_PAGEREAD
Definition: spim.h:49
void SPIM_EnterDirectMapMode(int is4ByteAddr, uint32_t u32RdCmd, uint32_t u32IdleIntvl)
Enter Direct Map mode.
Definition: spim.c:1299
#define SPIM_ENABLE_QUAD_OUTPUT_MODE()
Definition: spim.h:290
void SPIM_SetQuadEnable(int isEn, uint32_t u32NBit)
Set Quad Enable/disable.
Definition: spim.c:650
#define SPIM_ENABLE_SING_OUTPUT_MODE()
Definition: spim.h:254
#define SPIM_SET_DATA_NUM(x)
Definition: spim.h:229
#define SPIM_SET_OPMODE(x)
Definition: spim.h:315
#define SPIM_SET_DATA_WIDTH(x)
Definition: spim.h:213
#define SPIM_SET_SS_EN(x)
Definition: spim.h:408
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:1119
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:1274
#define SPIM_GET_CLOCK_DIVIDER()
Definition: spim.h:458
int SPIM_Enable_4Bytes_Mode(int isEn, uint32_t u32NBit)
Enter/Exit 4-byte address mode.
Definition: spim.c:838
#define SPIM_SET_SPIM_MODE(x)
Definition: spim.h:330
#define SPIM_ENABLE_DUAL_INPUT_MODE()
Definition: spim.h:263
#define SPIM_ENABLE_QUAD_INPUT_MODE()
Definition: spim.h:281
void SPIM_WinbondUnlock(uint32_t u32NBit)
Definition: spim.c:908
uint32_t SPIM_GetSClkFreq(void)
Get SPIM serial clock.
Definition: spim.c:479
void SPIM_EraseBlock(uint32_t u32Addr, int is4ByteAddr, uint8_t u8ErsCmd, uint32_t u32NBit, int isSync)
Erase one block.
Definition: spim.c:968
#define SPIM_SET_SS_ACTLVL(x)
Definition: spim.h:424
static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit)
Definition: spim.c:744
#define SPIM_WAIT_FREE()
Definition: spim.h:357
void SPIM_ExitDirectMapMode(void)
Exit Direct Map mode.
Definition: spim.c:1311
#define SPIM_ENABLE_SING_INPUT_MODE()
Definition: spim.h:245
#define SPIM_SET_IDL_INTVL(x)
Definition: spim.h:433
void SPIM_ReadJedecId(uint8_t idBuf[], uint32_t u32NRx, uint32_t u32NBit)
Issue JEDEC ID command.
Definition: spim.c:566
#define SPIM_ENABLE_DUAL_OUTPUT_MODE()
Definition: spim.h:272
#define SPIM_SET_4BYTE_ADDR_EN(x)
Definition: spim.h:177
#define SPIM_SET_GO()
Definition: spim.h:345
void SPIM_ChipErase(uint32_t u32NBit, int isSync)
Erase whole chip.
Definition: spim.c:941
static void spim_eon_set_qpi_mode(int isEn)
Enter/exit QPI mode.
Definition: spim.c:712
int SPIM_Is4ByteModeEnable(uint32_t u32NBit)
int SPIM_InitFlash(int clrWP)
Initialize SPIM flash.
Definition: spim.c:492
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:1225
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:1172
uint32_t SystemCoreClock
Definition: system_M480.c:21