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_open                                 PORTABLE C      */
42 /*                                                           6.3.0        */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Xiuwen Cai, Microsoft Corporation                                   */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function opens a NAND flash instance and ensures the           */
50 /*    NAND flash is in a coherent state.                                  */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    nand_flash                            NAND flash instance           */
55 /*    name                                  Name of NAND flash instance   */
56 /*    nand_driver_initialize                Driver initialize             */
57 /*    memory_ptr                            Pointer to memory used by the */
58 /*                                            LevelX for this NAND.       */
59 /*    memory_size                           Size of memory - must at least*/
60 /*                                            7 * total block count +     */
61 /*                                            2 * page size               */
62 /*                                                                        */
63 /*  OUTPUT                                                                */
64 /*                                                                        */
65 /*    return status                                                       */
66 /*                                                                        */
67 /*  CALLS                                                                 */
68 /*                                                                        */
69 /*    (nand_driver_initialize)              Driver initialize             */
70 /*    _lx_nand_flash_memory_initialize      Initialize buffer             */
71 /*    _lx_nand_flash_driver_block_status_get                              */
72 /*                                          Get block status              */
73 /*    lx_nand_flash_driver_pages_read       Read pages                    */
74 /*    _lx_nand_flash_free_block_list_add    Add free block to list        */
75 /*    _lx_nand_flash_mapped_block_list_add  Add mapped block to list      */
76 /*    _lx_nand_flash_system_error           System error handler          */
77 /*    tx_mutex_create                       Create thread-safe mutex      */
78 /*                                                                        */
79 /*  CALLED BY                                                             */
80 /*                                                                        */
81 /*    Application Code                                                    */
82 /*                                                                        */
83 /*  RELEASE HISTORY                                                       */
84 /*                                                                        */
85 /*    DATE              NAME                      DESCRIPTION             */
86 /*                                                                        */
87 /*  03-08-2023     Xiuwen Cai               Initial Version 6.2.1         */
88 /*  10-31-2023     Xiuwen Cai               Modified comment(s),          */
89 /*                                            avoided clearing user       */
90 /*                                            extension in flash control  */
91 /*                                            block,                      */
92 /*                                            resulting in version 6.3.0  */
93 /*                                                                        */
94 /**************************************************************************/
_lx_nand_flash_open(LX_NAND_FLASH * nand_flash,CHAR * name,UINT (* nand_driver_initialize)(LX_NAND_FLASH *),ULONG * memory_ptr,UINT memory_size)95 UINT  _lx_nand_flash_open(LX_NAND_FLASH  *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *),
96                           ULONG* memory_ptr, UINT memory_size)
97 {
98 
99 ULONG                       block;
100 ULONG                       page;
101 UCHAR                       block_status;
102 ULONG                       block_count;
103 UINT                        status;
104 LX_NAND_FLASH               *tail_ptr;
105 LX_NAND_DEVICE_INFO         *nand_device_info_page;
106 UCHAR                       *spare_buffer_ptr;
107 UCHAR                       *page_buffer_ptr;
108 ULONG                       page_type;
109 UCHAR                       page_index;
110 LX_INTERRUPT_SAVE_AREA
111 
112     LX_PARAMETER_NOT_USED(name);
113 
114     /* Clear the NAND flash control block. User extension is not cleared.  */
115     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));
116 
117     /* Call the flash driver's initialization function.  */
118     (nand_driver_initialize)(nand_flash);
119 
120     /* Determine if we can support this NAND flash size.  */
121     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)
122     {
123 
124         /* Return an error.  */
125         return(LX_ERROR);
126     }
127 
128     /* Check if it is new LevelX NAND driver.  */
129     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)
130     {
131 
132         /* Return an error.  */
133         return(LX_ERROR);
134     }
135 
136     /* Check the spare data length.  */
137     if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(ULONG))
138     {
139 
140         /* Return an error.  */
141         return(LX_ERROR);
142     }
143 
144     /* Calculate the number of words per block and per page.  */
145     nand_flash -> lx_nand_flash_words_per_page =   (nand_flash -> lx_nand_flash_bytes_per_page / sizeof(ULONG));
146     nand_flash -> lx_nand_flash_words_per_block =  (nand_flash -> lx_nand_flash_words_per_page * nand_flash -> lx_nand_flash_pages_per_block);
147 
148     /* Calculate the total pages.  */
149     nand_flash -> lx_nand_flash_total_pages =   nand_flash -> lx_nand_flash_total_blocks * nand_flash -> lx_nand_flash_pages_per_block;
150 
151     /* Initialize memory buffer.  */
152     status = _lx_nand_flash_memory_initialize(nand_flash, memory_ptr, memory_size);
153     if (status != LX_SUCCESS)
154     {
155         return(status);
156     }
157 
158     /* Initialize block numbers.  */
159     nand_flash -> lx_nand_flash_metadata_block_number = LX_NAND_BLOCK_UNMAPPED;
160     nand_flash -> lx_nand_flash_backup_metadata_block_number = LX_NAND_BLOCK_UNMAPPED;
161 
162     /* Setup page buffer and spare buffer pointers.  */
163     page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
164     spare_buffer_ptr = page_buffer_ptr + nand_flash -> lx_nand_flash_bytes_per_page;
165 
166     /* Loop through the blocks to check for bad blocks and determine the minimum and maximum erase count for each good block.  */
167     for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
168     {
169 
170         /* First, check to make sure this block is good.  */
171         status =  _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
172 
173         /* Check for an error from flash driver.   */
174         if (status)
175         {
176 
177             /* Call system error handler.  */
178             _lx_nand_flash_system_error(nand_flash, status, block, 0);
179 
180             /* Return an error.  */
181             return(LX_ERROR);
182         }
183 
184         /* Is this block bad?  */
185         if (block_status != LX_NAND_GOOD_BLOCK)
186         {
187 
188             /* Yes, this block is bad.  */
189 
190             /* Increment the number of bad blocks.  */
191             nand_flash -> lx_nand_flash_bad_blocks++;
192 
193             /* Save the block status.  */
194             nand_flash -> lx_nand_flash_block_status_table[block] = LX_NAND_BLOCK_STATUS_BAD;
195 
196             /* Continue to the next block.  */
197             continue;
198         }
199 
200         /* Call driver read function to read page 0.  */
201 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
202         status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, 0, page_buffer_ptr, spare_buffer_ptr, 1);
203 #else
204         status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, 0, page_buffer_ptr, spare_buffer_ptr, 1);
205 #endif
206 
207         /* Check for an error from flash driver.   */
208         if (status)
209         {
210 
211             /* Call system error handler.  */
212             _lx_nand_flash_system_error(nand_flash, status, block, 0);
213 
214             /* Determine if the error is fatal.  */
215             if (status != LX_NAND_ERROR_CORRECTED)
216             {
217 
218                 /* Return an error.  */
219                 return(LX_ERROR);
220             }
221         }
222 
223         /* Get the page type.  */
224         page_type = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);
225 
226         /* Check if the type is device info.  */
227         if (page_type == LX_NAND_PAGE_TYPE_DEVICE_INFO)
228         {
229 
230             /* Get the device info page.  */
231             nand_device_info_page = (LX_NAND_DEVICE_INFO*)page_buffer_ptr;
232 
233             /* Check signature.  */
234             if (nand_device_info_page -> lx_nand_device_info_signature1 == LX_NAND_DEVICE_INFO_SIGNATURE1 &&
235                 nand_device_info_page -> lx_nand_device_info_signature2 == LX_NAND_DEVICE_INFO_SIGNATURE2)
236             {
237 
238                 /* Save the block numbers.  */
239                 nand_flash -> lx_nand_flash_metadata_block_number = nand_device_info_page -> lx_nand_device_info_metadata_block_number;
240                 nand_flash -> lx_nand_flash_backup_metadata_block_number = nand_device_info_page -> lx_nand_device_info_backup_metadata_block_number;
241                 break;
242             }
243 
244         }
245 
246     }
247 
248     /* Check if we have found the metadata block.  */
249     if (nand_flash -> lx_nand_flash_metadata_block_number == LX_NAND_BLOCK_UNMAPPED)
250     {
251 
252         /* Not found, return an error.  */
253         return (LX_ERROR);
254     }
255 
256     /* Initialize metadata block numbers and lists.  */
257     nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number;
258     nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number;
259     nand_flash -> lx_nand_flash_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_metadata_block_number;
260     nand_flash -> lx_nand_flash_backup_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_backup_metadata_block_number;
261 
262     /* Found one metadata block.  */
263     nand_flash -> lx_nand_flash_metadata_block_count = 1;
264 
265     /* Clear searched block count.  */
266     block_count = 0;
267 
268     do
269     {
270 
271         /* Initialize next block to unmapped.  */
272         nand_flash -> lx_nand_flash_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED;
273         nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED;
274 
275         /* Loop to read pages in the metadata block.  */
276         for (page = 0; page < nand_flash -> lx_nand_flash_pages_per_block ; page++)
277         {
278 
279             /* Call driver read function to read page.  */
280 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
281             status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, page, page_buffer_ptr, spare_buffer_ptr, 1);
282 #else
283             status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, page, page_buffer_ptr, spare_buffer_ptr, 1);
284 #endif
285 
286             /* Check for an error from flash driver.   */
287             if (status)
288             {
289 
290                 /* Call system error handler.  */
291                 _lx_nand_flash_system_error(nand_flash, status, block, 0);
292 
293                 /* Determine if the error is fatal.  */
294                 if (status != LX_NAND_ERROR_CORRECTED)
295                 {
296 
297                     /* Return an error.  */
298                     return(LX_ERROR);
299                 }
300             }
301 
302             /* Get page type and page index.  */
303             page_type = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & (~LX_NAND_PAGE_TYPE_PAGE_NUMBER_MASK);
304             page_index = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_PAGE_NUMBER_MASK;
305 
306             /* Process metadata page by type.  */
307             switch (page_type)
308             {
309             case LX_NAND_PAGE_TYPE_DEVICE_INFO:
310 
311                 /* This page is for device info.  */
312                 nand_device_info_page = (LX_NAND_DEVICE_INFO*)page_buffer_ptr;
313 
314                 /* Get the base erase count.  */
315                 nand_flash -> lx_nand_flash_base_erase_count = nand_device_info_page -> lx_nand_device_info_base_erase_count;
316                 break;
317 
318             case LX_NAND_PAGE_TYPE_ERASE_COUNT_TABLE:
319 
320                 /* Check if page index is valid.  */
321                 if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_erase_count_table_size)
322                 {
323 
324                     /* Invalid page index. Return an error.  */
325                     status = LX_ERROR;
326                     break;
327                 }
328 
329                 /* Copy page data to erase count table.  */
330                 LX_MEMCPY(nand_flash -> lx_nand_flash_erase_count_table + page_index * nand_flash -> lx_nand_flash_bytes_per_page, /* Use case of memcpy is verified. */
331                             page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page);
332                 break;
333 
334             case LX_NAND_PAGE_TYPE_BLOCK_MAPPING_TABLE:
335 
336                 /* Check if page index is valid.  */
337                 if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_block_mapping_table_size)
338                 {
339 
340                     /* Invalid page index. Return an error.  */
341                     status = LX_ERROR;
342                     break;
343                 }
344 
345                 /* Copy page data to block mapping table.  */
346                 LX_MEMCPY(nand_flash -> lx_nand_flash_block_mapping_table + page_index * nand_flash -> lx_nand_flash_bytes_per_page / sizeof(*nand_flash -> lx_nand_flash_block_mapping_table), /* Use case of memcpy is verified. */
347                     page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page);
348                 break;
349 
350             case LX_NAND_PAGE_TYPE_BLOCK_STATUS_TABLE:
351 
352                 /* Check if page index is valid.  */
353                 if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_block_status_table_size)
354                 {
355 
356                     /* Invalid page index. Return an error.  */
357                     status = LX_ERROR;
358                     break;
359                 }
360 
361                 /* Copy page data to block status table.  */
362                 LX_MEMCPY(nand_flash -> lx_nand_flash_block_status_table + page_index * nand_flash -> lx_nand_flash_bytes_per_page / sizeof(*nand_flash -> lx_nand_flash_block_status_table), /* Use case of memcpy is verified. */
363                     page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page);
364                 break;
365 
366             case LX_NAND_PAGE_TYPE_FREE_PAGE:
367 
368                 /* Found a free page. Update current page.  */
369                 nand_flash -> lx_nand_flash_metadata_block_current_page = page;
370                 nand_flash -> lx_nand_flash_backup_metadata_block_current_page = page;
371 
372                 /* Skip all the remaining pages.  */
373                 page = nand_flash -> lx_nand_flash_pages_per_block;
374                 break;
375 
376             case LX_NAND_PAGE_TYPE_BLOCK_LINK:
377 
378                 /* Found next blocks. Update next block numbers.  */
379                 nand_flash -> lx_nand_flash_metadata_block_number_next = LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET]);
380                 nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET]);
381 
382                 /* Save block numbers in metadata block lists.  */
383                 nand_flash -> lx_nand_flash_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET]);
384                 nand_flash -> lx_nand_flash_backup_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET]);
385 
386                 /* Increase metadata block count.  */
387                 nand_flash -> lx_nand_flash_metadata_block_count++;
388 
389                 break;
390 
391             default:
392 
393                 /* Unknown type, return error.  */
394                 status = LX_ERROR;
395             }
396 
397             /* Check status.  */
398             if (status == LX_ERROR)
399             {
400 
401                 /* Error, break the loop.  */
402                 break;
403             }
404 
405         }
406 
407         /* Check if we have reached the last page.  */
408         if (page == nand_flash -> lx_nand_flash_pages_per_block)
409         {
410 
411             /* Move to next block.  */
412             nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number_next;
413             nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number_next;
414 
415             /* Make sure the block is valid.  */
416             if (nand_flash -> lx_nand_flash_metadata_block_number_current == LX_NAND_BLOCK_UNMAPPED)
417             {
418 
419                 /* Error, break the loop.  */
420                 break;
421             }
422 
423             /* Get the block to process.  */
424             block = nand_flash -> lx_nand_flash_metadata_block_number_current;
425         }
426 
427         /* Increase the processed block number.  */
428         block_count++;
429 
430         /* If block count is larger than total blocks, there is an error.  */
431         if (block_count >= nand_flash -> lx_nand_flash_total_blocks)
432         {
433 
434             /* Break the loop.  */
435             break;
436         }
437     } while (nand_flash -> lx_nand_flash_metadata_block_current_page == 0 && status != LX_ERROR);
438 
439     /* Check if metadata page is processed correctly.  */
440     if (nand_flash -> lx_nand_flash_metadata_block_current_page == 0 || status == LX_ERROR)
441     {
442 
443         /* Return an error.  */
444         return(LX_ERROR);
445     }
446 
447     /* Loop to build free and mapped block lists.  */
448     for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
449     {
450 
451         /* Check for free blocks.  */
452         if (nand_flash -> lx_nand_flash_block_status_table[block] == LX_NAND_BLOCK_STATUS_FREE)
453         {
454 
455             /* Add the block to free block list.  */
456             _lx_nand_flash_free_block_list_add(nand_flash, block);
457         }
458 
459         /* Check for mapped blocks.  */
460         if (nand_flash -> lx_nand_flash_block_mapping_table[block] != LX_NAND_BLOCK_UNMAPPED)
461         {
462 
463             /* Add the block to free block list.  */
464             _lx_nand_flash_mapped_block_list_add(nand_flash, block);
465         }
466     }
467 
468 
469 #ifdef LX_THREAD_SAFE_ENABLE
470 
471     /* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
472        in order to provide thread-safe operation.  */
473     status =  tx_mutex_create(&nand_flash -> lx_nand_flash_mutex, "NAND Flash Mutex", TX_NO_INHERIT);
474 
475     /* Determine if the mutex creation encountered an error.  */
476     if (status != LX_SUCCESS)
477     {
478 
479         /* Call system error handler, since this should not happen.  */
480         _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_MUTEX_CREATE_FAILED, 0, 0);
481 
482         /* Return error to caller.  */
483         return(LX_ERROR);
484     }
485 #endif
486 
487     /* Lockout interrupts.  */
488     LX_DISABLE
489 
490     /* At this point, the NAND flash has been opened successfully.  Place the
491        NAND flash control block on the linked list of currently opened NAND flashes.  */
492 
493     /* Set the NAND flash state to open.  */
494     nand_flash -> lx_nand_flash_state =  LX_NAND_FLASH_OPENED;
495 
496     /* Place the NAND flash control block on the list of opened NAND flashes.  First,
497        check for an empty list.  */
498     if (_lx_nand_flash_opened_count)
499     {
500 
501         /* List is not empty - other NAND flashes are open.  */
502 
503         /* Pickup tail pointer.  */
504         tail_ptr =  _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous;
505 
506         /* Place the new NAND flash control block in the list.  */
507         _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous =  nand_flash;
508         tail_ptr -> lx_nand_flash_open_next =                       nand_flash;
509 
510         /* Setup this NAND flash's opened links.  */
511         nand_flash -> lx_nand_flash_open_previous =  tail_ptr;
512         nand_flash -> lx_nand_flash_open_next =      _lx_nand_flash_opened_ptr;
513     }
514     else
515     {
516 
517         /* The opened NAND flash list is empty.  Add the NAND flash to empty list.  */
518         _lx_nand_flash_opened_ptr =                 nand_flash;
519         nand_flash -> lx_nand_flash_open_next =      nand_flash;
520         nand_flash -> lx_nand_flash_open_previous =  nand_flash;
521     }
522 
523     /* Increment the opened NAND flash counter.  */
524     _lx_nand_flash_opened_count++;
525 
526     /* Restore interrupts.  */
527     LX_RESTORE
528 
529     /* Return a successful completion.  */
530     return(LX_SUCCESS);
531 }
532 
533