GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_format.c Lines: 47 65 72.3 %
Date: 2024-03-11 05:20:25 Branches: 31 46 67.4 %

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
/**   NAND 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_nand_flash_format                               PORTABLE C      */
42
/*                                                           6.3.0        */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    Xiuwen Cai, Microsoft Corporation                                   */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function erases and formats a NAND flash.                      */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    nand_flash                            NAND flash instance           */
54
/*    name                                  Name of NAND flash instance   */
55
/*    nand_driver_initialize                Driver initialize             */
56
/*    memory_ptr                            Pointer to memory used by the */
57
/*                                            LevelX for this NAND.       */
58
/*    memory_size                           Size of memory - must at least*/
59
/*                                            7 * total block count +     */
60
/*                                            2 * page size               */
61
/*                                                                        */
62
/*  OUTPUT                                                                */
63
/*                                                                        */
64
/*    return status                                                       */
65
/*                                                                        */
66
/*  CALLS                                                                 */
67
/*                                                                        */
68
/*    (nand_driver_initialize)              Driver initialize             */
69
/*    LX_MEMSET                             Initialize memory             */
70
/*    _lx_nand_flash_memory_initialize      Initialize buffer             */
71
/*    _lx_nand_flash_driver_block_status_get                              */
72
/*                                          Driver block status get       */
73
/*    _lx_nand_flash_driver_block_status_set                              */
74
/*                                          Driver block status set       */
75
/*    _lx_nand_flash_metadata_build         Build metadata                */
76
/*    _lx_nand_flash_metadata_write         Write metadata                */
77
/*    _lx_nand_flash_driver_block_erase     Driver block erase            */
78
/*    _lx_nand_flash_system_error           System error handler          */
79
/*    tx_mutex_create                       Create thread-safe mutex      */
80
/*                                                                        */
81
/*  CALLED BY                                                             */
82
/*                                                                        */
83
/*    Application Code                                                    */
84
/*                                                                        */
85
/*  RELEASE HISTORY                                                       */
86
/*                                                                        */
87
/*    DATE              NAME                      DESCRIPTION             */
88
/*                                                                        */
89
/*  03-08-2023     Xiuwen Cai               Initial Version 6.2.1         */
90
/*  10-31-2023     Xiuwen Cai               Modified comment(s),          */
91
/*                                            avoided clearing user       */
92
/*                                            extension in flash control  */
93
/*                                            block,                      */
94
/*                                            resulting in version 6.3.0  */
95
/*                                                                        */
96
/**************************************************************************/
97
4
UINT  _lx_nand_flash_format(LX_NAND_FLASH* nand_flash, CHAR* name,
98
                            UINT(*nand_driver_initialize)(LX_NAND_FLASH*),
99
                            ULONG* memory_ptr, UINT memory_size)
100
{
101
102
ULONG                       block;
103
UCHAR                       block_status;
104
UINT                        status;
105
UCHAR                       *page_buffer_ptr;
106
107
    LX_PARAMETER_NOT_USED(name);
108
109
    /* Clear the NAND flash control block. User extension is not cleared.  */
110
1204
    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));
111
112
    /* Call the flash driver's initialization function.  */
113
4
    (nand_driver_initialize)(nand_flash);
114
115
    /* Determine if we can support this NAND flash size.  */
116

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)
117
    {
118
        return(LX_ERROR);
119
    }
120
121
    /* Check if it is new LevelX NAND driver.  */
122

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