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 /**   NOR 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_nor_flash_extended_cache_read                  PORTABLE C       */
42 /*                                                           6.2.1       */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    William E. Lamie, Microsoft Corporation                             */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function performs a read of the NOR flash memory.              */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    nor_flash                             NOR flash instance            */
54 /*    flash_address                         Address of NOR flash to read  */
55 /*    destination                           Destination for the read      */
56 /*    words                                 Number of words to read       */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    return status                                                       */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    (lx_nor_flash_driver_read)            Actual driver read            */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    Application Code                                                    */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
75 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
76 /*                                            resulting in version 6.1    */
77 /*  06-02-2021     Bhupendra Naphade        Modified comment(s),          */
78 /*                                            resulting in version 6.1.7  */
79 /*  03-08-2023     Xiuwen Cai               Modified comment(s),          */
80 /*                                            added new driver interface, */
81 /*                                            resulting in version 6.2.1 */
82 /*                                                                        */
83 /**************************************************************************/
_lx_nor_flash_driver_read(LX_NOR_FLASH * nor_flash,ULONG * flash_address,ULONG * destination,ULONG words)84 UINT  _lx_nor_flash_driver_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words)
85 {
86 #ifndef LX_NOR_DISABLE_EXTENDED_CACHE
87 
88 UINT    status;
89 UINT    i;
90 ULONG   *cache_entry_start;
91 ULONG   *cache_entry_end;
92 ULONG   cache_offset;
93 UINT    least_used_cache_entry;
94 
95 
96     /* Is the request a whole sector or a partial sector.  */
97     if ((words == 1) && (nor_flash -> lx_nor_flash_extended_cache_entries))
98     {
99 
100         /* One word request, which implies that it is a NOR flash metadata read.  */
101 
102 
103         /* Initialize the least used cache entry.  */
104         least_used_cache_entry =  0;
105 
106         do
107         {
108 
109             /* Loop through the cache entries to see if there is a sector in cache.  */
110             for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
111             {
112 
113                 /* Search through the cache to find the entry.  */
114 
115                 /* Determine the cache entry addresses.  */
116                 cache_entry_start =  nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
117                 cache_entry_end =    cache_entry_start + LX_NOR_SECTOR_SIZE;
118 
119                 /* Determine if the flash address in in the cache entry.  */
120                 if ((cache_entry_start) && (flash_address >= cache_entry_start) && (flash_address < cache_entry_end))
121                 {
122 
123                     /* Yes, we found the entry.  */
124 
125                     /* Increment the accessed count.  */
126                     nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count++;
127 
128                     /* Calculate the offset into the cache entry.  */
129                     cache_offset =  (ULONG)(flash_address - cache_entry_start);
130 
131                     /* Copy the word from the cache.  */
132                     *destination =  *(nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory + cache_offset);
133 
134                     /* Increment the number of cache hits.  */
135                     nor_flash -> lx_nor_flash_extended_cache_hits++;
136 
137                     /* Return success.  */
138                     return(LX_SUCCESS);
139                 }
140                 else
141                 {
142 
143                     /* Determine if we have a new least used sector.  */
144                     if (i != least_used_cache_entry)
145                     {
146 
147                         /* Determine if this entry has a smaller accessed count.  */
148                         if (nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count <
149                             nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_access_count)
150                         {
151 
152                             /* New least used entry.  */
153                             least_used_cache_entry =  i;
154                         }
155                     }
156                 }
157             }
158 
159             /* Now read in the sector into the cache.  */
160             cache_offset =  (ULONG)(flash_address - nor_flash -> lx_nor_flash_base_address);
161             cache_offset =  cache_offset & ~((ULONG) (LX_NOR_SECTOR_SIZE-1));
162             cache_entry_start =  nor_flash -> lx_nor_flash_base_address + cache_offset;
163 
164             /* Call the actual driver read function.  */
165 #ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
166             status =  (nor_flash -> lx_nor_flash_driver_read)(nor_flash, cache_entry_start,
167                             nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_memory,
168                             LX_NOR_SECTOR_SIZE);
169 #else
170             status =  (nor_flash -> lx_nor_flash_driver_read)(cache_entry_start,
171                             nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_memory,
172                             LX_NOR_SECTOR_SIZE);
173 #endif
174 
175             /* Determine if there was an error.  */
176             if (status != LX_SUCCESS)
177             {
178 
179                 /* Return the error to the caller.  */
180                 return(status);
181             }
182 
183             /* Setup the cache entry.  */
184             nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_address =  cache_entry_start;
185             nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_access_count =    0;
186 
187             /* Increment the number of cache misses.  */
188             nor_flash -> lx_nor_flash_extended_cache_misses++;
189 
190             /* Decrement the number of cache hits, so that the increment that will happen next will be cancelled out.  */
191             nor_flash -> lx_nor_flash_extended_cache_hits--;
192 
193         } while (status == LX_SUCCESS);
194 
195         /* Return success.  */
196         return(LX_SUCCESS);
197     }
198     else
199     {
200 
201         /* Call the actual driver read function.  */
202 #ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
203         status =  (nor_flash -> lx_nor_flash_driver_read)(nor_flash, flash_address, destination, words);
204 #else
205         status =  (nor_flash -> lx_nor_flash_driver_read)(flash_address, destination, words);
206 #endif
207 
208         /* Return completion status.  */
209         return(status);
210     }
211 #else
212 UINT    status;
213 
214 
215     /* Call the actual driver read function.  */
216 #ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
217     status =  (nor_flash -> lx_nor_flash_driver_read)(nor_flash, flash_address, destination, words);
218 #else
219     status =  (nor_flash -> lx_nor_flash_driver_read)(flash_address, destination, words);
220 #endif
221 
222     /* Return completion status.  */
223     return(status);
224 #endif
225 }
226 
227 
228