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