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