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