1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** LevelX Component */
17 /** */
18 /** NOR Flash */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define LX_SOURCE_CODE
24
25
26 /* Disable ThreadX error checking. */
27
28 #ifndef LX_DISABLE_ERROR_CHECKING
29 #define LX_DISABLE_ERROR_CHECKING
30 #endif
31
32
33 /* Include necessary system files. */
34
35 #include "lx_api.h"
36
37
38 /**************************************************************************/
39 /* */
40 /* FUNCTION RELEASE */
41 /* */
42 /* _lx_nor_flash_open PORTABLE C */
43 /* 6.3.0 */
44 /* AUTHOR */
45 /* */
46 /* William E. Lamie, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function opens a NOR flash instance and ensures the NOR flash */
51 /* is in a coherent state. */
52 /* */
53 /* INPUT */
54 /* */
55 /* nor_flash NOR flash instance */
56 /* name Name of NOR flash instance */
57 /* nor_driver_initialize Driver initialize */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* return status */
62 /* */
63 /* CALLS */
64 /* */
65 /* (nor_driver_initialize) Driver initialize */
66 /* _lx_nor_flash_driver_read Driver read */
67 /* _lx_nor_flash_driver_write Driver write */
68 /* (lx_nor_flash_driver_block_erased_verify) */
69 /* NOR flash verify block erased */
70 /* _lx_nor_flash_driver_block_erase Driver block erase */
71 /* _lx_nor_flash_logical_sector_find Find logical sector */
72 /* _lx_nor_flash_system_error System error handler */
73 /* tx_mutex_create Create thread-safe mutex */
74 /* */
75 /* CALLED BY */
76 /* */
77 /* Application Code */
78 /* */
79 /* RELEASE HISTORY */
80 /* */
81 /* DATE NAME DESCRIPTION */
82 /* */
83 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
84 /* 09-30-2020 William E. Lamie Modified comment(s), */
85 /* resulting in version 6.1 */
86 /* 11-09-2020 William E. Lamie Modified comment(s), */
87 /* fixed compiler warnings, */
88 /* resulting in version 6.1.2 */
89 /* 12-30-2020 William E. Lamie Modified comment(s), */
90 /* fixed compiler warnings, */
91 /* resulting in version 6.1.3 */
92 /* 06-02-2021 Bhupendra Naphade Modified comment(s), and */
93 /* updated product constants */
94 /* resulting in version 6.1.7 */
95 /* 03-08-2023 Xiuwen Cai Modified comment(s), */
96 /* added new driver interface, */
97 /* resulting in version 6.2.1 */
98 /* 10-31-2023 Xiuwen Cai Modified comment(s), */
99 /* added count for minimum */
100 /* erased blocks, added */
101 /* obsolete count cache, */
102 /* avoided clearing user */
103 /* extension in flash control */
104 /* block, */
105 /* resulting in version 6.3.0 */
106 /* */
107 /**************************************************************************/
_lx_nor_flash_open(LX_NOR_FLASH * nor_flash,CHAR * name,UINT (* nor_driver_initialize)(LX_NOR_FLASH *))108 UINT _lx_nor_flash_open(LX_NOR_FLASH *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *))
109 {
110 ULONG sectors_per_block;
111 ULONG sector_map_words;
112 ULONG bit_map_words;
113 ULONG bit_map_mask;
114 ULONG total_header_words;
115 ULONG header_sectors;
116 ULONG *block_word_ptr;
117 ULONG block_word;
118 ULONG temp;
119 ULONG free_sectors;
120 ULONG used_sectors;
121 ULONG *new_map_entry;
122 ULONG *new_sector_address;
123 ULONG erased_count, min_erased_count, max_erased_count, temp_erased_count, min_erased_blocks;
124 ULONG j, k, l;
125 UINT status;
126 #ifdef LX_FREE_SECTOR_DATA_VERIFY
127 ULONG *sector_word_ptr;
128 ULONG sector_word;
129 #endif
130 LX_NOR_FLASH *tail_ptr;
131 LX_INTERRUPT_SAVE_AREA
132
133 LX_PARAMETER_NOT_USED(name);
134
135 /* Clear the NOR flash control block. User extension is not cleared. */
136 LX_MEMSET(nor_flash, 0, (ULONG)((UCHAR*)&(nor_flash -> lx_nor_flash_open_previous) - (UCHAR*)nor_flash) + sizeof(nor_flash -> lx_nor_flash_open_previous));
137
138 /* Call the flash driver's initialization function. */
139 (nor_driver_initialize)(nor_flash);
140
141 #ifndef LX_DIRECT_READ
142
143 /* Determine if the driver supplied a RAM buffer for reading the NOR sector if direct read is not
144 supported. */
145 if (nor_flash -> lx_nor_flash_sector_buffer == LX_NULL)
146 {
147
148 /* Return an error. */
149 return(LX_NO_MEMORY);
150 }
151 #endif
152
153 /* Setup the offset to the free bit map. */
154 nor_flash -> lx_nor_flash_block_free_bit_map_offset = sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG);
155
156 /* Calculate the number of bits we need in the free physical sector bit map. Subtract 1 to account for the
157 flash block header itself. The case where multiple physical sectors are needed for certain sized flash
158 devices is handled below. */
159 sectors_per_block = (nor_flash -> lx_nor_flash_words_per_block / LX_NOR_SECTOR_SIZE) - 1;
160
161 /* Calculate the number of words required for the sector map array. */
162 sector_map_words = sectors_per_block;
163
164 /* Calculate the number of words we need for the free physical sector bit map. */
165 bit_map_words = (sectors_per_block + 31)/ 32;
166
167 /* Save the number of bit map words. */
168 nor_flash -> lx_nor_flash_block_bit_map_words = bit_map_words;
169
170 /* Setup the offset (in words) to the array of physical sector mapping. */
171 nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset = nor_flash -> lx_nor_flash_block_free_bit_map_offset + bit_map_words;
172
173 /* Calculate the total number of words required for the flash block header. */
174 total_header_words = sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG) + bit_map_words + sector_map_words;
175
176 /* Determine if more physical sectors are needed, which can happen on large devices. */
177 if (total_header_words <= LX_NOR_SECTOR_SIZE)
178 {
179
180 /* Round up to the size of 1 physical sector. */
181 total_header_words = LX_NOR_SECTOR_SIZE;
182 }
183 else
184 {
185
186 /* Otherwise calculate how many header sectors are necessary. */
187 header_sectors = (total_header_words-1)/LX_NOR_SECTOR_SIZE;
188
189 /* Round up to the next sector. */
190 header_sectors++;
191
192 /* Compute the total header words, rounding to the next sector. */
193 total_header_words = header_sectors * LX_NOR_SECTOR_SIZE;
194
195 /* Adjust the number of sectors per block. */
196 sectors_per_block = sectors_per_block - (header_sectors - 1);
197 }
198
199 /* Save the offset to the sector area. */
200 nor_flash -> lx_nor_flash_block_physical_sector_offset = total_header_words;
201
202 /* Save the physical sectors per block and total physical sectors. */
203 nor_flash -> lx_nor_flash_physical_sectors_per_block = sectors_per_block;
204 nor_flash -> lx_nor_flash_total_physical_sectors = nor_flash -> lx_nor_flash_total_blocks * sectors_per_block;
205
206 /* Build the free bit map mask, for the portion of the bit map that is less than 32 bits. */
207 if ((sectors_per_block % 32) != 0)
208 {
209 bit_map_mask = (ULONG)(1 << (sectors_per_block % 32));
210 bit_map_mask = bit_map_mask - 1;
211 }
212 else
213 {
214
215 /* Exactly 32 sectors for the bit map mask. */
216 bit_map_mask = LX_ALL_ONES;
217 }
218
219 /* Save the free bit map mask in the control block. */
220 nor_flash -> lx_nor_flash_block_bit_map_mask = bit_map_mask;
221
222 /* Setup default values for the max/min erased counts. */
223 min_erased_count = LX_ALL_ONES;
224 min_erased_blocks = 0;
225 max_erased_count = 0;
226
227 /* Setup the block word pointer to the first word of the first block, which is effectively the
228 flash base address. */
229 block_word_ptr = nor_flash -> lx_nor_flash_base_address;
230
231 /* Loop through the blocks to determine the minimum and maximum erase count. */
232 for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
233 {
234
235 /* Pickup the first word of the block. If the flash manager has executed before, this word contains the
236 erase count for the block. Otherwise, if the word is 0xFFFFFFFF, this flash block was either erased
237 or this is the first time it was used. */
238 #ifdef LX_DIRECT_READ
239
240 /* Read the word directly. */
241 block_word = *block_word_ptr;
242 #else
243
244
245
246 status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
247
248 /* Check for an error from flash driver. Drivers should never return an error.. */
249 if (status)
250 {
251
252 /* Call system error handler. */
253 _lx_nor_flash_system_error(nor_flash, status);
254
255 /* Return an error. */
256 return(LX_ERROR);
257 }
258 #endif
259
260 /* Is the block erased? */
261 if (((block_word & LX_BLOCK_ERASED) != LX_BLOCK_ERASED) && (block_word != LX_BLOCK_ERASE_STARTED))
262 {
263
264 /* No, valid block. Isolate the erased count. */
265 erased_count = (block_word & LX_BLOCK_ERASE_COUNT_MASK);
266
267 /* Is the erased count the minimum? */
268 if (erased_count == min_erased_count)
269 {
270
271 /* Yes, increment the minimum erased block count. */
272 min_erased_blocks++;
273 }
274
275 /* Is this the new minimum? */
276 if (erased_count < min_erased_count)
277 {
278
279 /* Yes, remember the new minimum. */
280 min_erased_count = erased_count;
281
282 /* Reset the minimum erased block count. */
283 min_erased_blocks = 1;
284 }
285
286 /* Is this the new maximum? */
287 if (erased_count > max_erased_count)
288 {
289
290 /* Yes, remember the new maximum. */
291 max_erased_count = erased_count;
292 }
293 }
294
295 /* Move to the next flash block. */
296 block_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
297 }
298
299 /* If we haven't found any erased counts, we can assume the flash is completely erased and needs to
300 be setup for the first time. */
301 if (min_erased_count == LX_ALL_ONES)
302 {
303
304 /* Indicate that this is the initial format. */
305 nor_flash -> lx_nor_flash_diagnostic_initial_format = LX_TRUE;
306
307 /* Setup the block word pointer to the first word of the first block, which is effectively the
308 flash base address. */
309 block_word_ptr = nor_flash -> lx_nor_flash_base_address;
310
311 /* Loop through the blocks to setup the flash the fist time. */
312 for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
313 {
314
315 /* Setup the free bit map that corresponds to the free physical sectors in this
316 block. Note that we only need to setup the portion of the free bit map that doesn't
317 have sectors associated with it. */
318 status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
319
320 /* Check for an error from flash driver. Drivers should never return an error.. */
321 if (status)
322 {
323
324 /* Call system error handler. */
325 _lx_nor_flash_system_error(nor_flash, status);
326
327 /* Return an error. */
328 return(LX_ERROR);
329 }
330
331 /* Setup the initial erase count to 1. */
332 block_word = ((ULONG) 1);
333
334 /* Write the initial erase count for the block. */
335 status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &block_word, 1);
336
337 /* Check for an error from flash driver. Drivers should never return an error.. */
338 if (status)
339 {
340
341 /* Call system error handler. */
342 _lx_nor_flash_system_error(nor_flash, status);
343
344 /* Return an error. */
345 return(LX_ERROR);
346 }
347
348 /* Update the overall minimum and maximum erase count. */
349 nor_flash -> lx_nor_flash_minimum_erase_count = 1;
350 nor_flash -> lx_nor_flash_minimum_erased_blocks = nor_flash -> lx_nor_flash_total_blocks;
351 nor_flash -> lx_nor_flash_maximum_erase_count = 1;
352
353 /* Update the number of free physical sectors. */
354 nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
355
356 /* Move to the next flash block. */
357 block_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
358 }
359 }
360 else
361 {
362
363 /* At this point, we have a previously managed flash structure. This needs to be traversed to prepare for the
364 current flash operation. */
365
366 /* Default the flash free sector search to an invalid value. */
367 nor_flash -> lx_nor_flash_free_block_search = nor_flash -> lx_nor_flash_total_blocks;
368
369 /* Setup the block word pointer to the first word of the first block, which is effectively the
370 flash base address. */
371 block_word_ptr = nor_flash -> lx_nor_flash_base_address;
372
373 /* Loop through the blocks. */
374 for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
375 {
376
377 /* First, determine if this block has a valid erase count. */
378 #ifdef LX_DIRECT_READ
379
380 /* Read the word directly. */
381 block_word = *block_word_ptr;
382 #else
383 status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
384
385 /* Check for an error from flash driver. Drivers should never return an error.. */
386 if (status)
387 {
388
389 /* Call system error handler. */
390 _lx_nor_flash_system_error(nor_flash, status);
391
392 /* Return an error. */
393 return(LX_ERROR);
394 }
395 #endif
396
397 /* Is the block erased? */
398 if (((block_word & LX_BLOCK_ERASED) == LX_BLOCK_ERASED) || (block_word == LX_BLOCK_ERASE_STARTED))
399 {
400
401 /* This can happen if we were previously in the process of erasing the flash block and a
402 power interruption occurs. It should only occur once though. */
403
404 /* Is this the first time? */
405 if (nor_flash -> lx_nor_flash_diagnostic_erased_block)
406 {
407
408 /* No, this is a potential format error, since this should only happen once in a given
409 NOR flash format. */
410 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
411
412 /* Return an error. */
413 return(LX_ERROR);
414 }
415
416 /* Increment the erased block diagnostic. */
417 nor_flash -> lx_nor_flash_diagnostic_erased_block++;
418
419 /* Check to see if the block is erased. */
420 #ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
421 status = (nor_flash -> lx_nor_flash_driver_block_erased_verify)(nor_flash, l);
422 #else
423 status = (nor_flash -> lx_nor_flash_driver_block_erased_verify)(l);
424 #endif
425
426 /* Is the block completely erased? */
427 if (status != LX_SUCCESS)
428 {
429
430 /* Is this the first time? */
431 if (nor_flash -> lx_nor_flash_diagnostic_re_erase_block)
432 {
433
434 /* No, this is a potential format error, since this should only happen once in a given
435 NOR flash format. */
436 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
437
438 /* Return an error. */
439 return(LX_ERROR);
440 }
441
442 /* Increment the erased block diagnostic. */
443 nor_flash -> lx_nor_flash_diagnostic_re_erase_block++;
444
445 /* No, the block is not fully erased, erase it again. */
446 status = _lx_nor_flash_driver_block_erase(nor_flash, l, max_erased_count);
447
448 /* Check for an error from flash driver. Drivers should never return an error.. */
449 if (status)
450 {
451
452 /* Call system error handler. */
453 _lx_nor_flash_system_error(nor_flash, status);
454
455 /* Return an error. */
456 return(LX_ERROR);
457 }
458 }
459
460 /* Setup the free bit map that corresponds to the free physical sectors in this
461 block. Note that we only need to setup the portion of the free bit map that doesn't
462 have sectors associated with it. */
463 status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
464
465 /* Check for an error from flash driver. Drivers should never return an error.. */
466 if (status)
467 {
468
469 /* Call system error handler. */
470 _lx_nor_flash_system_error(nor_flash, status);
471
472 /* Return an error. */
473 return(LX_ERROR);
474 }
475
476 /* Write the initial erase count for the block with upper bit set. */
477 temp_erased_count = (max_erased_count | LX_BLOCK_ERASED);
478 status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erased_count, 1);
479
480 /* Check for an error from flash driver. Drivers should never return an error.. */
481 if (status)
482 {
483
484 /* Call system error handler. */
485 _lx_nor_flash_system_error(nor_flash, status);
486
487 /* Return an error. */
488 return(LX_ERROR);
489 }
490
491 /* Write the final initial erase count for the block. */
492 status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &max_erased_count, 1);
493
494 /* Check for an error from flash driver. Drivers should never return an error.. */
495 if (status)
496 {
497
498 /* Call system error handler. */
499 _lx_nor_flash_system_error(nor_flash, status);
500
501 /* Return an error. */
502 return(LX_ERROR);
503 }
504
505 /* Update the number of free physical sectors. */
506 nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
507 }
508 else
509 {
510
511 /* Calculate the number of free sectors from the free sector bit map. */
512 free_sectors = 0;
513 for (j = 0; j < bit_map_words; j++)
514 {
515
516 /* Read this word of the free sector bit map. */
517 #ifdef LX_DIRECT_READ
518
519 /* Read the word directly. */
520 block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
521 #else
522 status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
523
524 /* Check for an error from flash driver. Drivers should never return an error.. */
525 if (status)
526 {
527
528 /* Call system error handler. */
529 _lx_nor_flash_system_error(nor_flash, status);
530
531 /* Return an error. */
532 return(LX_ERROR);
533 }
534 #endif
535
536 /* Count the number of set bits (free sectors). */
537 for (k = 0; k < 32; k++)
538 {
539
540 /* Is this sector free? */
541 if (block_word & 1)
542 {
543 /* Yes, this sector is free, increment the free sectors count. */
544 free_sectors++;
545
546 /* Determine if we need to update the search pointer. */
547 if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
548 {
549
550 /* Remember the block with free sectors. */
551 nor_flash -> lx_nor_flash_free_block_search = l;
552 }
553 }
554
555 /* Shift down the free sector. */
556 block_word = block_word >> 1;
557 }
558 }
559
560 /* Update the number of free physical sectors. */
561 nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + free_sectors;
562
563 /* We need to now examine the mapping list. */
564
565 /* Calculate how many non-free sectors there are - this includes valid and obsolete sectors. */
566 used_sectors = sectors_per_block - free_sectors;
567
568 /* Now walk the list of logical-physical sector mapping. */
569 for (j = 0; j < sectors_per_block; j++)
570 {
571
572 /* Read this word of the sector mapping list. */
573 #ifdef LX_DIRECT_READ
574
575 /* Read the word directly. */
576 block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
577 #else
578 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);
579
580 /* Check for an error from flash driver. Drivers should never return an error.. */
581 if (status)
582 {
583
584 /* Call system error handler. */
585 _lx_nor_flash_system_error(nor_flash, status);
586
587 /* Return an error. */
588 return(LX_ERROR);
589 }
590 #endif
591
592 /* Determine if we are expecting to find a used sector. */
593 if (used_sectors)
594 {
595
596 /* Yes, we expect this entry to be used. */
597
598 /* Is this sector in-use? */
599 if ((block_word & LX_NOR_LOGICAL_SECTOR_MASK) != LX_NOR_LOGICAL_SECTOR_MASK)
600 {
601
602 /* Determine if the valid bit is set and the superceded bit is clear. This indicates the block was
603 about to become obsolete. */
604 if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) && ((block_word & LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) == 0))
605 {
606
607
608 /* Increment the being obsoleted count. */
609 nor_flash -> lx_nor_flash_diagnostic_sector_being_obsoleted++;
610
611 /* Save the currently mapped physical sectors. */
612 temp = nor_flash -> lx_nor_flash_mapped_physical_sectors;
613
614 /* Indicate all the physical sectors are mapped for the purpose of this search. */
615 nor_flash -> lx_nor_flash_mapped_physical_sectors = nor_flash -> lx_nor_flash_total_physical_sectors;
616
617 /* Yes, this block was about to become obsolete. Perform a search for a logical sector entry that
618 has both of these bits set. */
619 _lx_nor_flash_logical_sector_find(nor_flash, (block_word & LX_NOR_LOGICAL_SECTOR_MASK), LX_TRUE, &new_map_entry, &new_sector_address);
620
621 /* Restore the number of mapped physical sectors. */
622 nor_flash -> lx_nor_flash_mapped_physical_sectors = temp;
623
624 /* Determine if the new logical sector entry is present. */
625 if (new_map_entry)
626 {
627
628 /* Yes, make the current entry obsolete in favor of the new entry. */
629 block_word = block_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
630 status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
631
632 /* Check for an error from flash driver. Drivers should never return an error.. */
633 if (status)
634 {
635
636 /* Call system error handler. */
637 _lx_nor_flash_system_error(nor_flash, status);
638
639 /* Return an error. */
640 return(LX_ERROR);
641 }
642
643 /* Is this the first time? */
644 if (nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted)
645 {
646
647 /* No, this is a potential format error, since this should only happen once in a given
648 NOR flash format. */
649 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
650
651 /* Return an error. */
652 return(LX_ERROR);
653 }
654
655 /* Increment the obsoleted count. */
656 nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted++;
657 }
658 }
659 }
660
661 /* Determine if the sector is free. */
662 else if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
663 {
664
665 /* A free entry when there are still used sectors implies that the sector was allocated and a power interruption
666 took place prior to writing the new logical sector number into the list. */
667
668 /* Is this the first time? */
669 if (nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated)
670 {
671
672 /* No, this is a potential format error, since this should only happen once in a given
673 NOR flash format. */
674 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
675
676 /* Return an error. */
677 return(LX_ERROR);
678 }
679
680 /* Write 0s out to this entry to invalidate the sector entry. */
681 block_word = 0;
682 status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
683
684 /* Check for an error from flash driver. Drivers should never return an error.. */
685 if (status)
686 {
687
688 /* Call system error handler. */
689 _lx_nor_flash_system_error(nor_flash, status);
690
691 /* Return an error. */
692 return(LX_ERROR);
693 }
694
695 /* Increment the number of mapping invalidates. */
696 nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated++;
697 }
698
699 /* Yes, now determine if the sector is obsolete. */
700 if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
701 {
702
703 /* Increment the number of obsolete sectors. */
704 nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
705 }
706
707 /* Determine if the mapping for this sector isn't yet valid. */
708 else if (block_word & LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)
709 {
710
711 /* Yes, a power interruption or reset occurred while the sector mapping entry was being written. */
712
713 /* Increment the number of obsolete sectors. */
714 nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
715
716 /* Increment the interrupted mapping counter. */
717 nor_flash -> lx_nor_flash_diagnostic_mapping_write_interrupted++;
718
719 /* Invalidate this entry - clearing valid bit, superceded bit and logical sector. */
720 block_word = 0;
721 status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
722
723 /* Check for an error from flash driver. Drivers should never return an error.. */
724 if (status)
725 {
726
727 /* Call system error handler. */
728 _lx_nor_flash_system_error(nor_flash, status);
729
730 /* Return an error. */
731 return(LX_ERROR);
732 }
733 }
734 else
735 {
736 /* Increment the number of mapped physical sectors. */
737 nor_flash -> lx_nor_flash_mapped_physical_sectors++;
738 }
739
740 /* Decrease the number of used sectors. */
741 used_sectors--;
742 }
743 else
744 {
745
746 /* No more used sectors in this flash block. */
747
748 /* In this case the entry must be free or there is a serious NOR flash format error present. */
749 if (block_word != LX_NOR_PHYSICAL_SECTOR_FREE)
750 {
751
752 /* Increment the sector not free diagnostic. */
753 nor_flash -> lx_nor_flash_diagnostic_sector_not_free++;
754
755 /* NOR flash format. */
756 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
757
758 /* Write 0s out to this entry to invalidate the sector entry. */
759 block_word = 0;
760 status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
761
762 /* Check for an error from flash driver. Drivers should never return an error.. */
763 if (status)
764 {
765
766 /* Call system error handler. */
767 _lx_nor_flash_system_error(nor_flash, status);
768
769 /* Return an error. */
770 return(LX_ERROR);
771 }
772 }
773
774 #ifdef LX_FREE_SECTOR_DATA_VERIFY
775
776 /* Pickup address of the free sector data area. */
777 sector_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_offset) + (j * LX_NOR_SECTOR_SIZE);
778
779 /* Determine if the data for this sector is free. */
780 for (k = 0; k < LX_NOR_SECTOR_SIZE; k++)
781 {
782
783 #ifdef LX_DIRECT_READ
784
785 /* Read the word directly. */
786 sector_word = *(sector_word_ptr);
787 #else
788 status = _lx_nor_flash_driver_read(nor_flash, (sector_word_ptr), §or_word, 1);
789
790 /* Check for an error from flash driver. Drivers should never return an error.. */
791 if (status)
792 {
793
794 /* Call system error handler. */
795 _lx_nor_flash_system_error(nor_flash, status);
796
797 /* Return an error. */
798 return(LX_ERROR);
799 }
800 #endif
801
802 /* Determine if this word is not available. */
803 if (sector_word != LX_NOR_PHYSICAL_SECTOR_FREE)
804 {
805
806 /* Increment the sector data not free diagnostic. */
807 nor_flash -> lx_nor_flash_diagnostic_sector_data_not_free++;
808
809 /* This is a format error. */
810 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
811
812 /* Return an error. */
813 return(LX_ERROR);
814 }
815
816 /* Move to the next word in the sector. */
817 sector_word_ptr++;
818 }
819 #endif
820 }
821 }
822 }
823
824 /* Move to the next flash block. */
825 block_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
826 }
827
828 /* Update the overall minimum and maximum erase count. */
829 nor_flash -> lx_nor_flash_minimum_erase_count = min_erased_count;
830 nor_flash -> lx_nor_flash_minimum_erased_blocks = min_erased_blocks;
831 nor_flash -> lx_nor_flash_maximum_erase_count = max_erased_count;
832
833 /* Determine if we need to update the free sector search pointer. */
834 if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
835 {
836
837 /* Just start at the beginning. */
838 nor_flash -> lx_nor_flash_free_block_search = 0;
839 }
840 }
841
842 #ifdef LX_THREAD_SAFE_ENABLE
843
844 /* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
845 in order to provide thread-safe operation. */
846 status = tx_mutex_create(&nor_flash -> lx_nor_flash_mutex, "NOR Flash Mutex", TX_NO_INHERIT);
847
848 /* Determine if the mutex creation encountered an error. */
849 if (status != LX_SUCCESS)
850 {
851
852 /* Call system error handler, since this should not happen. */
853 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_MUTEX_CREATE_FAILED);
854
855 /* Return error to caller. */
856 return(LX_ERROR);
857 }
858 #endif
859
860 /* Enable the sector mapping cache. */
861 nor_flash -> lx_nor_flash_sector_mapping_cache_enabled = LX_TRUE;
862
863 /* Initialize the last found block and sector markers. */
864 nor_flash -> lx_nor_flash_found_block_search = 0;
865 nor_flash -> lx_nor_flash_found_sector_search = 0;
866
867 /* Lockout interrupts. */
868 LX_DISABLE
869
870 /* At this point, the NOR flash has been opened successfully. Place the
871 NOR flash control block on the linked list of currently opened NOR flashes. */
872
873 /* Set the NOR flash state to open. */
874 nor_flash -> lx_nor_flash_state = LX_NOR_FLASH_OPENED;
875
876 /* Place the NOR flash control block on the list of opened NOR flashes. First,
877 check for an empty list. */
878 if (_lx_nor_flash_opened_count)
879 {
880
881 /* List is not empty - other NOR flashes are open. */
882
883 /* Pickup tail pointer. */
884 tail_ptr = _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous;
885
886 /* Place the new NOR flash control block in the list. */
887 _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous = nor_flash;
888 tail_ptr -> lx_nor_flash_open_next = nor_flash;
889
890 /* Setup this NOR flash's opened links. */
891 nor_flash -> lx_nor_flash_open_previous = tail_ptr;
892 nor_flash -> lx_nor_flash_open_next = _lx_nor_flash_opened_ptr;
893 }
894 else
895 {
896
897 /* The opened NOR flash list is empty. Add the NOR flash to empty list. */
898 _lx_nor_flash_opened_ptr = nor_flash;
899 nor_flash -> lx_nor_flash_open_next = nor_flash;
900 nor_flash -> lx_nor_flash_open_previous = nor_flash;
901 }
902
903 /* Increment the opened NOR flash counter. */
904 _lx_nor_flash_opened_count++;
905
906 /* Restore interrupts. */
907 LX_RESTORE
908
909 /* Return a successful completion. */
910 return(LX_SUCCESS);
911 }
912
913