GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_format_extended.c Lines: 48 66 72.7 %
Date: 2026-03-06 18:45:40 Branches: 31 46 67.4 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 * Copyright (c) 2025 STMicroelectronics
5
 *
6
 * This program and the accompanying materials are made available under the
7
 * terms of the MIT License which is available at
8
 * https://opensource.org/licenses/MIT.
9
 *
10
 * SPDX-License-Identifier: MIT
11
 **************************************************************************/
12
13
14
/**************************************************************************/
15
/**************************************************************************/
16
/**                                                                       */
17
/** LevelX Component                                                      */
18
/**                                                                       */
19
/**   NAND Flash                                                          */
20
/**                                                                       */
21
/**************************************************************************/
22
/**************************************************************************/
23
24
#define LX_SOURCE_CODE
25
26
27
/* Disable ThreadX error checking.  */
28
29
#ifndef LX_DISABLE_ERROR_CHECKING
30
#define LX_DISABLE_ERROR_CHECKING
31
#endif
32
33
34
/* Include necessary system files.  */
35
36
#include "lx_api.h"
37
38
39
/**************************************************************************/
40
/*                                                                        */
41
/*  FUNCTION                                               RELEASE        */
42
/*                                                                        */
43
/*    _lx_nand_flash_format_extended                      PORTABLE C      */
44
/*                                                                        */
45
/*  AUTHOR                                                                */
46
/*                                                                        */
47
/*    Xiuwen Cai, Microsoft Corporation                                   */
48
/*                                                                        */
49
/*  DESCRIPTION                                                           */
50
/*                                                                        */
51
/*    This function erases and formats a NAND flash.                      */
52
/*                                                                        */
53
/*  INPUT                                                                 */
54
/*                                                                        */
55
/*    nand_flash                            NAND flash instance           */
56
/*    name                                  Name of NAND flash instance   */
57
/*    nand_driver_initialize                Driver initialize             */
58
/*    nand_driver_info_ptr                  Driver user data pointer      */
59
/*    memory_ptr                            Pointer to memory used by the */
60
/*                                            LevelX for this NAND.       */
61
/*    memory_size                           Size of memory - must at least*/
62
/*                                            7 * total block count +     */
63
/*                                            2 * page size               */
64
/*                                                                        */
65
/*  OUTPUT                                                                */
66
/*                                                                        */
67
/*    return status                                                       */
68
/*                                                                        */
69
/*  CALLS                                                                 */
70
/*                                                                        */
71
/*    (nand_driver_initialize)              Driver initialize             */
72
/*    LX_MEMSET                             Initialize memory             */
73
/*    _lx_nand_flash_memory_initialize      Initialize buffer             */
74
/*    _lx_nand_flash_driver_block_status_get                              */
75
/*                                          Driver block status get       */
76
/*    _lx_nand_flash_driver_block_status_set                              */
77
/*                                          Driver block status set       */
78
/*    _lx_nand_flash_metadata_build         Build metadata                */
79
/*    _lx_nand_flash_metadata_write         Write metadata                */
80
/*    _lx_nand_flash_driver_block_erase     Driver block erase            */
81
/*    _lx_nand_flash_system_error           System error handler          */
82
/*    tx_mutex_create                       Create thread-safe mutex      */
83
/*                                                                        */
84
/*  CALLED BY                                                             */
85
/*                                                                        */
86
/*    Application Code                                                    */
87
/*                                                                        */
88
/**************************************************************************/
89
4
UINT  _lx_nand_flash_format_extended(LX_NAND_FLASH* nand_flash, CHAR* name,
90
                                    UINT(*nand_driver_initialize)(LX_NAND_FLASH*),VOID* nand_driver_info_ptr,
91
                                    ULONG* memory_ptr, UINT memory_size)
