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