1 /*
2 * Copyright 2019-2020 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdbool.h>
8
9 #include "mflash_drv.h"
10
11 #include "fsl_flexspi.h"
12 #include "fsl_cache.h"
13 #include "pin_mux.h"
14
15 #define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 2
16 #define NOR_CMD_LUT_SEQ_IDX_READ_FAST 1
17 #define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 0 // set it to index0 to align with xip settings
18 #define NOR_CMD_LUT_SEQ_IDX_READSTATUS 3
19 #define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 4
20 #define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
21 #define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE 6
22 #define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
23 #define NOR_CMD_LUT_SEQ_IDX_READID 8
24 #define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 9
25 #define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
26 #define NOR_CMD_LUT_SEQ_IDX_EXITQPI 11
27 #define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 12
28
29 #define CUSTOM_LUT_LENGTH 60
30 #define FLASH_BUSY_STATUS_POL 1
31 #define FLASH_BUSY_STATUS_OFFSET 0
32
33 #define FLASH_SIZE 0x10000
34
35 #ifndef XIP_EXTERNAL_FLASH
36 flexspi_device_config_t deviceconfig = {
37 .flexspiRootClk = 100000000,
38 .flashSize = FLASH_SIZE,
39 .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
40 .CSInterval = 2,
41 .CSHoldTime = 3,
42 .CSSetupTime = 3,
43 .dataValidTime = 0,
44 .columnspace = 0,
45 .enableWordAddress = 0,
46 .AWRSeqIndex = 0,
47 .AWRSeqNumber = 0,
48 .ARDSeqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD,
49 .ARDSeqNumber = 1,
50 .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
51 .AHBWriteWaitInterval = 0,
52 };
53 #endif
54
55 static uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
56 /* Normal read mode -SDR */
57 [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =
58 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
59 [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =
60 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
61
62 /* Fast read mode - SDR */
63 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST] =
64 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
65 /* In XIP, the speed of external flash is set to 133MHz, and the external flash require to match 8 corresponding dummy cycles.
66 * However, cm4 core cases or other non XIP boot targets are not suitable for XIP boot flow, uses flash default configuration */
67 #if defined(XIP_BOOT_HEADER_ENABLE) && XIP_BOOT_HEADER_ENABLE
68 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] = FLEXSPI_LUT_SEQ(
69 kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x0B, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
70 #else
71 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] = FLEXSPI_LUT_SEQ(
72 kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
73 #endif
74
75 /* Fast read quad mode - SDR */
76 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =
77 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),
78 #if defined(XIP_BOOT_HEADER_ENABLE) && XIP_BOOT_HEADER_ENABLE
79 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(
80 kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x09, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),
81 #else
82 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(
83 kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),
84 #endif
85
86 /* Read extend parameters */
87 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =
88 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
89
90 /* Write Enable */
91 [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =
92 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
93
94 /* Erase Sector */
95 [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =
96 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
97
98 /* Page Program - single mode */
99 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =
100 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
101 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =
102 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
103
104 /* Page Program - quad mode */
105 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] =
106 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
107 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] =
108 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
109
110 /* Read ID */
111 [4 * NOR_CMD_LUT_SEQ_IDX_READID] =
112 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xAB, kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x18),
113 [4 * NOR_CMD_LUT_SEQ_IDX_READID + 1] =
114 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
115
116 /* Enable Quad mode */
117 [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
118 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
119
120 /* Enter QPI mode */
121 [4 * NOR_CMD_LUT_SEQ_IDX_ENTERQPI] =
122 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
123
124 /* Exit QPI mode */
125 [4 * NOR_CMD_LUT_SEQ_IDX_EXITQPI] =
126 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
127
128 /* Read status register */
129 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] =
130 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
131 };
132
flexspi_nor_wait_bus_busy(FLEXSPI_Type * base)133 static status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base)
134 {
135 /* Wait status ready. */
136 bool isBusy;
137 uint32_t readValue;
138 status_t status;
139 flexspi_transfer_t flashXfer;
140
141 flashXfer.deviceAddress = 0;
142 flashXfer.port = kFLEXSPI_PortA1;
143 flashXfer.cmdType = kFLEXSPI_Read;
144 flashXfer.SeqNumber = 1;
145 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUSREG;
146 flashXfer.data = &readValue;
147 flashXfer.dataSize = 1;
148
149 do
150 {
151 status = FLEXSPI_TransferBlocking(base, &flashXfer);
152
153 if (status != kStatus_Success)
154 {
155 return status;
156 }
157 if (FLASH_BUSY_STATUS_POL)
158 {
159 if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
160 {
161 isBusy = true;
162 }
163 else
164 {
165 isBusy = false;
166 }
167 }
168 else
169 {
170 if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
171 {
172 isBusy = false;
173 }
174 else
175 {
176 isBusy = true;
177 }
178 }
179
180 } while (isBusy);
181
182 return status;
183 }
184
flexspi_nor_write_enable(FLEXSPI_Type * base,uint32_t baseAddr)185 static status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr)
186 {
187 flexspi_transfer_t flashXfer;
188 status_t status;
189
190 /* Write neable */
191 flashXfer.deviceAddress = baseAddr;
192 flashXfer.port = kFLEXSPI_PortA1;
193 flashXfer.cmdType = kFLEXSPI_Command;
194 flashXfer.SeqNumber = 1;
195 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;
196
197 status = FLEXSPI_TransferBlocking(base, &flashXfer);
198
199 return status;
200 }
201
flexspi_nor_enable_quad_mode(FLEXSPI_Type * base)202 status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base)
203 {
204 flexspi_transfer_t flashXfer;
205 status_t status;
206 uint32_t writeValue = 0x40;
207
208 /* Write neable */
209 status = flexspi_nor_write_enable(base, 0);
210
211 if (status != kStatus_Success)
212 {
213 return status;
214 }
215
216 /* Enable quad mode. */
217 flashXfer.deviceAddress = 0;
218 flashXfer.port = kFLEXSPI_PortA1;
219 flashXfer.cmdType = kFLEXSPI_Write;
220 flashXfer.SeqNumber = 1;
221 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG;
222 flashXfer.data = &writeValue;
223 flashXfer.dataSize = 1;
224
225 status = FLEXSPI_TransferBlocking(base, &flashXfer);
226 if (status != kStatus_Success)
227 {
228 return status;
229 }
230
231 status = flexspi_nor_wait_bus_busy(base);
232
233 return status;
234 }
235
flexspi_nor_flash_sector_erase(FLEXSPI_Type * base,uint32_t address)236 static status_t flexspi_nor_flash_sector_erase(FLEXSPI_Type *base, uint32_t address)
237 {
238 status_t status;
239 flexspi_transfer_t flashXfer;
240
241 /* Write enable */
242 status = flexspi_nor_write_enable(base, 0);
243
244 if (status != kStatus_Success)
245 {
246 return status;
247 }
248
249 flashXfer.deviceAddress = address;
250 flashXfer.port = kFLEXSPI_PortA1;
251 flashXfer.cmdType = kFLEXSPI_Command;
252 flashXfer.SeqNumber = 1;
253 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR;
254 status = FLEXSPI_TransferBlocking(base, &flashXfer);
255
256 if (status != kStatus_Success)
257 {
258 return status;
259 }
260
261 status = flexspi_nor_wait_bus_busy(base);
262
263 return status;
264 }
265
flexspi_nor_flash_page_program(FLEXSPI_Type * base,uint32_t address,const uint32_t * src)266 static status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src)
267 {
268 status_t status;
269 flexspi_transfer_t flashXfer;
270
271 /* Write enable */
272 status = flexspi_nor_write_enable(base, address);
273
274 if (status != kStatus_Success)
275 {
276 return status;
277 }
278
279 /* Prepare page program command */
280 flashXfer.deviceAddress = address;
281 flashXfer.port = kFLEXSPI_PortA1;
282 flashXfer.cmdType = kFLEXSPI_Write;
283 flashXfer.SeqNumber = 1;
284 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;
285 flashXfer.data = (uint32_t *)src;
286 flashXfer.dataSize = MFLASH_PAGE_SIZE;
287 status = FLEXSPI_TransferBlocking(base, &flashXfer);
288
289 if (status != kStatus_Success)
290 {
291 return status;
292 }
293
294 status = flexspi_nor_wait_bus_busy(base);
295
296 return status;
297 }
298
flexspi_nor_read_data(FLEXSPI_Type * base,uint32_t startAddress,uint32_t * buffer,uint32_t length)299 static status_t flexspi_nor_read_data(FLEXSPI_Type *base, uint32_t startAddress, uint32_t *buffer, uint32_t length)
300 {
301 status_t status;
302 flexspi_transfer_t flashXfer;
303 uint32_t readAddress = startAddress;
304
305 /* Read page. */
306 flashXfer.deviceAddress = readAddress;
307 flashXfer.port = kFLEXSPI_PortA1;
308 flashXfer.cmdType = kFLEXSPI_Read;
309 flashXfer.SeqNumber = 1;
310 flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD;
311 flashXfer.data = buffer;
312 flashXfer.dataSize = length;
313
314 status = FLEXSPI_TransferBlocking(base, &flashXfer);
315
316 return status;
317 }
318
319 /* Initialize flash peripheral,
320 * cannot be invoked directly, requires calling wrapper in non XIP memory */
mflash_drv_init_internal(void)321 static int32_t mflash_drv_init_internal(void)
322 {
323 status_t status = kStatus_Success;
324
325 /* NOTE: Multithread access is not supported for SRAM target.
326 * XIP target MUST be protected by disabling global interrupts
327 * since all ISR (and API that is used inside) is placed at XIP.
328 * It is necessary to place at least "mflash_drv.o", "fsl_flexspi.o" to SRAM */
329 /* disable interrupts when running from XIP */
330 uint32_t primask = __get_PRIMASK();
331
332 __asm("cpsid i");
333
334 #ifndef XIP_EXTERNAL_FLASH
335 flexspi_config_t config;
336
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.ahbConfig.enableAHBBufferable = true;
343 config.ahbConfig.enableAHBCachable = true;
344 config.rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackFromDqsPad;
345 FLEXSPI_Init(MFLASH_FLEXSPI, &config);
346
347 /* AHB Read Address option bit. This option bit is intend to remove AHB burst start address alignment limitation */
348 MFLASH_FLEXSPI->AHBCR |= FLEXSPI_AHBCR_READADDROPT_MASK;
349
350 /* Configure flash settings according to serial flash feature. */
351 FLEXSPI_SetFlashConfig(MFLASH_FLEXSPI, &deviceconfig, kFLEXSPI_PortA1);
352 #endif
353
354 /* Update LUT table. */
355 FLEXSPI_UpdateLUT(MFLASH_FLEXSPI, 0, customLUT, CUSTOM_LUT_LENGTH);
356
357 #ifndef XIP_EXTERNAL_FLASH
358 /* Enter quad mode. */
359 status = flexspi_nor_enable_quad_mode(MFLASH_FLEXSPI);
360 #endif
361
362 /* Do software reset. */
363 FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
364
365 if (primask == 0)
366 {
367 __asm("cpsie i");
368 }
369
370 return status;
371 }
372
373 /* API - initialize 'mflash' */
mflash_drv_init(void)374 int32_t mflash_drv_init(void)
375 {
376 /* Necessary to have double wrapper call in non_xip memory */
377 return mflash_drv_init_internal();
378 }
379
380 /* Internal - erase single sector */
mflash_drv_sector_erase_internal(uint32_t sector_addr)381 static int32_t mflash_drv_sector_erase_internal(uint32_t sector_addr)
382 {
383 status_t status;
384 uint32_t primask = __get_PRIMASK();
385
386 __asm("cpsid i");
387
388 status = flexspi_nor_flash_sector_erase(MFLASH_FLEXSPI, sector_addr);
389
390 /* Do software reset. */
391 FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
392
393 DCACHE_InvalidateByRange(MFLASH_BASE_ADDRESS + sector_addr, MFLASH_SECTOR_SIZE);
394
395 if (primask == 0)
396 {
397 __asm("cpsie i");
398 }
399
400 /* Flush pipeline to allow pending interrupts take place
401 * before starting next loop */
402 __ISB();
403
404 return status;
405 }
406
407 /* Calling wrapper for 'mflash_drv_sector_erase_internal'.
408 * Erase one sector starting at 'sector_addr' - must be sector aligned.
409 */
mflash_drv_sector_erase(uint32_t sector_addr)410 int32_t mflash_drv_sector_erase(uint32_t sector_addr)
411 {
412 if (0 == mflash_drv_is_sector_aligned(sector_addr))
413 return kStatus_InvalidArgument;
414
415 return mflash_drv_sector_erase_internal(sector_addr);
416 }
417
418 /* Internal - write single page */
mflash_drv_page_program_internal(uint32_t page_addr,uint32_t * data)419 static int32_t mflash_drv_page_program_internal(uint32_t page_addr, uint32_t *data)
420 {
421 uint32_t primask = __get_PRIMASK();
422
423 __asm("cpsid i");
424
425 status_t status;
426 status = flexspi_nor_flash_page_program(MFLASH_FLEXSPI, page_addr, data);
427
428 /* Do software reset. */
429 FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
430
431 DCACHE_InvalidateByRange(MFLASH_BASE_ADDRESS + page_addr, MFLASH_PAGE_SIZE);
432
433 if (primask == 0)
434 {
435 __asm("cpsie i");
436 }
437
438 /* Flush pipeline to allow pending interrupts take place
439 * before starting next loop */
440 __ISB();
441
442 return status;
443 }
444
445 /* Calling wrapper for 'mflash_drv_page_program_internal'.
446 * Write 'data' to 'page_addr' - must be page aligned.
447 * NOTE: Don't try to store constant data that are located in XIP !!
448 */
mflash_drv_page_program(uint32_t page_addr,uint32_t * data)449 int32_t mflash_drv_page_program(uint32_t page_addr, uint32_t *data)
450 {
451 if (0 == mflash_drv_is_page_aligned(page_addr))
452 return kStatus_InvalidArgument;
453
454 return mflash_drv_page_program_internal(page_addr, data);
455 }
456
457 /* Internal - read data */
mflash_drv_read_internal(uint32_t addr,uint32_t * buffer,uint32_t len)458 static int32_t mflash_drv_read_internal(uint32_t addr, uint32_t *buffer, uint32_t len)
459 {
460 uint32_t primask = __get_PRIMASK();
461
462 __asm("cpsid i");
463
464 status_t status;
465 status = flexspi_nor_read_data(MFLASH_FLEXSPI, addr, buffer, len);
466
467 /* Do software reset. */
468 FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
469
470 if (primask == 0)
471 {
472 __asm("cpsie i");
473 }
474
475 /* Flush pipeline to allow pending interrupts take place
476 * before starting next loop */
477 __ISB();
478
479 return status;
480 }
481
482 /* API - Read data */
mflash_drv_read(uint32_t addr,uint32_t * buffer,uint32_t len)483 int32_t mflash_drv_read(uint32_t addr, uint32_t *buffer, uint32_t len)
484 {
485 /* Check alignment */
486 if (((uint32_t)buffer % 4) || (len % 4))
487 return kStatus_InvalidArgument;
488
489 return mflash_drv_read_internal(addr, buffer, len);
490 }
491
492 /* API - Get pointer to FLASH region */
mflash_drv_phys2log(uint32_t addr,uint32_t len)493 void *mflash_drv_phys2log(uint32_t addr, uint32_t len)
494 {
495 return (void *)(addr + MFLASH_BASE_ADDRESS);
496 }
497
498 /* API - Get pointer to FLASH region */
mflash_drv_log2phys(void * ptr,uint32_t len)499 uint32_t mflash_drv_log2phys(void *ptr, uint32_t len)
500 {
501 if ((uint32_t)ptr < MFLASH_BASE_ADDRESS)
502 return kStatus_InvalidArgument;
503
504 return ((uint32_t)ptr - MFLASH_BASE_ADDRESS);
505 }
506