92
{
93
94
ULONG                       block;
95
UCHAR                       block_status;
96
UINT                        status;
97
UCHAR                       *page_buffer_ptr;
98
99
    LX_PARAMETER_NOT_USED(name);
100
101
    /* Clear the NAND flash control block. User extension is not cleared.  */
102
1220
    LX_MEMSET(nand_flash, 0, (ULONG)((UCHAR*)&(nand_flash -> lx_nand_flash_open_previous) - (UCHAR*)nand_flash) + sizeof(nand_flash -> lx_nand_flash_open_previous));
103
104
4
    nand_flash -> lx_nand_flash_driver_info_ptr = nand_driver_info_ptr;
105
    /* Call the flash driver's initialization function.  */
106
4
    (nand_driver_initialize)(nand_flash);
107
108
    /* Determine if we can support this NAND flash size.  */
109

4
    if (nand_flash -> lx_nand_flash_pages_per_block > LX_NAND_MAX_PAGE_PER_BLOCK || nand_flash -> lx_nand_flash_total_blocks > LX_NAND_MAX_BLOCK_COUNT)
110
    {
111
        return(LX_ERROR);
112
    }
113
114
    /* Check if it is new LevelX NAND driver.  */
115

4
    if (nand_flash -> lx_nand_flash_driver_pages_read == LX_NULL || nand_flash -> lx_nand_flash_driver_pages_write == LX_NULL || nand_flash -> lx_nand_flash_driver_pages_copy == LX_NULL)
116
    {
117
        return(LX_ERROR);
118
    }
119
120
    /* Check the spare data length.  */
121
4
    if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(ULONG))
122
    {
123
        return(LX_ERROR);
124
    }
125
126
    /* Calculate the number of words per block and per page.  */
127
4
    nand_flash -> lx_nand_flash_words_per_page = (nand_flash -> lx_nand_flash_bytes_per_page / sizeof(ULONG));
128
4
    nand_flash -> lx_nand_flash_words_per_block = (nand_flash -> lx_nand_flash_words_per_page * nand_flash -> lx_nand_flash_pages_per_block);
129
130
    /* Calculate the total pages.  */
131
4
    nand_flash -> lx_nand_flash_total_pages = nand_flash -> lx_nand_flash_total_blocks * nand_flash -> lx_nand_flash_pages_per_block;
132
133
    /* Initialize memory buffer.  */
134
4
    status = _lx_nand_flash_memory_initialize(nand_flash, memory_ptr, memory_size);
135
4
    if (status != LX_SUCCESS)
136
    {
137
        return(status);
138
    }
139
140
    /* Initialize block numbers.  */
141
4
    nand_flash -> lx_nand_flash_metadata_block_number = LX_NAND_BLOCK_UNMAPPED;
142
4
    nand_flash -> lx_nand_flash_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED;
143
4
    nand_flash -> lx_nand_flash_backup_metadata_block_number = LX_NAND_BLOCK_UNMAPPED;
144
4
    nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED;
145
146
    /* Initialize the block status buffer.  */
147
8196
    LX_MEMSET(nand_flash -> lx_nand_flash_block_status_table, 0xFF, nand_flash -> lx_nand_flash_block_status_table_size);
148
149
    /* Loop through the blocks to check for bad blocks and determine the minimum and maximum erase count for each good block.  */
150
4100
    for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
151
    {
152
153
        /* First, check to make sure this block is good.  */
154
4096
        status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
155
156
        /* Check for an error from flash driver.   */
157
4096
        if (status)
158
        {
159
160
            /* Call system error handler.  */
161
            _lx_nand_flash_system_error(nand_flash, status, block, 0);
162
163
            /* Return an error.  */
164
            return(LX_ERROR);
165
        }
166
167
        /* Is this block bad?  */
168
4096
        if (block_status != LX_NAND_GOOD_BLOCK)
169
        {
170
171
            /* Yes, this block is bad.  */
172
173
            /* Increment the number of bad blocks.  */
174
            nand_flash -> lx_nand_flash_bad_blocks++;
175
176
            /* Save the block status.  */
177
            nand_flash -> lx_nand_flash_block_status_table[block] = LX_NAND_BLOCK_STATUS_BAD;
178
179
            /* Continue to the next block.  */
180
            continue;
181
        }
182
183
        /* Erase the block.  */
184
4096
        status = _lx_nand_flash_driver_block_erase(nand_flash, block, 0);
185
186
        /* Check for an error from flash driver.   */
187
4096
        if (status)
188
        {
189
190
            /* Call system error handler.  */
191
            _lx_nand_flash_system_error(nand_flash, status, block, 0);
192
193
            /* Attempt to mark this block as bad.  */
194
            status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK);
195
196
            /* Check for error in setting the block status.  */
197
            if (status)
198
            {
199
200
                /* Call system error handler.  */
201
                _lx_nand_flash_system_error(nand_flash, status, block, 0);
202
            }
203
204
            /* Increment the bad block count.  */
205
            nand_flash -> lx_nand_flash_bad_blocks++;
206
207
            /* Save the block status.  */
208
            nand_flash -> lx_nand_flash_block_status_table[block] = LX_NAND_BLOCK_STATUS_BAD;
209
        }
