1 /*
2  * Copyright 2022 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #include "board.h"
8 #include "fsl_common.h"
9 #include "fsl_device_registers.h"
10 #include "fsl_lpspi_mem_adapter.h"
11 #if (FSL_FEATURE_SOC_LPSPI_COUNT > 0)
12 #include "fsl_lpspi.h"
13 #endif
14 
15 /*******************************************************************************
16  * Definitions
17  ******************************************************************************/
18 enum
19 {
20     kFlashCmd_ReadId          = 0x9F,
21     kFlashCmd_ReadStatus      = 0x05,
22     kFlashCmd_ReadMemory24Bit = 0x03,
23     kFlashCmd_FastRead        = 0x0B,
24 
25     kFlashCmd_WriteEnable  = 0x06,
26     kFlashCmd_WriteDisable = 0x04,
27     kFlashCmd_PageProgram  = 0x02,
28 
29     kFlashCmd_ErasePage = 0x81,
30     kFlashCmd_Erase4K   = 0x20,
31     kFlashCmd_Erase32K  = 0x52,
32     kFlashCmd_Erase64K  = 0xD8,
33     kFlashCmd_EraseAll  = 0x60,
34 };
35 
36 /*******************************************************************************
37  * Prototypes
38  ******************************************************************************/
39 extern void BOARD_LpspiPcsPinControl(bool isSelected);
40 extern void BOARD_LpspiIomuxConfig(spi_pin_mode_t pinMode);
41 
42 static status_t LPSPI_MemWaitBusy(LPSPI_Type *base);
43 
44 /*******************************************************************************
45  * Codes
46  ******************************************************************************/
LPSPI_MemInit(spi_master_config_t * config,LPSPI_Type * base)47 status_t LPSPI_MemInit(spi_master_config_t *config, LPSPI_Type *base)
48 {
49     status_t status = kStatus_Fail;
50     do
51     {
52         if (config == NULL)
53         {
54             status = kStatus_InvalidArgument;
55             break;
56         }
57 
58         BOARD_LpspiIomuxConfig(kSpiIomux_SpiMode);
59 
60         lpspi_master_config_t lpspiMasterCfg;
61         LPSPI_MasterGetDefaultConfig(&lpspiMasterCfg);
62 
63         lpspiMasterCfg.baudRate                      = config->baudRate;
64         lpspiMasterCfg.pcsToSckDelayInNanoSec        = 1000000000U / lpspiMasterCfg.baudRate;
65         lpspiMasterCfg.lastSckToPcsDelayInNanoSec    = 1000000000U / lpspiMasterCfg.baudRate;
66         lpspiMasterCfg.betweenTransferDelayInNanoSec = 1000000000U / lpspiMasterCfg.baudRate;
67 
68         LPSPI_Type *lpspiInstance = base;
69         BOARD_LpspiPcsPinControl(false);
70 
71         LPSPI_MasterInit(lpspiInstance, &lpspiMasterCfg, config->clockFreq);
72         status = kStatus_Success;
73     } while (false);
74 
75     return status;
76 }
77 
78 #if defined(__ICCARM__)
79 #pragma optimize = speed
80 #endif
LPSPI_MemXfer(spi_mem_xfer_t * xfer,LPSPI_Type * base)81 status_t LPSPI_MemXfer(spi_mem_xfer_t *xfer, LPSPI_Type *base)
82 {
83     status_t status = kStatus_Fail;
84 
85     do
86     {
87         if (xfer == NULL)
88         {
89             status = kStatus_InvalidArgument;
90             break;
91         }
92 
93 #if (FSL_FEATURE_SOC_LPSPI_COUNT > 0)
94         BOARD_LpspiPcsPinControl(true);
95 
96         switch (xfer->mode)
97         {
98             case kSpiMem_Xfer_CommandOnly:
99             {
100                 lpspi_transfer_t txXfer;
101                 txXfer.txData      = xfer->cmd;
102                 txXfer.dataSize    = xfer->cmdSize;
103                 txXfer.rxData      = NULL;
104                 txXfer.configFlags = (uint32_t)kLPSPI_MasterPcs0 | (uint32_t)kLPSPI_MasterPcsContinuous;
105                 status             = LPSPI_MasterTransferBlocking(base, &txXfer);
106             }
107             break;
108             case kSpiMem_Xfer_CommandWriteData:
109             {
110                 lpspi_transfer_t cmdXfer;
111                 cmdXfer.txData      = xfer->cmd;
112                 cmdXfer.dataSize    = xfer->cmdSize;
113                 cmdXfer.rxData      = NULL;
114                 cmdXfer.configFlags = (uint32_t)kLPSPI_MasterPcs0 | (uint32_t)kLPSPI_MasterPcsContinuous;
115                 lpspi_transfer_t dataXfer;
116                 dataXfer.txData      = xfer->data;
117                 dataXfer.dataSize    = xfer->dataSize;
118                 dataXfer.rxData      = NULL;
119                 dataXfer.configFlags = (uint32_t)kLPSPI_MasterPcs0 | (uint32_t)kLPSPI_MasterPcsContinuous;
120                 status               = LPSPI_MasterTransferBlocking(base, &cmdXfer);
121                 if (status != kStatus_Success)
122                 {
123                     break;
124                 }
125                 status = LPSPI_MasterTransferBlocking(base, &dataXfer);
126             }
127             break;
128             case kSpiMem_Xfer_CommandReadData:
129             {
130                 lpspi_transfer_t cmdXfer;
131                 cmdXfer.txData      = xfer->cmd;
132                 cmdXfer.dataSize    = xfer->cmdSize;
133                 cmdXfer.rxData      = NULL;
134                 cmdXfer.configFlags = (uint32_t)kLPSPI_MasterPcs0 | (uint32_t)kLPSPI_MasterPcsContinuous;
135                 lpspi_transfer_t dataXfer;
136                 dataXfer.txData      = NULL;
137                 dataXfer.dataSize    = xfer->dataSize;
138                 dataXfer.rxData      = xfer->data;
139                 dataXfer.configFlags = (uint32_t)kLPSPI_MasterPcs0 | (uint32_t)kLPSPI_MasterPcsContinuous;
140                 status               = LPSPI_MasterTransferBlocking(base, &cmdXfer);
141                 if (status != kStatus_Success)
142                 {
143                     break;
144                 }
145                 status = LPSPI_MasterTransferBlocking(base, &dataXfer);
146             }
147             break;
148             default:
149                 /* To avoid MISRA-C 2012 rule 16.4 issue. */
150                 break;
151         }
152         BOARD_LpspiPcsPinControl(false);
153 
154 #endif
155     } while (false);
156 
157     return status;
158 }
159 
LPSPI_MemReadId(flash_id_t * flashId,LPSPI_Type * base)160 status_t LPSPI_MemReadId(flash_id_t *flashId, LPSPI_Type *base)
161 {
162     status_t status = kStatus_Fail;
163 
164     do
165     {
166         if (flashId == NULL)
167         {
168             status = kStatus_InvalidArgument;
169             break;
170         }
171 
172         uint8_t cmdBuffer[1] = {kFlashCmd_ReadId};
173         uint8_t dataBuffer[sizeof(flash_id_t)];
174         spi_mem_xfer_t spiMemXfer;
175         spiMemXfer.cmd      = cmdBuffer;
176         spiMemXfer.cmdSize  = sizeof(cmdBuffer);
177         spiMemXfer.data     = dataBuffer;
178         spiMemXfer.dataSize = sizeof(dataBuffer);
179         spiMemXfer.mode     = kSpiMem_Xfer_CommandReadData;
180         status              = LPSPI_MemXfer(&spiMemXfer, base);
181 
182         if (status != kStatus_Success)
183         {
184             break;
185         }
186 
187         (void)memcpy(&flashId->mid, dataBuffer, sizeof(flash_id_t));
188 
189         // According to JEP106AV, the valid ID starts from 0x01 to 0xFE, in which bit7 is the odd checksum bit,
190         // and 0x7F is Continuation code
191         uint32_t tempMid = flashId->mid;
192         // Invalid manufacturer id
193         if ((tempMid == 0u) || (tempMid == 0xFFu))
194         {
195             status = kStatus_Fail;
196             break;
197         }
198 
199         uint8_t *id_buf = (uint8_t *)dataBuffer;
200         for (uint32_t i = 0u; i < sizeof(flash_id_t); i++)
201         {
202             if (*id_buf == 0x7Fu)
203             {
204                 ++id_buf;
205                 continue;
206             }
207             break;
208         }
209 
210         tempMid              = *id_buf;
211         uint32_t oddBitCount = 0u;
212         for (uint32_t i = 0u; i < 8u; i++)
213         {
214             if ((tempMid & 1u) != 0U)
215             {
216                 ++oddBitCount;
217             }
218             tempMid >>= 1u;
219         }
220         // Parity: Odd
221         if ((oddBitCount & 1u) == 0u)
222         {
223             status = kStatus_Fail;
224             break;
225         }
226 
227         flashId->mid    = id_buf[0];
228         flashId->did[0] = id_buf[1];
229         flashId->did[1] = id_buf[2];
230 
231         status = kStatus_Success;
232 
233     } while (false);
234 
235     return status;
236 }
237 
LPSPI_MemWaitBusy(LPSPI_Type * base)238 static status_t LPSPI_MemWaitBusy(LPSPI_Type *base)
239 {
240     bool isBusy     = true;
241     status_t status = kStatus_Fail;
242     do
243     {
244         uint8_t cmdBuffer[] = {kFlashCmd_ReadStatus};
245         uint8_t flashStatus = 0u;
246         spi_mem_xfer_t spiMemXfer;
247         spiMemXfer.cmd      = cmdBuffer;
248         spiMemXfer.cmdSize  = sizeof(cmdBuffer);
249         spiMemXfer.data     = &flashStatus;
250         spiMemXfer.dataSize = 1u;
251         spiMemXfer.mode     = kSpiMem_Xfer_CommandReadData;
252 
253         status = LPSPI_MemXfer(&spiMemXfer, base);
254         if (status != kStatus_Success)
255         {
256             break;
257         }
258 
259         isBusy = (flashStatus & 1U) != 0U;
260     } while (isBusy);
261 
262     return status;
263 }
264 
LPSPI_MemIsBusy(LPSPI_Type * base,bool * isBusy)265 status_t LPSPI_MemIsBusy(LPSPI_Type *base, bool *isBusy)
266 {
267     status_t status = kStatus_Fail;
268 
269     uint8_t cmdBuffer[] = {kFlashCmd_ReadStatus};
270     uint8_t flashStatus = 0u;
271     spi_mem_xfer_t spiMemXfer;
272     spiMemXfer.cmd      = cmdBuffer;
273     spiMemXfer.cmdSize  = sizeof(cmdBuffer);
274     spiMemXfer.data     = &flashStatus;
275     spiMemXfer.dataSize = 1u;
276     spiMemXfer.mode     = kSpiMem_Xfer_CommandReadData;
277 
278     status = LPSPI_MemXfer(&spiMemXfer, base);
279     if (status != kStatus_Success)
280     {
281         return status;
282     }
283 
284     *isBusy = (flashStatus & 1U) != 0U;
285 
286     return status;
287 }
288 
LPSPI_MemRead(uint32_t addr,uint8_t * buffer,uint32_t lengthInBytes,bool isFastRead,LPSPI_Type * base)289 status_t LPSPI_MemRead(uint32_t addr, uint8_t *buffer, uint32_t lengthInBytes, bool isFastRead, LPSPI_Type *base)
290 {
291     status_t status = kStatus_Fail;
292 
293     uint8_t cmdBuffer[5];
294     uint32_t cmdSize = 4u;
295 
296     if (isFastRead)
297     {
298         cmdBuffer[0] = kFlashCmd_FastRead;
299         cmdSize      = 5u;
300         cmdBuffer[4] = 0x00u; // DUMMY byte for fast read operation.
301     }
302     else
303     {
304         cmdBuffer[0] = kFlashCmd_ReadMemory24Bit;
305     }
306 
307     uint32_t tmpAddr = addr;
308     for (uint32_t i = 3u; i > 0u; i--)
309     {
310         cmdBuffer[i] = (uint8_t)(tmpAddr & 0xFFu);
311         tmpAddr >>= 8u;
312     }
313 
314     spi_mem_xfer_t spiMemXfer;
315     spiMemXfer.cmd      = cmdBuffer;
316     spiMemXfer.cmdSize  = cmdSize;
317     spiMemXfer.data     = buffer;
318     spiMemXfer.dataSize = lengthInBytes;
319     spiMemXfer.mode     = kSpiMem_Xfer_CommandReadData;
320 
321     status = LPSPI_MemXfer(&spiMemXfer, base);
322 
323     return status;
324 }
325 
LPSPI_MemWriteEnable(LPSPI_Type * base)326 status_t LPSPI_MemWriteEnable(LPSPI_Type *base)
327 {
328     status_t status = kStatus_Fail;
329 
330     uint8_t cmdBuffer[5];
331     uint32_t cmdSize = 4u;
332 
333     cmdBuffer[0] = kFlashCmd_WriteEnable;
334     cmdSize      = 1u;
335 
336     spi_mem_xfer_t spiMemXfer;
337     spiMemXfer.cmd      = cmdBuffer;
338     spiMemXfer.cmdSize  = cmdSize;
339     spiMemXfer.data     = NULL;
340     spiMemXfer.dataSize = 0U;
341     spiMemXfer.mode     = kSpiMem_Xfer_CommandOnly;
342 
343     status = LPSPI_MemXfer(&spiMemXfer, base);
344 
345     return status;
346 }
347 
LPSPI_MemWritePage(uint32_t addr,uint8_t * buffer,uint32_t lengthInBytes,bool blocking,LPSPI_Type * base)348 status_t LPSPI_MemWritePage(uint32_t addr, uint8_t *buffer, uint32_t lengthInBytes, bool blocking, LPSPI_Type *base)
349 {
350     status_t status = kStatus_Fail;
351 
352     do
353     {
354         if (lengthInBytes == 0u)
355         {
356             status = kStatus_Success;
357             break;
358         }
359 
360         uint8_t cmdBuffer[5];
361         uint32_t cmdSize = 4u;
362 
363         status = LPSPI_MemWriteEnable(base);
364         if (status != kStatus_Success)
365         {
366             break;
367         }
368 
369         cmdBuffer[0]     = kFlashCmd_PageProgram;
370         uint32_t tmpAddr = addr;
371 
372         for (uint32_t i = 3u; i > 0u; i--)
373         {
374             cmdBuffer[i] = (uint8_t)(tmpAddr & 0xFFu);
375             tmpAddr >>= 8u;
376         }
377 
378         spi_mem_xfer_t spiMemXfer;
379         spiMemXfer.cmd      = cmdBuffer;
380         spiMemXfer.cmdSize  = cmdSize;
381         spiMemXfer.data     = buffer;
382         spiMemXfer.dataSize = lengthInBytes;
383         spiMemXfer.mode     = kSpiMem_Xfer_CommandWriteData;
384 
385         status = LPSPI_MemXfer(&spiMemXfer, base);
386         if (status != kStatus_Success)
387         {
388             break;
389         }
390 
391         if (true == blocking)
392         {
393             status = LPSPI_MemWaitBusy(base);
394         }
395     } while (false);
396 
397     return status;
398 }
399 
LPSPI_MemErase(uint32_t addr,eraseOptions_t option,bool blocking,LPSPI_Type * base)400 status_t LPSPI_MemErase(uint32_t addr, eraseOptions_t option, bool blocking, LPSPI_Type *base)
401 {
402     status_t status = kStatus_Fail;
403 
404     do
405     {
406         uint8_t cmdBuffer[5];
407         uint32_t cmdSize = 4u;
408 
409         status = LPSPI_MemWriteEnable(base);
410         if (status != kStatus_Success)
411         {
412             break;
413         }
414 
415         if (option == kSize_EraseAll)
416         {
417             cmdBuffer[0] = kFlashCmd_EraseAll;
418             cmdSize      = 1u;
419         }
420         else
421         {
422             switch (option)
423             {
424                 case kSize_ErasePage:
425                     cmdBuffer[0] = kFlashCmd_ErasePage;
426                     break;
427 
428                 case kSize_Erase4K:
429                     cmdBuffer[0] = kFlashCmd_Erase4K;
430                     break;
431 
432                 case kSize_Erase32K:
433                     cmdBuffer[0] = kFlashCmd_Erase32K;
434                     break;
435 
436                 case kSize_Erase64K:
437                     cmdBuffer[0] = kFlashCmd_Erase64K;
438                     break;
439 
440                 default:
441                     status = kStatus_Fail;
442                     break;
443             }
444             if (status != kStatus_Success)
445             {
446                 break;
447             }
448             uint32_t tmpAddr = addr;
449             for (uint32_t i = 3u; i > 0u; i--)
450             {
451                 cmdBuffer[i] = (uint8_t)(tmpAddr & 0xFFu);
452                 tmpAddr >>= 8u;
453             }
454         }
455 
456         spi_mem_xfer_t spiMemXfer;
457         spiMemXfer.cmd      = cmdBuffer;
458         spiMemXfer.cmdSize  = cmdSize;
459         spiMemXfer.data     = NULL;
460         spiMemXfer.dataSize = 0U;
461         spiMemXfer.mode     = kSpiMem_Xfer_CommandOnly;
462 
463         status = LPSPI_MemXfer(&spiMemXfer, base);
464         if (status != kStatus_Success)
465         {
466             break;
467         }
468 
469         if (true == blocking)
470         {
471             status = LPSPI_MemWaitBusy(base);
472         }
473     } while (false);
474 
475     return status;
476 }
477 
LPSPI_MemDeinit(LPSPI_Type * base)478 status_t LPSPI_MemDeinit(LPSPI_Type *base)
479 {
480     status_t status = kStatus_Fail;
481     do
482     {
483         // Assert the PCS to high first
484         BOARD_LpspiPcsPinControl(true);
485         // De-initialize LPSPI
486         LPSPI_Type *lpspiInstance = base;
487         LPSPI_Deinit(lpspiInstance);
488 
489         BOARD_LpspiIomuxConfig(kSpiIomux_DefaultMode);
490 
491         status = kStatus_Success;
492     } while (false);
493 
494     return status;
495 }
496