Callisto4Bootloader: lib/c4_qspi.c Source File

Callisto4Bootloader

c4_qspi.c
Go to the documentation of this file.
1
10 //************************************************************************
11 //
12 // MODULES USED
13 //
14 //************************************************************************
15
16 #include "c4_qspi_types.h"
17 #include "c4_privilege_modes.h"
18 #include "c4_qspi.h" // include this first. It must not depend on any other header.
19 #include "bl_api.h"
20
21 #include "fsl_debug_console.h"
22 #include <stdbool.h>
23 #include <stddef.h>
24
25
26 extern void BL_SysTick_DelayTicks(uint32_t n);
27
28 //************************************************************************
29 //
30 // DEFINITIONS AND MACROS
31 //
32 //************************************************************************
33
34 //************************************************************************
35 //
36 // TYPEDEFS, ENUMS, UNIONS AND STRUCTURES
37 //
38 //************************************************************************
39
40 //************************************************************************
41 //
42 // LOCAL PROTOTYPES
43 //
44 //************************************************************************
45
56 ptrdiff_t writeSector(uintptr_t pSect, const uint8_t *pData);
57
58 //************************************************************************
59 //
60 // LOCAL VARIABLES AND CONSTS
61 //
62 //************************************************************************
63
64 flexspi_nor_config_t sFlashConfig;
65 static serial_nor_config_option_t sFlashConfigOption;
66 bool FLASH_INITIALISED = false;
67
68 //************************************************************************
69 //
70 // EXPORTED FUNCTIONS
71 //
72 //************************************************************************
73
74 exit_code_t C4_QSPI_init(void)
75 {
76 exit_code_t rc = C4_ERR_OK;
77
78 if (!FLASH_INITIALISED) // this hasn't been done before.
79 {
80 bl_api_init();
81 sFlashConfigOption.option0.U = 0xc0000007;
82 C4_QSPI_getConfig(&sFlashConfig);
83 status_t status = flexspi_nor_flash_init(C4_FLASH_INSTANCE, &sFlashConfig);
84 if (kStatus_Success == status)
85 FLASH_INITIALISED = true;
86 else
87 {
88 rc = C4_ERR_HARDWARE;
89 }
90 }
91
92 return rc;
93 }
94 /*
95 * ***********************************************************************
96 */
97 exit_code_t C4_QSPI_getConfig(flexspi_nor_config_t *pConfig)
98 {
99 exit_code_t rc = C4_ERR_OK;
100
101 status_t status = flexspi_nor_get_config(C4_FLASH_INSTANCE, pConfig, &sFlashConfigOption);
102 if (status != kStatus_Success)
103 {
104 C4_PRINT("flexspi_nor_get_config returns %ld\n", status);
105 rc = C4_ERR_HARDWARE;
106 }
107 else
108 {
109 C4_PRINT("Flash get configuration passed\n");
110 C4_PRINT("Got NOR Flash configuration\n");
111 C4_PRINT("\tpConfig->memConfig.tag 0x%08lx\n", pConfig->memConfig.tag);
112 C4_PRINT("\tpConfig->memConfig.version 0x%08lx\n", pConfig->memConfig.version);
113
114 /* The fields available in flexspi_nor_config_t are in drivers/flexspi_nor_flash.h */
115
116 }
117 return rc;
118 }
119 /*
120 * ***********************************************************************
121 */
122
123 exit_code_t C4_QSPI_erase(uintptr_t addr, size_t len)
124 {
125 exit_code_t rc = C4_ERR_OK;
126
127 // C4_PRINT("%s(0x%p, %d, 0x%p)\n", __FUNCTION__, addr, len);
128
129 if (0 == len)
130 {
131 // nothing to do
132 return C4_ERR_OK;
133 }
134
135 if (!FLASH_INITIALISED)
136 {
137 C4_PRINT("%s QSPI uninitialised\n", __FUNCTION__);
138 return C4_ERR_UNINITIALISED;
139 }
140
141 // test in range
142 if ((FlexSPI_AMBA_BASE > addr) ||
143 (FlexSPI_AMBA_BASE + sFlashConfig.memConfig.sflashA1Size <= addr + len))
144 {
145 C4_PRINT("%s target range (0x%p - 0x%p) outside flash range (0x%p - 0x%p)\n",
146 __FUNCTION__,
147 (void *)(addr),
148 (void *)(addr + len),
149 (void *)(FlexSPI_AMBA_BASE),
150 (void *)(FlexSPI_AMBA_BASE + sFlashConfig.memConfig.sflashA1Size -1));
151 return C4_ERR_RANGE;
152 }
153
154 // minimum erase is one sector so if we don't cover an exact number of sectors
155 // call C4_QSPI_write with FF data.
156
157
158 if ( (((addr - FlexSPI_AMBA_BASE) % C4_FLASH_SECTOR_SIZE) == 0) &&
159 ((len % C4_FLASH_SECTOR_SIZE) == 0))
160 {
161 C4_PRINT("Erasing whole sector(s)\n");
162 status_t status = flexspi_nor_flash_erase(C4_FLASH_INSTANCE, &sFlashConfig, addr, len);
163
164 if (kStatus_Success != status)
165 {
166 C4_PRINT("flexspi_nor_flash_erase returns %ld\n", status);
167 rc = C4_ERR_HARDWARE;
168 }
169 }
170 else
171 {
172 C4_PRINT("Erasing partial sector(s)\n");
173 uint8_t buf[len+1];
174 memset(buf, 0xFF, len);
175 buf[len] = '\0';
176 C4_QSPI_write(addr, len, buf);
177 }
178 return rc;
179 }
180 /*
181 * ***********************************************************************
182 */
183
184 exit_code_t C4_QSPI_read(uintptr_t addr, size_t len, uint8_t *pData)
185 {
186 exit_code_t rc = C4_ERR_OK;
187
188 // C4_PRINT("%s(0x%p, %d, 0x%p)\n", __FUNCTION__, addr, len, pData);
189
190 if (0 == len)
191 {
192 // nothing to do
193 return C4_ERR_OK;
194 }
195
196 if (!FLASH_INITIALISED)
197 {
198 C4_PRINT("%s QSPI uninitialised\n", __FUNCTION__);
199 return C4_ERR_UNINITIALISED;
200 }
201
202 // test in range
203 if ((FlexSPI_AMBA_BASE > addr) ||
204 (FlexSPI_AMBA_BASE + sFlashConfig.memConfig.sflashA1Size <= addr + len))
205 {
206 C4_PRINT("%s target range (0x%p - 0x%p) outside flash range (0x%p - 0x%p)\n",
207 __FUNCTION__,
208 (void *)(addr),
209 (void *)(addr + len),
210 (void *)(FlexSPI_AMBA_BASE),
211 (void *)(FlexSPI_AMBA_BASE + sFlashConfig.memConfig.sflashA1Size -1));
212 return C4_ERR_RANGE;
213 }
214
216 status_t status = flexspi_nor_flash_read(C4_FLASH_INSTANCE, &sFlashConfig, (uint32_t *)pData, addr, len);
217 if (kStatus_Success != status)
218 {
219 C4_PRINT("flexspi_nor_flash_read returns %ld\n", status);
220 rc = C4_ERR_HARDWARE;
221 }
222
223 return rc;
224 }
225
226 /*
227 * ***********************************************************************
228 */
229
230 exit_code_t C4_QSPI_write(uintptr_t dstAddr, size_t len, const uint8_t *pData)
231 {
232 exit_code_t rc = C4_ERR_OK;
233 // C4_PRINT("%s(0x%p, %d, 0x%p)\n", __FUNCTION__, dstAddr, len, pData);
234
235 if (0 == len)
236 {
237 // nothing to do
238 return C4_ERR_OK;
239 }
240
241 if (!FLASH_INITIALISED)
242 {
243 C4_PRINT("%s QSPI uninitialised\n", __FUNCTION__);
244 return C4_ERR_UNINITIALISED;
245 }
246
247 if ((FlexSPI_AMBA_BASE > dstAddr) ||
248 (FlexSPI_AMBA_BASE + sFlashConfig.memConfig.sflashA1Size <= dstAddr + len))
249 {
250 C4_PRINT("%s target range (0x%p - 0x%p) outside flash range (0x%p - 0x%p)\n",
251 __FUNCTION__,
252 (void *)(dstAddr),
253 (void *)(dstAddr + len),
254 (void *)(FlexSPI_AMBA_BASE),
255 (void *)(FlexSPI_AMBA_BASE + sFlashConfig.memConfig.sflashA1Size -1));
256 return C4_ERR_RANGE;
257 }
258
259 uintptr_t lastAddr = dstAddr + len - 1;
260
261 // find first sector
262 const uint32_t firstSector = (dstAddr - FlexSPI_AMBA_BASE) / C4_FLASH_SECTOR_SIZE;
263
264 // and last sector
265 const uint32_t lastSector = (lastAddr - FlexSPI_AMBA_BASE) / C4_FLASH_SECTOR_SIZE;
266
267 // C4_PRINT("start address 0x%08x first Sector %d\nend address 0x%08x last Sector %d\n",
268 // dstAddr, firstSector, lastAddr, lastSector);
269
270 // calculate the start address within the first sector
271 uintptr_t sectAddr = dstAddr - FlexSPI_AMBA_BASE - firstSector * C4_FLASH_SECTOR_SIZE;
272 // C4_PRINT("sectAddr = %d\n", sectAddr);
273
274 uint32_t sector = firstSector;
275 do {
276
277 // base address of sector in flash
278 uintptr_t sectorBase = sector * C4_FLASH_SECTOR_SIZE;
279
280 // number of bytes in the sector
281 size_t bytes = C4_FLASH_SECTOR_SIZE;
282
283 // Is this a complete sector?
284 if ((sectAddr == 0) || (len >= C4_FLASH_SECTOR_SIZE))
285 {
286 // just write sector
287 // C4_PRINT("wrC4_PRINTwhole sector %d\n", sector);
288 if (C4_FLASH_SECTOR_SIZE != writeSector(sectorBase, pData))
289 rc = C4_ERR_FAILED;
290 }
291 else
292 {
293 // Not a complete sector, which will happen for the first and last sectors only.
294 // The first sector may have an sectAddr > 0 and the last sectAddr + len < sector length.
295 // They may be the same sector, consecutive sectors or have intervening complete sectors.
296
297 // read-modify-erase-write sector
298 uint8_t buf[C4_FLASH_SECTOR_SIZE];
299
300 // C4_PRINT("reading sector %d (0x%p - 0x%p)\n",
301 // sector, sectorBase, sectorBase+C4_FLASH_SECTOR_SIZE-1);
302 // read the contents of the sector.
303 status_t status = flexspi_nor_flash_read(C4_FLASH_INSTANCE, &sFlashConfig, (uint32_t *)buf, sectorBase, C4_FLASH_SECTOR_SIZE);
304 if (kStatus_Success != status)
305 {
306 C4_PRINT("flexspi_nor_flash_read returns %ld\n", status);
307 rc = C4_ERR_HARDWARE;
308 }
309
310 // calculate the number of bytes remaining in the sector
311 bytes -= sectAddr;
312
313 // If the number of bytes remaining is more than the number we want to write then
314 // reduce the number of bytes.
315 if (bytes > len)
316 bytes = len;
317
318 // C4_PRINT("Copying %d bytes from 0x%p \"%s\" into sector @ 0x%p\n", bytes, pData, pData, buf+sectAddr);
319 // copy the new data into the sector
320 memcpy(buf+sectAddr, pData, bytes);
321
322 // write sector
323 // C4_PRINT("writing sector %d\n", sector);
324 // C4_PRINT("writing sector %d (0x%p - 0x%p) from 0x%p via 0x%p\n",
325 // sector, sectorBase, sectorBase+C4_FLASH_SECTOR_SIZE-1, pData, buf);
326 if (C4_FLASH_SECTOR_SIZE != writeSector(sectorBase, buf))
327 rc = C4_ERR_FAILED;
328 }
329
330 // reduce number of bytes remaining
331 len -= bytes;
332 // move data pointer forward
333 pData += bytes;
334
335 sectAddr = 0; // always start at the beginning of subsequent sectors.
336
337 ++sector;
338 } while (lastSector >= sector);
339 return rc;
340 }
341
342 /*************************************************************************
343 * Local Functions
344 ************************************************************************/
345
346 ptrdiff_t writeSector(uintptr_t pSect, const uint8_t *pData)
347 {
348 ptrdiff_t len = 0;
349
350 // erase sector
351 // C4_PRINT("LINE %d erasing sector 0x%p - 0x%p\n", __LINE__,
352 // pSect, pSect+C4_FLASH_SECTOR_SIZE-1);
353 status_t status = flexspi_nor_flash_erase(C4_FLASH_INSTANCE, &sFlashConfig, pSect, C4_FLASH_SECTOR_SIZE);
354 if (kStatus_Success != status)
355 {
356 C4_PRINT("flexspi_nor_flash_erase returns %ld\n", status);
357 return 0;
358 }
359
360 while (len < C4_FLASH_SECTOR_SIZE)
361 {
362 // C4_PRINT("LINE %d writing \"%c\" @ 0x%p len %d\n", __LINE__,
363 // *pData, pSect, len);
364 status = flexspi_nor_flash_page_program(C4_FLASH_INSTANCE, &sFlashConfig, pSect, (const uint32_t *)pData);
365 if (kStatus_Success != status)
366 {
367 C4_PRINT("flexspi_nor_flash_page_program returns %ld\n", status);
368 return len;
369 }
370 pSect += C4_FLASH_PAGE_SIZE;
371 pData += C4_FLASH_PAGE_SIZE;
372 len += C4_FLASH_PAGE_SIZE;
373 }
374 return len;
375 }
376 // EOF
sFlashConfigOption
static serial_nor_config_option_t sFlashConfigOption
Definition: c4_qspi.c:65
_serial_nor_config_option::option0
union _serial_nor_config_option::@75 option0
flexspi_nor_flash_page_program
status_t flexspi_nor_flash_page_program(uint32_t instance, flexspi_nor_config_t *config, uint32_t dstAddr, const uint32_t *src)
Program data to Serial NOR via FlexSPI.
C4_FLASH_SECTOR_SIZE
#define C4_FLASH_SECTOR_SIZE
Definition: c4_qspi_types.h:25
flexspi_nor_flash_read
status_t flexspi_nor_flash_read(uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t start, uint32_t bytes)
Read data from Serial NOR.
C4_QSPI_erase
exit_code_t C4_QSPI_erase(uintptr_t addr, size_t len)
Erase region in QSPI flash memory.
Definition: c4_qspi.c:123
_FlexSPIConfig::tag
uint32_t tag
[0x000-0x003] Tag, fixed value 0x42464346UL
Definition: fsl_flexspi.h:193
C4_QSPI_getConfig
exit_code_t C4_QSPI_getConfig(flexspi_nor_config_t *pConfig)
Get the current config of the QSPI flash.
Definition: c4_qspi.c:97
C4_FLASH_PAGE_SIZE
#define C4_FLASH_PAGE_SIZE
Definition: c4_qspi_types.h:24
bl_api_init
void bl_api_init(void)
Definition: bl_api.c:20
c4_qspi_types.h
Private header file for QSPI interface to allow definitions to be shared with test.
FLASH_INITIALISED
bool FLASH_INITIALISED
Definition: c4_qspi.c:66
_serial_nor_config_option::U
uint32_t U
Definition: flexspi_nor_flash.h:125
C4_QSPI_read
exit_code_t C4_QSPI_read(uintptr_t addr, size_t len, uint8_t *pData)
Read data from QSPI flash memory.
Definition: c4_qspi.c:184
c4_qspi.h
Interface to QSPI Flash.
exit_code_t
exit_code_t
Enumeration of error codes.
Definition: c4_error_codes.h:96
flexspi_nor_flash_erase
status_t flexspi_nor_flash_erase(uint32_t instance, flexspi_nor_config_t *config, uint32_t start, uint32_t length)
Erase Flash Region specified by address and length.
_FlexSPIConfig::version
uint32_t version
[0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix
Definition: fsl_flexspi.h:194
C4_QSPI_init
exit_code_t C4_QSPI_init(void)
Initialise the flexSPI interface to QSPI.
Definition: c4_qspi.c:74
FlexSPI_AMBA_BASE
#define FlexSPI_AMBA_BASE
Definition: MIMXRT1062.h:20168
flexspi_nor_get_config
status_t flexspi_nor_get_config(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option)
Get FlexSPI NOR Configuration Block based on specified option.
_flexspi_nor_config::memConfig
flexspi_mem_config_t memConfig
Common memory configuration info via FlexSPI.
Definition: flexspi_nor_flash.h:186
C4_FLASH_INSTANCE
#define C4_FLASH_INSTANCE
Definition: c4_qspi_types.h:22
C4_PRINT
#define C4_PRINT(...)
Wrapper to call print as a privileged operation.
Definition: c4_privilege_modes.h:109
writeSector
ptrdiff_t writeSector(uintptr_t pSect, const uint8_t *pData)
Write a whole sector.
Definition: c4_qspi.c:345
flexspi_nor_flash_init
status_t flexspi_nor_flash_init(uint32_t instance, flexspi_nor_config_t *config)
Initialize Serial NOR devices via FlexSPI.
_FlexSPIConfig::sflashA1Size
uint32_t sflashA1Size
[0x050-0x053] Size of Flash connected to A1
Definition: fsl_flexspi.h:225
sFlashConfig
flexspi_nor_config_t sFlashConfig
Definition: c4_qspi.c:64
BL_SysTick_DelayTicks
void BL_SysTick_DelayTicks(uint32_t n)
Sets a delay.
Definition: bootloader.c:317
c4_privilege_modes.h
Provide mechanisms to specify which stack to use and for the processor to operate in Unprivileged mod...
_serial_nor_config_option
Definition: flexspi_nor_flash.h:110
C4_QSPI_write
exit_code_t C4_QSPI_write(uintptr_t dstAddr, size_t len, const uint8_t *pData)
Write data to QSPI flash memory.
Definition: c4_qspi.c:230
bl_api.h
_flexspi_nor_config
Definition: flexspi_nor_flash.h:184