210
        else
211
        {
212
213
            /* Allocate blocks for metadata.  */
214
4096
            if (nand_flash -> lx_nand_flash_metadata_block_number == LX_NAND_BLOCK_UNMAPPED)
215
            {
216
4
                nand_flash -> lx_nand_flash_metadata_block_number = block;
217
4
                nand_flash -> lx_nand_flash_metadata_block_number_current = block;
218
            }
219
4092
            else if (nand_flash -> lx_nand_flash_backup_metadata_block_number == LX_NAND_BLOCK_UNMAPPED)
220
            {
221
4
                nand_flash -> lx_nand_flash_backup_metadata_block_number = block;
222
4
                nand_flash -> lx_nand_flash_backup_metadata_block_number_current = block;
223
            }
224
4088
            else if (nand_flash -> lx_nand_flash_metadata_block_number_next == LX_NAND_BLOCK_UNMAPPED)
225
            {
226
4
                nand_flash -> lx_nand_flash_metadata_block_number_next = block;
227
            }
228
4084
            else if (nand_flash -> lx_nand_flash_backup_metadata_block_number_next == LX_NAND_BLOCK_UNMAPPED)
229
            {
230
4
                nand_flash -> lx_nand_flash_backup_metadata_block_number_next = block;
231
            }
232
        }
233
    }
234
235
    /* There should be enough blocks for metadata.  */
236
4
    if (nand_flash -> lx_nand_flash_backup_metadata_block_number_next == LX_NAND_BLOCK_UNMAPPED)
237
    {
238
        return (LX_NO_BLOCKS);
239
    }
240
241
    /* Save the block status for metadata.  */
242
4
    nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_backup_metadata_block_number_next] = LX_NAND_BLOCK_STATUS_ALLOCATED;
243
4
    nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_metadata_block_number_next] = LX_NAND_BLOCK_STATUS_ALLOCATED;
244
4
    nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_backup_metadata_block_number] = (USHORT)nand_flash -> lx_nand_flash_backup_metadata_block_number_next;
245
4
    nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_metadata_block_number] = (USHORT)nand_flash -> lx_nand_flash_metadata_block_number_next;
246
247
    /* Initialize the mapping table.  */
248
8196
    LX_MEMSET(nand_flash -> lx_nand_flash_block_mapping_table, 0xFF, nand_flash -> lx_nand_flash_block_mapping_table_size);
249
250
    /* Build initial metadata.  */
251
4
    status = _lx_nand_flash_metadata_build(nand_flash);
252
4
    if (status != LX_SUCCESS)
253
    {
254
        /* Return error status.  */
255
        return(status);
256
    }
257
258
    /* Get buffer for page data.  */
259
4
    page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
260
261
    /* Initialize the page buffer.  */
262
2052
    LX_MEMSET(page_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page);
263
264
    /* Set the next block numbers.  */
265
4
    LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET], nand_flash -> lx_nand_flash_metadata_block_number_next);
266
4
    LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET], nand_flash -> lx_nand_flash_backup_metadata_block_number_next);
267
268
    /* Save the next block numbers to metadata block.  */
269
4
    status = _lx_nand_flash_metadata_write(nand_flash, page_buffer_ptr, LX_NAND_PAGE_TYPE_BLOCK_LINK);
270
271
4
    if (status != LX_SUCCESS)
272
    {
273
        /* Return error status.  */
274
        return(status);
275
    }
276
277
    /* Return a successful completion.  */
278
4
    return(LX_SUCCESS);
279
}
280