1 /**************************************************************************//**
2  * @file    spim.c
3  * @version V1.00
4  * @brief   M480 series SPIM driver
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include "NuMicro.h"
13 
14 
15 /** @addtogroup Standard_Driver Standard Driver
16   @{
17 */
18 
19 /** @addtogroup SPIM_Driver SPIM Driver
20   @{
21 */
22 
23 /** @addtogroup SPIM_EXPORTED_FUNCTIONS SPIM Exported Functions
24   @{
25 */
26 
27 
28 /** @cond HIDDEN_SYMBOLS */
29 
30 
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 
N_delay(int n)71 static void  N_delay(int n)
72 {
73     while (n-- > 0)
74     {
75         __NOP();
76     }
77 }
78 
SwitchNBitOutput(uint32_t u32NBit)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 
SwitchNBitInput(uint32_t u32NBit)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 
122 /**
123   * @brief      Write data to SPI slave.
124   * @param      pu8TxBuf    Transmit buffer.
125   * @param      u32NTx      Number of bytes to transmit.
126   * @return     None.
127   */
spim_write(uint8_t pu8TxBuf[],uint32_t u32NTx)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 
195 /**
196   * @brief      Read data from SPI slave.
197   * @param      pu8TxBuf    Receive buffer.
198   * @param      u32NRx      Size of receive buffer in bytes.
199   * @return     None.
200   */
spim_read(uint8_t pu8RxBuf[],uint32_t u32NRx)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 
264 /**
265   * @brief      Issue Read Status Register #1 command.
266   * @param      dataBuf     Receive buffer.
267   * @param      u32NRx      Size of receive buffer.
268  * @param       u32NBit     N-bit transmit/receive.
269   * @return     None.
270   */
SPIM_ReadStatusRegister(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)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 
283 /**
284   * @brief      Issue Write Status Register #1 command.
285   * @param      dataBuf     Transmit buffer.
286   * @param      u32NTx      Size of transmit buffer.
287   * @param      u32NBit     N-bit transmit/receive.
288   * @return     None.
289   */
SPIM_WriteStatusRegister(uint8_t dataBuf[],uint32_t u32NTx,uint32_t u32NBit)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 
301 /**
302   * @brief      Issue Read Status Register #2 command.
303   * @param      dataBuf     Receive buffer.
304   * @param      u32NRx      Size of receive buffer.
305  * @param       u32NBit     N-bit transmit/receive.
306   * @return     None.
307   */
SPIM_ReadStatusRegister2(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)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 
320 /**
321   * @brief      Issue Winbond Write Status Register command. This command write both Status Register-1
322   *             and Status Register-2.
323   * @param      dataBuf     Transmit buffer.
324   * @param      u32NTx      Size of transmit buffer.
325   * @param      u32NBit     N-bit transmit/receive.
326   * @return     None.
327   */
SPIM_WriteStatusRegister2(uint8_t dataBuf[],uint32_t u32NTx,uint32_t u32NBit)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 /**
343   * @brief      Issue Write Status Register #3 command.
344   * @param      dataBuf     Transmit buffer.
345   * @param      u32NTx      Size of transmit buffer.
346   * @param      u32NBit     N-bit transmit/receive.
347   * @return     None.
348   */
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 
361 /**
362   * @brief      Issue Read Status Register #3 command.
363   * @param      dataBuf     Receive buffer.
364   * @param      u32NRx      Size of receive buffer.
365   * @param      u32NBit     N-bit transmit/receive.
366   * @return     None.
367   */
SPIM_ReadStatusRegister3(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)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 /**
382   * @brief      Issue Write Security Register command.
383   * @param      dataBuf     Transmit buffer.
384   * @param      u32NTx      Size of transmit buffer.
385   * @param      u32NBit     N-bit transmit/receive.
386   * @return     None.
387   */
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 
400 /**
401   * @brief      Issue Read Security Register command.
402   * @param      dataBuf     Receive buffer.
403   * @param      u32NRx      Size of receive buffer.
404   * @param      u32NBit     N-bit transmit/receive.
405   * @return     None.
406   */
SPIM_ReadSecurityRegister(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)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 
419 /**
420   * @brief      Check if Erase/Write is done.
421   * @return     0: Not done. 1: Done.
422   */
spim_is_write_done(uint32_t u32NBit)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 
430 /**
431   * @brief      Wait until Erase/Write done.
432   * @param      u32NBit     N-bit transmit/receive.
433   * @return     0           SPIM write done.
434   */
spim_wait_write_done(uint32_t u32NBit)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 
455 /**
456   * @brief      Issue Write Enable/disable command.
457   * @param      isEn        Enable/disable.
458   * @param      u32NBit     N-bit transmit/receive.
459   * @return     None.
460   */
spim_set_write_enable(int isEn,uint32_t u32NBit)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 
472 /** @endcond HIDDEN_SYMBOLS */
473 
474 /**
475   * @brief      Get SPIM serial clock.
476   * @return     SPI serial clock.
477   * @details    This function calculates the serial clock of SPI in Hz.
478   */
SPIM_GetSClkFreq(void)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 
486 /**
487   * @brief      Initialize SPIM flash.
488   * @param      clrWP       Clear Write Protect or not.
489   * @return     0    Success.
490   * @return     -1   Unrecognized manufacture ID or failed on reading manufacture ID.
491   */
SPIM_InitFlash(int clrWP)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 
499     SPIM_SET_SS_ACTLVL(0);
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 
559 /**
560   * @brief      Issue JEDEC ID command.
561   * @param      idBuf       ID buffer.
562   * @param      u32NRx      Size of ID buffer.
563   * @param      u32NBit     N-bit transmit/receive.
564   * @return     None.
565   */
SPIM_ReadJedecId(uint8_t idBuf[],uint32_t u32NRx,uint32_t u32NBit)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 
578 /** @cond HIDDEN_SYMBOLS */
579 
spim_enable_spansion_quad_mode(int isEn)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 
642 /** @endcond HIDDEN_SYMBOLS */
643 
644 /**
645   * @brief      Set Quad Enable/disable.
646   * @param      isEn        Enable/disable.
647   * @param      u32NBit     N-bit transmit/receive.
648   * @return     None.
649   */
SPIM_SetQuadEnable(int isEn,uint32_t u32NBit)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 
701 /**
702   * @brief      Enter/exit QPI mode.
703   * @param      isEn        Enable/disable.
704   * @return     None.
705   */
spim_eon_set_qpi_mode(int isEn)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 
SPIM_SPANSION_4Bytes_Enable(int isEn,uint32_t u32NBit)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 
770 /** @cond HIDDEN_SYMBOLS */
771 
772 /**
773   * @brief      Query 4-byte address mode enabled or not.
774   * @param      u32NBit     N-bit transmit/receive.
775   * @return     0: 4-byte address mode disabled. 1: 4-byte address mode enabled.
776   */
SPIM_Is4ByteModeEnable(uint32_t u32NBit)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 
822 /** @endcond HIDDEN_SYMBOLS  */
823 
824 
825 /**
826   * @brief      Enter/Exit 4-byte address mode.
827   * @param      isEn        Enable/disable.
828   * @param      u32NBit     N-bit transmit/receive.
829   * @return     0           success
830   *             -1          failed
831   */
SPIM_Enable_4Bytes_Mode(int isEn,uint32_t u32NBit)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 
SPIM_WinbondUnlock(uint32_t u32NBit)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 
920 /**
921   * @brief      Erase whole chip.
922   * @param      u32NBit     N-bit transmit/receive.
923   * @param      isSync      Block or not.
924   * @return     None.
925   */
SPIM_ChipErase(uint32_t u32NBit,int isSync)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 
944 /**
945   * @brief      Erase one block.
946   * @param      u32Addr         Block to erase which contains the u32Addr.
947   * @param      is4ByteAddr     4-byte u32Address or not.
948   * @param      u8ErsCmd        Erase command.
949   * @param      u32NBit         N-bit transmit/receive.
950   * @param      isSync      Block or not.
951   * @return     None.
952   */
SPIM_EraseBlock(uint32_t u32Addr,int is4ByteAddr,uint8_t u8ErsCmd,uint32_t u32NBit,int isSync)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 
988 /** @cond HIDDEN_SYMBOLS */
989 
990 /**
991   * @brief      Write data in the same page by I/O mode.
992   * @param      u32Addr     Start u32Address to write.
993   * @param      is4ByteAddr 4-byte u32Address or not.
994   * @param      u32NTx      Number of bytes to write.
995   * @param      pu8TxBuf    Transmit buffer.
996   * @param      wrCmd       Write command.
997   * @param      u32NBitCmd  N-bit transmit command.
998   * @param      u32NBitAddr N-bit transmit u32Address.
999   * @param      u32NBitDat  N-bit transmit/receive data.
1000   * @param      isSync      Block or not.
1001   * @return     None.
1002   */
SPIM_WriteInPageDataByIo(uint32_t u32Addr,int is4ByteAddr,uint32_t u32NTx,uint8_t pu8TxBuf[],uint8_t wrCmd,uint32_t u32NBitCmd,uint32_t u32NBitAddr,uint32_t u32NBitDat,int isSync)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 
1046 /**
1047   * @brief      Write data in the same page by Page Write mode.
1048   * @param      u32Addr     Start u32Address to write.
1049   * @param      is4ByteAddr 4-byte u32Address or not.
1050   * @param      u32NTx      Number of bytes to write.
1051   * @param      pu8TxBuf    Transmit buffer.
1052   * @param      wrCmd       Write command.
1053   * @param      isSync      Block or not.
1054   * @return     None.
1055   */
SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr,int is4ByteAddr,uint32_t u32NTx,uint8_t pu8TxBuf[],uint32_t wrCmd,int isSync)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 
1090 /** @endcond HIDDEN_SYMBOLS */
1091 
1092 /**
1093   * @brief      Write data to SPI Flash by sending commands manually (I/O mode).
1094   * @param      u32Addr: Start u32Address to write.
1095   * @param      is4ByteAddr: 4-byte u32Address or not.
1096   * @param      u32NTx: Number of bytes to write.
1097   * @param      pu8TxBuf: Transmit buffer.
1098   * @param      wrCmd: Write command.
1099   * @param      u32NBitCmd: N-bit transmit command.
1100   * @param      u32NBitAddr: N-bit transmit u32Address.
1101   * @param      u32NBitDat: N-bit transmit/receive data.
1102   * @return     None.
1103   */
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)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 
1144 /**
1145   * @brief      Read data from SPI Flash by sending commands manually (I/O mode).
1146   * @param      u32Addr     Start u32Address to read.
1147   * @param      is4ByteAddr 4-byte u32Address or not.
1148   * @param      u32NRx      Number of bytes to read.
1149   * @param      pu8RxBuf    Receive buffer.
1150   * @param      rdCmd       Read command.
1151   * @param      u32NBitCmd  N-bit transmit command.
1152   * @param      u32NBitAddr N-bit transmit u32Address.
1153   * @param      u32NBitDat  N-bit transmit/receive data.
1154   * @param      u32NDummy   Number of dummy bytes following address.
1155   * @return     None.
1156   */
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)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 
1201 /**
1202   * @brief      Write data to SPI Flash by Page Write mode.
1203   * @param      u32Addr     Start address to write.
1204   * @param      is4ByteAddr 4-byte address or not.
1205   * @param      u32NTx      Number of bytes to write.
1206   * @param      pu8TxBuf    Transmit buffer.
1207   * @param      wrCmd       Write command.
1208   * @return     None.
1209   */
SPIM_DMA_Write(uint32_t u32Addr,int is4ByteAddr,uint32_t u32NTx,uint8_t pu8TxBuf[],uint32_t wrCmd)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 
1249 /**
1250   * @brief      Read data from SPI Flash by Page Read mode.
1251   * @param      u32Addr     Start address to read.
1252   * @param      is4ByteAddr 4-byte u32Address or not.
1253   * @param      u32NRx      Number of bytes to read.
1254   * @param      pu8RxBuf    Receive buffer.
1255   * @param      u32RdCmd    Read command.
1256   * @param      isSync      Block or not.
1257   * @return     None.
1258   */
SPIM_DMA_Read(uint32_t u32Addr,int is4ByteAddr,uint32_t u32NRx,uint8_t pu8RxBuf[],uint32_t u32RdCmd,int isSync)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 
1277 /**
1278   * @brief      Enter Direct Map mode.
1279   * @param      is4ByteAddr     4-byte u32Address or not.
1280   * @param      u32RdCmd        Read command.
1281   * @param      u32IdleIntvl    Idle interval.
1282   * @return     None.
1283   */
SPIM_EnterDirectMapMode(int is4ByteAddr,uint32_t u32RdCmd,uint32_t u32IdleIntvl)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 
1292 /**
1293   * @brief      Exit Direct Map mode.
1294   * @return     None.
1295   */
SPIM_ExitDirectMapMode(void)1296 void SPIM_ExitDirectMapMode(void)
1297 {
1298     SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO);       /* Switch back to Normal mode.  */
1299 }
1300 
1301 
1302 /*@}*/ /* end of group SPIM_EXPORTED_FUNCTIONS */
1303 
1304 /*@}*/ /* end of group SPIM_Driver */
1305 
1306 /*@}*/ /* end of group Standard_Driver */
1307 
1308 /*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/
1309