1 /*
2 * Copyright 2017-2020, 2024 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdint.h>
8
9 #include "mflash_drv.h"
10
11 #define IFLASH_CMD_RD1ALL 0x00U // Read 1s all
12 #define IFLASH_CMD_RD1BLK 0x01U // Read 1s block
13 #define IFLASH_CMD_RD1SCR 0x02U // Read 1s sector
14 #define IFLASH_CMD_RD1PG 0x03U // Read 1s page
15 #define IFLASH_CMD_RD1PHR 0x04U // Read 1s phrase
16 #define IFLASH_CMD_RDMISR 0x05U // Read into MISR
17 #define IFLASH_CMD_RD1ISCR 0x12U // Read 1s IFR sector
18 #define IFLASH_CMD_RD1IPG 0x13U // Read 1s IFR page
19 #define IFLASH_CMD_RD1IPHR 0x14U // Read 1s IFR phrase
20 #define IFLASH_CMD_RDIMISR 0x15U // Read IFR into MISR
21 #define IFLASH_CMD_PGMPG 0x23U // Program page
22 #define IFLASH_CMD_PGMPHR 0x24U // Program phrase
23 #define IFLASH_CMD_ERSALL 0x40U // Erase all
24 #define IFLASH_CMD_ERSSCR 0x42U // Erase sector
25
26 #define IFLASH_ERROR_STAT_FLAGS (FMU_FSTAT_ACCERR_MASK | FMU_FSTAT_PVIOL_MASK | FMU_FSTAT_CMDABT_MASK)
27
iflash_prepare(void)28 static void iflash_prepare(void)
29 {
30 uint32_t fmu_fstat = FMU0->FSTAT;
31
32 while ((fmu_fstat & FMU_FSTAT_CCIF_MASK) != FMU_FSTAT_CCIF(1))
33 {
34 fmu_fstat = FMU0->FSTAT;
35 }
36
37 if ((fmu_fstat & IFLASH_ERROR_STAT_FLAGS) != 0UL)
38 {
39 FMU0->FSTAT = IFLASH_ERROR_STAT_FLAGS;
40 }
41 }
42
iflash_launch_command(bool pe_command,uint8_t pe_type)43 static status_t iflash_launch_command(bool pe_command, uint8_t pe_type)
44 {
45 FMU0->FSTAT = FMU_FSTAT_CCIF_MASK;
46
47 if (pe_command)
48 {
49 uint32_t fmu_fstat = FMU0->FSTAT;
50
51 while ((fmu_fstat & FMU_FSTAT_PEWEN_MASK) != FMU_FSTAT_PEWEN(pe_type))
52 {
53 if ((fmu_fstat & FMU_FSTAT_CCIF_MASK) != 0UL)
54 {
55 return kStatus_Fail;
56 }
57
58 fmu_fstat = FMU0->FSTAT;
59 }
60 }
61
62 return kStatus_Success;
63 }
64
iflash_finish_command(bool pe_command)65 static status_t iflash_finish_command(bool pe_command)
66 {
67 uint32_t fmu_fstat;
68
69 if (pe_command)
70 {
71 fmu_fstat = FMU0->FSTAT;
72
73 while ((fmu_fstat & FMU_FSTAT_PERDY_MASK) != FMU_FSTAT_PERDY(1))
74 {
75 if ((fmu_fstat & FMU_FSTAT_CCIF_MASK) != 0UL)
76 {
77 return kStatus_Fail;
78 }
79
80 fmu_fstat = FMU0->FSTAT;
81 }
82
83 FMU0->FSTAT = FMU_FSTAT_PERDY_MASK;
84 }
85
86 fmu_fstat = FMU0->FSTAT;
87
88 while ((fmu_fstat & FMU_FSTAT_CCIF_MASK) == 0UL)
89 {
90 fmu_fstat = FMU0->FSTAT;
91 }
92
93 return kStatus_Success;
94 }
95
mflash_drv_init(void)96 int32_t mflash_drv_init(void)
97 {
98 /* enable the Flash clock if not already set */
99 CLOCK_SetupClockCtrl(SYSCON_CLOCK_CTRL_FRO12MHZ_ENA_MASK);
100
101 return kStatus_Success;
102 }
103
mflash_drv_sector_erase(uint32_t sector_addr)104 int32_t mflash_drv_sector_erase(uint32_t sector_addr)
105 {
106 status_t ret;
107 uint32_t primask;
108
109 if ((sector_addr % MFLASH_SECTOR_SIZE) != 0UL)
110 {
111 return kStatus_InvalidArgument;
112 }
113
114 primask = __get_PRIMASK();
115 __disable_irq();
116
117 iflash_prepare();
118
119 FMU0->FCCOB[0] = IFLASH_CMD_ERSSCR;
120 FMU0->FCCOB[1] = 0x00U;
121
122 ret = iflash_launch_command(true, 1);
123
124 if (ret != kStatus_Success)
125 {
126 goto cleanup;
127 }
128
129 *(uint32_t *)(sector_addr) = 0UL;
130 *(uint32_t *)(sector_addr + 0x04UL) = 0UL;
131 *(uint32_t *)(sector_addr + 0x08UL) = 0UL;
132 *(uint32_t *)(sector_addr + 0x0CUL) = 0UL;
133
134 ret = iflash_finish_command(true);
135
136 cleanup:
137
138 if (primask == 0UL)
139 {
140 __enable_irq();
141 }
142
143 /* Flush pipeline to allow pending interrupts take place
144 * before starting next loop */
145 __ISB();
146
147 return ret;
148 }
149
mflash_drv_page_program(uint32_t page_addr,uint32_t * data)150 int32_t mflash_drv_page_program(uint32_t page_addr, uint32_t *data)
151 {
152 status_t ret;
153 uint32_t primask;
154
155 if ((page_addr % MFLASH_PAGE_SIZE) != 0UL)
156 {
157 return kStatus_InvalidArgument;
158 }
159
160 primask = __get_PRIMASK();
161 __disable_irq();
162
163 iflash_prepare();
164
165 FMU0->FCCOB[0] = IFLASH_CMD_PGMPG;
166 FMU0->FCCOB[1] = 0x00U;
167
168 ret = iflash_launch_command(true, 2);
169 if (ret != kStatus_Success)
170 {
171 goto cleanup;
172 }
173
174 for (uint32_t i = 0UL; i < MFLASH_PAGE_SIZE; i += 4UL)
175 {
176 *(uint32_t *)(page_addr + i) = ((uint32_t *)data)[i / 4UL];
177 }
178
179 ret = iflash_finish_command(true);
180
181 cleanup:
182
183 if (primask == 0UL)
184 {
185 __enable_irq();
186 }
187
188 /* Flush pipeline to allow pending interrupts take place
189 * before starting next loop */
190 __ISB();
191
192 return ret;
193 }
194
mflash_drv_phrase_program(uint32_t phrase_addr,uint32_t * data)195 int32_t mflash_drv_phrase_program(uint32_t phrase_addr, uint32_t *data)
196 {
197 status_t ret;
198 uint32_t primask;
199
200 if ((phrase_addr % MFLASH_PHRASE_SIZE) != 0UL)
201 {
202 return kStatus_InvalidArgument;
203 }
204
205 primask = __get_PRIMASK();
206 __disable_irq();
207
208 iflash_prepare();
209
210 FMU0->FCCOB[0] = IFLASH_CMD_PGMPHR;
211 FMU0->FCCOB[1] = 0x00U;
212
213 ret = iflash_launch_command(true, 1);
214 if (ret != kStatus_Success)
215 {
216 goto cleanup;
217 }
218
219 for (uint32_t i = 0UL; i < MFLASH_PHRASE_SIZE; i += 4UL)
220 {
221 *(uint32_t *)(phrase_addr + i) = ((uint32_t *)data)[i / 4UL];
222 }
223
224 ret = iflash_finish_command(true);
225
226 cleanup:
227
228 if (primask == 0UL)
229 {
230 __enable_irq();
231 }
232
233 /* Flush pipeline to allow pending interrupts take place
234 * before starting next loop */
235 __ISB();
236
237 return ret;
238 }
239
mflash_drv_read(uint32_t addr,uint32_t * buffer,uint32_t len)240 int32_t mflash_drv_read(uint32_t addr, uint32_t *buffer, uint32_t len)
241 {
242 (void)memcpy((void *)buffer, (void *)addr, len);
243 return kStatus_Success;
244 }
245
mflash_drv_phys2log(uint32_t addr,uint32_t len)246 void *mflash_drv_phys2log(uint32_t addr, uint32_t len)
247 {
248 /* FLASH is directly mapped in the address space */
249 return (void *)(addr);
250 }
251
mflash_drv_log2phys(void * ptr,uint32_t len)252 uint32_t mflash_drv_log2phys(void *ptr, uint32_t len)
253 {
254 /* FLASH is directly mapped in the address space */
255 return (uint32_t)ptr;
256 }
257