GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_format_extended.c Lines: 48 66 72.7 %
Date: 2026-01-12 23:08:29 Branches: 31 46 67.4 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2025 STMicroelectronics
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** LevelX Component                                                      */
17
/**                                                                       */
18
/**   NAND 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_nand_flash_format_extended                      PORTABLE C      */
43
/*                                                                        */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    Xiuwen Cai, Microsoft Corporation                                   */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function erases and formats a NAND flash.                      */
51
/*                                                                        */
52
/*  INPUT                                                                 */
53
/*                                                                        */
54
/*    nand_flash                            NAND flash instance           */
55
/*    name                                  Name of NAND flash instance   */
56
/*    nand_driver_initialize                Driver initialize             */
57
/*    nand_driver_info_ptr                  Driver user data pointer      */
58
/*    memory_ptr                            Pointer to memory used by the */
59
/*                                            LevelX for this NAND.       */
60
/*    memory_size                           Size of memory - must at least*/
61
/*                                            7 * total block count +     */
62
/*                                            2 * page size               */
63
/*                                                                        */
64
/*  OUTPUT                                                                */
65
/*                                                                        */
66
/*    return status                                                       */
67
/*                                                                        */
68
/*  CALLS                                                                 */
69
/*                                                                        */
70
/*    (nand_driver_initialize)              Driver initialize             */
71
/*    LX_MEMSET                             Initialize memory             */
72
/*    _lx_nand_flash_memory_initialize      Initialize buffer             */
73
/*    _lx_nand_flash_driver_block_status_get                              */
74
/*                                          Driver block status get       */
75
/*    _lx_nand_flash_driver_block_status_set                              */
76
/*                                          Driver block status set       */
77
/*    _lx_nand_flash_metadata_build         Build metadata                */
78
/*    _lx_nand_flash_metadata_write         Write metadata                */
79
/*    _lx_nand_flash_driver_block_erase     Driver block erase            */
80
/*    _lx_nand_flash_system_error           System error handler          */
81
/*    tx_mutex_create                       Create thread-safe mutex      */
82
/*                                                                        */
83
/*  CALLED BY                                                             */
84
/*                                                                        */
85
/*    Application Code                                                    */
86
/*                                                                        */
87
/**************************************************************************/
88
4
UINT  _lx_nand_flash_format_extended(LX_NAND_FLASH* nand_flash, CHAR* name,
89
                                    UINT(*nand_driver_initialize)(LX_NAND_FLASH*),VOID* nand_driver_info_ptr,
90
                                    ULONG* memory_ptr, UINT memory_size)
91
{
92
93
ULONG                       block;
94
UCHAR                       block_status;
95
UINT                        status;
96
UCHAR                       *page_buffer_ptr;
97
98
    LX_PARAMETER_NOT_USED(name);
99
100
    /* Clear the NAND flash control block. User extension is not cleared.  */
101
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));
102
103
4
    nand_flash -> lx_nand_flash_driver_info_ptr = nand_driver_info_ptr;
104
    /* Call the flash driver's initialization function.  */
105
4
    (nand_driver_initialize)(nand_flash);
106
107
    /* Determine if we can support this NAND flash size.  */
108

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)
109
    {
110
        return(LX_ERROR);
111
    }
112
113
    /* Check if it is new LevelX NAND driver.  */
114

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