]> git.proxmox.com Git - mirror_edk2.git/blame - UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.c
UefiPayloadPkg: Apply uncrustify changes
[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
e5efcf8b 10SPI_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
17SPI_INSTANCE *\r
18GetSpiInstance (\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
40EFI_STATUS\r
41EFIAPI\r
42SpiConstructor (\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
166EFI_STATUS\r
167EFIAPI\r
168SpiFlashRead (\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
193EFI_STATUS\r
194EFIAPI\r
195SpiFlashWrite (\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
219EFI_STATUS\r
220EFIAPI\r
221SpiFlashErase (\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
245EFI_STATUS\r
246EFIAPI\r
247SpiFlashReadSfdp (\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
288EFI_STATUS\r
289EFIAPI\r
290SpiFlashReadJedecId (\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
329EFI_STATUS\r
330EFIAPI\r
331SpiFlashWriteStatus (\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
352EFI_STATUS\r
353EFIAPI\r
354SpiFlashReadStatus (\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
377EFI_STATUS\r
378EFIAPI\r
379SpiReadPchSoftStrap (\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
418EFI_STATUS\r
419SendSpiCmd (\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
749SendSpiCmdEnd:\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
773BOOLEAN\r
774WaitForSpiCycleComplete (\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
818EFI_STATUS\r
819EFIAPI\r
820SpiGetRegionAddress (\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