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