1 /**************************************************************************//**
2  * @file    spim.c
3  * @version V1.00
4  * @brief   M460 series SPIM driver
5  *
6  * @copyright SPDX-License-Identifier: Apache-2.0
7  * @copyright Copyright (C) 2021 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 int32_t spim_write(uint8_t pu8TxBuf[], uint32_t u32NTx);
52 static int32_t 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 int32_t 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   * @retval     SPIM_OK          SPIM operation OK.
127   * @retval     SPIM_ERR_TIMEOUT SPIM operation abort due to timeout error.
128   * @note       This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
129   */
spim_write(uint8_t pu8TxBuf[],uint32_t u32NTx)130 static int32_t spim_write(uint8_t pu8TxBuf[], uint32_t u32NTx)
131 {
132     uint32_t  buf_idx = 0UL;
133     uint32_t u32TimeOutCount = 0UL;
134 
135     while (u32NTx)
136     {
137         uint32_t dataNum = 0UL, dataNum2;
138 
139         if (u32NTx >= 16UL)
140         {
141             dataNum = 4UL;
142         }
143         else if (u32NTx >= 12UL)
144         {
145             dataNum = 3UL;
146         }
147         else if (u32NTx >= 8UL)
148         {
149             dataNum = 2UL;
150         }
151         else if (u32NTx >= 4UL)
152         {
153             dataNum = 1UL;
154         }
155 
156         dataNum2 = dataNum;
157         while (dataNum2)
158         {
159             uint32_t tmp;
160 
161             memcpy(&tmp, &pu8TxBuf[buf_idx], 4U);
162             buf_idx += 4UL;
163             u32NTx -= 4UL;
164 
165             dataNum2 --;
166             /*  *((__O uint32_t *) &SPIM->TX0 + dataNum2) = tmp; */
167             SPIM->TX[dataNum2] = tmp;
168         }
169 
170         if (dataNum)
171         {
172             SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO);    /* Switch to Normal mode. */
173             SPIM_SET_DATA_WIDTH(32UL);
174             SPIM_SET_DATA_NUM(dataNum);
175             SPIM_SET_GO();
176             u32TimeOutCount = SPIM_TIMEOUT;
177             SPIM_WAIT_FREE()
178             {
179                 if(--u32TimeOutCount == 0) return SPIM_ERR_TIMEOUT;
180             }
181         }
182 
183         if (u32NTx && (u32NTx < 4UL))
184         {
185             uint32_t  rnm, tmp;
186 
187             rnm = u32NTx;
188             memcpy(&tmp, &pu8TxBuf[buf_idx], u32NTx);
189             buf_idx += u32NTx;
190             u32NTx = 0UL;
191             SPIM->TX[0] = tmp;
192 
193             SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO);    /* Switch to Normal mode. */
194             SPIM_SET_DATA_WIDTH(rnm * 8UL);
195             SPIM_SET_DATA_NUM(1UL);
196             SPIM_SET_GO();
197             u32TimeOutCount = SPIM_TIMEOUT;
198             SPIM_WAIT_FREE()
199             {
200                 if(--u32TimeOutCount == 0) return SPIM_ERR_TIMEOUT;
201             }
202         }
203     }
204 
205     return SPIM_OK;
206 }
207 
208 /**
209   * @brief      Read data from SPI slave.
210   * @param      pu8TxBuf    Receive buffer.
211   * @param      u32NRx      Size of receive buffer in bytes.
212   * @retval     SPIM_OK          SPIM operation OK.
213   * @retval     SPIM_ERR_TIMEOUT SPIM operation abort due to timeout error.
214   * @note       This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
215   */
spim_read(uint8_t pu8RxBuf[],uint32_t u32NRx)216 static int32_t spim_read(uint8_t pu8RxBuf[], uint32_t u32NRx)
217 {
218     uint32_t  buf_idx = 0UL;
219     uint32_t u32TimeOutCount = 0UL;
220 
221     while (u32NRx)
222     {
223         uint32_t dataNum = 0UL;   /* number of words */
224 
225         if (u32NRx >= 16UL)
226         {
227             dataNum = 4UL;
228         }
229         else if (u32NRx >= 12UL)
230         {
231             dataNum = 3UL;
232         }
233         else if (u32NRx >= 8UL)
234         {
235             dataNum = 2UL;
236         }
237         else if (u32NRx >= 4UL)
238         {
239             dataNum = 1UL;
240         }
241 
242         if (dataNum)
243         {
244             SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO);    /* Switch to Normal mode. */
245             SPIM_SET_DATA_WIDTH(32UL);
246             SPIM_SET_DATA_NUM(dataNum);
247             SPIM_SET_GO();
248             u32TimeOutCount = SPIM_TIMEOUT;
249             SPIM_WAIT_FREE()
250             {
251                 if(--u32TimeOutCount == 0) return SPIM_ERR_TIMEOUT;
252             }
253         }
254 
255         while (dataNum)
256         {
257             uint32_t tmp;
258 
259             tmp = SPIM->RX[dataNum-1UL];
260             memcpy(&pu8RxBuf[buf_idx], &tmp, 4U);
261             buf_idx += 4UL;
262             dataNum --;
263             u32NRx -= 4UL;
264         }
265 
266         if (u32NRx && (u32NRx < 4UL))
267         {
268             uint32_t tmp;
269 
270             SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO);    /* Switch to Normal mode. */
271             SPIM_SET_DATA_WIDTH(u32NRx * 8UL);
272             SPIM_SET_DATA_NUM(1UL);
273             SPIM_SET_GO();
274             u32TimeOutCount = SPIM_TIMEOUT;
275             SPIM_WAIT_FREE()
276             {
277                 if(--u32TimeOutCount == 0) return SPIM_ERR_TIMEOUT;
278             }
279 
280             tmp = SPIM->RX[0];
281             memcpy(&pu8RxBuf[buf_idx], &tmp, u32NRx);
282             buf_idx += u32NRx;
283             u32NRx = 0UL;
284         }
285     }
286 
287     return SPIM_OK;
288 }
289 
290 /**
291   * @brief      Issue Read Status Register #1 command.
292   * @param      dataBuf     Receive buffer.
293   * @param      u32NRx      Size of receive buffer.
294   * @param      u32NBit     N-bit transmit/receive.
295   * @return     None.
296   */
SPIM_ReadStatusRegister(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)297 static void SPIM_ReadStatusRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
298 {
299     uint8_t cmdBuf[] = {OPCODE_RDSR};            /* 1-byte Read Status Register #1 command. */
300 
301     SPIM_SET_SS_EN(1);                          /* CS activated. */
302     SwitchNBitOutput(u32NBit);
303     spim_write(cmdBuf, sizeof (cmdBuf));
304     SwitchNBitInput(u32NBit);
305     spim_read(dataBuf, u32NRx);
306     SPIM_SET_SS_EN(0);                          /* CS deactivated. */
307 }
308 
309 /**
310   * @brief      Issue Write Status Register #1 command.
311   * @param      dataBuf     Transmit buffer.
312   * @param      u32NTx      Size of transmit buffer.
313   * @param      u32NBit     N-bit transmit/receive.
314   * @return     None.
315   */
SPIM_WriteStatusRegister(uint8_t dataBuf[],uint32_t u32NTx,uint32_t u32NBit)316 static void SPIM_WriteStatusRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
317 {
318     uint8_t cmdBuf[] = {OPCODE_WRSR, 0x00U};     /* 1-byte Write Status Register #1 command + 1-byte data. */
319 
320     cmdBuf[1] = dataBuf[0];
321     SPIM_SET_SS_EN(1);                          /* CS activated. */
322     SwitchNBitOutput(u32NBit);
323     spim_write(cmdBuf, sizeof (cmdBuf));
324     SPIM_SET_SS_EN(0);                          /* CS deactivated. */
325 }
326 
327 /**
328   * @brief      Issue Read Status Register #2 command.
329   * @param      dataBuf     Receive buffer.
330   * @param      u32NRx      Size of receive buffer.
331  * @param       u32NBit     N-bit transmit/receive.
332   * @return     None.
333   */
SPIM_ReadStatusRegister2(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)334 static void SPIM_ReadStatusRegister2(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
335 {
336     uint8_t cmdBuf[] = {OPCODE_RDSR2};           /* 1-byte Read Status Register #1 command. */
337 
338     SPIM_SET_SS_EN(1);                          /* CS activated.  */
339     SwitchNBitOutput(u32NBit);
340     spim_write(cmdBuf, sizeof (cmdBuf));
341     SwitchNBitInput(u32NBit);
342     spim_read(dataBuf, u32NRx);
343     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
344 }
345 
346 /**
347   * @brief      Issue Winbond Write Status Register command. This command write both Status Register-1
348   *             and Status Register-2.
349   * @param      dataBuf     Transmit buffer.
350   * @param      u32NTx      Size of transmit buffer.
351   * @param      u32NBit     N-bit transmit/receive.
352   * @return     None.
353   */
SPIM_WriteStatusRegister2(uint8_t dataBuf[],uint32_t u32NTx,uint32_t u32NBit)354 static void SPIM_WriteStatusRegister2(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
355 {
356     uint8_t cmdBuf[3] = {OPCODE_WRSR, 0U, 0U};
357 
358     cmdBuf[1] = dataBuf[0];
359     cmdBuf[2] = dataBuf[1];
360 
361     SPIM_SET_SS_EN(1);                          /* CS activated.    */
362     SwitchNBitOutput(u32NBit);
363     spim_write(cmdBuf, sizeof (cmdBuf));
364     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
365 }
366 
367 #if 0  /* not used */
368 /**
369   * @brief      Issue Write Status Register #3 command.
370   * @param      dataBuf     Transmit buffer.
371   * @param      u32NTx      Size of transmit buffer.
372   * @param      u32NBit     N-bit transmit/receive.
373   * @return     None.
374   */
375 static void SPIM_WriteStatusRegister3(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
376 {
377     uint8_t cmdBuf[] = {OPCODE_WRSR3, 0x00U};    /* 1-byte Write Status Register #2 command + 1-byte data. */
378     cmdBuf[1] = dataBuf[0];
379 
380     SPIM_SET_SS_EN(1);                          /* CS activated. */
381     SwitchNBitOutput(u32NBit);
382     spim_write(cmdBuf, sizeof (cmdBuf));
383     SPIM_SET_SS_EN(0);                          /* CS deactivated. */
384 }
385 #endif
386 
387 /**
388   * @brief      Issue Read Status Register #3 command.
389   * @param      dataBuf     Receive buffer.
390   * @param      u32NRx      Size of receive buffer.
391   * @param      u32NBit     N-bit transmit/receive.
392   * @return     None.
393   */
SPIM_ReadStatusRegister3(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)394 static void SPIM_ReadStatusRegister3(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
395 {
396     uint8_t cmdBuf[] = {OPCODE_RDSR3};           /* 1-byte Read Status Register #1 command. */
397 
398     SPIM_SET_SS_EN(1);                          /* CS activated. */
399     SwitchNBitOutput(u32NBit);
400     spim_write(cmdBuf, sizeof (cmdBuf));
401     SwitchNBitInput(u32NBit);
402     spim_read(dataBuf, u32NRx);
403     SPIM_SET_SS_EN(0);                          /* CS deactivated. */
404 }
405 
406 #if 0  /* not used */
407 /**
408   * @brief      Issue Write Security Register command.
409   * @param      dataBuf     Transmit buffer.
410   * @param      u32NTx      Size of transmit buffer.
411   * @param      u32NBit     N-bit transmit/receive.
412   * @return     None.
413   */
414 static void SPIM_WriteSecurityRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
415 {
416     uint8_t cmdBuf[] = {OPCODE_WRSCUR, 0x00U};   /* 1-byte Write Status Register #2 command + 1-byte data. */
417     cmdBuf[1] = dataBuf[0];
418 
419     SPIM_SET_SS_EN(1);                          /* CS activated. */
420     SwitchNBitOutput(u32NBit);
421     spim_write(cmdBuf, sizeof (cmdBuf));
422     SPIM_SET_SS_EN(0);                          /* CS deactivated. */
423 }
424 #endif
425 
426 /**
427   * @brief      Issue Read Security Register command.
428   * @param      dataBuf     Receive buffer.
429   * @param      u32NRx      Size of receive buffer.
430   * @param      u32NBit     N-bit transmit/receive.
431   * @return     None.
432   */
SPIM_ReadSecurityRegister(uint8_t dataBuf[],uint32_t u32NRx,uint32_t u32NBit)433 static void SPIM_ReadSecurityRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
434 {
435     uint8_t cmdBuf[] = {OPCODE_RDSCUR};          /* 1-byte Read Status Register #1 command. */
436 
437     SPIM_SET_SS_EN(1);                          /* CS activated. */
438     SwitchNBitOutput(u32NBit);
439     spim_write(cmdBuf, sizeof (cmdBuf));
440     SwitchNBitInput(u32NBit);
441     spim_read(dataBuf, u32NRx);
442     SPIM_SET_SS_EN(0);                          /* CS deactivated. */
443 }
444 
445 /**
446   * @brief      Check if Erase/Write is done.
447   * @return     0: Not done. 1: Done.
448   */
spim_is_write_done(uint32_t u32NBit)449 static int spim_is_write_done(uint32_t u32NBit)
450 {
451     uint8_t status[1];
452     SPIM_ReadStatusRegister(status, sizeof (status), u32NBit);
453     return ! (status[0] & SR_WIP);
454 }
455 
456 /**
457   * @brief      Wait until Erase/Write done.
458   * @param      u32NBit     N-bit transmit/receive.
459   * @return     0           SPIM write done.
460   */
spim_wait_write_done(uint32_t u32NBit)461 static int spim_wait_write_done(uint32_t u32NBit)
462 {
463     uint32_t   count;
464     int        ret = -1;
465 
466     for (count = 0UL; count < SystemCoreClock/1000UL; count++)
467     {
468         if (spim_is_write_done(u32NBit))
469         {
470             ret = 0;
471             break;
472         }
473     }
474     if (ret != 0)
475     {
476         SPIM_DBGMSG("spim_wait_write_done time-out!!\n");
477     }
478     return ret;
479 }
480 
481 /**
482   * @brief      Issue Write Enable/disable command.
483   * @param      isEn        Enable/disable.
484   * @param      u32NBit     N-bit transmit/receive.
485   * @return     None.
486   */
spim_set_write_enable(int isEn,uint32_t u32NBit)487 static void spim_set_write_enable(int isEn, uint32_t u32NBit)
488 {
489     uint8_t cmdBuf[] = {0U};                     /* 1-byte Write Enable command. */
490     cmdBuf[0] = isEn ? OPCODE_WREN : OPCODE_WRDI;
491 
492     SPIM_SET_SS_EN(1);                          /* CS activated.   */
493     SwitchNBitOutput(u32NBit);
494     spim_write(cmdBuf, sizeof (cmdBuf));
495     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
496 }
497 
498 /** @endcond HIDDEN_SYMBOLS */
499 
500 /**
501   * @brief      Get SPIM serial clock.
502   * @return     SPI serial clock.
503   * @details    This function calculates the serial clock of SPI in Hz.
504   */
SPIM_GetSClkFreq(void)505 uint32_t SPIM_GetSClkFreq(void)
506 {
507     uint32_t clkDiv = SPIM_GET_CLOCK_DIVIDER();
508 
509     return clkDiv ? SystemCoreClock / (clkDiv * 2U) : SystemCoreClock;
510 }
511 
512 /**
513   * @brief      Initialize SPIM flash.
514   * @param      clrWP       Clear Write Protect or not.
515   * @return     0    Success.
516   * @return     -1   Unrecognized manufacture ID or failed on reading manufacture ID.
517   */
SPIM_InitFlash(int clrWP)518 int SPIM_InitFlash(int clrWP)
519 {
520     uint8_t   idBuf[3];
521     uint8_t   cmdBuf[1];
522     uint32_t  i;
523     int32_t   ret = -1;
524 
525     SPIM_SET_SS_ACTLVL(0);
526 
527     /*
528      * Because not sure in SPI or QPI mode, do QPI reset and then SPI reset.
529      */
530     /* QPI Reset Enable */
531     cmdBuf[0] = OPCODE_RSTEN;
532     SPIM_SET_SS_EN(1);                          /* CS activated.    */
533     SPIM_ENABLE_QUAD_OUTPUT_MODE();             /* 1-bit, Output.   */
534     spim_write(cmdBuf, sizeof (cmdBuf));
535     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
536 
537     /* QPI Reset */
538     cmdBuf[0] = OPCODE_RST;
539     SPIM_SET_SS_EN(1);                          /* CS activated.    */
540     SPIM_ENABLE_QUAD_OUTPUT_MODE();             /* 1-bit, Output.   */
541     spim_write(cmdBuf, sizeof (cmdBuf));
542     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
543 
544     /* SPI ResetEnable */
545     cmdBuf[0] = OPCODE_RSTEN;
546     SPIM_SET_SS_EN(1);                          /* CS activated.    */
547     SPIM_ENABLE_SING_OUTPUT_MODE();             /* 1-bit, Output.   */
548     spim_write(cmdBuf, sizeof (cmdBuf));
549     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
550 
551     /* SPI Reset */
552     cmdBuf[0] = OPCODE_RST;
553     SPIM_SET_SS_EN(1);                          /* CS activated.    */
554     SPIM_ENABLE_SING_OUTPUT_MODE();             /* 1-bit, Output.   */
555     spim_write(cmdBuf, sizeof (cmdBuf));
556     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
557 
558     if (clrWP)
559     {
560         uint8_t dataBuf[] = {0x00U};
561 
562         spim_set_write_enable(1, 1UL);           /* Clear Block Protect. */
563         SPIM_WriteStatusRegister(dataBuf, sizeof (dataBuf), 1U);
564         spim_wait_write_done(1UL);
565     }
566 
567     SPIM_ReadJedecId(idBuf, sizeof (idBuf), 1UL);
568 
569     /* printf("ID: 0x%x, 0x%x, px%x\n", idBuf[0], idBuf[1], idBuf[2]); */
570 
571     for (i = 0UL; i < sizeof(g_Supported_List)/sizeof(g_Supported_List[0]); i++)
572     {
573         if (idBuf[0] == g_Supported_List[i])
574         {
575             ret = 0;
576         }
577     }
578     if (ret != 0)
579     {
580         SPIM_DBGMSG("Flash initialize failed!! 0x%x\n", idBuf[0]);
581     }
582     return ret;
583 }
584 
585 /**
586   * @brief      Issue JEDEC ID command.
587   * @param      idBuf       ID buffer.
588   * @param      u32NRx      Size of ID buffer.
589   * @param      u32NBit     N-bit transmit/receive.
590   * @return     None.
591   */
SPIM_ReadJedecId(uint8_t idBuf[],uint32_t u32NRx,uint32_t u32NBit)592 void SPIM_ReadJedecId(uint8_t idBuf[], uint32_t u32NRx, uint32_t u32NBit)
593 {
594     uint8_t cmdBuf[] = { OPCODE_RDID };          /* 1-byte JEDEC ID command.  */
595 
596     SPIM_SET_SS_EN(1);                          /* CS activated.    */
597     SwitchNBitOutput(u32NBit);
598     spim_write(cmdBuf, sizeof (cmdBuf));
599     SwitchNBitInput(u32NBit);
600     spim_read(idBuf, u32NRx);
601     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
602 }
603 
604 /** @cond HIDDEN_SYMBOLS */
605 
spim_enable_spansion_quad_mode(int isEn)606 static void spim_enable_spansion_quad_mode(int isEn)
607 {
608     uint8_t cmdBuf[3];
609     uint8_t dataBuf[1], status1;
610 
611     cmdBuf[0] = 0x5U;                            /* Read Status Register-1 */
612 
613     SPIM_SET_SS_EN(1);
614     SwitchNBitOutput(1UL);
615     spim_write(cmdBuf, sizeof (cmdBuf));
616     SwitchNBitInput(1UL);
617     spim_read(dataBuf, sizeof (dataBuf));
618     SPIM_SET_SS_EN(0);
619     /* SPIM_DBGMSG("SR1 = 0x%x\n", dataBuf[0]); */
620 
621     status1 = dataBuf[0];
622 
623     cmdBuf[0] = 0x35U;                           /* Read Configuration Register-1 */
624 
625     SPIM_SET_SS_EN(1);
626     SwitchNBitOutput(1UL);
627     spim_write(cmdBuf, sizeof (cmdBuf));
628     SwitchNBitInput(1UL);
629     spim_read(dataBuf, sizeof (dataBuf));
630     SPIM_SET_SS_EN(0);
631     /* SPIM_DBGMSG("CR1 = 0x%x\n", dataBuf[0]); */
632 
633     spim_set_write_enable(1, 1UL);
634 
635     cmdBuf[0] =  0x1U;                           /* Write register   */
636     cmdBuf[1] =  status1;
637 
638     if (isEn)
639     {
640         cmdBuf[2] = dataBuf[0] | 0x2U;           /* set QUAD         */
641     }
642     else
643     {
644         cmdBuf[2] = dataBuf[0] & ~0x2U;          /* clear QUAD       */
645     }
646 
647     SPIM_SET_SS_EN(1);
648     SwitchNBitOutput(1UL);
649     spim_write(cmdBuf, 3UL);
650     SPIM_SET_SS_EN(0);
651 
652     spim_set_write_enable(0, 1UL);
653 
654 
655     cmdBuf[0] = 0x35U;                           /* Read Configuration Register-1 */
656 
657     SPIM_SET_SS_EN(1);
658     SwitchNBitOutput(1UL);
659     spim_write(cmdBuf, sizeof (cmdBuf));
660     SwitchNBitInput(1UL);
661     spim_read(dataBuf, sizeof (dataBuf));
662     SPIM_SET_SS_EN(0);
663 
664     /* SPIM_DBGMSG("CR1 = 0x%x\n", dataBuf[0]); */
665     N_delay(10000);
666 }
667 
668 /** @endcond HIDDEN_SYMBOLS */
669 
670 /**
671   * @brief      Set Quad Enable/disable.
672   * @param      isEn        Enable/disable.
673   * @param      u32NBit     N-bit transmit/receive.
674   * @return     None.
675   */
SPIM_SetQuadEnable(int isEn,uint32_t u32NBit)676 void SPIM_SetQuadEnable(int isEn, uint32_t u32NBit)
677 {
678     uint8_t  idBuf[3];
679     uint8_t  dataBuf[2];
680 
681     SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
682 
683     SPIM_DBGMSG("SPIM_SetQuadEnable - Flash ID is 0x%x\n", idBuf[0]);
684 
685     switch (idBuf[0])
686     {
687     case MFGID_WINBOND:                      /* Winbond SPI flash  */
688         SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
689         SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
690         SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
691         if (isEn)
692         {
693             dataBuf[1] |= SR2_QE;
694         }
695         else
696         {
697             dataBuf[1] &= ~SR2_QE;
698         }
699 
700         spim_set_write_enable(1, u32NBit);   /* Write Enable.    */
701         SPIM_WriteStatusRegister2(dataBuf, sizeof (dataBuf), u32NBit);
702         spim_wait_write_done(u32NBit);
703 
704         SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
705         SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
706         SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
707         break;
708 
709     case MFGID_MXIC:                         /* MXIC SPI flash.  */
710     case MFGID_EON:
711     case MFGID_ISSI:                         /* ISSI SPI flash.  */
712         spim_set_write_enable(1, u32NBit);   /* Write Enable.    */
713         dataBuf[0] = isEn ? SR_QE : 0U;
714         SPIM_WriteStatusRegister(dataBuf, sizeof (dataBuf), u32NBit);
715         spim_wait_write_done(u32NBit);
716         break;
717 
718     case MFGID_SPANSION:
719         spim_enable_spansion_quad_mode(isEn);
720         break;
721 
722     default:
723         break;
724     }
725 }
726 
727 /**
728   * @brief      Enter/exit QPI mode.
729   * @param      isEn        Enable/disable.
730   * @return     None.
731   */
spim_eon_set_qpi_mode(int isEn)732 static void spim_eon_set_qpi_mode(int isEn)
733 {
734     uint8_t cmdBuf[1];                           /* 1-byte command.  */
735 
736     uint8_t status[1];
737     SPIM_ReadStatusRegister(status, sizeof (status), 1UL);
738     SPIM_DBGMSG("Status: 0x%x\n", status[0]);
739 
740     if (isEn)                                    /* Assume in SPI mode. */
741     {
742         cmdBuf[0] = OPCODE_ENQPI;
743 
744         SPIM_SET_SS_EN(1);                      /* CS activated.    */
745         SwitchNBitOutput(1UL);
746         spim_write(cmdBuf, sizeof (cmdBuf));
747         SPIM_SET_SS_EN(0);                      /* CS deactivated.  */
748     }
749     else                                         /* Assume in QPI mode. */
750     {
751         cmdBuf[0] = OPCODE_EXQPI;
752 
753         SPIM_SET_SS_EN(1);                      /* CS activated.    */
754         SwitchNBitOutput(4UL);
755         spim_write(cmdBuf, sizeof (cmdBuf));
756         SPIM_SET_SS_EN(0);                      /* CS deactivated.  */
757     }
758 
759     SPIM_ReadStatusRegister(status, sizeof (status), 1UL);
760     SPIM_DBGMSG("Status: 0x%x\n", status[0]);
761 }
762 
763 
SPIM_SPANSION_4Bytes_Enable(int isEn,uint32_t u32NBit)764 static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit)
765 {
766     uint8_t cmdBuf[2];
767     uint8_t dataBuf[1];
768 
769     cmdBuf[0] = OPCODE_BRRD;
770     SPIM_SET_SS_EN(1);                          /* CS activated.    */
771     SwitchNBitOutput(u32NBit);
772     spim_write(cmdBuf, 1UL);
773     SwitchNBitInput(1UL);
774     spim_read(dataBuf, 1UL);
775     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
776 
777     SPIM_DBGMSG("Bank Address register= 0x%x\n", dataBuf[0]);
778 
779     cmdBuf[0] =  OPCODE_BRWR;
780 
781     if (isEn)
782     {
783         cmdBuf[1] = dataBuf[0] | 0x80U;          /* set EXTADD       */
784     }
785     else
786     {
787         cmdBuf[1] = dataBuf[0] & ~0x80U;         /* clear EXTADD     */
788     }
789 
790     SPIM_SET_SS_EN(1);                          /* CS activated.    */
791     SwitchNBitOutput(1UL);
792     spim_write(cmdBuf, 2UL);
793     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
794 }
795 
796 /** @cond HIDDEN_SYMBOLS */
797 
798 /**
799   * @brief      Query 4-byte address mode enabled or not.
800   * @param      u32NBit     N-bit transmit/receive.
801   * @return     0: 4-byte address mode disabled. 1: 4-byte address mode enabled.
802   */
SPIM_Is4ByteModeEnable(uint32_t u32NBit)803 int SPIM_Is4ByteModeEnable(uint32_t u32NBit)
804 {
805     int  isEn = 0;
806     int  isSupt = 0;
807     uint8_t  idBuf[3];
808     uint8_t  dataBuf[1];
809 
810     SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
811 
812     /* Based on Flash size, check if 4-byte address mode is supported.  */
813     switch (idBuf[0])
814     {
815     case MFGID_WINBOND:
816     case MFGID_MXIC:
817     case MFGID_EON:
818         isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
819         break;
820 
821     case MFGID_ISSI:
822         isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
823         break;
824 
825     default:
826         break;
827     }
828 
829     if (isSupt != 0)
830     {
831         if (idBuf[0] == MFGID_WINBOND)
832         {
833             /* Winbond SPI flash. */
834             SPIM_ReadStatusRegister3(dataBuf, sizeof (dataBuf), u32NBit);
835             isEn = !! (dataBuf[0] & SR3_ADR);
836         }
837         else if ((idBuf[0] == MFGID_MXIC) || (idBuf[0] ==MFGID_EON))
838         {
839             /* MXIC/EON SPI flash. */
840             SPIM_ReadSecurityRegister(dataBuf, sizeof (dataBuf), u32NBit);
841             isEn = !! (dataBuf[0] & SCUR_4BYTE);
842         }
843     }
844 
845     return isEn;
846 }
847 
848 /** @endcond HIDDEN_SYMBOLS  */
849 
850 
851 /**
852   * @brief      Enter/Exit 4-byte address mode.
853   * @param      isEn        Enable/disable.
854   * @param      u32NBit     N-bit transmit/receive.
855   * @return     0           success
856   *             -1          failed
857   */
SPIM_Enable_4Bytes_Mode(int isEn,uint32_t u32NBit)858 int SPIM_Enable_4Bytes_Mode(int isEn, uint32_t u32NBit)
859 {
860     int  isSupt = 0L, ret = -1;
861     uint8_t idBuf[3];
862     uint8_t cmdBuf[1];                           /* 1-byte Enter/Exit 4-Byte Mode command. */
863     int32_t i32TimeOutCount = 0;
864 
865     SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
866 
867     /* Based on Flash size, check if 4-byte address mode is supported. */
868     switch (idBuf[0])
869     {
870     case MFGID_WINBOND:
871         isSupt = (idBuf[2] < 0x16U) ? 0L : 1L;
872         break;
873     case MFGID_MXIC:
874     case MFGID_EON:
875         isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
876         break;
877 
878     case MFGID_ISSI:
879         isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
880         break;
881 
882     case MFGID_SPANSION:
883         SPIM_SPANSION_4Bytes_Enable(isEn, u32NBit);
884         isSupt = 1L;
885         ret = 0L;
886         break;
887 
888     default:
889         break;
890     }
891 
892     if ((isSupt) && (idBuf[0] != MFGID_SPANSION))
893     {
894         cmdBuf[0] = isEn ? OPCODE_EN4B : OPCODE_EX4B;
895 
896         SPIM_SET_SS_EN(1);                      /* CS activated.    */
897         SwitchNBitOutput(u32NBit);
898         spim_write(cmdBuf, sizeof (cmdBuf));
899         SPIM_SET_SS_EN(0);                      /* CS deactivated.  */
900 
901         /*
902          * FIXME: Per test, 4BYTE Indicator bit doesn't set after EN4B, which
903          * doesn't match spec(MX25L25635E), so skip the check below.
904          */
905         ret = 0;
906         if (idBuf[0] != MFGID_MXIC)
907         {
908             /*
909              *  About over 100 instrucsions executed, just want to give
910              *  a time-out about 1 seconds to avoid infinite loop
911              */
912             i32TimeOutCount = (SystemCoreClock)/100;
913 
914             if (isEn)
915             {
916                 while ((i32TimeOutCount-- > 0) && !SPIM_Is4ByteModeEnable(u32NBit)) { }
917             }
918             else
919             {
920                 while ((i32TimeOutCount-- > 0) && SPIM_Is4ByteModeEnable(u32NBit)) { }
921             }
922             if (i32TimeOutCount <= 0)
923                 ret = -1;
924         }
925     }
926     return ret;
927 }
928 
929 
SPIM_WinbondUnlock(uint32_t u32NBit)930 void SPIM_WinbondUnlock(uint32_t u32NBit)
931 {
932     uint8_t   idBuf[3];
933     uint8_t   dataBuf[4];
934 
935     SPIM_ReadJedecId(idBuf, sizeof (idBuf), u32NBit);
936 
937     if ((idBuf[0] != MFGID_WINBOND) || (idBuf[1] != 0x40) || (idBuf[2] != 0x16))
938     {
939         SPIM_DBGMSG("SPIM_WinbondUnlock - Not W25Q32, do nothing.\n");
940         return;
941     }
942 
943     SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
944     SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
945     SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
946     dataBuf[1] &= ~0x40;    /* clear Status Register-1 SEC bit */
947 
948     spim_set_write_enable(1, u32NBit);   /* Write Enable.    */
949     SPIM_WriteStatusRegister2(dataBuf, sizeof (dataBuf), u32NBit);
950     spim_wait_write_done(u32NBit);
951 
952     SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
953     SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
954     SPIM_DBGMSG("Status Register (after unlock): 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
955 }
956 
957 /**
958   * @brief      Erase whole chip.
959   * @param      u32NBit     N-bit transmit/receive.
960   * @param      isSync      Block or not.
961   * @return     None.
962   */
SPIM_ChipErase(uint32_t u32NBit,int isSync)963 void SPIM_ChipErase(uint32_t u32NBit, int isSync)
964 {
965     uint8_t cmdBuf[] = { OPCODE_CHIP_ERASE };    /* 1-byte Chip Erase command. */
966 
967     spim_set_write_enable(1, u32NBit);           /* Write Enable.    */
968 
969     SPIM_SET_SS_EN(1);                          /* CS activated.    */
970     SwitchNBitOutput(u32NBit);
971     spim_write(cmdBuf, sizeof (cmdBuf));
972     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
973 
974     if (isSync)
975     {
976         spim_wait_write_done(u32NBit);
977     }
978 }
979 
980 
981 /**
982   * @brief      Erase one block.
983   * @param      u32Addr         Block to erase which contains the u32Addr.
984   * @param      is4ByteAddr     4-byte u32Address or not.
985   * @param      u8ErsCmd        Erase command.
986   * @param      u32NBit         N-bit transmit/receive.
987   * @param      isSync      Block or not.
988   * @return     None.
989   */
SPIM_EraseBlock(uint32_t u32Addr,int is4ByteAddr,uint8_t u8ErsCmd,uint32_t u32NBit,int isSync)990 void SPIM_EraseBlock(uint32_t u32Addr, int is4ByteAddr, uint8_t u8ErsCmd, uint32_t u32NBit, int isSync)
991 {
992     uint8_t  cmdBuf[16];
993     uint32_t  buf_idx = 0UL;
994 
995     spim_set_write_enable(1, u32NBit);           /* Write Enable.    */
996 
997     cmdBuf[buf_idx++] = u8ErsCmd;
998 
999     if (is4ByteAddr)
1000     {
1001         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1002         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1003         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1004         cmdBuf[buf_idx++] = (uint8_t) (u32Addr & 0xFFUL);
1005     }
1006     else
1007     {
1008         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1009         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1010         cmdBuf[buf_idx++] = (uint8_t) (u32Addr & 0xFFUL);
1011     }
1012 
1013     SPIM_SET_SS_EN(1);                      /* CS activated.    */
1014     SwitchNBitOutput(u32NBit);
1015     spim_write(cmdBuf, buf_idx);
1016     SPIM_SET_SS_EN(0);                      /* CS deactivated.  */
1017 
1018     if (isSync)
1019     {
1020         spim_wait_write_done(u32NBit);
1021     }
1022 }
1023 
1024 
1025 /** @cond HIDDEN_SYMBOLS */
1026 
1027 /**
1028   * @brief      Write data in the same page by I/O mode.
1029   * @param      u32Addr     Start u32Address to write.
1030   * @param      is4ByteAddr 4-byte u32Address or not.
1031   * @param      u32NTx      Number of bytes to write.
1032   * @param      pu8TxBuf    Transmit buffer.
1033   * @param      wrCmd       Write command.
1034   * @param      u32NBitCmd  N-bit transmit command.
1035   * @param      u32NBitAddr N-bit transmit u32Address.
1036   * @param      u32NBitDat  N-bit transmit/receive data.
1037   * @param      isSync      Block or not.
1038   * @return     None.
1039   */
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)1040 static void SPIM_WriteInPageDataByIo(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1041                                      uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int isSync)
1042 {
1043     uint8_t   cmdBuf[16];
1044     uint32_t  buf_idx;
1045 
1046     spim_set_write_enable(1, u32NBitCmd);        /* Write Enable.    */
1047 
1048     SPIM_SET_SS_EN(1);                          /* CS activated.    */
1049 
1050     SwitchNBitOutput(u32NBitCmd);
1051     cmdBuf[0] = wrCmd;
1052     spim_write(cmdBuf, 1UL);                     /* Write out command. */
1053 
1054     buf_idx = 0UL;
1055     if (is4ByteAddr)
1056     {
1057         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1058         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1059         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1060         cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1061     }
1062     else
1063     {
1064         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1065         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1066         cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1067     }
1068 
1069     SwitchNBitOutput(u32NBitAddr);
1070     spim_write(cmdBuf, buf_idx);                 /* Write out u32Address. */
1071 
1072     SwitchNBitOutput(u32NBitDat);
1073     spim_write(pu8TxBuf, u32NTx);                /* Write out data.  */
1074 
1075     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
1076 
1077     if (isSync)
1078     {
1079         spim_wait_write_done(u32NBitCmd);
1080     }
1081 }
1082 
1083 /**
1084   * @brief      Write data in the same page by Page Write mode.
1085   * @param      u32Addr     Start u32Address to write.
1086   * @param      is4ByteAddr 4-byte u32Address or not.
1087   * @param      u32NTx      Number of bytes to write.
1088   * @param      pu8TxBuf    Transmit buffer.
1089   * @param      wrCmd       Write command.
1090   * @param      isSync      Block or not.
1091   * @retval     SPIM_OK          SPIM operation OK.
1092   * @retval     SPIM_ERR_TIMEOUT SPIM operation abort due to timeout error.
1093   * @note       This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
1094   */
SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr,int is4ByteAddr,uint32_t u32NTx,uint8_t pu8TxBuf[],uint32_t wrCmd,int isSync)1095 static int32_t SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
1096         uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync)
1097 {
1098     uint32_t u32TimeOutCount;
1099 
1100     if ((wrCmd == CMD_QUAD_PAGE_PROGRAM_WINBOND) ||
1101             (wrCmd == CMD_QUAD_PAGE_PROGRAM_MXIC))
1102     {
1103         SPIM_SetQuadEnable(1, 1UL);              /* Set Quad Enable. */
1104     }
1105     else if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1106     {
1107         SPIM_SetQuadEnable(1, 1UL);              /* Set Quad Enable. */
1108         spim_eon_set_qpi_mode(1);                /* Enter QPI mode.  */
1109     }
1110 
1111     SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEWRITE);/* Switch to Page Write mode.   */
1112     SPIM_SET_SPIM_MODE(wrCmd);                  /* SPIM mode.       */
1113     SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr);        /* Enable/disable 4-Byte Address.  */
1114 
1115     SPIM->SRAMADDR = (uint32_t) pu8TxBuf;        /* SRAM u32Address. */
1116     SPIM->DMACNT = u32NTx;                       /* Transfer length. */
1117     SPIM->FADDR = u32Addr;                       /* Flash u32Address.*/
1118     SPIM_SET_GO();                               /* Go.              */
1119 
1120     if (isSync)
1121     {
1122         u32TimeOutCount = SPIM_TIMEOUT;
1123         SPIM_WAIT_FREE()
1124         {
1125             if(--u32TimeOutCount == 0) return SPIM_ERR_TIMEOUT;
1126         }
1127     }
1128 
1129     if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
1130     {
1131         spim_eon_set_qpi_mode(0);                /* Exit QPI mode.   */
1132     }
1133 
1134     return SPIM_OK;
1135 }
1136 
1137 /** @endcond HIDDEN_SYMBOLS */
1138 
1139 /**
1140   * @brief      Write data to SPI Flash by sending commands manually (I/O mode).
1141   * @param      u32Addr: Start u32Address to write.
1142   * @param      is4ByteAddr: 4-byte u32Address or not.
1143   * @param      u32NTx: Number of bytes to write.
1144   * @param      pu8TxBuf: Transmit buffer.
1145   * @param      wrCmd: Write command.
1146   * @param      u32NBitCmd: N-bit transmit command.
1147   * @param      u32NBitAddr: N-bit transmit u32Address.
1148   * @param      u32NBitDat: N-bit transmit/receive data.
1149   * @return     None.
1150   */
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)1151 void SPIM_IO_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
1152                    uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat)
1153 {
1154     uint32_t  pageOffset, toWr;
1155     uint32_t  buf_idx = 0UL;
1156 
1157     pageOffset = u32Addr % 256UL;
1158 
1159     if ((pageOffset + u32NTx) <= 256UL)          /* Do all the bytes fit onto one page ? */
1160     {
1161         SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, u32NTx, &pu8TxBuf[buf_idx],
1162                                  wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1163     }
1164     else
1165     {
1166         toWr = 256UL - pageOffset;               /* Size of data remaining on the first page. */
1167 
1168         SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1169                                  wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1170         u32Addr += toWr;                         /* Advance indicator.  */
1171         u32NTx -= toWr;
1172         buf_idx += toWr;
1173 
1174         while (u32NTx)
1175         {
1176             toWr = 256UL;
1177             if (toWr > u32NTx)
1178             {
1179                 toWr = u32NTx;
1180             }
1181 
1182             SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
1183                                      wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
1184             u32Addr += toWr;                 /* Advance indicator.  */
1185             u32NTx -= toWr;
1186             buf_idx += toWr;
1187         }
1188     }
1189 }
1190 
1191 /**
1192   * @brief      Read data from SPI Flash by sending commands manually (I/O mode).
1193   * @param      u32Addr     Start u32Address to read.
1194   * @param      is4ByteAddr 4-byte u32Address or not.
1195   * @param      u32NRx      Number of bytes to read.
1196   * @param      pu8RxBuf    Receive buffer.
1197   * @param      rdCmd       Read command.
1198   * @param      u32NBitCmd  N-bit transmit command.
1199   * @param      u32NBitAddr N-bit transmit u32Address.
1200   * @param      u32NBitDat  N-bit transmit/receive data.
1201   * @param      u32NDummy   Number of dummy bytes following address.
1202   * @return     None.
1203   */
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)1204 void SPIM_IO_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[], uint8_t rdCmd,
1205                   uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int u32NDummy)
1206 {
1207     uint8_t   cmdBuf[16];
1208     uint32_t  buf_idx;
1209 
1210     SPIM_SET_SS_EN(1);                      /* CS activated.    */
1211 
1212     cmdBuf[0] = rdCmd;
1213     SwitchNBitOutput(u32NBitCmd);
1214     spim_write(cmdBuf, 1UL);                 /* Write out command. */
1215 
1216     buf_idx = 0UL;
1217     if (is4ByteAddr)
1218     {
1219         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 24);
1220         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1221         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1222         cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1223     }
1224     else
1225     {
1226         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 16);
1227         cmdBuf[buf_idx++] = (uint8_t) (u32Addr >> 8);
1228         cmdBuf[buf_idx++] = (uint8_t) u32Addr;
1229     }
1230     SwitchNBitOutput(u32NBitAddr);
1231     spim_write(cmdBuf, buf_idx);                 /* Write out u32Address. */
1232 
1233     buf_idx = 0UL;
1234     while (u32NDummy --)
1235     {
1236         cmdBuf[buf_idx++] = 0x00U;
1237     }
1238 
1239     /* Same bit mode as above. */
1240     spim_write(cmdBuf, buf_idx);                 /* Write out dummy bytes. */
1241 
1242     SwitchNBitInput(u32NBitDat);
1243     spim_read(pu8RxBuf, u32NRx);                 /* Read back data.  */
1244 
1245     SPIM_SET_SS_EN(0);                          /* CS deactivated.  */
1246 }
1247 
1248 /**
1249   * @brief      Write data to SPI Flash by Page Write mode.
1250   * @param      u32Addr     Start address to write.
1251   * @param      is4ByteAddr 4-byte address or not.
1252   * @param      u32NTx      Number of bytes to write.
1253   * @param      pu8TxBuf    Transmit buffer.
1254   * @param      wrCmd       Write command.
1255   * @return     None.
1256   */
SPIM_DMA_Write(uint32_t u32Addr,int is4ByteAddr,uint32_t u32NTx,uint8_t pu8TxBuf[],uint32_t wrCmd)1257 void SPIM_DMA_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint32_t wrCmd)
1258 {
1259     uint32_t   pageOffset, toWr;
1260     uint32_t   buf_idx = 0UL;
1261 
1262     pageOffset = u32Addr % 256UL;
1263 
1264     if ((pageOffset + u32NTx) <= 256UL)
1265     {
1266         /* Do all the bytes fit onto one page ? */
1267         SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, u32NTx, pu8TxBuf, wrCmd, 1);
1268     }
1269     else
1270     {
1271         toWr = 256UL - pageOffset;               /* Size of data remaining on the first page. */
1272 
1273         SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1274 
1275         u32Addr += toWr;                         /* Advance indicator. */
1276         u32NTx -= toWr;
1277         buf_idx += toWr;
1278 
1279         while (u32NTx)
1280         {
1281             toWr = 256UL;
1282             if (toWr > u32NTx)
1283             {
1284                 toWr = u32NTx;
1285             }
1286 
1287             SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
1288 
1289             u32Addr += toWr;                 /* Advance indicator. */
1290             u32NTx -= toWr;
1291             buf_idx += toWr;
1292         }
1293     }
1294 }
1295 
1296 /**
1297   * @brief      Read data from SPI Flash by Page Read mode.
1298   * @param      u32Addr     Start address to read.
1299   * @param      is4ByteAddr 4-byte u32Address or not.
1300   * @param      u32NRx      Number of bytes to read.
1301   * @param      pu8RxBuf    Receive buffer.
1302   * @param      u32RdCmd    Read command.
1303   * @param      isSync      Block or not.
1304   * @retval     SPIM_OK          SPIM operation OK.
1305   * @retval     SPIM_ERR_TIMEOUT SPIM operation abort due to timeout error.
1306   * @note       This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
1307   */
SPIM_DMA_Read(uint32_t u32Addr,int is4ByteAddr,uint32_t u32NRx,uint8_t pu8RxBuf[],uint32_t u32RdCmd,int isSync)1308 int32_t SPIM_DMA_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[],
1309                    uint32_t u32RdCmd, int isSync)
1310 {
1311     uint32_t u32TimeOutCount;
1312 
1313     SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEREAD); /* Switch to Page Read mode. */
1314     SPIM_SET_SPIM_MODE(u32RdCmd);               /* SPIM mode.       */
1315     SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr);        /* Enable/disable 4-Byte Address. */
1316 
1317     SPIM->SRAMADDR = (uint32_t) pu8RxBuf;        /* SRAM u32Address. */
1318     SPIM->DMACNT = u32NRx;                       /* Transfer length. */
1319     SPIM->FADDR = u32Addr;                       /* Flash u32Address.*/
1320     SPIM_SET_GO();                              /* Go.              */
1321 
1322     if (isSync)
1323     {
1324         u32TimeOutCount = SPIM_TIMEOUT;
1325         SPIM_WAIT_FREE()                       /* Wait for DMA done.  */
1326         {
1327             if(--u32TimeOutCount == 0) return SPIM_ERR_TIMEOUT;
1328         }
1329     }
1330 
1331     return SPIM_OK;
1332 }
1333 
1334 /**
1335   * @brief      Enter Direct Map mode.
1336   * @param      is4ByteAddr     4-byte u32Address or not.
1337   * @param      u32RdCmd        Read command.
1338   * @param      u32IdleIntvl    Idle interval.
1339   * @return     None.
1340   */
SPIM_EnterDirectMapMode(int is4ByteAddr,uint32_t u32RdCmd,uint32_t u32IdleIntvl)1341 void SPIM_EnterDirectMapMode(int is4ByteAddr, uint32_t u32RdCmd, uint32_t u32IdleIntvl)
1342 {
1343     SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr);        /* Enable/disable 4-byte u32Address. */
1344     SPIM_SET_SPIM_MODE(u32RdCmd);               /* SPIM mode.       */
1345     SPIM_SET_IDL_INTVL(u32IdleIntvl);            /* Idle interval.   */
1346     SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_DIRECTMAP);   /* Switch to Direct Map mode.     */
1347 }
1348 
1349 /**
1350   * @brief      Exit Direct Map mode.
1351   * @return     None.
1352   */
SPIM_ExitDirectMapMode(void)1353 void SPIM_ExitDirectMapMode(void)
1354 {
1355     SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO);       /* Switch back to Normal mode.  */
1356 }
1357 
1358 
1359 /*@}*/ /* end of group SPIM_EXPORTED_FUNCTIONS */
1360 
1361 /*@}*/ /* end of group SPIM_Driver */
1362 
1363 /*@}*/ /* end of group Standard_Driver */
1364