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