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