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