1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** LevelX Component */
16 /** */
17 /** NOR Flash */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define LX_SOURCE_CODE
23
24
25 /* Disable ThreadX error checking. */
26
27 #ifndef LX_DISABLE_ERROR_CHECKING
28 #define LX_DISABLE_ERROR_CHECKING
29 #endif
30
31
32 /* Include necessary system files. */
33
34 #include "lx_api.h"
35
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _lx_nor_flash_extended_cache_enable PORTABLE C */
42 /* 6.3.0 */
43 /* AUTHOR */
44 /* */
45 /* William E. Lamie, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function enables or disables the extended cache. */
50 /* */
51 /* INPUT */
52 /* */
53 /* nor_flash NOR flash instance */
54 /* memory Address of RAM for cache */
55 /* size Size of the RAM for cache */
56 /* */
57 /* OUTPUT */
58 /* */
59 /* return status */
60 /* */
61 /* CALLS */
62 /* */
63 /* None */
64 /* */
65 /* CALLED BY */
66 /* */
67 /* Application Code */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
74 /* 09-30-2020 William E. Lamie Modified comment(s), */
75 /* resulting in version 6.1 */
76 /* 12-31-2020 William E. Lamie Modified comment(s), */
77 /* fixed compiler warnings, */
78 /* resulting in version 6.1.3 */
79 /* 06-02-2021 Bhupendra Naphade Modified comment(s), and */
80 /* updated product constants */
81 /* resulting in version 6.1.7 */
82 /* 10-15-2021 Bhupendra Naphade Modified comment(s), and */
83 /* added check for out of */
84 /* bound memory access, */
85 /* resulting in version 6.1.9 */
86 /* 10-31-2023 Xiuwen Cai Modified comment(s), */
87 /* added mapping bitmap cache, */
88 /* added obsolete count cache, */
89 /* resulting in version 6.3.0 */
90 /* */
91 /**************************************************************************/
_lx_nor_flash_extended_cache_enable(LX_NOR_FLASH * nor_flash,VOID * memory,ULONG size)92 UINT _lx_nor_flash_extended_cache_enable(LX_NOR_FLASH *nor_flash, VOID *memory, ULONG size)
93 {
94 #ifndef LX_NOR_DISABLE_EXTENDED_CACHE
95
96 UINT i;
97 ULONG cache_size;
98 ULONG *cache_memory;
99 #ifdef LX_NOR_ENABLE_MAPPING_BITMAP
100 ULONG mapping_bitmap_words;
101 ULONG mapping_bitmap_word;
102 ULONG logical_sector;
103 ULONG *mapping_bitmap_ptr;
104 #endif
105 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
106 ULONG obsolete_count_words;
107 ULONG obsolete_sectors;
108 #endif
109 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP) || defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
110 ULONG *block_word_ptr;
111 UINT j;
112 UINT status;
113 ULONG block_word;
114 #endif
115
116
117 /* Determine if memory was specified but with an invalid size (less than one NOR sector). */
118 if ((memory) && (size < LX_NOR_SECTOR_SIZE))
119 {
120
121 /* Error in memory size supplied. */
122 return(LX_ERROR);
123 }
124
125 #ifdef LX_THREAD_SAFE_ENABLE
126
127 /* Obtain the thread safe mutex. */
128 tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
129 #endif
130
131 /* Initialize the internal NOR cache. */
132 nor_flash -> lx_nor_flash_extended_cache_entries = 0;
133
134 /* Calculate cache size in words. */
135 cache_size = size/sizeof(ULONG);
136
137 /* Setup cache memory pointer. */
138 cache_memory = (ULONG *) memory;
139
140 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP) || defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
141
142 /* Check if the NOR flash is opened. */
143 if (nor_flash -> lx_nor_flash_state == LX_NOR_FLASH_OPENED)
144 {
145 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP)
146
147 /* Get the mapping bitmap cache size. */
148 mapping_bitmap_words = (nor_flash -> lx_nor_flash_total_physical_sectors + 31) / 32;
149
150 /* Check if the mapping bitmap cache fits in the suppiled cache memory. */
151 if (cache_size < mapping_bitmap_words)
152 {
153
154 /* Update the cache size. */
155 mapping_bitmap_words = cache_size;
156 }
157
158 /* Setup the mapping bitmap cache. */
159 nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap = cache_memory;
160
161 /* Setup the mapping bitmap cache size. */
162 nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector = mapping_bitmap_words * 32;
163
164 /* Clear the mapping bitmap cache. */
165 for (i = 0; i < mapping_bitmap_words; i++)
166 {
167 cache_memory[i] = 0;
168 }
169
170 /* Update the cache memory pointer. */
171 mapping_bitmap_ptr = cache_memory;
172
173 /* Update the cache size. */
174 cache_size = cache_size - mapping_bitmap_words;
175
176 /* Update the cache memory pointer. */
177 cache_memory = cache_memory + mapping_bitmap_words;
178 #endif
179
180 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
181
182 /* Get the obsolete count cache size. */
183 obsolete_count_words = nor_flash -> lx_nor_flash_total_blocks * sizeof(LX_NOR_OBSOLETE_COUNT_CACHE_TYPE) / 4;
184
185 /* Check if the obsolete count cache fits in the suppiled cache memory. */
186 if (cache_size < obsolete_count_words)
187 {
188
189 /* Update the cache size. */
190 obsolete_count_words = cache_size;
191 }
192
193 /* Setup the obsolete count cache. */
194 nor_flash -> lx_nor_flash_extended_cache_obsolete_count = (LX_NOR_OBSOLETE_COUNT_CACHE_TYPE*)cache_memory;
195
196 /* Setup the obsolete count cache size. */
197 nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block = obsolete_count_words * 4 / sizeof(LX_NOR_OBSOLETE_COUNT_CACHE_TYPE);
198
199 /* Update the cache size. */
200 cache_size = cache_size - obsolete_count_words;
201
202 /* Update the cache memory pointer. */
203 cache_memory = cache_memory + obsolete_count_words;
204 #endif
205
206 /* Loop through the blocks. */
207 for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
208 {
209 /* Setup the block word pointer to the first word of the block. */
210 block_word_ptr = (nor_flash -> lx_nor_flash_base_address + (i * nor_flash -> lx_nor_flash_words_per_block));
211
212 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
213
214 /* Initialize the obsolete count cache. */
215 obsolete_sectors = 0;
216 #endif
217
218 /* Now walk the list of logical-physical sector mapping. */
219 for (j = 0; j < nor_flash ->lx_nor_flash_physical_sectors_per_block; j++)
220 {
221
222 /* Read this word of the sector mapping list. */
223 #ifdef LX_DIRECT_READ
224
225 /* Read the word directly. */
226 block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
227 #else
228 status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
229
230 /* Check for an error from flash driver. Drivers should never return an error.. */
231 if (status)
232 {
233
234 /* Call system error handler. */
235 _lx_nor_flash_system_error(nor_flash, status);
236
237 /* Return an error. */
238 return(LX_ERROR);
239 }
240 #endif
241 /* Determine if the entry hasn't been used. */
242 if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
243 {
244 break;
245 }
246
247 /* Is this entry valid? */
248 if ((block_word & (LX_NOR_PHYSICAL_SECTOR_VALID | LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)) == LX_NOR_PHYSICAL_SECTOR_VALID)
249 {
250 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP)
251
252 /* Yes, get the logical sector. */
253 logical_sector = block_word & LX_NOR_LOGICAL_SECTOR_MASK;
254
255 /* Get the mapping bitmap word. */
256 mapping_bitmap_word = logical_sector >> 5;
257
258 /* Check if the mapping bitmap word is within the cache. */
259 if (mapping_bitmap_word < mapping_bitmap_words)
260 {
261
262 /* Set the bit in the mapping bitmap. */
263 mapping_bitmap_ptr[mapping_bitmap_word] |= (ULONG)(1 << (logical_sector & 31));
264 }
265 #endif
266
267 }
268 else
269 {
270 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
271
272 /* Increment the obsolete sector count. */
273 obsolete_sectors++;
274 #endif
275 }
276 }
277 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
278
279 /* Check if the block is cached by obsolete count cache. */
280 if (i < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
281 {
282
283 /* Yes, cache the obsolete sector count. */
284 nor_flash -> lx_nor_flash_extended_cache_obsolete_count[i] = (LX_NOR_OBSOLETE_COUNT_CACHE_TYPE)obsolete_sectors;
285 }
286 #endif
287 }
288 }
289 #endif
290
291 /* Loop through the memory supplied and assign to cache entries. */
292 i = 0;
293 while (cache_size >= LX_NOR_SECTOR_SIZE)
294 {
295
296 /* Setup this cache entry. */
297 nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address = LX_NULL;
298 nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory = cache_memory;
299 nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count = 0;
300
301 /* Move the cache memory forward. */
302 cache_memory = cache_memory + LX_NOR_SECTOR_SIZE;
303
304 /* Decrement the size. */
305 cache_size = cache_size - LX_NOR_SECTOR_SIZE;
306
307 /* Move to next cache entry. */
308 i++;
309 }
310
311 /* Save the number of cache entries. */
312 if(i > LX_NOR_EXTENDED_CACHE_SIZE)
313 {
314
315 nor_flash -> lx_nor_flash_extended_cache_entries = LX_NOR_EXTENDED_CACHE_SIZE;
316 }
317 else
318 {
319
320 nor_flash -> lx_nor_flash_extended_cache_entries = i;
321 }
322
323 #ifdef LX_THREAD_SAFE_ENABLE
324
325 /* Release the thread safe mutex. */
326 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
327 #endif
328
329 /* Return successful completion. */
330 return(LX_SUCCESS);
331 #else
332
333 LX_PARAMETER_NOT_USED(nor_flash);
334 LX_PARAMETER_NOT_USED(memory);
335 LX_PARAMETER_NOT_USED(size);
336
337 /* Return disabled error message. */
338 return(LX_DISABLED);
339 #endif
340 }
341
342
343