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