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_spifi.h"
12 #include "pin_mux.h"
13
14 /* Command ID */
15 #define COMMAND_NUM (6)
16 #define READ (0)
17 #define PROGRAM_PAGE (1)
18 #define GET_STATUS (2)
19 #define ERASE_SECTOR (3)
20 #define WRITE_ENABLE (4)
21 #define WRITE_REGISTER (5)
22
23 /* Commands definition, taken from SPIFI demo */
24 static spifi_command_t command[COMMAND_NUM] = {
25 /* read */
26 {MFLASH_PAGE_SIZE, false, kSPIFI_DataInput, 1, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeAddrThreeBytes, 0x0B},
27 /* program */
28 {MFLASH_PAGE_SIZE, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeAddrThreeBytes, 0x2},
29 /* status */
30 {1, false, kSPIFI_DataInput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeOnly, 0x05},
31 /* erase */
32 {0, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeAddrThreeBytes, 0x20},
33 /* write enable */
34 {0, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeOnly, 0x06},
35 /* write register */
36 {4, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeOnly, 0x01}};
37
38 /* Wait until command finishes */
mflash_drv_check_if_finish(void)39 static inline void mflash_drv_check_if_finish(void)
40 {
41 uint8_t val = 0;
42 do
43 {
44 SPIFI_SetCommand(MFLASH_SPIFI, &command[GET_STATUS]);
45 while ((MFLASH_SPIFI->STAT & SPIFI_STAT_INTRQ_MASK) == 0U)
46 {
47 }
48 val = SPIFI_ReadDataByte(MFLASH_SPIFI);
49 } while (val & 0x1);
50 }
51
mflash_drv_read_mode(void)52 static void mflash_drv_read_mode(void)
53 {
54 /* Switch back to read mode */
55 SPIFI_ResetCommand(MFLASH_SPIFI);
56 SPIFI_SetMemoryCommand(MFLASH_SPIFI, &command[READ]);
57 }
58
59 /* Initialize SPIFI & flash peripheral,
60 * cannot be invoked directly, requires calling wrapper in non XIP memory */
mflash_drv_init_internal(void)61 static int32_t mflash_drv_init_internal(void)
62 {
63 /* NOTE: Multithread access is not supported for SRAM target.
64 * XIP target MUST be protected by disabling global interrupts
65 * since all ISR (and API that is used inside) is placed at XIP.
66 * It is necessary to place at least "mflash_drv_drv.o", "fsl_spifi.o" to SRAM */
67 /* disable interrupts when running from XIP
68 * TODO: store/restore previous PRIMASK on stack to avoid
69 * failure in case of nested critical sections !! */
70 uint32_t primask = __get_PRIMASK();
71
72 __asm("cpsid i");
73
74 spifi_config_t config = {0};
75
76 #ifndef XIP_IMAGE
77 uint32_t sourceClockFreq;
78 #if 0 /* Pinmuxing shall be initialized during board startup */
79 BOARD_InitSPIFI();
80 #endif
81 /* Reset peripheral */
82 RESET_PeripheralReset(kSPIFI_RST_SHIFT_RSTn);
83 /* Set SPIFI clock source */
84 CLOCK_AttachClk(kFRO_HF_to_SPIFI_CLK);
85 sourceClockFreq = CLOCK_GetSpifiClkFreq();
86 /* Set the clock divider */
87 CLOCK_SetClkDiv(kCLOCK_DivSpifiClk, sourceClockFreq / MFLASH_BAUDRATE, false);
88 /* Enable SPIFI clock */
89 CLOCK_EnableClock(kCLOCK_Spifi);
90 #endif
91
92 SPIFI_GetDefaultConfig(&config);
93 config.dualMode = kSPIFI_DualMode;
94 #ifdef XIP_IMAGE
95 config.disablePrefetch = false; // true;
96 config.disableCachePrefech = false; // true;
97 #else
98 config.disablePrefetch = false; // true;
99 config.disableCachePrefech = false; // true;
100 #endif
101
102 /* Reset the Command register */
103 SPIFI_ResetCommand(MFLASH_SPIFI);
104
105 /* Set time delay parameter */
106 MFLASH_SPIFI->CTRL = SPIFI_CTRL_TIMEOUT(config.timeout) | SPIFI_CTRL_CSHIGH(config.csHighTime) |
107 SPIFI_CTRL_D_PRFTCH_DIS(config.disablePrefetch) | SPIFI_CTRL_MODE3(config.spiMode) |
108 SPIFI_CTRL_PRFTCH_DIS(config.disableCachePrefech) | SPIFI_CTRL_DUAL(config.dualMode) |
109 SPIFI_CTRL_RFCLK(config.isReadFullClockCycle) | SPIFI_CTRL_FBCLK(config.isFeedbackClock);
110
111 mflash_drv_read_mode();
112
113 if (primask == 0)
114 {
115 __asm("cpsie i");
116 }
117
118 return kStatus_Success;
119 }
120
121 /* API - initialize 'mflash' - calling wrapper */
mflash_drv_init(void)122 int32_t mflash_drv_init(void)
123 {
124 return mflash_drv_init_internal();
125 }
126
127 /* Erase single sector */
mflash_drv_sector_erase_internal(uint32_t sector_addr)128 static int32_t mflash_drv_sector_erase_internal(uint32_t sector_addr)
129 {
130 uint32_t primask = __get_PRIMASK();
131
132 __asm("cpsid i");
133
134 /* Reset the SPIFI to switch to command mode */
135 SPIFI_ResetCommand(MFLASH_SPIFI);
136
137 /* Write enable */
138 SPIFI_SetCommand(MFLASH_SPIFI, &command[WRITE_ENABLE]);
139 /* Set address */
140 SPIFI_SetCommandAddress(MFLASH_SPIFI, sector_addr);
141 /* Erase sector */
142 SPIFI_SetCommand(MFLASH_SPIFI, &command[ERASE_SECTOR]);
143 /* Check if finished */
144 mflash_drv_check_if_finish();
145 /* Switch to read mode to enable interrupts as soon ass possible */
146 mflash_drv_read_mode();
147
148 if (primask == 0)
149 {
150 __asm("cpsie i");
151 }
152
153 /* Flush pipeline to allow pending interrupts take place */
154 __ISB();
155
156 return kStatus_Success;
157 }
158
159 /* API - Erase single sector - calling wrapper */
mflash_drv_sector_erase(uint32_t sector_addr)160 int32_t mflash_drv_sector_erase(uint32_t sector_addr)
161 {
162 return mflash_drv_sector_erase_internal(sector_addr);
163 }
164
165 /* Page program */
mflash_drv_page_program_internal(uint32_t page_addr,const uint32_t * data)166 static int32_t mflash_drv_page_program_internal(uint32_t page_addr, const uint32_t *data)
167 {
168 uint32_t primask = __get_PRIMASK();
169
170 __asm("cpsid i");
171
172 /* Program page */
173 SPIFI_ResetCommand(MFLASH_SPIFI);
174 SPIFI_SetCommand(MFLASH_SPIFI, &command[WRITE_ENABLE]);
175 SPIFI_SetCommandAddress(MFLASH_SPIFI, page_addr);
176 SPIFI_SetCommand(MFLASH_SPIFI, &command[PROGRAM_PAGE]);
177
178 /* Store 4B in each loop. Sector has always 4B alignment and size multiple of 4 */
179 for (uint32_t i = 0; i < MFLASH_PAGE_SIZE / sizeof(data[0]); i++)
180 {
181 SPIFI_WriteData(MFLASH_SPIFI, data[i]);
182 }
183
184 mflash_drv_check_if_finish();
185 /* Switch to read mode to enable interrupts as soon ass possible */
186 mflash_drv_read_mode();
187
188 if (primask == 0)
189 {
190 __asm("cpsie i");
191 }
192
193 /* Flush pipeline to allow pending interrupts take place */
194 __ISB();
195
196 return kStatus_Success;
197 }
198
199 /* API - Page program - calling wrapper */
mflash_drv_page_program(uint32_t page_addr,uint32_t * data)200 int32_t mflash_drv_page_program(uint32_t page_addr, uint32_t *data)
201 {
202 return mflash_drv_page_program_internal(page_addr, data);
203 }
204
205 /* API - Read data */
mflash_drv_read(uint32_t addr,uint32_t * buffer,uint32_t len)206 int32_t mflash_drv_read(uint32_t addr, uint32_t *buffer, uint32_t len)
207 {
208 void *ptr = mflash_drv_phys2log(addr, len);
209
210 if (ptr == NULL)
211 {
212 return kStatus_InvalidArgument;
213 }
214
215 memcpy(buffer, ptr, len);
216 return kStatus_Success;
217 }
218
219 /* API - Get pointer to FLASH region */
mflash_drv_phys2log(uint32_t addr,uint32_t len)220 void *mflash_drv_phys2log(uint32_t addr, uint32_t len)
221 {
222 uint32_t last_addr = addr + (len != 0 ? len - 1 : 0);
223
224 if (last_addr > (FSL_FEATURE_SPIFI_END_ADDR - FSL_FEATURE_SPIFI_START_ADDR))
225 {
226 return NULL;
227 }
228
229 return (void *)(addr + FSL_FEATURE_SPIFI_START_ADDR);
230 }
231
232 /* API - Get pointer to FLASH region */
mflash_drv_log2phys(void * ptr,uint32_t len)233 uint32_t mflash_drv_log2phys(void *ptr, uint32_t len)
234 {
235 uint32_t log_addr = (uint32_t)ptr;
236
237 if (log_addr < FSL_FEATURE_SPIFI_START_ADDR || log_addr > FSL_FEATURE_SPIFI_END_ADDR)
238 {
239 return MFLASH_INVALID_ADDRESS;
240 }
241
242 if (log_addr + len > FSL_FEATURE_SPIFI_END_ADDR + 1)
243 {
244 return MFLASH_INVALID_ADDRESS;
245 }
246
247 return (log_addr - FSL_FEATURE_SPIFI_START_ADDR);
248 }
249