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