M480 BSP V3.05.006
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/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
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 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
706static 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
738static 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
777int 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
832int 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 int32_t tout;
838
839 SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
840
841 /* Based on Flash size, check if 4-byte address mode is supported. */
842 switch (idBuf[0])
843 {
844 case MFGID_WINBOND:
845 case MFGID_MXIC:
846 case MFGID_EON:
847 isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
848 break;
849
850 case MFGID_ISSI:
851 isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
852 break;
853
854 case MFGID_SPANSION:
855 SPIM_SPANSION_4Bytes_Enable(isEn, u32NBit);
856 isSupt = 1L;
857 ret = 0L;
858 break;
859
860 default:
861 break;
862 }
863
864 if ((isSupt) && (idBuf[0] != MFGID_SPANSION))
865 {
866 cmdBuf[0] = isEn ? OPCODE_EN4B : OPCODE_EX4B;
867
868 SPIM_SET_SS_EN(1); /* CS activated. */
869 SwitchNBitOutput(u32NBit);
870 spim_write(cmdBuf, sizeof (cmdBuf));
871 SPIM_SET_SS_EN(0); /* CS deactivated. */
872
873 /*
874 * FIXME: Per test, 4BYTE Indicator bit doesn't set after EN4B, which
875 * doesn't match spec(MX25L25635E), so skip the check below.
876 */
877 ret = 0;
878 if (idBuf[0] != MFGID_MXIC)
879 {
880 /*
881 * About over 100 instrucsions executed, just want to give
882 * a time-out about 1 seconds to avoid infinite loop
883 */
884 tout = (SystemCoreClock)/100;
885
886 if (isEn)
887 {
888 while ((tout-- > 0) && !SPIM_Is4ByteModeEnable(u32NBit)) { }
889 }
890 else
891 {
892 while ((tout-- > 0) && SPIM_Is4ByteModeEnable(u32NBit)) { }
893 }
894 if (tout <= 0)
895 ret = -1;
896 }
897 }
898 return ret;
899}
900
901
902void SPIM_WinbondUnlock(uint32_t u32NBit)
903{
904 uint8_t idBuf[3];
905 uint8_t dataBuf[4];
906
907 SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
908
909 if ((idBuf[0] != MFGID_WINBOND) || (idBuf[1] != 0x40) || (idBuf[2] != 0x16))
910 {
911 SPIM_DBGMSG("SPIM_WinbondUnlock - Not W25Q32, do nothing.\n");
912 return;
913 }
914
915 SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
916 SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
917 SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
918 dataBuf[1] &= ~0x40; /* clear Status Register-1 SEC bit */
919
920 spim_set_write_enable(1, u32NBit); /* Write Enable. */
921 SPIM_WriteStatusRegister2(dataBuf, sizeof (dataBuf), u32NBit);
922 spim_wait_write_done(u32NBit);
923
924 SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
925 SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
926 SPIM_DBGMSG("Status Register (after unlock): 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
927}
928
935void SPIM_ChipErase(uint32_t u32NBit, int isSync)
936{
937 uint8_t cmdBuf[] = { OPCODE_CHIP_ERASE }; /* 1-byte Chip Erase command. */
938
939 spim_set_write_enable(1, u32NBit); /* Write Enable. */
940
941 SPIM_SET_SS_EN(1); /* CS activated. */
942 SwitchNBitOutput(u32NBit);
943 spim_write(cmdBuf, sizeof (cmdBuf));
944 SPIM_SET_SS_EN(0); /* CS deactivated. */
945
946 if (isSync)
947 {
948 spim_wait_write_done(u32NBit);
949 }
950}
951
952
962void SPIM_EraseBlock(uint32_t u32Addr, int is4ByteAddr, uint8_t u8ErsCmd, uint32_t u32NBit, int isSync)
963{
964 uint8_t cmdBuf[16];
965 uint32_t buf_idx = 0UL;
966
967 spim_set_write_enable(1, u32NBit); /* Write Enable. */
968
969 cmdBuf[buf_idx++] = u8ErsCmd;
970
971 if (is4ByteAddr)
972 {
973 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
974 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
975 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
976 cmdBuf[buf_idx++] = (uint8_t) (u32Addr & 0xFFUL);
977 }
978 else
979 {
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
985 SPIM_SET_SS_EN(1); /* CS activated. */
986 SwitchNBitOutput(u32NBit);
987 spim_write(cmdBuf, buf_idx);
988 SPIM_SET_SS_EN(0); /* CS deactivated. */
989
990 if (isSync)
991 {
992 spim_wait_write_done(u32NBit);
993 }
994}
995
996
1012static void SPIM_WriteInPageDataByIo(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1013 uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int isSync)
1014{
1015 uint8_t cmdBuf[16];
1016 uint32_t buf_idx;
1017
1018 spim_set_write_enable(1, u32NBitCmd); /* Write Enable. */
1019
1020 SPIM_SET_SS_EN(1); /* CS activated. */
1021
1022 SwitchNBitOutput(u32NBitCmd);
1023 cmdBuf[0] = wrCmd;
1024 spim_write(cmdBuf, 1UL); /* Write out command. */
1025
1026 buf_idx = 0UL;
1027 if (is4ByteAddr)
1028 {
1029 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1030 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1031 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1032 cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1033 }
1034 else
1035 {
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
1041 SwitchNBitOutput(u32NBitAddr);
1042 spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
1043
1044 SwitchNBitOutput(u32NBitDat);
1045 spim_write(pu8TxBuf, u32NTx); /* Write out data. */
1046
1047 SPIM_SET_SS_EN(0); /* CS deactivated. */
1048
1049 if (isSync)
1050 {
1051 spim_wait_write_done(u32NBitCmd);
1052 }
1053}
1054
1065static void SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
1066 uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync)
1067{
1068 if ((wrCmd == CMD_QUAD_PAGE_PROGRAM_WINBOND) ||
1069 (wrCmd == CMD_QUAD_PAGE_PROGRAM_MXIC))
1070 {
1071 SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
1072 }
1073 else if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1074 {
1075 SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
1076 spim_eon_set_qpi_mode(1); /* Enter QPI mode. */
1077 }
1078
1079 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEWRITE);/* Switch to Page Write mode. */
1080 SPIM_SET_SPIM_MODE(wrCmd); /* SPIM mode. */
1081 SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
1082
1083 SPIM->SRAMADDR = (uint32_t) pu8TxBuf; /* SRAM u32Address. */
1084 SPIM->DMACNT = u32NTx; /* Transfer length. */
1085 SPIM->FADDR = u32Addr; /* Flash u32Address.*/
1086 SPIM_SET_GO(); /* Go. */
1087
1088 if (isSync)
1089 {
1091 }
1092
1093 if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1094 {
1095 spim_eon_set_qpi_mode(0); /* Exit QPI mode. */
1096 }
1097}
1098
1113void SPIM_IO_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1114 uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat)
1115{
1116 uint32_t pageOffset, toWr;
1117 uint32_t buf_idx = 0UL;
1118
1119 pageOffset = u32Addr % 256UL;
1120
1121 if ((pageOffset + u32NTx) <= 256UL) /* Do all the bytes fit onto one page ? */
1122 {
1123 SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, u32NTx, &pu8TxBuf[buf_idx],
1124 wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1125 }
1126 else
1127 {
1128 toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
1129
1130 SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1131 wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1132 u32Addr += toWr; /* Advance indicator. */
1133 u32NTx -= toWr;
1134 buf_idx += toWr;
1135
1136 while (u32NTx)
1137 {
1138 toWr = 256UL;
1139 if (toWr > u32NTx)
1140 {
1141 toWr = u32NTx;
1142 }
1143
1144 SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1145 wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1146 u32Addr += toWr; /* Advance indicator. */
1147 u32NTx -= toWr;
1148 buf_idx += toWr;
1149 }
1150 }
1151}
1152
1166void SPIM_IO_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[], uint8_t rdCmd,
1167 uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int u32NDummy)
1168{
1169 uint8_t cmdBuf[16];
1170 uint32_t buf_idx;
1171
1172 SPIM_SET_SS_EN(1); /* CS activated. */
1173
1174 cmdBuf[0] = rdCmd;
1175 SwitchNBitOutput(u32NBitCmd);
1176 spim_write(cmdBuf, 1UL); /* Write out command. */
1177
1178 buf_idx = 0UL;
1179 if (is4ByteAddr)
1180 {
1181 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1182 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1183 cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1184 cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1185 }
1186 else
1187 {
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 SwitchNBitOutput(u32NBitAddr);
1193 spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
1194
1195 buf_idx = 0UL;
1196 while (u32NDummy --)
1197 {
1198 cmdBuf[buf_idx++] = 0x00U;
1199 }
1200
1201 /* Same bit mode as above. */
1202 spim_write(cmdBuf, buf_idx); /* Write out dummy bytes. */
1203
1204 SwitchNBitInput(u32NBitDat);
1205 spim_read(pu8RxBuf, u32NRx); /* Read back data. */
1206
1207 SPIM_SET_SS_EN(0); /* CS deactivated. */
1208}
1209
1219void SPIM_DMA_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint32_t wrCmd)
1220{
1221 uint32_t pageOffset, toWr;
1222 uint32_t buf_idx = 0UL;
1223
1224 pageOffset = u32Addr % 256UL;
1225
1226 if ((pageOffset + u32NTx) <= 256UL)
1227 {
1228 /* Do all the bytes fit onto one page ? */
1229 SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, u32NTx, pu8TxBuf, wrCmd, 1);
1230 }
1231 else
1232 {
1233 toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
1234
1235 SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1236
1237 u32Addr += toWr; /* Advance indicator. */
1238 u32NTx -= toWr;
1239 buf_idx += toWr;
1240
1241 while (u32NTx)
1242 {
1243 toWr = 256UL;
1244 if (toWr > u32NTx)
1245 {
1246 toWr = u32NTx;
1247 }
1248
1249 SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1250
1251 u32Addr += toWr; /* Advance indicator. */
1252 u32NTx -= toWr;
1253 buf_idx += toWr;
1254 }
1255 }
1256}
1257
1268void SPIM_DMA_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[],
1269 uint32_t u32RdCmd, int isSync)
1270{
1271 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEREAD); /* Switch to Page Read mode. */
1272 SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
1273 SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
1274
1275 SPIM->SRAMADDR = (uint32_t) pu8RxBuf; /* SRAM u32Address. */
1276 SPIM->DMACNT = u32NRx; /* Transfer length. */
1277 SPIM->FADDR = u32Addr; /* Flash u32Address.*/
1278 SPIM_SET_GO(); /* Go. */
1279
1280 if (isSync)
1281 {
1282 SPIM_WAIT_FREE(); /* Wait for DMA done. */
1283 }
1284}
1285
1293void SPIM_EnterDirectMapMode(int is4ByteAddr, uint32_t u32RdCmd, uint32_t u32IdleIntvl)
1294{
1295 SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-byte u32Address. */
1296 SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
1297 SPIM_SET_IDL_INTVL(u32IdleIntvl); /* Idle interval. */
1298 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_DIRECTMAP); /* Switch to Direct Map mode. */
1299}
1300
1306{
1307 SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch back to Normal mode. */
1308}
1309
1310 /* end of group SPIM_EXPORTED_FUNCTIONS */
1312 /* end of group SPIM_Driver */
1314 /* end of group Standard_Driver */
1316
1317/*** (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:1293
#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:1113
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:1268
#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:832
#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:902
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:962
#define SPIM_SET_SS_ACTLVL(x)
Definition: spim.h:424
static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit)
Definition: spim.c:738
#define SPIM_WAIT_FREE()
Definition: spim.h:357
void SPIM_ExitDirectMapMode(void)
Exit Direct Map mode.
Definition: spim.c:1305
#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:935
static void spim_eon_set_qpi_mode(int isEn)
Enter/exit QPI mode.
Definition: spim.c:706
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:1219
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:1166
uint32_t SystemCoreClock
Definition: system_M480.c:21