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_data_page_copy PORTABLE C */
43 /* 6.2.1 */
44 /* AUTHOR */
45 /* */
46 /* Xiuwen Cai, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function copies logical sectors into new block. */
51 /* */
52 /* INPUT */
53 /* */
54 /* nand_flash NAND flash instance */
55 /* logical_sector Logical sector number */
56 /* source_block Source block number */
57 /* src_block_status Source block status */
58 /* destination_block Destination block number */
59 /* dest_block_status_ptr Pointer to destination block */
60 /* status */
61 /* sectors Number of sectors to copy */
62 /* */
63 /* OUTPUT */
64 /* */
65 /* return status */
66 /* */
67 /* CALLS */
68 /* */
69 /* lx_nand_flash_driver_pages_copy Driver pages copy */
70 /* lx_nand_flash_driver_pages_read Driver pages read */
71 /* _lx_nand_flash_system_error Internal system error handler */
72 /* */
73 /* CALLED BY */
74 /* */
75 /* Internal LevelX */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
82 /* */
83 /**************************************************************************/
_lx_nand_flash_data_page_copy(LX_NAND_FLASH * nand_flash,ULONG logical_sector,ULONG source_block,USHORT src_block_status,ULONG destination_block,USHORT * dest_block_status_ptr,ULONG sectors)84 UINT _lx_nand_flash_data_page_copy(LX_NAND_FLASH* nand_flash, ULONG logical_sector, ULONG source_block, USHORT src_block_status,
85 ULONG destination_block, USHORT* dest_block_status_ptr, ULONG sectors)
86 {
87
88 LONG source_page;
89 ULONG destination_page;
90 UINT status = LX_SUCCESS;
91 UINT i;
92 ULONG available_pages;
93 ULONG spare_data1;
94 UCHAR *spare_buffer_ptr;
95 ULONG dest_block_status;
96 ULONG number_of_pages;
97
98
99 /* Get the destination block status. */
100 dest_block_status = *dest_block_status_ptr;
101
102 /* Get the current page number of the destination block. */
103 destination_page = dest_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK;
104
105 /* Get the available pages in the source block. */
106 available_pages = (src_block_status & LX_NAND_BLOCK_STATUS_FULL) ? (nand_flash -> lx_nand_flash_pages_per_block) : (src_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK);
107
108 /* Check if pages in the source block are sequential. */
109 if (src_block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
110 {
111
112 /* Get buffer for spare data. */
113 spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page;
114
115 /* Loop to copy the data. */
116 for (i = 0; i < sectors; i++)
117 {
118
119 /* Loop to search the page. */
120 for (source_page = (LONG)(available_pages - 1); source_page >= 0; source_page--)
121 {
122
123 /* Read one page. */
124 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
125 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1);
126 #else
127 status = (nand_flash -> lx_nand_flash_driver_pages_read)(source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1);
128 #endif
129
130 /* Check for an error from flash driver. */
131 if (status)
132 {
133
134 /* Call system error handler. */
135 _lx_nand_flash_system_error(nand_flash, status, source_block, 0);
136
137 /* Return an error. */
138 return(LX_ERROR);
139 }
140
141 /* Get the spare data. */
142 spare_data1 = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);
143
144 /* Check the address match. */
145 if ((spare_data1 & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == (logical_sector + i))
146 {
147
148 /* Check if the page contains valid data. */
149 if ((spare_data1 & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == (LX_NAND_PAGE_TYPE_USER_DATA))
150 {
151
152 /* Call the driver to copy the page. */
153 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
154 status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, 1, nand_flash -> lx_nand_flash_page_buffer);
155 #else
156 status = (nand_flash -> lx_nand_flash_driver_pages_copy)(source_block, (ULONG)source_page, destination_block, destination_page, 1, nand_flash -> lx_nand_flash_page_buffer);
157 #endif
158
159 /* Check for an error from flash driver. */
160 if (status)
161 {
162
163 /* Call system error handler. */
164 _lx_nand_flash_system_error(nand_flash, status, source_block, 0);
165
166 /* Return an error. */
167 return(LX_ERROR);
168 }
169
170 /* Check if the pages in destination block is still sequential. */
171 if ((destination_page) != (logical_sector + i % nand_flash -> lx_nand_flash_pages_per_block))
172 {
173 /* Mark the block status as non sequential. */
174 dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
175 }
176
177 /* Update the available pages. */
178 destination_page++;
179
180 /* Check if available page count reaches pages per block. */
181 if (destination_page == nand_flash -> lx_nand_flash_pages_per_block)
182 {
183
184 /* Set block full flag. */
185 dest_block_status |= LX_NAND_BLOCK_STATUS_FULL;
186 }
187 }
188 break;
189 }
190 }
191 }
192 }
193 else
194 {
195
196 /* Get the source page number. */
197 source_page = (LONG)(logical_sector % nand_flash -> lx_nand_flash_pages_per_block);
198
199 /* Check if the page to copy is greater than the available pages. */
200 number_of_pages = ((ULONG)source_page + sectors) > available_pages ?
201 (available_pages > (ULONG)source_page ? available_pages - (ULONG)source_page : 0) : sectors;
202
203 /* Check if there is any pages to be copied. */
204 if (number_of_pages)
205 {
206
207 /* Call the driver to copy pages. */
208 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
209 status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, number_of_pages, nand_flash -> lx_nand_flash_page_buffer);
210 #else
211 status = (nand_flash -> lx_nand_flash_driver_pages_copy)(source_block, (ULONG)source_page, destination_block, destination_page, number_of_pages, nand_flash -> lx_nand_flash_page_buffer);
212 #endif
213
214 /* Check for an error from flash driver. */
215 if (status)
216 {
217
218 /* Call system error handler. */
219 _lx_nand_flash_system_error(nand_flash, status, source_block, 0);
220
221 /* Return an error. */
222 return(LX_ERROR);
223 }
224
225 /* Check if the pages in destination block is still sequential. */
226 if ((ULONG)source_page != destination_page)
227 {
228
229 /* Mark the block status as non sequential. */
230 dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
231 }
232
233 /* Update the available pages. */
234 destination_page += number_of_pages;
235
236 /* Check if available page count reaches pages per block. */
237 if (destination_page == nand_flash -> lx_nand_flash_pages_per_block)
238 {
239
240 /* Set block full flag. */
241 dest_block_status |= LX_NAND_BLOCK_STATUS_FULL;
242 }
243 }
244 }
245
246 /* Return the block status. */
247 *dest_block_status_ptr = (USHORT)(destination_page | (dest_block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
248
249 /* Return status. */
250 return(status);
251 }
252
253