GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nor_flash_open.c Lines: 131 189 69.3 %
Date: 2024-03-11 05:20:25 Branches: 70 100 70.0 %

Line Branch Exec Source
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
/**************************************************************************/
107
19
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
9215
    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
19
    (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
19
    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
19
    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
19
    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
19
    sector_map_words =  sectors_per_block;
162
163
    /* Calculate the number of words we need for the free physical sector bit map.  */
164
19
    bit_map_words =  (sectors_per_block + 31)/ 32;
165
166
    /* Save the number of bit map words.  */
167
19
    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
19
    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
19
    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
19
    if (total_header_words <= LX_NOR_SECTOR_SIZE)
177
    {
178
179
        /* Round up to the size of 1 physical sector.  */
180
19
        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
19
    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
19
    nor_flash -> lx_nor_flash_physical_sectors_per_block =  sectors_per_block;
203
19
    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
19
    if ((sectors_per_block % 32) != 0)
207
    {
208
19
        bit_map_mask =  (ULONG)(1 << (sectors_per_block % 32));
209
19
        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
19
    nor_flash -> lx_nor_flash_block_bit_map_mask =  bit_map_mask;
220
221
    /* Setup default values for the max/min erased counts.  */
222
19
    min_erased_count =  LX_ALL_ONES;
223
19
    min_erased_blocks = 0;
224
19
    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
19
    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
171
    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
152
        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
152
        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

152
        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
92
            erased_count =  (block_word & LX_BLOCK_ERASE_COUNT_MASK);
265
266
            /* Is the erased count the minimum?  */
267
92
            if (erased_count == min_erased_count)
268
            {
269
270
                /* Yes, increment the minimum erased block count.  */
271
80
                min_erased_blocks++;
272
            }
273
274
            /* Is this the new minimum?  */
275
92
            if (erased_count < min_erased_count)
276
            {
277
278
                /* Yes, remember the new minimum.  */
279
12
                min_erased_count =  erased_count;
280
281
                /* Reset the minimum erased block count.  */
282
12
                min_erased_blocks =  1;
283
            }
284
285
            /* Is this the new maximum?  */
286
92
            if (erased_count > max_erased_count)
287
            {
288
289
                /* Yes, remember the new maximum.  */
290
12
                max_erased_count =  erased_count;
291
            }
292
        }
293
294
        /* Move to the next flash block.  */
295
152
        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
19
    if (min_erased_count == LX_ALL_ONES)
301
    {
302
303
        /* Indicate that this is the initial format.  */
304
7
        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
7
        block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
309
310
        /* Loop through the blocks to setup the flash the fist time.  */
311
63
        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
56
            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
56
            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
56
            block_word =  ((ULONG) 1);
332
333
            /* Write the initial erase count for the block.  */
334
56
            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
56
            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
56
            nor_flash -> lx_nor_flash_minimum_erase_count =  1;
349
56
            nor_flash -> lx_nor_flash_minimum_erased_blocks =  nor_flash -> lx_nor_flash_total_blocks;
350
56
            nor_flash -> lx_nor_flash_maximum_erase_count =  1;
351
352
            /* Update the number of free physical sectors.  */
353
56
            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
56
            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
12
        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
12
        block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
371
372
        /* Loop through the blocks.  */
373
108
        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
96
            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
96
            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

96
            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
4
                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
4
                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
4
                status =  (nor_flash -> lx_nor_flash_driver_block_erased_verify)(l);
423
#endif
424
425
                /* Is the block completely erased?  */
426
4
                if (status != LX_SUCCESS)
427
                {
428
429
                    /* Is this the first time?  */
430
2
                    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
2
                    nor_flash -> lx_nor_flash_diagnostic_re_erase_block++;
443
444
                    /* No, the block is not fully erased, erase it again.  */
445
2
                    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
2
                    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
4
                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
4
                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
4
                temp_erased_count =  (max_erased_count | LX_BLOCK_ERASED);
477
4
                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
4
                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
4
                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
4
                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
4
                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
92
                free_sectors =  0;
512
184
                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
92
                    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
92
                    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
3036
                    for (k = 0; k < 32; k++)
537
                    {
538
539
                        /* Is this sector free?  */
540
2944
                        if (block_word & 1)
541
                        {
542
                            /* Yes, this sector is free, increment the free sectors count.  */
543
1252
                            free_sectors++;
544
545
                            /* Determine if we need to update the search pointer.  */
546
1252
                            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
12
                                nor_flash -> lx_nor_flash_free_block_search =  l;
551
                            }
552
                        }
553
554
                        /* Shift down the free sector.  */
555
2944
                        block_word =  block_word >> 1;
556
                    }
557
                }
558
559
                /* Update the number of free physical sectors.  */
560
92
                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
92
                used_sectors =  sectors_per_block - free_sectors;
566
567
                /* Now walk the list of logical-physical sector mapping.  */
568
1472
                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
1380
                    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
1380
                    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
1380
                    if (used_sectors)
593
                    {
594
595
                        /* Yes, we expect this entry to be used.  */
596
597
                        /* Is this sector in-use?  */
598
128
                        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

122
                            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
4
                                nor_flash -> lx_nor_flash_diagnostic_sector_being_obsoleted++;
609
610
                                /* Save the currently mapped physical sectors.  */
611
4
                                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
4
                                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
4
                                _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
4
                                nor_flash -> lx_nor_flash_mapped_physical_sectors =  temp;
622
623
                                /* Determine if the new logical sector entry is present.  */
624
4
                                if (new_map_entry)
625
                                {
626
627
                                    /* Yes, make the current entry obsolete in favor of the new entry.  */
628
2
                                    block_word =  block_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
629
2
                                    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
2
                                    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
2
                                    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
2
                                    nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted++;
656
                                }
657
                            }
658
                        }
659
660
                        /* Determine if the sector is free.  */
661
6
                        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
6
                            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
6
                            block_word =  0;
681
6
                            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
6
                            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
6
                            nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated++;
696
                        }
