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