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_sector_read                          PORTABLE C      */
42 /*                                                           6.2.1       */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Xiuwen Cai, Microsoft Corporation                                   */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function reads a logical sector from NAND flash.               */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    nand_flash                            NAND flash instance           */
54 /*    logical_sector                        Logical sector number         */
55 /*    buffer                                Pointer to buffer to read into*/
56 /*                                            (the size is number of      */
57 /*                                             bytes in a page)           */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    return status                                                       */
62 /*                                                                        */
63 /*  CALLS                                                                 */
64 /*                                                                        */
65 /*    _lx_nand_flash_block_find             Find the mapped block         */
66 /*    lx_nand_flash_driver_pages_read       Read pages                    */
67 /*    _lx_nand_flash_system_error           Internal system error handler */
68 /*    tx_mutex_get                          Get thread protection         */
69 /*    tx_mutex_put                          Release thread protection     */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    Application Code                                                    */
74 /*                                                                        */
75 /*  RELEASE HISTORY                                                       */
76 /*                                                                        */
77 /*    DATE              NAME                      DESCRIPTION             */
78 /*                                                                        */
79 /*  03-08-2023     Xiuwen Cai               Initial Version 6.2.1        */
80 /*                                                                        */
81 /**************************************************************************/
_lx_nand_flash_sector_read(LX_NAND_FLASH * nand_flash,ULONG logical_sector,VOID * buffer)82 UINT  _lx_nand_flash_sector_read(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer)
83 {
84 
85 UINT        status;
86 ULONG       i;
87 ULONG       *word_ptr;
88 ULONG       block;
89 USHORT      block_status;
90 UCHAR       *spare_buffer_ptr;
91 ULONG       available_pages;
92 LONG        page;
93 
94 #ifdef LX_THREAD_SAFE_ENABLE
95 
96     /* Obtain the thread safe mutex.  */
97     tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
98 #endif
99 
100     /* Increment the number of read requests.  */
101     nand_flash -> lx_nand_flash_diagnostic_sector_read_requests++;
102 
103     /* See if we can find the sector in the current mapping.  */
104     status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
105 
106     /* Check return status.   */
107     if (status != LX_SUCCESS)
108     {
109 
110         /* Call system error handler.  */
111         _lx_nand_flash_system_error(nand_flash, status, block, 0);
112 
113         /* Determine if the error is fatal.  */
114         if (status != LX_NAND_ERROR_CORRECTED)
115         {
116 #ifdef LX_THREAD_SAFE_ENABLE
117 
118             /* Release the thread safe mutex.  */
119             tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
120 #endif
121             /* Return an error.  */
122             return(LX_ERROR);
123         }
124     }
125 
126     /* Determine if the block is mapped.  */
127     if (block != LX_NAND_BLOCK_UNMAPPED)
128     {
129 
130         /* Setup spare buffer pointer.  */
131         spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
132 
133         /* Get available pages in this block.  */
134         available_pages = block_status & LX_NAND_BLOCK_STATUS_FULL ? nand_flash -> lx_nand_flash_pages_per_block : block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK;
135 
136         /* Determine if the pages are recorded sequentially.  */
137         if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
138         {
139 
140             /* Loop to search the logical page.  */
141             for (page = (LONG)available_pages - 1; page >= 0; page--)
142             {
143 
144                 /* Read a page.  */
145 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
146                 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, (UCHAR*)buffer, spare_buffer_ptr, 1);
147 #else
148                 status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, (UCHAR*)buffer, spare_buffer_ptr, 1);
149 #endif
150 
151                 /* Check for an error from flash driver.   */
152                 if (status)
153                 {
154 
155                     /* Call system error handler.  */
156                     _lx_nand_flash_system_error(nand_flash, status, block, 0);
157 #ifdef LX_THREAD_SAFE_ENABLE
158 
159                     /* Release the thread safe mutex.  */
160                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
161 #endif
162                     /* Return an error.  */
163                     return(LX_ERROR);
164                 }
165 
166                 /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number.  */
167                 if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == logical_sector)
168                 {
169 #ifdef LX_THREAD_SAFE_ENABLE
170 
171                     /* Release the thread safe mutex.  */
172                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
173 #endif
174                     /* Return successful completion.  */
175                     return(LX_SUCCESS);
176                 }
177             }
178         }
179         else
180         {
181 
182             /* Check if the logical sector is available.  */
183             if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages)
184             {
185 
186                 /* Read a page.  */
187 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
188                 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, logical_sector % nand_flash -> lx_nand_flash_pages_per_block, (UCHAR*)buffer, spare_buffer_ptr, 1);
189 #else
190                 status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, logical_sector % nand_flash -> lx_nand_flash_pages_per_block, (UCHAR*)buffer, spare_buffer_ptr, 1);
191 #endif
192 
193                 /* Check for an error from flash driver.   */
194                 if (status)
195                 {
196 
197                     /* Call system error handler.  */
198                     _lx_nand_flash_system_error(nand_flash, status, block, 0);
199 
200 #ifdef LX_THREAD_SAFE_ENABLE
201 
202                     /* Release the thread safe mutex.  */
203                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
204 #endif
205                     /* Return an error.  */
206                     return(LX_ERROR);
207                 }
208 #ifdef LX_THREAD_SAFE_ENABLE
209 
210                 /* Release the thread safe mutex.  */
211                 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
212 #endif
213                 /* Return successful completion.  */
214                 return(LX_SUCCESS);
215             }
216         }
217     }
218 
219     /* Sector hasn't been written. Simply fill the destination buffer with ones and return success.  */
220 
221     /* Setup pointer to users buffer.  */
222     word_ptr =  (ULONG *) buffer;
223 
224     /* Put all ones in he buffer.  */
225     for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++)
226     {
227 
228         /* Copy a word.  */
229         *word_ptr++ =  LX_ALL_ONES;
230     }
231 
232     /* Set the status to success.  */
233     status =  LX_SUCCESS;
234 
235 #ifdef LX_THREAD_SAFE_ENABLE
236 
237     /* Release the thread safe mutex.  */
238     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
239 #endif
240 
241     /* Return status.  */
242     return(status);
243 }
244 
245