]>
Commit | Line | Data |
---|---|---|
1d66480a GD |
1 | /** @file\r |
2 | Generic driver using Hardware Sequencing registers.\r | |
3 | \r | |
4 | Copyright (c) 2017-2021, Intel Corporation. All rights reserved.<BR>\r | |
5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
6 | \r | |
7 | **/\r | |
8 | #include "SpiCommon.h"\r | |
9 | \r | |
e5efcf8b | 10 | SPI_INSTANCE *mSpiInstance = NULL;\r |
1d66480a GD |
11 | \r |
12 | /**\r | |
13 | Get SPI Instance from library global data..\r | |
14 | \r | |
15 | @retval SpiInstance Return SPI instance\r | |
16 | **/\r | |
17 | SPI_INSTANCE *\r | |
18 | GetSpiInstance (\r | |
19 | VOID\r | |
e5efcf8b | 20 | )\r |
1d66480a GD |
21 | {\r |
22 | if (mSpiInstance == NULL) {\r | |
e5efcf8b | 23 | mSpiInstance = AllocatePool (sizeof (SPI_INSTANCE));\r |
1d66480a GD |
24 | if (mSpiInstance == NULL) {\r |
25 | return NULL;\r | |
26 | }\r | |
e5efcf8b MK |
27 | \r |
28 | ZeroMem (mSpiInstance, sizeof (SPI_INSTANCE));\r | |
1d66480a GD |
29 | }\r |
30 | \r | |
31 | return mSpiInstance;\r | |
32 | }\r | |
33 | \r | |
1d66480a GD |
34 | /**\r |
35 | Initialize an SPI library.\r | |
36 | \r | |
37 | @retval EFI_SUCCESS The protocol instance was properly initialized\r | |
38 | @retval EFI_NOT_FOUND The expected SPI info could not be found\r | |
39 | **/\r | |
40 | EFI_STATUS\r | |
41 | EFIAPI\r | |
42 | SpiConstructor (\r | |
43 | VOID\r | |
44 | )\r | |
45 | {\r | |
e5efcf8b MK |
46 | UINT32 ScSpiBar0;\r |
47 | UINT8 Comp0Density;\r | |
48 | SPI_INSTANCE *SpiInstance;\r | |
49 | EFI_HOB_GUID_TYPE *GuidHob;\r | |
50 | SPI_FLASH_INFO *SpiFlashInfo;\r | |
1d66480a GD |
51 | \r |
52 | //\r | |
53 | // Find SPI flash hob\r | |
54 | //\r | |
55 | GuidHob = GetFirstGuidHob (&gSpiFlashInfoGuid);\r | |
56 | if (GuidHob == NULL) {\r | |
57 | ASSERT (FALSE);\r | |
58 | return EFI_NOT_FOUND;\r | |
59 | }\r | |
e5efcf8b MK |
60 | \r |
61 | SpiFlashInfo = (SPI_FLASH_INFO *)GET_GUID_HOB_DATA (GuidHob);\r | |
1d66480a GD |
62 | \r |
63 | //\r | |
64 | // Initialize the SPI instance\r | |
65 | //\r | |
66 | SpiInstance = GetSpiInstance ();\r | |
67 | if (SpiInstance == NULL) {\r | |
68 | return EFI_NOT_FOUND;\r | |
69 | }\r | |
e5efcf8b | 70 | \r |
1d66480a GD |
71 | DEBUG ((DEBUG_INFO, "SpiInstance = %08X\n", SpiInstance));\r |
72 | \r | |
e5efcf8b MK |
73 | SpiInstance->Signature = SC_SPI_PRIVATE_DATA_SIGNATURE;\r |
74 | SpiInstance->Handle = NULL;\r | |
1d66480a GD |
75 | \r |
76 | //\r | |
77 | // Check the SPI address\r | |
78 | //\r | |
79 | if ((SpiFlashInfo->SpiAddress.AddressSpaceId != EFI_ACPI_3_0_PCI_CONFIGURATION_SPACE) ||\r | |
80 | (SpiFlashInfo->SpiAddress.RegisterBitWidth != 32) ||\r | |
81 | (SpiFlashInfo->SpiAddress.RegisterBitOffset != 0) ||\r | |
e5efcf8b MK |
82 | (SpiFlashInfo->SpiAddress.AccessSize != EFI_ACPI_3_0_DWORD))\r |
83 | {\r | |
1d66480a GD |
84 | DEBUG ((DEBUG_ERROR, "SPI FLASH HOB is not expected. need check the hob or enhance SPI flash driver.\n"));\r |
85 | }\r | |
e5efcf8b | 86 | \r |
1d66480a GD |
87 | SpiInstance->PchSpiBase = (UINT32)(UINTN)SpiFlashInfo->SpiAddress.Address;\r |
88 | SpiInstance->Flags = SpiFlashInfo->Flags;\r | |
89 | DEBUG ((DEBUG_INFO, "PchSpiBase at 0x%x\n", SpiInstance->PchSpiBase));\r | |
90 | \r | |
91 | ScSpiBar0 = AcquireSpiBar0 (SpiInstance->PchSpiBase);\r | |
92 | DEBUG ((DEBUG_INFO, "ScSpiBar0 at 0x%08X\n", ScSpiBar0));\r | |
93 | \r | |
94 | if (ScSpiBar0 == 0) {\r | |
95 | ASSERT (FALSE);\r | |
96 | }\r | |
97 | \r | |
98 | if ((MmioRead32 (ScSpiBar0 + R_SPI_HSFS) & B_SPI_HSFS_FDV) == 0) {\r | |
99 | DEBUG ((DEBUG_ERROR, "SPI Flash descriptor invalid, cannot use Hardware Sequencing registers!\n"));\r | |
100 | ASSERT (FALSE);\r | |
101 | }\r | |
102 | \r | |
103 | MmioOr32 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);\r | |
104 | SpiInstance->RegionPermission = MmioRead16 (ScSpiBar0 + R_SPI_FRAP);\r | |
105 | SpiInstance->SfdpVscc0Value = MmioRead32 (ScSpiBar0 + R_SPI_LVSCC);\r | |
106 | SpiInstance->SfdpVscc1Value = MmioRead32 (ScSpiBar0 + R_SPI_UVSCC);\r | |
107 | \r | |
108 | //\r | |
109 | // Select to Flash Map 0 Register to get the number of flash Component\r | |
110 | //\r | |
111 | MmioAndThenOr32 (\r | |
112 | ScSpiBar0 + R_SPI_FDOC,\r | |
e5efcf8b MK |
113 | (UINT32)(~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),\r |
114 | (UINT32)(V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP0)\r | |
1d66480a GD |
115 | );\r |
116 | \r | |
117 | //\r | |
118 | // Copy Zero based Number Of Components\r | |
119 | //\r | |
e5efcf8b | 120 | SpiInstance->NumberOfComponents = (UINT8)((MmioRead16 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FDBAR_NC) >> N_SPI_FDBAR_NC);\r |
1d66480a GD |
121 | \r |
122 | MmioAndThenOr32 (\r | |
123 | ScSpiBar0 + R_SPI_FDOC,\r | |
e5efcf8b MK |
124 | (UINT32)(~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),\r |
125 | (UINT32)(V_SPI_FDOC_FDSS_COMP | R_SPI_FCBA_FLCOMP)\r | |
1d66480a GD |
126 | );\r |
127 | \r | |
128 | //\r | |
129 | // Copy Component 0 Density\r | |
130 | //\r | |
e5efcf8b MK |
131 | Comp0Density = (UINT8)MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FLCOMP_COMP1_MASK;\r |
132 | SpiInstance->Component1StartAddr = (UINT32)(SIZE_512KB << Comp0Density);\r | |
1d66480a GD |
133 | \r |
134 | //\r | |
135 | // Select FLASH_MAP1 to get Flash SC Strap Base Address\r | |
136 | //\r | |
137 | MmioAndThenOr32 (\r | |
138 | (ScSpiBar0 + R_SPI_FDOC),\r | |
e5efcf8b MK |
139 | (UINT32)(~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),\r |
140 | (UINT32)(V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP1)\r | |
1d66480a GD |
141 | );\r |
142 | \r | |
143 | SpiInstance->StrapBaseAddress = MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FDBAR_FPSBA;\r | |
144 | \r | |
145 | //\r | |
146 | // Align FPSBA with address bits for the SC Strap portion of flash descriptor\r | |
147 | //\r | |
148 | SpiInstance->StrapBaseAddress &= B_SPI_FDBAR_FPSBA;\r | |
149 | \r | |
150 | return EFI_SUCCESS;\r | |
151 | }\r | |
152 | \r | |
1d66480a GD |
153 | /**\r |
154 | Read data from the flash part.\r | |
155 | \r | |
156 | @param[in] FlashRegionType The Flash Region type for flash cycle which is listed in the Descriptor.\r | |
157 | @param[in] Address The Flash Linear Address must fall within a region for which BIOS has access permissions.\r | |
158 | @param[in] ByteCount Number of bytes in the data portion of the SPI cycle.\r | |
159 | @param[out] Buffer The Pointer to caller-allocated buffer containing the data received.\r | |
160 | It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.\r | |
161 | \r | |
162 | @retval EFI_SUCCESS Command succeed.\r | |
163 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
164 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
165 | **/\r | |
166 | EFI_STATUS\r | |
167 | EFIAPI\r | |
168 | SpiFlashRead (\r | |
169 | IN FLASH_REGION_TYPE FlashRegionType,\r | |
170 | IN UINT32 Address,\r | |
171 | IN UINT32 ByteCount,\r | |
172 | OUT UINT8 *Buffer\r | |
173 | )\r | |
174 | {\r | |
e5efcf8b | 175 | EFI_STATUS Status;\r |
1d66480a GD |
176 | \r |
177 | Status = SendSpiCmd (FlashRegionType, FlashCycleRead, Address, ByteCount, Buffer);\r | |
178 | return Status;\r | |
179 | }\r | |
180 | \r | |
181 | /**\r | |
182 | Write data to the flash part.\r | |
183 | \r | |
184 | @param[in] FlashRegionType The Flash Region type for flash cycle which is listed in the Descriptor.\r | |
185 | @param[in] Address The Flash Linear Address must fall within a region for which BIOS has access permissions.\r | |
186 | @param[in] ByteCount Number of bytes in the data portion of the SPI cycle.\r | |
187 | @param[in] Buffer Pointer to caller-allocated buffer containing the data sent during the SPI cycle.\r | |
188 | \r | |
189 | @retval EFI_SUCCESS Command succeed.\r | |
190 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
191 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
192 | **/\r | |
193 | EFI_STATUS\r | |
194 | EFIAPI\r | |
195 | SpiFlashWrite (\r | |
196 | IN FLASH_REGION_TYPE FlashRegionType,\r | |
197 | IN UINT32 Address,\r | |
198 | IN UINT32 ByteCount,\r | |
199 | IN UINT8 *Buffer\r | |
200 | )\r | |
201 | {\r | |
e5efcf8b | 202 | EFI_STATUS Status;\r |
1d66480a GD |
203 | \r |
204 | Status = SendSpiCmd (FlashRegionType, FlashCycleWrite, Address, ByteCount, Buffer);\r | |
205 | return Status;\r | |
206 | }\r | |
207 | \r | |
208 | /**\r | |
209 | Erase some area on the flash part.\r | |
210 | \r | |
211 | @param[in] FlashRegionType The Flash Region type for flash cycle which is listed in the Descriptor.\r | |
212 | @param[in] Address The Flash Linear Address must fall within a region for which BIOS has access permissions.\r | |
213 | @param[in] ByteCount Number of bytes in the data portion of the SPI cycle.\r | |
214 | \r | |
215 | @retval EFI_SUCCESS Command succeed.\r | |
216 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
217 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
218 | **/\r | |
219 | EFI_STATUS\r | |
220 | EFIAPI\r | |
221 | SpiFlashErase (\r | |
222 | IN FLASH_REGION_TYPE FlashRegionType,\r | |
223 | IN UINT32 Address,\r | |
224 | IN UINT32 ByteCount\r | |
225 | )\r | |
226 | {\r | |
e5efcf8b | 227 | EFI_STATUS Status;\r |
1d66480a GD |
228 | \r |
229 | Status = SendSpiCmd (FlashRegionType, FlashCycleErase, Address, ByteCount, NULL);\r | |
230 | return Status;\r | |
231 | }\r | |
232 | \r | |
233 | /**\r | |
234 | Read SFDP data from the flash part.\r | |
235 | \r | |
236 | @param[in] ComponentNumber The Component Number for chip select\r | |
237 | @param[in] ByteCount Number of bytes in SFDP data portion of the SPI cycle, the max number is 64\r | |
238 | @param[out] SfdpData The Pointer to caller-allocated buffer containing the SFDP data received\r | |
239 | It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.\r | |
240 | \r | |
241 | @retval EFI_SUCCESS Command succeed.\r | |
242 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
243 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
244 | **/\r | |
245 | EFI_STATUS\r | |
246 | EFIAPI\r | |
247 | SpiFlashReadSfdp (\r | |
e5efcf8b MK |
248 | IN UINT8 ComponentNumber,\r |
249 | IN UINT32 ByteCount,\r | |
250 | OUT UINT8 *SfdpData\r | |
1d66480a GD |
251 | )\r |
252 | {\r | |
e5efcf8b MK |
253 | EFI_STATUS Status;\r |
254 | UINT32 Address;\r | |
255 | SPI_INSTANCE *SpiInstance;\r | |
1d66480a GD |
256 | \r |
257 | SpiInstance = GetSpiInstance ();\r | |
258 | if (SpiInstance == NULL) {\r | |
259 | return EFI_DEVICE_ERROR;\r | |
260 | }\r | |
261 | \r | |
262 | if ((ByteCount > 64) || (ComponentNumber > SpiInstance->NumberOfComponents)) {\r | |
263 | ASSERT (FALSE);\r | |
264 | return EFI_INVALID_PARAMETER;\r | |
265 | }\r | |
266 | \r | |
267 | Address = 0;\r | |
268 | if (ComponentNumber == FlashComponent1) {\r | |
269 | Address = SpiInstance->Component1StartAddr;\r | |
270 | }\r | |
271 | \r | |
272 | Status = SendSpiCmd (0, FlashCycleReadSfdp, Address, ByteCount, SfdpData);\r | |
273 | return Status;\r | |
274 | }\r | |
275 | \r | |
276 | /**\r | |
277 | Read Jedec Id from the flash part.\r | |
278 | \r | |
279 | @param[in] ComponentNumber The Component Number for chip select\r | |
280 | @param[in] ByteCount Number of bytes in JedecId data portion of the SPI cycle, the data size is 3 typically\r | |
281 | @param[out] JedecId The Pointer to caller-allocated buffer containing JEDEC ID received\r | |
282 | It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.\r | |
283 | \r | |
284 | @retval EFI_SUCCESS Command succeed.\r | |
285 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
286 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
287 | **/\r | |
288 | EFI_STATUS\r | |
289 | EFIAPI\r | |
290 | SpiFlashReadJedecId (\r | |
e5efcf8b MK |
291 | IN UINT8 ComponentNumber,\r |
292 | IN UINT32 ByteCount,\r | |
293 | OUT UINT8 *JedecId\r | |
1d66480a GD |
294 | )\r |
295 | {\r | |
e5efcf8b MK |
296 | EFI_STATUS Status;\r |
297 | UINT32 Address;\r | |
298 | SPI_INSTANCE *SpiInstance;\r | |
1d66480a GD |
299 | \r |
300 | SpiInstance = GetSpiInstance ();\r | |
301 | if (SpiInstance == NULL) {\r | |
302 | return EFI_DEVICE_ERROR;\r | |
303 | }\r | |
304 | \r | |
305 | if (ComponentNumber > SpiInstance->NumberOfComponents) {\r | |
306 | ASSERT (FALSE);\r | |
307 | return EFI_INVALID_PARAMETER;\r | |
308 | }\r | |
309 | \r | |
310 | Address = 0;\r | |
311 | if (ComponentNumber == FlashComponent1) {\r | |
312 | Address = SpiInstance->Component1StartAddr;\r | |
313 | }\r | |
314 | \r | |
315 | Status = SendSpiCmd (0, FlashCycleReadJedecId, Address, ByteCount, JedecId);\r | |
316 | return Status;\r | |
317 | }\r | |
318 | \r | |
319 | /**\r | |
320 | Write the status register in the flash part.\r | |
321 | \r | |
322 | @param[in] ByteCount Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically\r | |
323 | @param[in] StatusValue The Pointer to caller-allocated buffer containing the value of Status register writing\r | |
324 | \r | |
325 | @retval EFI_SUCCESS Command succeed.\r | |
326 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
327 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
328 | **/\r | |
329 | EFI_STATUS\r | |
330 | EFIAPI\r | |
331 | SpiFlashWriteStatus (\r | |
e5efcf8b MK |
332 | IN UINT32 ByteCount,\r |
333 | IN UINT8 *StatusValue\r | |
1d66480a GD |
334 | )\r |
335 | {\r | |
e5efcf8b | 336 | EFI_STATUS Status;\r |
1d66480a GD |
337 | \r |
338 | Status = SendSpiCmd (0, FlashCycleWriteStatus, 0, ByteCount, StatusValue);\r | |
339 | return Status;\r | |
340 | }\r | |
341 | \r | |
342 | /**\r | |
343 | Read status register in the flash part.\r | |
344 | \r | |
345 | @param[in] ByteCount Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically\r | |
346 | @param[out] StatusValue The Pointer to caller-allocated buffer containing the value of Status register received.\r | |
347 | \r | |
348 | @retval EFI_SUCCESS Command succeed.\r | |
349 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
350 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
351 | **/\r | |
352 | EFI_STATUS\r | |
353 | EFIAPI\r | |
354 | SpiFlashReadStatus (\r | |
e5efcf8b MK |
355 | IN UINT32 ByteCount,\r |
356 | OUT UINT8 *StatusValue\r | |
1d66480a GD |
357 | )\r |
358 | {\r | |
e5efcf8b | 359 | EFI_STATUS Status;\r |
1d66480a GD |
360 | \r |
361 | Status = SendSpiCmd (0, FlashCycleReadStatus, 0, ByteCount, StatusValue);\r | |
362 | return Status;\r | |
363 | }\r | |
364 | \r | |
365 | /**\r | |
366 | Read SC Soft Strap Values\r | |
367 | \r | |
368 | @param[in] SoftStrapAddr SC Soft Strap address offset from FPSBA.\r | |
369 | @param[in] ByteCount Number of bytes in SoftStrap data portion of the SPI cycle\r | |
370 | @param[out] SoftStrapValue The Pointer to caller-allocated buffer containing SC Soft Strap Value.\r | |
371 | It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.\r | |
372 | \r | |
373 | @retval EFI_SUCCESS Command succeed.\r | |
374 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
375 | @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.\r | |
376 | **/\r | |
377 | EFI_STATUS\r | |
378 | EFIAPI\r | |
379 | SpiReadPchSoftStrap (\r | |
e5efcf8b MK |
380 | IN UINT32 SoftStrapAddr,\r |
381 | IN UINT32 ByteCount,\r | |
382 | OUT UINT8 *SoftStrapValue\r | |
1d66480a GD |
383 | )\r |
384 | {\r | |
e5efcf8b MK |
385 | UINT32 StrapFlashAddr;\r |
386 | EFI_STATUS Status;\r | |
387 | SPI_INSTANCE *SpiInstance;\r | |
1d66480a GD |
388 | \r |
389 | SpiInstance = GetSpiInstance ();\r | |
390 | if (SpiInstance == NULL) {\r | |
391 | return EFI_DEVICE_ERROR;\r | |
392 | }\r | |
393 | \r | |
394 | ASSERT (SpiInstance->StrapBaseAddress != 0);\r | |
395 | //\r | |
396 | // SC Strap Flash Address = FPSBA + RamAddr\r | |
397 | //\r | |
398 | StrapFlashAddr = SpiInstance->StrapBaseAddress + SoftStrapAddr;\r | |
399 | \r | |
400 | Status = SendSpiCmd (FlashRegionDescriptor, FlashCycleRead, StrapFlashAddr, ByteCount, SoftStrapValue);\r | |
401 | return Status;\r | |
402 | }\r | |
403 | \r | |
404 | /**\r | |
405 | This function sends the programmed SPI command to the slave device.\r | |
406 | \r | |
407 | @param[in] FlashRegionType The SPI Region type for flash cycle which is listed in the Descriptor\r | |
408 | @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (Hardware Sequencing Flash Control Register) register\r | |
409 | @param[in] Address The Flash Linear Address must fall within a region for which BIOS has access permissions.\r | |
410 | @param[in] ByteCount Number of bytes in the data portion of the SPI cycle.\r | |
411 | @param[in,out] Buffer Pointer to caller-allocated buffer containing the data received or sent during the SPI cycle.\r | |
412 | \r | |
413 | @retval EFI_SUCCESS SPI command completes successfully.\r | |
414 | @retval EFI_DEVICE_ERROR Device error, the command aborts abnormally.\r | |
415 | @retval EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode\r | |
416 | @retval EFI_INVALID_PARAMETER The parameters specified are not valid.\r | |
417 | **/\r | |
418 | EFI_STATUS\r | |
419 | SendSpiCmd (\r | |
420 | IN FLASH_REGION_TYPE FlashRegionType,\r | |
421 | IN FLASH_CYCLE_TYPE FlashCycleType,\r | |
422 | IN UINT32 Address,\r | |
423 | IN UINT32 ByteCount,\r | |
424 | IN OUT UINT8 *Buffer\r | |
425 | )\r | |
426 | {\r | |
e5efcf8b MK |
427 | EFI_STATUS Status;\r |
428 | UINT32 Index;\r | |
429 | UINTN SpiBaseAddress;\r | |
430 | UINT32 ScSpiBar0;\r | |
431 | UINT32 LimitAddress;\r | |
432 | UINT32 HardwareSpiAddr;\r | |
433 | UINT16 PermissionBit;\r | |
434 | UINT32 SpiDataCount;\r | |
435 | UINT32 FlashCycle;\r | |
436 | UINT8 BiosCtlSave;\r | |
437 | SPI_INSTANCE *SpiInstance;\r | |
438 | UINT32 Data32;\r | |
1d66480a GD |
439 | \r |
440 | SpiInstance = GetSpiInstance ();\r | |
441 | if (SpiInstance == NULL) {\r | |
442 | return EFI_DEVICE_ERROR;\r | |
443 | }\r | |
444 | \r | |
e5efcf8b MK |
445 | Status = EFI_SUCCESS;\r |
446 | SpiBaseAddress = SpiInstance->PchSpiBase;\r | |
447 | ScSpiBar0 = AcquireSpiBar0 (SpiBaseAddress);\r | |
448 | BiosCtlSave = 0;\r | |
1d66480a GD |
449 | SpiInstance->RegionPermission = MmioRead16 (ScSpiBar0 + R_SPI_FRAP);\r |
450 | \r | |
451 | //\r | |
452 | // If it's write cycle, disable Prefetching, Caching and disable BIOS Write Protect\r | |
453 | //\r | |
454 | if ((FlashCycleType == FlashCycleWrite) || (FlashCycleType == FlashCycleErase)) {\r | |
455 | Status = DisableBiosWriteProtect (SpiBaseAddress, mSpiInstance->Flags & FLAGS_SPI_DISABLE_SMM_WRITE_PROTECT);\r | |
456 | if (EFI_ERROR (Status)) {\r | |
457 | goto SendSpiCmdEnd;\r | |
458 | }\r | |
e5efcf8b | 459 | \r |
1d66480a GD |
460 | BiosCtlSave = SaveAndDisableSpiPrefetchCache (SpiBaseAddress);\r |
461 | }\r | |
462 | \r | |
463 | //\r | |
464 | // Make sure it's safe to program the command.\r | |
465 | //\r | |
466 | if (!WaitForSpiCycleComplete (ScSpiBar0, FALSE)) {\r | |
467 | Status = EFI_DEVICE_ERROR;\r | |
468 | goto SendSpiCmdEnd;\r | |
469 | }\r | |
470 | \r | |
471 | HardwareSpiAddr = Address;\r | |
472 | if ((FlashCycleType == FlashCycleRead) ||\r | |
473 | (FlashCycleType == FlashCycleWrite) ||\r | |
e5efcf8b MK |
474 | (FlashCycleType == FlashCycleErase))\r |
475 | {\r | |
1d66480a | 476 | switch (FlashRegionType) {\r |
e5efcf8b MK |
477 | case FlashRegionDescriptor:\r |
478 | if (FlashCycleType == FlashCycleRead) {\r | |
479 | PermissionBit = B_SPI_FRAP_BRRA_FLASHD;\r | |
480 | } else {\r | |
481 | PermissionBit = B_SPI_FRAP_BRWA_FLASHD;\r | |
482 | }\r | |
1d66480a | 483 | \r |
e5efcf8b MK |
484 | Data32 = MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD);\r |
485 | HardwareSpiAddr += (Data32 & B_SPI_FREG0_BASE_MASK) << N_SPI_FREG0_BASE;\r | |
486 | LimitAddress = (Data32 & B_SPI_FREG0_LIMIT_MASK) >> N_SPI_FREG0_LIMIT;\r | |
487 | break;\r | |
1d66480a | 488 | \r |
e5efcf8b MK |
489 | case FlashRegionBios:\r |
490 | if (FlashCycleType == FlashCycleRead) {\r | |
491 | PermissionBit = B_SPI_FRAP_BRRA_BIOS;\r | |
492 | } else {\r | |
493 | PermissionBit = B_SPI_FRAP_BRWA_BIOS;\r | |
494 | }\r | |
1d66480a | 495 | \r |
e5efcf8b MK |
496 | Data32 = MmioRead32 (ScSpiBar0 + R_SPI_FREG1_BIOS);\r |
497 | HardwareSpiAddr += (Data32 & B_SPI_FREG1_BASE_MASK) << N_SPI_FREG1_BASE;\r | |
498 | LimitAddress = (Data32 & B_SPI_FREG1_LIMIT_MASK) >> N_SPI_FREG1_LIMIT;\r | |
499 | break;\r | |
1d66480a | 500 | \r |
e5efcf8b MK |
501 | case FlashRegionMe:\r |
502 | if (FlashCycleType == FlashCycleRead) {\r | |
503 | PermissionBit = B_SPI_FRAP_BRRA_SEC;\r | |
504 | } else {\r | |
505 | PermissionBit = B_SPI_FRAP_BRWA_SEC;\r | |
506 | }\r | |
1d66480a | 507 | \r |
e5efcf8b MK |
508 | Data32 = MmioRead32 (ScSpiBar0 + R_SPI_FREG2_SEC);\r |
509 | HardwareSpiAddr += (Data32 & B_SPI_FREG2_BASE_MASK) << N_SPI_FREG2_BASE;\r | |
510 | LimitAddress = (Data32 & B_SPI_FREG2_LIMIT_MASK) >> N_SPI_FREG2_LIMIT;\r | |
511 | break;\r | |
1d66480a | 512 | \r |
e5efcf8b MK |
513 | case FlashRegionGbE:\r |
514 | if (FlashCycleType == FlashCycleRead) {\r | |
515 | PermissionBit = B_SPI_FRAP_BRRA_GBE;\r | |
516 | } else {\r | |
517 | PermissionBit = B_SPI_FRAP_BRWA_GBE;\r | |
518 | }\r | |
519 | \r | |
520 | Data32 = MmioRead32 (ScSpiBar0 + R_SPI_FREG3_GBE);\r | |
521 | HardwareSpiAddr += (Data32 & B_SPI_FREG3_BASE_MASK) << N_SPI_FREG3_BASE;\r | |
522 | LimitAddress = (Data32 & B_SPI_FREG3_LIMIT_MASK) >> N_SPI_FREG3_LIMIT;\r | |
523 | break;\r | |
524 | \r | |
525 | case FlashRegionPlatformData:\r | |
526 | if (FlashCycleType == FlashCycleRead) {\r | |
527 | PermissionBit = B_SPI_FRAP_BRRA_PLATFORM;\r | |
528 | } else {\r | |
529 | PermissionBit = B_SPI_FRAP_BRWA_PLATFORM;\r | |
530 | }\r | |
531 | \r | |
532 | Data32 = MmioRead32 (ScSpiBar0 + R_SPI_FREG4_PLATFORM_DATA);\r | |
533 | HardwareSpiAddr += (Data32 & B_SPI_FREG4_BASE_MASK) << N_SPI_FREG4_BASE;\r | |
534 | LimitAddress = (Data32 & B_SPI_FREG4_LIMIT_MASK) >> N_SPI_FREG4_LIMIT;\r | |
535 | break;\r | |
536 | \r | |
537 | case FlashRegionAll:\r | |
538 | //\r | |
539 | // FlashRegionAll indicates address is relative to flash device\r | |
540 | // No error checking for this case\r | |
541 | //\r | |
542 | LimitAddress = 0;\r | |
543 | PermissionBit = 0;\r | |
544 | break;\r | |
545 | \r | |
546 | default:\r | |
547 | Status = EFI_UNSUPPORTED;\r | |
548 | goto SendSpiCmdEnd;\r | |
1d66480a GD |
549 | }\r |
550 | \r | |
551 | if ((LimitAddress != 0) && (Address > LimitAddress)) {\r | |
552 | Status = EFI_INVALID_PARAMETER;\r | |
553 | goto SendSpiCmdEnd;\r | |
554 | }\r | |
555 | \r | |
556 | //\r | |
557 | // If the operation is read, but the region attribute is not read allowed, return error.\r | |
558 | // If the operation is write, but the region attribute is not write allowed, return error.\r | |
559 | //\r | |
560 | if ((PermissionBit != 0) && ((SpiInstance->RegionPermission & PermissionBit) == 0)) {\r | |
561 | Status = EFI_ACCESS_DENIED;\r | |
562 | goto SendSpiCmdEnd;\r | |
563 | }\r | |
564 | }\r | |
565 | \r | |
566 | //\r | |
567 | // Check for SC SPI hardware sequencing required commands\r | |
568 | //\r | |
569 | FlashCycle = 0;\r | |
570 | switch (FlashCycleType) {\r | |
e5efcf8b MK |
571 | case FlashCycleRead:\r |
572 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_READ << N_SPI_HSFS_CYCLE);\r | |
573 | break;\r | |
1d66480a | 574 | \r |
e5efcf8b MK |
575 | case FlashCycleWrite:\r |
576 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_WRITE << N_SPI_HSFS_CYCLE);\r | |
577 | break;\r | |
1d66480a | 578 | \r |
e5efcf8b MK |
579 | case FlashCycleErase:\r |
580 | if (((ByteCount % SIZE_4KB) != 0) || ((HardwareSpiAddr % SIZE_4KB) != 0)) {\r | |
581 | DEBUG ((DEBUG_ERROR, "Erase and erase size must be 4KB aligned. \n"));\r | |
582 | ASSERT (FALSE);\r | |
583 | Status = EFI_INVALID_PARAMETER;\r | |
584 | goto SendSpiCmdEnd;\r | |
585 | }\r | |
1d66480a | 586 | \r |
e5efcf8b | 587 | break;\r |
1d66480a | 588 | \r |
e5efcf8b MK |
589 | case FlashCycleReadSfdp:\r |
590 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_READ_SFDP << N_SPI_HSFS_CYCLE);\r | |
591 | break;\r | |
1d66480a | 592 | \r |
e5efcf8b MK |
593 | case FlashCycleReadJedecId:\r |
594 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_READ_JEDEC_ID << N_SPI_HSFS_CYCLE);\r | |
595 | break;\r | |
1d66480a | 596 | \r |
e5efcf8b MK |
597 | case FlashCycleWriteStatus:\r |
598 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_WRITE_STATUS << N_SPI_HSFS_CYCLE);\r | |
599 | break;\r | |
1d66480a | 600 | \r |
e5efcf8b MK |
601 | case FlashCycleReadStatus:\r |
602 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_READ_STATUS << N_SPI_HSFS_CYCLE);\r | |
603 | break;\r | |
604 | \r | |
605 | default:\r | |
606 | //\r | |
607 | // Unrecognized Operation\r | |
608 | //\r | |
609 | ASSERT (FALSE);\r | |
610 | Status = EFI_INVALID_PARAMETER;\r | |
611 | goto SendSpiCmdEnd;\r | |
612 | break;\r | |
1d66480a GD |
613 | }\r |
614 | \r | |
615 | do {\r | |
616 | SpiDataCount = ByteCount;\r | |
617 | if ((FlashCycleType == FlashCycleRead) || (FlashCycleType == FlashCycleWrite)) {\r | |
618 | //\r | |
619 | // Trim at 256 byte boundary per operation,\r | |
620 | // - SC SPI controller requires trimming at 4KB boundary\r | |
621 | // - Some SPI chips require trimming at 256 byte boundary for write operation\r | |
622 | // - Trimming has limited performance impact as we can read / write at most 64 byte\r | |
623 | // per operation\r | |
624 | //\r | |
625 | if (HardwareSpiAddr + ByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) {\r | |
e5efcf8b | 626 | SpiDataCount = (((UINT32)(HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32)(HardwareSpiAddr);\r |
1d66480a | 627 | }\r |
e5efcf8b | 628 | \r |
1d66480a GD |
629 | //\r |
630 | // Calculate the number of bytes to shift in/out during the SPI data cycle.\r | |
631 | // Valid settings for the number of bytes during each data portion of the\r | |
632 | // SC SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64\r | |
633 | //\r | |
634 | if (SpiDataCount >= 64) {\r | |
635 | SpiDataCount = 64;\r | |
636 | } else if ((SpiDataCount &~0x07) != 0) {\r | |
637 | SpiDataCount = SpiDataCount &~0x07;\r | |
638 | }\r | |
639 | }\r | |
640 | \r | |
641 | if (FlashCycleType == FlashCycleErase) {\r | |
642 | if (((ByteCount / SIZE_64KB) != 0) &&\r | |
643 | ((ByteCount % SIZE_64KB) == 0) &&\r | |
e5efcf8b MK |
644 | ((HardwareSpiAddr % SIZE_64KB) == 0))\r |
645 | {\r | |
1d66480a GD |
646 | if (HardwareSpiAddr < SpiInstance->Component1StartAddr) {\r |
647 | //\r | |
648 | // Check whether Component0 support 64k Erase\r | |
649 | //\r | |
650 | if ((SpiInstance->SfdpVscc0Value & B_SPI_LVSCC_EO_64K) != 0) {\r | |
651 | SpiDataCount = SIZE_64KB;\r | |
652 | } else {\r | |
653 | SpiDataCount = SIZE_4KB;\r | |
654 | }\r | |
655 | } else {\r | |
656 | //\r | |
657 | // Check whether Component1 support 64k Erase\r | |
658 | //\r | |
659 | if ((SpiInstance->SfdpVscc1Value & B_SPI_LVSCC_EO_64K) != 0) {\r | |
660 | SpiDataCount = SIZE_64KB;\r | |
661 | } else {\r | |
662 | SpiDataCount = SIZE_4KB;\r | |
663 | }\r | |
664 | }\r | |
665 | } else {\r | |
666 | SpiDataCount = SIZE_4KB;\r | |
667 | }\r | |
e5efcf8b | 668 | \r |
1d66480a | 669 | if (SpiDataCount == SIZE_4KB) {\r |
e5efcf8b | 670 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_4K_ERASE << N_SPI_HSFS_CYCLE);\r |
1d66480a | 671 | } else {\r |
e5efcf8b | 672 | FlashCycle = (UINT32)(V_SPI_HSFS_CYCLE_64K_ERASE << N_SPI_HSFS_CYCLE);\r |
1d66480a GD |
673 | }\r |
674 | }\r | |
675 | \r | |
676 | //\r | |
677 | // If it's write cycle, load data into the SPI data buffer.\r | |
678 | //\r | |
679 | if ((FlashCycleType == FlashCycleWrite) || (FlashCycleType == FlashCycleWriteStatus)) {\r | |
680 | if ((SpiDataCount & 0x07) != 0) {\r | |
681 | //\r | |
682 | // Use Byte write if Data Count is 0, 1, 2, 3, 4, 5, 6, 7\r | |
683 | //\r | |
684 | for (Index = 0; Index < SpiDataCount; Index++) {\r | |
685 | MmioWrite8 (ScSpiBar0 + R_SPI_FDATA00 + Index, Buffer[Index]);\r | |
686 | }\r | |
687 | } else {\r | |
688 | //\r | |
689 | // Use Dword write if Data Count is 8, 16, 24, 32, 40, 48, 56, 64\r | |
690 | //\r | |
691 | for (Index = 0; Index < SpiDataCount; Index += sizeof (UINT32)) {\r | |
e5efcf8b | 692 | MmioWrite32 (ScSpiBar0 + R_SPI_FDATA00 + Index, *(UINT32 *)(Buffer + Index));\r |
1d66480a GD |
693 | }\r |
694 | }\r | |
695 | }\r | |
696 | \r | |
697 | //\r | |
698 | // Set the Flash Address\r | |
699 | //\r | |
e5efcf8b | 700 | MmioWrite32 (ScSpiBar0 + R_SPI_FADDR, (UINT32)(HardwareSpiAddr & B_SPI_FADDR_MASK));\r |
1d66480a GD |
701 | \r |
702 | //\r | |
703 | // Set Data count, Flash cycle, and Set Go bit to start a cycle\r | |
704 | //\r | |
705 | MmioAndThenOr32 (\r | |
706 | ScSpiBar0 + R_SPI_HSFS,\r | |
e5efcf8b MK |
707 | (UINT32)(~(B_SPI_HSFS_FDBC_MASK | B_SPI_HSFS_CYCLE_MASK)),\r |
708 | (UINT32)(((SpiDataCount - 1) << N_SPI_HSFS_FDBC) | FlashCycle | B_SPI_HSFS_CYCLE_FGO)\r | |
1d66480a GD |
709 | );\r |
710 | \r | |
711 | //\r | |
712 | // Wait for command execution complete.\r | |
713 | //\r | |
714 | if (!WaitForSpiCycleComplete (ScSpiBar0, TRUE)) {\r | |
715 | Status = EFI_DEVICE_ERROR;\r | |
716 | goto SendSpiCmdEnd;\r | |
717 | }\r | |
718 | \r | |
719 | //\r | |
720 | // If it's read cycle, load data into the caller's buffer.\r | |
721 | //\r | |
722 | if ((FlashCycleType == FlashCycleRead) ||\r | |
723 | (FlashCycleType == FlashCycleReadSfdp) ||\r | |
724 | (FlashCycleType == FlashCycleReadJedecId) ||\r | |
e5efcf8b MK |
725 | (FlashCycleType == FlashCycleReadStatus))\r |
726 | {\r | |
1d66480a GD |
727 | if ((SpiDataCount & 0x07) != 0) {\r |
728 | //\r | |
729 | // Use Byte read if Data Count is 0, 1, 2, 3, 4, 5, 6, 7\r | |
730 | //\r | |
731 | for (Index = 0; Index < SpiDataCount; Index++) {\r | |
732 | Buffer[Index] = MmioRead8 (ScSpiBar0 + R_SPI_FDATA00 + Index);\r | |
733 | }\r | |
734 | } else {\r | |
735 | //\r | |
736 | // Use Dword read if Data Count is 8, 16, 24, 32, 40, 48, 56, 64\r | |
737 | //\r | |
738 | for (Index = 0; Index < SpiDataCount; Index += sizeof (UINT32)) {\r | |
e5efcf8b | 739 | *(UINT32 *)(Buffer + Index) = MmioRead32 (ScSpiBar0 + R_SPI_FDATA00 + Index);\r |
1d66480a GD |
740 | }\r |
741 | }\r | |
742 | }\r | |
743 | \r | |
744 | HardwareSpiAddr += SpiDataCount;\r | |
745 | Buffer += SpiDataCount;\r | |
746 | ByteCount -= SpiDataCount;\r | |
747 | } while (ByteCount > 0);\r | |
748 | \r | |
749 | SendSpiCmdEnd:\r | |
750 | ///\r | |
751 | /// Restore the settings for SPI Prefetching and Caching and enable BIOS Write Protect\r | |
752 | ///\r | |
753 | if ((FlashCycleType == FlashCycleWrite) || (FlashCycleType == FlashCycleErase)) {\r | |
e5efcf8b | 754 | EnableBiosWriteProtect (SpiBaseAddress, mSpiInstance->Flags & FLAGS_SPI_DISABLE_SMM_WRITE_PROTECT);\r |
1d66480a GD |
755 | SetSpiBiosControlRegister (SpiBaseAddress, BiosCtlSave);\r |
756 | }\r | |
757 | \r | |
758 | ReleaseSpiBar0 (SpiBaseAddress);\r | |
759 | \r | |
760 | return Status;\r | |
761 | }\r | |
762 | \r | |
763 | /**\r | |
764 | Wait execution cycle to complete on the SPI interface.\r | |
765 | \r | |
766 | @param[in] ScSpiBar0 Spi MMIO base address\r | |
767 | @param[in] ErrorCheck TRUE if the SpiCycle needs to do the error check\r | |
768 | \r | |
769 | @retval TRUE SPI cycle completed on the interface.\r | |
770 | @retval FALSE Time out while waiting the SPI cycle to complete.\r | |
771 | It's not safe to program the next command on the SPI interface.\r | |
772 | **/\r | |
773 | BOOLEAN\r | |
774 | WaitForSpiCycleComplete (\r | |
e5efcf8b MK |
775 | IN UINT32 ScSpiBar0,\r |
776 | IN BOOLEAN ErrorCheck\r | |
1d66480a GD |
777 | )\r |
778 | {\r | |
e5efcf8b MK |
779 | UINT64 WaitTicks;\r |
780 | UINT64 WaitCount;\r | |
781 | UINT32 Data32;\r | |
1d66480a GD |
782 | \r |
783 | //\r | |
784 | // Convert the wait period allowed into to tick count\r | |
785 | //\r | |
786 | WaitCount = WAIT_TIME / WAIT_PERIOD;\r | |
787 | //\r | |
788 | // Wait for the SPI cycle to complete.\r | |
789 | //\r | |
790 | for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {\r | |
791 | Data32 = MmioRead32 (ScSpiBar0 + R_SPI_HSFS);\r | |
792 | if ((Data32 & B_SPI_HSFS_SCIP) == 0) {\r | |
793 | MmioWrite32 (ScSpiBar0 + R_SPI_HSFS, B_SPI_HSFS_FCERR | B_SPI_HSFS_FDONE);\r | |
794 | if (((Data32 & B_SPI_HSFS_FCERR) != 0) && ErrorCheck) {\r | |
795 | return FALSE;\r | |
796 | } else {\r | |
797 | return TRUE;\r | |
798 | }\r | |
799 | }\r | |
e5efcf8b MK |
800 | \r |
801 | MicroSecondDelay (WAIT_PERIOD);\r | |
1d66480a | 802 | }\r |
e5efcf8b | 803 | \r |
1d66480a GD |
804 | return FALSE;\r |
805 | }\r | |
806 | \r | |
807 | /**\r | |
808 | Get the SPI region base and size, based on the enum type\r | |
809 | \r | |
810 | @param[in] FlashRegionType The Flash Region type for for the base address which is listed in the Descriptor.\r | |
811 | @param[out] BaseAddress The Flash Linear Address for the Region 'n' Base\r | |
812 | @param[out] RegionSize The size for the Region 'n'\r | |
813 | \r | |
814 | @retval EFI_SUCCESS Read success\r | |
815 | @retval EFI_INVALID_PARAMETER Invalid region type given\r | |
816 | @retval EFI_DEVICE_ERROR The region is not used\r | |
817 | **/\r | |
818 | EFI_STATUS\r | |
819 | EFIAPI\r | |
820 | SpiGetRegionAddress (\r | |
821 | IN FLASH_REGION_TYPE FlashRegionType,\r | |
e35dd328 | 822 | OUT UINT32 *BaseAddress OPTIONAL,\r |
1d66480a GD |
823 | OUT UINT32 *RegionSize OPTIONAL\r |
824 | )\r | |
825 | {\r | |
e5efcf8b MK |
826 | UINT32 ScSpiBar0;\r |
827 | UINT32 ReadValue;\r | |
828 | UINT32 Base;\r | |
829 | SPI_INSTANCE *SpiInstance;\r | |
1d66480a GD |
830 | \r |
831 | if (FlashRegionType >= FlashRegionMax) {\r | |
832 | return EFI_INVALID_PARAMETER;\r | |
833 | }\r | |
834 | \r | |
e5efcf8b | 835 | SpiInstance = GetSpiInstance ();\r |
1d66480a GD |
836 | if (SpiInstance == NULL) {\r |
837 | return EFI_DEVICE_ERROR;\r | |
838 | }\r | |
839 | \r | |
840 | if (FlashRegionType == FlashRegionAll) {\r | |
841 | if (BaseAddress != NULL) {\r | |
e5efcf8b | 842 | *BaseAddress = 0;\r |
1d66480a | 843 | }\r |
e5efcf8b | 844 | \r |
1d66480a | 845 | if (RegionSize != NULL) {\r |
e5efcf8b | 846 | *RegionSize = SpiInstance->Component1StartAddr;\r |
1d66480a | 847 | }\r |
e5efcf8b | 848 | \r |
1d66480a GD |
849 | return EFI_SUCCESS;\r |
850 | }\r | |
851 | \r | |
852 | ScSpiBar0 = AcquireSpiBar0 (SpiInstance->PchSpiBase);\r | |
e5efcf8b | 853 | ReadValue = MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD + S_SPI_FREGX * (UINT32)FlashRegionType);\r |
1d66480a GD |
854 | ReleaseSpiBar0 (SpiInstance->PchSpiBase);\r |
855 | \r | |
856 | //\r | |
857 | // If the region is not used, the Region Base is 7FFFh and Region Limit is 0000h\r | |
858 | //\r | |
859 | if (ReadValue == B_SPI_FREGX_BASE_MASK) {\r | |
860 | return EFI_DEVICE_ERROR;\r | |
861 | }\r | |
862 | \r | |
863 | Base = (ReadValue & B_SPI_FREG1_BASE_MASK) << N_SPI_FREG1_BASE;\r | |
864 | if (BaseAddress != NULL) {\r | |
865 | *BaseAddress = Base;\r | |
866 | }\r | |
867 | \r | |
868 | if (RegionSize != NULL) {\r | |
869 | *RegionSize = ((((ReadValue & B_SPI_FREGX_LIMIT_MASK) >> N_SPI_FREGX_LIMIT) + 1) <<\r | |
e5efcf8b | 870 | N_SPI_FREGX_LIMIT_REPR) - Base;\r |
1d66480a GD |
871 | }\r |
872 | \r | |
873 | return EFI_SUCCESS;\r | |
874 | }\r |