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