1 /*
2 * Copyright 2017-2021 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdbool.h>
8
9 #include "mflash_drv.h"
10 #include "fsl_flexspi.h"
11 #include "fsl_cache.h"
12 #include "board.h"
13
14 #define FLASH_PORT kFLEXSPI_PortB1
15
16 #if !defined(BOARD_FLASH_RESET_GPIO) || !defined(BOARD_FLASH_RESET_GPIO_PORT) || !defined(BOARD_FLASH_RESET_GPIO_PIN)
17 #error FLASH reset pin needs to be specified. Please define BOARD_FLASH_RESET_GPIO, BOARD_FLASH_RESET_GPIO_PORT and BOARD_FLASH_RESET_GPIO_PIN in your board.h file.
18 #endif
19
20 #define NOR_CMD_LUT_SEQ_IDX_READ 0
21 #define NOR_CMD_LUT_SEQ_IDX_READSTATUS 1
22 #define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 2
23 #define NOR_CMD_LUT_SEQ_IDX_READID_OPI 3
24 #define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE_OPI 4
25 #define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
26 #define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 6
27 #define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 7
28 #define NOR_CMD_LUT_SEQ_IDX_ENTEROPI 8
29
30 /* NOTE: Workaround for debugger.
31 Must define AHB write FlexSPI sequence index to 9 to avoid debugger issue.
32 Debugger can attach to the CM33 core only when ROM executes to certain place.
33 At that point, AHB write FlexSPI sequence index is set to 9, but in LUT, the
34 command is not filled by ROM. If the debugger sets software breakpoint at flash
35 after reset/attachment, FlexSPI AHB write command will be triggered. It may
36 cause AHB bus hang if the command in LUT sequence index 9 is any read opeartion.
37 So we need to ensure at any time, the FlexSPI LUT sequence 9 for the flash must
38 be set to STOP command to avoid unexpected debugger behaivor.
39 */
40 #define NOR_CMD_LUT_SEQ_IDX_WRITE 9
41 #define NOR_CMD_LUT_SEQ_IDX_READSTATUS_OPI 10
42
43 #define CUSTOM_LUT_LENGTH 60
44 #define FLASH_BUSY_STATUS_POL 1
45 #define FLASH_BUSY_STATUS_OFFSET 0
46 #define FLASH_ERROR_STATUS_MASK 0x0e
47 #define FLASH_ENABLE_OCTAL_CMD 0x02
48 #define CACHE_MAINTAIN 1
49
50 #ifndef XIP_EXTERNAL_FLASH
51 static flexspi_device_config_t deviceconfig = {
52 .flexspiRootClk = 99000000,
53 .flashSize = FLASH_SIZE / 1024, /* flash size in KB */
54 .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
55 .CSInterval = 2,
56 .CSHoldTime = 3,
57 .CSSetupTime = 3,
58 .dataValidTime = 2,
59 .columnspace = 0,
60 .enableWordAddress = 0,
61 .AWRSeqIndex = NOR_CMD_LUT_SEQ_IDX_WRITE,
62 .AWRSeqNumber = 1,
63 .ARDSeqIndex = NOR_CMD_LUT_SEQ_IDX_READ,
64 .ARDSeqNumber = 1,
65 .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
66 .AHBWriteWaitInterval = 0,
67 };
68 #endif
69
70 static uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
71
72 /* OPI DDR read */
73 [4 * NOR_CMD_LUT_SEQ_IDX_READ + 0] =
74 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xEE, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x11),
75 [4 * NOR_CMD_LUT_SEQ_IDX_READ + 1] = FLEXSPI_LUT_SEQ(
76 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_8PAD, 0x29),
77 [4 * NOR_CMD_LUT_SEQ_IDX_READ + 2] =
78 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
79
80 /* Read status register */
81 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =
82 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
83
84 /* Write Enable */
85 [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =
86 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
87
88 /* Read ID */
89 [4 * NOR_CMD_LUT_SEQ_IDX_READID_OPI] =
90 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x9F, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x60),
91 [4 * NOR_CMD_LUT_SEQ_IDX_READID_OPI + 1] = FLEXSPI_LUT_SEQ(
92 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_8PAD, 0x16),
93 [4 * NOR_CMD_LUT_SEQ_IDX_READID_OPI + 2] =
94 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
95
96 /* Write Enable */
97 [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE_OPI] =
98 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x06, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xF9),
99
100 /* Erase Sector */
101 [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =
102 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x21, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xDE),
103 [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] =
104 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_STOP, kFLEXSPI_8PAD, 0),
105
106 /* Erase Chip */
107 [4 * NOR_CMD_LUT_SEQ_IDX_CHIPERASE] =
108 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x60, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x9F),
109
110 /* Program */
111 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =
112 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x12, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xED),
113 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(
114 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04),
115
116 /* Enter OPI mode */
117 [4 * NOR_CMD_LUT_SEQ_IDX_ENTEROPI] =
118 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x72, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x20),
119 [4 * NOR_CMD_LUT_SEQ_IDX_ENTEROPI + 1] =
120 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
121
122 /* Dummy write, do nothing when AHB write command is triggered. */
123 [4 * NOR_CMD_LUT_SEQ_IDX_WRITE] =
124 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
125
126 /* Read status register using Octal DDR read */
127 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS_OPI] =
128 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xFA),
129 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS_OPI + 1] = FLEXSPI_LUT_SEQ(
130 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_8PAD, 0x20),
131 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS_OPI + 2] =
132 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0),
133 };
134
flexspi_nor_wait_bus_busy(FLEXSPI_Type * base,bool enableOctal)135 static status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base, bool enableOctal)
136 {
137 /* Wait status ready. */
138 bool isBusy;
139 uint32_t readValue;
140 status_t status;
141 flexspi_transfer_t flashXfer;
142
143 flashXfer.deviceAddress = 0;
144 flashXfer.port = FLASH_PORT;
145 flashXfer.cmdType = kFLEXSPI_Read;
146 flashXfer.SeqNumber = 1;
147 if (enableOctal)
148 {
149 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUS_OPI;
150 }
151 else
152 {
153 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUS;
154 }
155
156 flashXfer.data = &readValue;
157 flashXfer.dataSize = 1;
158
159 do
160 {
161 status = FLEXSPI_TransferBlocking(base, &flashXfer);
162
163 if (status != kStatus_Success)
164 {
165 return status;
166 }
167 if (FLASH_BUSY_STATUS_POL)
168 {
169 if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
170 {
171 isBusy = true;
172 }
173 else
174 {
175 isBusy = false;
176 }
177 }
178 else
179 {
180 if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
181 {
182 isBusy = false;
183 }
184 else
185 {
186 isBusy = true;
187 }
188 }
189
190 } while (isBusy);
191
192 return status;
193 }
194
flexspi_nor_write_enable(FLEXSPI_Type * base,uint32_t baseAddr,bool enableOctal)195 static status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr, bool enableOctal)
196 {
197 flexspi_transfer_t flashXfer;
198 status_t status;
199
200 /* Write enable */
201 flashXfer.deviceAddress = baseAddr;
202 flashXfer.port = FLASH_PORT;
203 flashXfer.cmdType = kFLEXSPI_Command;
204 flashXfer.SeqNumber = 1;
205 if (enableOctal)
206 {
207 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE_OPI;
208 }
209 else
210 {
211 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;
212 }
213
214 status = FLEXSPI_TransferBlocking(base, &flashXfer);
215
216 return status;
217 }
218
flexspi_nor_enable_octal_mode(FLEXSPI_Type * base)219 static status_t flexspi_nor_enable_octal_mode(FLEXSPI_Type *base)
220 {
221 flexspi_transfer_t flashXfer;
222 status_t status;
223 uint32_t writeValue = FLASH_ENABLE_OCTAL_CMD;
224
225 /* Write enable */
226 status = flexspi_nor_write_enable(base, 0, false);
227
228 if (status != kStatus_Success)
229 {
230 return status;
231 }
232
233 /* Enable quad mode. */
234 flashXfer.deviceAddress = 0;
235 flashXfer.port = FLASH_PORT;
236 flashXfer.cmdType = kFLEXSPI_Write;
237 flashXfer.SeqNumber = 1;
238 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ENTEROPI;
239 flashXfer.data = &writeValue;
240 flashXfer.dataSize = 1;
241
242 status = FLEXSPI_TransferBlocking(base, &flashXfer);
243 if (status != kStatus_Success)
244 {
245 return status;
246 }
247
248 status = flexspi_nor_wait_bus_busy(base, true);
249
250 return status;
251 }
252
253 /* Internal - erase single sector */
flexspi_nor_flash_sector_erase(FLEXSPI_Type * base,uint32_t address)254 static status_t flexspi_nor_flash_sector_erase(FLEXSPI_Type *base, uint32_t address)
255 {
256 status_t status;
257 flexspi_transfer_t flashXfer;
258
259 /* Write enable */
260 status = flexspi_nor_write_enable(base, 0, true);
261
262 if (status != kStatus_Success)
263 {
264 return status;
265 }
266
267 flashXfer.deviceAddress = address;
268 flashXfer.port = FLASH_PORT;
269 flashXfer.cmdType = kFLEXSPI_Command;
270 flashXfer.SeqNumber = 1;
271 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR;
272 status = FLEXSPI_TransferBlocking(base, &flashXfer);
273
274 if (status != kStatus_Success)
275 {
276 return status;
277 }
278
279 status = flexspi_nor_wait_bus_busy(base, true);
280
281 return status;
282 }
283
284 /* Program page into serial flash using QSPI polling way */
flexspi_nor_flash_page_program(FLEXSPI_Type * base,uint32_t address,const uint32_t * src)285 static status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src)
286 {
287 status_t status;
288 flexspi_transfer_t flashXfer;
289
290 /* Write neable */
291 status = flexspi_nor_write_enable(base, address, true);
292
293 if (status != kStatus_Success)
294 {
295 return status;
296 }
297
298 /* Prepare page program command */
299 flashXfer.deviceAddress = address;
300 flashXfer.port = FLASH_PORT;
301 flashXfer.cmdType = kFLEXSPI_Write;
302 flashXfer.SeqNumber = 1;
303 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM;
304 flashXfer.data = (uint32_t *)src;
305 flashXfer.dataSize = MFLASH_PAGE_SIZE;
306 status = FLEXSPI_TransferBlocking(base, &flashXfer);
307
308 if (status != kStatus_Success)
309 {
310 return status;
311 }
312
313 status = flexspi_nor_wait_bus_busy(base, true);
314
315 return status;
316 }
317
mflash_drv_init_internal(void)318 static int32_t mflash_drv_init_internal(void)
319 {
320 uint64_t delay = USEC_TO_COUNT(20, SystemCoreClock);
321 uint32_t primask = __get_PRIMASK();
322
323 /* Define the init structure for the reset pin*/
324 gpio_pin_config_t reset_config = {
325 kGPIO_DigitalOutput,
326 1,
327 };
328
329 __asm("cpsid i");
330
331 /* Init output reset pin. */
332 GPIO_PortInit(GPIO, BOARD_FLASH_RESET_GPIO_PORT);
333 GPIO_PinInit(GPIO, BOARD_FLASH_RESET_GPIO_PORT, BOARD_FLASH_RESET_GPIO_PIN, &reset_config);
334
335 #ifndef XIP_EXTERNAL_FLASH
336 flexspi_config_t config;
337 /*Get FLEXSPI default settings and configure the flexspi. */
338 FLEXSPI_GetDefaultConfig(&config);
339
340 /*Set AHB buffer size for reading data through AHB bus. */
341 config.ahbConfig.enableAHBPrefetch = true;
342 config.rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackInternally;
343 #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)
344 config.enableCombination = true;
345 #endif
346 config.ahbConfig.enableAHBBufferable = true;
347 config.ahbConfig.enableAHBCachable = true;
348 FLEXSPI_Init(MFLASH_FLEXSPI, &config);
349
350 /* Configure flash settings according to serial flash feature. */
351 FLEXSPI_SetFlashConfig(MFLASH_FLEXSPI, &deviceconfig, FLASH_PORT);
352 #endif
353
354 /* Update LUT table. */
355 FLEXSPI_UpdateLUT(MFLASH_FLEXSPI, 0, customLUT, CUSTOM_LUT_LENGTH);
356
357 /* Hardware reset of external FLASH */
358 do
359 {
360 /* activate OSPI nRESET */
361 BOARD_FLASH_RESET_GPIO->B[BOARD_FLASH_RESET_GPIO_PORT][BOARD_FLASH_RESET_GPIO_PIN] = 0;
362 for (uint64_t i = 0; i < delay; i++)
363 {
364 __asm("nop");
365 }
366 /* deactivate OSPI nRESET */
367 BOARD_FLASH_RESET_GPIO->B[BOARD_FLASH_RESET_GPIO_PORT][BOARD_FLASH_RESET_GPIO_PIN] = 1;
368 flexspi_nor_enable_octal_mode(MFLASH_FLEXSPI);
369 } while (0);
370
371 /* Do software reset. */
372 // FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
373
374 // #if defined(EXAMPLE_INVALIDATE_FLEXSPI_CACHE)
375 // EXAMPLE_INVALIDATE_FLEXSPI_CACHE();
376 // #endif
377
378 if (primask == 0)
379 {
380 __asm("cpsie i");
381 }
382
383 return kStatus_Success;
384 }
385
386 /* API - initialize 'mflash' */
mflash_drv_init(void)387 int32_t mflash_drv_init(void)
388 {
389 /* Necessary to have double wrapper call in non_xip memory */
390 return mflash_drv_init_internal();
391 }
392
393 /* Internal - erase single sector */
mflash_drv_sector_erase_internal(uint32_t sector_addr)394 static int32_t mflash_drv_sector_erase_internal(uint32_t sector_addr)
395 {
396 status_t status;
397 uint32_t primask = __get_PRIMASK();
398
399 __asm("cpsid i");
400
401 status = flexspi_nor_flash_sector_erase(MFLASH_FLEXSPI, sector_addr);
402
403 /* Do software reset. */
404 // FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
405
406 DCACHE_InvalidateByRange(MFLASH_BASE_ADDRESS + sector_addr, MFLASH_SECTOR_SIZE);
407
408 if (primask == 0)
409 {
410 __asm("cpsie i");
411 }
412
413 /* Flush pipeline to allow pending interrupts take place
414 * before starting next loop */
415 __ISB();
416
417 return status;
418 }
419
420 /* Calling wrapper for 'mflash_drv_sector_erase_internal'.
421 * Erase one sector starting at 'sector_addr' - must be sector aligned.
422 */
mflash_drv_sector_erase(uint32_t sector_addr)423 int32_t mflash_drv_sector_erase(uint32_t sector_addr)
424 {
425 if (0 == mflash_drv_is_sector_aligned(sector_addr))
426 return kStatus_InvalidArgument;
427
428 return mflash_drv_sector_erase_internal(sector_addr);
429 }
430
431 /* Internal - write single page */
mflash_drv_page_program_internal(uint32_t page_addr,uint32_t * data)432 static int32_t mflash_drv_page_program_internal(uint32_t page_addr, uint32_t *data)
433 {
434 uint32_t primask = __get_PRIMASK();
435
436 __asm("cpsid i");
437
438 status_t status;
439 status = flexspi_nor_flash_page_program(MFLASH_FLEXSPI, page_addr, data);
440
441 /* Do software reset. */
442 // FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
443
444 DCACHE_InvalidateByRange(MFLASH_BASE_ADDRESS + page_addr, MFLASH_PAGE_SIZE);
445
446 if (primask == 0)
447 {
448 __asm("cpsie i");
449 }
450
451 /* Flush pipeline to allow pending interrupts take place
452 * before starting next loop */
453 __ISB();
454
455 return status;
456 }
457
458 /* Calling wrapper for 'mflash_drv_page_program_internal'.
459 * Write 'data' to 'page_addr' - must be page aligned.
460 * NOTE: Don't try to store constant data that are located in XIP !!
461 */
mflash_drv_page_program(uint32_t page_addr,uint32_t * data)462 int32_t mflash_drv_page_program(uint32_t page_addr, uint32_t *data)
463 {
464 if (0 == mflash_drv_is_page_aligned(page_addr))
465 return kStatus_InvalidArgument;
466
467 return mflash_drv_page_program_internal(page_addr, data);
468 }
469
470 /* API - Read data */
mflash_drv_read(uint32_t addr,uint32_t * buffer,uint32_t len)471 int32_t mflash_drv_read(uint32_t addr, uint32_t *buffer, uint32_t len)
472 {
473 memcpy(buffer, (void *)(addr + MFLASH_BASE_ADDRESS), len);
474 return kStatus_Success;
475 }
476
477 /* API - Get pointer to FLASH region */
mflash_drv_phys2log(uint32_t addr,uint32_t len)478 void *mflash_drv_phys2log(uint32_t addr, uint32_t len)
479 {
480 /* FLASH starts at MFLASH_BASE_ADDRESS */
481 return (void *)(addr + MFLASH_BASE_ADDRESS);
482 }
483
484 /* API - Get pointer to FLASH region */
mflash_drv_log2phys(void * ptr,uint32_t len)485 uint32_t mflash_drv_log2phys(void *ptr, uint32_t len)
486 {
487 if ((uint32_t)ptr < MFLASH_BASE_ADDRESS)
488 return kStatus_InvalidArgument;
489
490 /* FLASH starts at MFLASH_BASE_ADDRESS */
491 return ((uint32_t)ptr - MFLASH_BASE_ADDRESS);
492 }
493