1 /*
2  * Copyright 2017-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 0x8000
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, 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, 0x0A, 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, 0x08, 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, 0xD7, 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     if (primask == 0)
363     {
364         __asm("cpsie i");
365     }
366 
367     return status;
368 }
369 
370 /* API - initialize 'mflash' */
mflash_drv_init(void)371 int32_t mflash_drv_init(void)
372 {
373     /* Necessary to have double wrapper call in non_xip memory */
374     return mflash_drv_init_internal();
375 }
376 
377 /* Internal - erase single sector */
mflash_drv_sector_erase_internal(uint32_t sector_addr)378 static int32_t mflash_drv_sector_erase_internal(uint32_t sector_addr)
379 {
380     status_t status;
381     uint32_t primask = __get_PRIMASK();
382 
383     __asm("cpsid i");
384 
385     status = flexspi_nor_flash_sector_erase(MFLASH_FLEXSPI, sector_addr);
386 
387     /* Do software reset. */
388     FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
389 
390     DCACHE_InvalidateByRange(MFLASH_BASE_ADDRESS + sector_addr, MFLASH_SECTOR_SIZE);
391 
392     if (primask == 0)
393     {
394         __asm("cpsie i");
395     }
396 
397     /* Flush pipeline to allow pending interrupts take place
398      * before starting next loop */
399     __ISB();
400 
401     return status;
402 }
403 
404 /* Calling wrapper for 'mflash_drv_sector_erase_internal'.
405  * Erase one sector starting at 'sector_addr' - must be sector aligned.
406  */
mflash_drv_sector_erase(uint32_t sector_addr)407 int32_t mflash_drv_sector_erase(uint32_t sector_addr)
408 {
409     if (0 == mflash_drv_is_sector_aligned(sector_addr))
410         return kStatus_InvalidArgument;
411 
412     return mflash_drv_sector_erase_internal(sector_addr);
413 }
414 
415 /* Internal - write single page */
mflash_drv_page_program_internal(uint32_t page_addr,uint32_t * data)416 static int32_t mflash_drv_page_program_internal(uint32_t page_addr, uint32_t *data)
417 {
418     uint32_t primask = __get_PRIMASK();
419 
420     __asm("cpsid i");
421 
422     status_t status;
423     status = flexspi_nor_flash_page_program(MFLASH_FLEXSPI, page_addr, data);
424 
425     /* Do software reset. */
426     FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
427 
428     DCACHE_InvalidateByRange(MFLASH_BASE_ADDRESS + page_addr, MFLASH_PAGE_SIZE);
429 
430     if (primask == 0)
431     {
432         __asm("cpsie i");
433     }
434 
435     /* Flush pipeline to allow pending interrupts take place
436      * before starting next loop */
437     __ISB();
438 
439     return status;
440 }
441 
442 /* Calling wrapper for 'mflash_drv_page_program_internal'.
443  * Write 'data' to 'page_addr' - must be page aligned.
444  * NOTE: Don't try to store constant data that are located in XIP !!
445  */
mflash_drv_page_program(uint32_t page_addr,uint32_t * data)446 int32_t mflash_drv_page_program(uint32_t page_addr, uint32_t *data)
447 {
448     if (0 == mflash_drv_is_page_aligned(page_addr))
449         return kStatus_InvalidArgument;
450 
451     return mflash_drv_page_program_internal(page_addr, data);
452 }
453 
454 /* Internal - read data */
mflash_drv_read_internal(uint32_t addr,uint32_t * buffer,uint32_t len)455 static int32_t mflash_drv_read_internal(uint32_t addr, uint32_t *buffer, uint32_t len)
456 {
457     uint32_t primask = __get_PRIMASK();
458 
459     __asm("cpsid i");
460 
461     status_t status;
462     status = flexspi_nor_read_data(MFLASH_FLEXSPI, addr, buffer, len);
463 
464     /* Do software reset. */
465     FLEXSPI_SoftwareReset(MFLASH_FLEXSPI);
466 
467     if (primask == 0)
468     {
469         __asm("cpsie i");
470     }
471 
472     /* Flush pipeline to allow pending interrupts take place
473      * before starting next loop */
474     __ISB();
475 
476     return status;
477 }
478 
479 /* API - Read data */
mflash_drv_read(uint32_t addr,uint32_t * buffer,uint32_t len)480 int32_t mflash_drv_read(uint32_t addr, uint32_t *buffer, uint32_t len)
481 {
482     /* Check alignment */
483     if (((uint32_t)buffer % 4) || (len % 4))
484         return kStatus_InvalidArgument;
485 
486     return mflash_drv_read_internal(addr, buffer, len);
487 }
488 
489 /* API - Get pointer to FLASH region */
mflash_drv_phys2log(uint32_t addr,uint32_t len)490 void *mflash_drv_phys2log(uint32_t addr, uint32_t len)
491 {
492     return (void *)(addr + MFLASH_BASE_ADDRESS);
493 }
494 
495 /* API - Get pointer to FLASH region */
mflash_drv_log2phys(void * ptr,uint32_t len)496 uint32_t mflash_drv_log2phys(void *ptr, uint32_t len)
497 {
498     if ((uint32_t)ptr < MFLASH_BASE_ADDRESS)
499         return kStatus_InvalidArgument;
500 
501     return ((uint32_t)ptr - MFLASH_BASE_ADDRESS);
502 }
503