697
698
                        /* Yes, now determine if the sector is obsolete.  */
699
128
                        if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
700
                        {
701
702
                            /* Increment the number of obsolete sectors.  */
703
20
                            nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
704
                        }
705
706
                        /* Determine if the mapping for this sector isn't yet valid.  */
707
108
                        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
108
                            nor_flash -> lx_nor_flash_mapped_physical_sectors++;
737
                        }
738
739
                        /* Decrease the number of used sectors.  */
740
128
                        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
1252
                        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), &sector_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
96
            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
12
        nor_flash -> lx_nor_flash_minimum_erase_count =  min_erased_count;
829
12
        nor_flash -> lx_nor_flash_minimum_erased_blocks =  min_erased_blocks;
830
12
        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
12
        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
19
    nor_flash -> lx_nor_flash_sector_mapping_cache_enabled =  LX_TRUE;
861
862
    /* Initialize the last found block and sector markers.  */
863
19
    nor_flash -> lx_nor_flash_found_block_search =   0;
864
19
    nor_flash -> lx_nor_flash_found_sector_search =  0;
865
866
    /* Lockout interrupts.  */
867
19
    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
19
    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
19
    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
19
        _lx_nor_flash_opened_ptr =                 nor_flash;
898
19
        nor_flash -> lx_nor_flash_open_next =      nor_flash;
899
19
        nor_flash -> lx_nor_flash_open_previous =  nor_flash;
900
    }
901
902
    /* Increment the opened NOR flash counter.  */
903
19
    _lx_nor_flash_opened_count++;
904
905
    /* Restore interrupts.  */
906
19
    LX_RESTORE
907
908
    /* Return a successful completion.  */
909
19
    return(LX_SUCCESS);
910
}
911