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