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