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