]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c
QuarkSocPkg: Spi/Common: remove set but unused variables
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Spi / Common / SpiCommon.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2PCH SPI Common Driver implements the SPI Host Controller Compatibility Interface.\r
3\r
4Copyright (c) 2013-2015 Intel Corporation.\r
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "PchSpi.h"\r
17\r
18VOID\r
19FillOutPublicInfoStruct (\r
20 SPI_INSTANCE *SpiInstance\r
21 )\r
22/*++\r
23\r
24Routine Description:\r
25\r
26 Fillout SpiInstance->InitInfo;\r
27\r
28Arguments:\r
29\r
30 SpiInstance - Pointer to SpiInstance to initialize\r
31\r
32Returns:\r
33\r
34 NONE\r
35\r
36--*/\r
37{\r
38 UINT8 Index;\r
39\r
40 SpiInstance->InitInfo.InitTable = &SpiInstance->SpiInitTable;\r
41\r
42 //\r
43 // Give invalid index in case operation not supported.\r
44 //\r
45 SpiInstance->InitInfo.JedecIdOpcodeIndex = 0xff;\r
46 SpiInstance->InitInfo.OtherOpcodeIndex = 0xff;\r
47 SpiInstance->InitInfo.WriteStatusOpcodeIndex = 0xff;\r
48 SpiInstance->InitInfo.ProgramOpcodeIndex = 0xff;\r
49 SpiInstance->InitInfo.ReadOpcodeIndex = 0xff;\r
50 SpiInstance->InitInfo.EraseOpcodeIndex = 0xff;\r
51 SpiInstance->InitInfo.ReadStatusOpcodeIndex = 0xff;\r
52 SpiInstance->InitInfo.FullChipEraseOpcodeIndex = 0xff;\r
53 for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {\r
54 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {\r
55 SpiInstance->InitInfo.JedecIdOpcodeIndex = Index;\r
56 }\r
57 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationOther) {\r
58 SpiInstance->InitInfo.OtherOpcodeIndex = Index;\r
59 }\r
60 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {\r
61 SpiInstance->InitInfo.WriteStatusOpcodeIndex = Index;\r
62 }\r
63 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_1_Byte ||\r
64 SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_64_Byte) {\r
65 SpiInstance->InitInfo.ProgramOpcodeIndex = Index;\r
66 }\r
67 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData ||\r
68 SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead ||\r
69 SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) {\r
70 SpiInstance->InitInfo.ReadOpcodeIndex = Index;\r
71 }\r
72 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_256_Byte ||\r
73 SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_4K_Byte ||\r
74 SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_8K_Byte ||\r
75 SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_64K_Byte) {\r
76 SpiInstance->InitInfo.EraseOpcodeIndex = Index;\r
77 }\r
78 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadStatus) {\r
79 SpiInstance->InitInfo.ReadStatusOpcodeIndex = Index;\r
80 }\r
81 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFullChipErase) {\r
82 SpiInstance->InitInfo.FullChipEraseOpcodeIndex = Index;\r
83 }\r
84 }\r
85}\r
86\r
87EFI_STATUS\r
88SpiProtocolConstructor (\r
89 SPI_INSTANCE *SpiInstance\r
90 )\r
91/*++\r
92\r
93Routine Description:\r
94\r
95 Initialize an SPI protocol instance.\r
96 The function will assert in debug if PCH RCBA has not been initialized\r
97\r
98Arguments:\r
99\r
100 SpiInstance - Pointer to SpiInstance to initialize\r
101\r
102Returns:\r
103\r
104 EFI_SUCCESS The protocol instance was properly initialized\r
105 EFI_UNSUPPORTED The PCH is not supported by this module\r
106\r
107--*/\r
108{\r
109 SpiInstance->InitDone = FALSE; // Indicate NOT READY.\r
110\r
111 //\r
112 // Check if the current PCH is known and supported by this code\r
113 //\r
114 if (!IsQncSupported ()) {\r
115 DEBUG ((DEBUG_ERROR, "PCH SPI Protocol not supported due to no proper QNC LPC found!\n"));\r
116 return EFI_UNSUPPORTED;\r
117 }\r
118 //\r
119 // Initialize the SPI protocol instance\r
120 //\r
121 SpiInstance->Signature = PCH_SPI_PRIVATE_DATA_SIGNATURE;\r
122 SpiInstance->Handle = NULL;\r
123 SpiInstance->SpiProtocol.Init = SpiProtocolInit;\r
124 SpiInstance->SpiProtocol.Lock = SpiProtocolLock;\r
125 SpiInstance->SpiProtocol.Execute = SpiProtocolExecute;\r
126 SpiInstance->SpiProtocol.Info = SpiProtocolInfo;\r
127\r
128 //\r
129 // Sanity check to ensure PCH RCBA initialization has occurred previously.\r
130 //\r
131 SpiInstance->PchRootComplexBar = MmioRead32 (\r
132 PciDeviceMmBase (PCI_BUS_NUMBER_QNC,\r
133 PCI_DEVICE_NUMBER_QNC_LPC,\r
134 PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_RCBA\r
135 ) & B_QNC_LPC_RCBA_MASK;\r
136 ASSERT (SpiInstance->PchRootComplexBar != 0);\r
137\r
138 return EFI_SUCCESS;\r
139}\r
140\r
141EFI_STATUS\r
142EFIAPI\r
143UnlockFlashComponents (\r
144 IN EFI_SPI_PROTOCOL *This,\r
145 IN UINT8 UnlockCmdOpcodeIndex\r
146 )\r
147/*++\r
148\r
149Routine Description:\r
150\r
151 Issue unlock command to disable block protection, this only needs to be done once per SPI power on\r
152\r
153Arguments:\r
154\r
155 This A pointer to "EFI_SPI_PROTOCOL" for issuing commands\r
156 UnlockCmdOpcodeIndex The index of the Unlock command\r
157\r
158Returns:\r
159\r
160 EFI_SUCCESS UnLock operation succeed.\r
161 EFI_DEVICE_ERROR Device error, operation failed.\r
162\r
163--*/\r
164{\r
165 EFI_STATUS Status;\r
166 SPI_INSTANCE *SpiInstance;\r
167 UINT8 SpiStatus;\r
9b6bbcdb
MK
168\r
169 if (UnlockCmdOpcodeIndex >= SPI_NUM_OPCODE) {\r
170 return EFI_UNSUPPORTED;\r
171 }\r
172\r
173 SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
9b6bbcdb
MK
174\r
175 //\r
176 // Issue unlock command to disable block protection, this only needs to be done once per SPI power on\r
177 //\r
178 SpiStatus = 0;\r
179 //\r
180 // Issue unlock command to the flash component 1 at first\r
181 //\r
182 Status = SpiProtocolExecute (\r
183 This,\r
184 UnlockCmdOpcodeIndex,\r
185 SpiInstance->SpiInitTable.PrefixOpcode[0] == PCH_SPI_COMMAND_WRITE_ENABLE ? 0 : 1,\r
186 TRUE,\r
187 TRUE,\r
188 TRUE,\r
189 (UINTN) 0,\r
190 sizeof (SpiStatus),\r
191 &SpiStatus,\r
192 EnumSpiRegionAll\r
193 );\r
194 if (EFI_ERROR (Status)) {\r
195 DEBUG ((EFI_D_ERROR, "Unlock flash component 1 fail!\n"));\r
196 return Status;\r
197 }\r
198\r
199 return EFI_SUCCESS;\r
200}\r
201\r
202EFI_STATUS\r
203EFIAPI\r
204SpiProtocolInit (\r
205 IN EFI_SPI_PROTOCOL *This,\r
206 IN SPI_INIT_TABLE *InitTable\r
207 )\r
208/*++\r
209\r
210Routine Description:\r
211\r
212 Initialize the host controller to execute SPI command.\r
213\r
214Arguments:\r
215\r
216 This Pointer to the EFI_SPI_PROTOCOL instance.\r
217 InitTable Initialization data to be programmed into the SPI host controller.\r
218\r
219Returns:\r
220\r
221 EFI_SUCCESS Initialization completed.\r
222 EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down.\r
223 EFI_INVALID_PARAMETER Bad input parameters.\r
224 EFI_UNSUPPORTED Can't get Descriptor mode VSCC values\r
225--*/\r
226{\r
227 EFI_STATUS Status;\r
228 UINT8 Index;\r
229 UINT16 OpcodeType;\r
230 SPI_INSTANCE *SpiInstance;\r
9b6bbcdb 231 UINTN PchRootComplexBar;\r
9b6bbcdb 232 UINT8 UnlockCmdOpcodeIndex;\r
9b6bbcdb
MK
233 UINT8 FlashPartId[3];\r
234\r
235 SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
236 PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
237\r
238 if (InitTable != NULL) {\r
239 //\r
240 // Copy table into SPI driver Private data structure\r
241 //\r
242 CopyMem (\r
243 &SpiInstance->SpiInitTable,\r
244 InitTable,\r
245 sizeof (SPI_INIT_TABLE)\r
246 );\r
247 } else {\r
248 return EFI_INVALID_PARAMETER;\r
249 }\r
250 //\r
251 // Check if the SPI interface has been locked-down.\r
252 //\r
253 if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {\r
254 ASSERT_EFI_ERROR (EFI_ACCESS_DENIED);\r
255 return EFI_ACCESS_DENIED;\r
256 }\r
257 //\r
258 // Clear all the status bits for status regs.\r
259 //\r
260 MmioOr16 (\r
261 (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),\r
262 (UINT16) ((B_QNC_RCRB_SPIS_CDS | B_QNC_RCRB_SPIS_BAS))\r
263 );\r
264 MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);\r
265\r
266 //\r
267 // Set the Prefix Opcode registers.\r
268 //\r
269 MmioWrite16 (\r
270 PchRootComplexBar + R_QNC_RCRB_SPIPREOP,\r
271 (SpiInstance->SpiInitTable.PrefixOpcode[1] << 8) | InitTable->PrefixOpcode[0]\r
272 );\r
273 MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIPREOP);\r
274\r
275 //\r
276 // Set Opcode Type Configuration registers.\r
277 //\r
278 for (Index = 0, OpcodeType = 0; Index < SPI_NUM_OPCODE; Index++) {\r
279 switch (SpiInstance->SpiInitTable.OpcodeMenu[Index].Type) {\r
280 case EnumSpiOpcodeRead:\r
281 OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_READ << (Index * 2));\r
282 break;\r
283 case EnumSpiOpcodeWrite:\r
284 OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_WRITE << (Index * 2));\r
285 break;\r
286 case EnumSpiOpcodeWriteNoAddr:\r
287 OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE << (Index * 2));\r
288 break;\r
289 default:\r
290 OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_READ << (Index * 2));\r
291 break;\r
292 }\r
293 }\r
294 MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE, OpcodeType);\r
295 MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE);\r
296\r
297 //\r
298 // Setup the Opcode Menu registers.\r
299 //\r
9b6bbcdb
MK
300 UnlockCmdOpcodeIndex = SPI_NUM_OPCODE;\r
301 for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {\r
302 MmioWrite8 (\r
303 PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index,\r
304 SpiInstance->SpiInitTable.OpcodeMenu[Index].Code\r
305 );\r
306 MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index);\r
307 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {\r
308 Status = SpiProtocolExecute (\r
309 This,\r
310 Index,\r
311 0,\r
312 TRUE,\r
313 TRUE,\r
314 FALSE,\r
315 (UINTN) 0,\r
316 3,\r
317 FlashPartId,\r
318 EnumSpiRegionDescriptor\r
319 );\r
320 if (EFI_ERROR (Status)) {\r
321 return Status;\r
322 }\r
323 if (FlashPartId[0] != SpiInstance->SpiInitTable.VendorId ||\r
324 FlashPartId[1] != SpiInstance->SpiInitTable.DeviceId0 ||\r
325 FlashPartId[2] != SpiInstance->SpiInitTable.DeviceId1) {\r
326 return EFI_INVALID_PARAMETER;\r
327 }\r
328 }\r
329\r
9b6bbcdb
MK
330 if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {\r
331 UnlockCmdOpcodeIndex = Index;\r
332 }\r
333 }\r
334\r
9b6bbcdb
MK
335 Status = UnlockFlashComponents (\r
336 This,\r
337 UnlockCmdOpcodeIndex\r
338 );\r
339 if (EFI_ERROR (Status)) {\r
340 DEBUG ((EFI_D_ERROR, "Unlock flash components fail!\n"));\r
341 }\r
342\r
343 SpiPhaseInit ();\r
344 FillOutPublicInfoStruct (SpiInstance);\r
345 SpiInstance->InitDone = TRUE;\r
346 return EFI_SUCCESS;\r
347}\r
348\r
349EFI_STATUS\r
350EFIAPI\r
351SpiProtocolLock (\r
352 IN EFI_SPI_PROTOCOL *This\r
353 )\r
354/*++\r
355\r
356Routine Description:\r
357\r
358 Lock the SPI Static Configuration Interface.\r
359 Once locked, the interface can not be changed and can only be clear by system reset.\r
360\r
361Arguments:\r
362\r
363 This Pointer to the EFI_SPI_PROTOCOL instance.\r
364\r
365Returns:\r
366\r
367 EFI_SUCCESS Lock operation succeed.\r
368 EFI_DEVICE_ERROR Device error, operation failed.\r
369 EFI_ACCESS_DENIED The interface has already been locked.\r
370\r
371--*/\r
372{\r
373 SPI_INSTANCE *SpiInstance;\r
374 UINTN PchRootComplexBar;\r
375\r
376 SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
377 PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
378\r
379 //\r
380 // Check if the SPI interface has been locked-down.\r
381 //\r
382 if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {\r
383 return EFI_ACCESS_DENIED;\r
384 }\r
385\r
386 //\r
387 // Lock-down the configuration interface.\r
388 //\r
389 MmioOr16 ((UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), (UINT16) (B_QNC_RCRB_SPIS_SCL));\r
390\r
391 //\r
392 // Verify if it's really locked.\r
393 //\r
394 if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) == 0) {\r
395 return EFI_DEVICE_ERROR;\r
396 } else {\r
397 //\r
398 // Save updated register in S3 Boot script.\r
399 //\r
400 S3BootScriptSaveMemWrite (\r
401 S3BootScriptWidthUint16,\r
402 (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),\r
403 1,\r
404 (VOID *) (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS)\r
405 );\r
406 }\r
407\r
408 return EFI_SUCCESS;\r
409}\r
410\r
411EFI_STATUS\r
412EFIAPI\r
413SpiProtocolExecute (\r
414 IN EFI_SPI_PROTOCOL *This,\r
415 IN UINT8 OpcodeIndex,\r
416 IN UINT8 PrefixOpcodeIndex,\r
417 IN BOOLEAN DataCycle,\r
418 IN BOOLEAN Atomic,\r
419 IN BOOLEAN ShiftOut,\r
420 IN UINTN Address,\r
421 IN UINT32 DataByteCount,\r
422 IN OUT UINT8 *Buffer,\r
423 IN SPI_REGION_TYPE SpiRegionType\r
424 )\r
425/*++\r
426\r
427Routine Description:\r
428\r
429 Execute SPI commands from the host controller.\r
430 This function would be called by runtime driver, please do not use any MMIO marco here\r
431\r
432Arguments:\r
433\r
434 This Pointer to the EFI_SPI_PROTOCOL instance.\r
435 OpcodeIndex Index of the command in the OpCode Menu.\r
436 PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.\r
437 DataCycle TRUE if the SPI cycle contains data\r
438 Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.\r
439 ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.\r
440 Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
441 Region, this value specifies the offset from the Region Base; for BIOS Region,\r
442 this value specifies the offset from the start of the BIOS Image. In Non\r
443 Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
444 Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
445 Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
446 supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
447 the flash (in Non Descriptor Mode)\r
448 DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the\r
449 data transfer into multiple operations. This function ensures each operation does\r
450 not cross 256 byte flash address boundary.\r
451 *NOTE: if there is some SPI chip that has a stricter address boundary requirement\r
452 (e.g., its write page size is < 256 byte), then the caller cannot rely on this\r
453 function to cut the data transfer at proper address boundaries, and it's the\r
454 caller's reponsibility to pass in a properly cut DataByteCount parameter.\r
455 Buffer Pointer to caller-allocated buffer containing the dada received or sent during the\r
456 SPI cycle.\r
457 SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
458 EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
459 Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
460 and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
461 to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
462\r
463Returns:\r
464\r
465 EFI_SUCCESS Command succeed.\r
466 EFI_INVALID_PARAMETER The parameters specified are not valid.\r
467 EFI_UNSUPPORTED Command not supported.\r
468 EFI_DEVICE_ERROR Device error, command aborts abnormally.\r
469\r
470--*/\r
471{\r
472 EFI_STATUS Status;\r
473 UINT16 BiosCtlSave;\r
474 UINT32 SmiEnSave;\r
475\r
476 BiosCtlSave = 0;\r
477 SmiEnSave = 0;\r
478\r
479 //\r
480 // Check if the parameters are valid.\r
481 //\r
482 if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) {\r
483 return EFI_INVALID_PARAMETER;\r
484 }\r
485 //\r
486 // Make sure it's safe to program the command.\r
487 //\r
488 if (!WaitForSpiCycleComplete (This, FALSE)) {\r
489 return EFI_DEVICE_ERROR;\r
490 }\r
491\r
492 //\r
493 // Acquire access to the SPI interface is not required any more.\r
494 //\r
495 //\r
496 // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI\r
497 // whose SMI handler accesses flash (e.g. for error logging)\r
498 //\r
499 SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
500 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));\r
501\r
502 //\r
503 // Save BIOS Ctrl register\r
504 //\r
505 BiosCtlSave = PciRead16 (\r
506 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
507 PCI_DEVICE_NUMBER_QNC_LPC,\r
508 PCI_FUNCTION_NUMBER_QNC_LPC,\r
509 R_QNC_LPC_BIOS_CNTL)\r
510 ) & (B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP);\r
511\r
512 //\r
513 // Enable flash writing\r
514 //\r
515 PciOr16 (\r
516 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
517 PCI_DEVICE_NUMBER_QNC_LPC,\r
518 PCI_FUNCTION_NUMBER_QNC_LPC,\r
519 R_QNC_LPC_BIOS_CNTL),\r
520 (UINT16) (B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)\r
521 );\r
522\r
523 //\r
524 // If shifts the data out, disable Prefetching and Caching.\r
525 //\r
526 if (ShiftOut) {\r
527 PciAndThenOr16 (\r
528 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
529 PCI_DEVICE_NUMBER_QNC_LPC,\r
530 PCI_FUNCTION_NUMBER_QNC_LPC,\r
531 R_QNC_LPC_BIOS_CNTL),\r
532 (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE)),\r
533 (UINT16) ((B_QNC_LPC_BIOS_CNTL_BCD))\r
534 );\r
535 }\r
536 //\r
537 // Sends the command to the SPI interface to execute.\r
538 //\r
539 Status = SendSpiCmd (\r
540 This,\r
541 OpcodeIndex,\r
542 PrefixOpcodeIndex,\r
543 DataCycle,\r
544 Atomic,\r
545 ShiftOut,\r
546 Address,\r
547 DataByteCount,\r
548 Buffer,\r
549 SpiRegionType\r
550 );\r
551\r
552 //\r
553 // Restore BIOS Ctrl register\r
554 //\r
555 PciAndThenOr16 (\r
556 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
557 PCI_DEVICE_NUMBER_QNC_LPC,\r
558 PCI_FUNCTION_NUMBER_QNC_LPC,\r
559 R_QNC_LPC_BIOS_CNTL),\r
560 (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)),\r
561 (UINT16) (BiosCtlSave)\r
562 );\r
563 //\r
564 // Restore SMIs.\r
565 //\r
566 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, SmiEnSave);\r
567\r
568 return Status;\r
569}\r
570\r
571VOID\r
572SpiOffset2Physical (\r
573 IN EFI_SPI_PROTOCOL *This,\r
574 IN UINTN SpiRegionOffset,\r
575 IN SPI_REGION_TYPE SpiRegionType,\r
576 OUT UINTN *HardwareSpiAddress,\r
577 OUT UINTN *BaseAddress,\r
578 OUT UINTN *LimitAddress\r
579 )\r
580/*++\r
581\r
582Routine Description:\r
583\r
584 Convert SPI offset to Physical address of SPI hardware\r
585\r
586Arguments:\r
587\r
588 This Pointer to the EFI_SPI_PROTOCOL instance.\r
589 SpiRegionOffset In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
590 Region, this value specifies the offset from the Region Base; for BIOS Region,\r
591 this value specifies the offset from the start of the BIOS Image. In Non\r
592 Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
593 Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
594 Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
595 supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
596 the flash (in Non Descriptor Mode)\r
597 BaseAddress Base Address of the region.\r
598 SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
599 EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
600 Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
601 and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
602 to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
603 HardwareSpiAddress Return absolution SPI address (i.e., Flash Linear Address)\r
604 BaseAddress Return base address of the region type\r
605 LimitAddress Return limit address of the region type\r
606\r
607Returns:\r
608\r
609 EFI_SUCCESS Command succeed.\r
610\r
611--*/\r
612{\r
613 SPI_INSTANCE *SpiInstance;\r
9b6bbcdb
MK
614\r
615 SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
9b6bbcdb
MK
616\r
617 if (SpiRegionType == EnumSpiRegionAll) {\r
618 //\r
619 // EnumSpiRegionAll indicates address is relative to flash device (i.e., address is Flash\r
620 // Linear Address)\r
621 //\r
622 *HardwareSpiAddress = SpiRegionOffset;\r
623 } else {\r
624 //\r
625 // Otherwise address is relative to BIOS image\r
626 //\r
627 *HardwareSpiAddress = SpiRegionOffset + SpiInstance->SpiInitTable.BiosStartOffset;\r
628 }\r
629}\r
630\r
631EFI_STATUS\r
632SendSpiCmd (\r
633 IN EFI_SPI_PROTOCOL *This,\r
634 IN UINT8 OpcodeIndex,\r
635 IN UINT8 PrefixOpcodeIndex,\r
636 IN BOOLEAN DataCycle,\r
637 IN BOOLEAN Atomic,\r
638 IN BOOLEAN ShiftOut,\r
639 IN UINTN Address,\r
640 IN UINT32 DataByteCount,\r
641 IN OUT UINT8 *Buffer,\r
642 IN SPI_REGION_TYPE SpiRegionType\r
643 )\r
644/*++\r
645\r
646Routine Description:\r
647\r
648 This function sends the programmed SPI command to the slave device.\r
649\r
650Arguments:\r
651\r
652 OpcodeIndex Index of the command in the OpCode Menu.\r
653 PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.\r
654 DataCycle TRUE if the SPI cycle contains data\r
655 Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.\r
656 ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.\r
657 Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
658 Region, this value specifies the offset from the Region Base; for BIOS Region,\r
659 this value specifies the offset from the start of the BIOS Image. In Non\r
660 Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
661 Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
662 Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
663 supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
664 the flash (in Non Descriptor Mode)\r
665 DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the\r
666 data transfer into multiple operations. This function ensures each operation does\r
667 not cross 256 byte flash address boundary.\r
668 *NOTE: if there is some SPI chip that has a stricter address boundary requirement\r
669 (e.g., its write page size is < 256 byte), then the caller cannot rely on this\r
670 function to cut the data transfer at proper address boundaries, and it's the\r
671 caller's reponsibility to pass in a properly cut DataByteCount parameter.\r
672 Buffer Data received or sent during the SPI cycle.\r
673 SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
674 EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
675 Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
676 and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
677 to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
678\r
679Returns:\r
680\r
681 EFI_SUCCESS SPI command completes successfully.\r
682 EFI_DEVICE_ERROR Device error, the command aborts abnormally.\r
683 EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode\r
684 EFI_INVALID_PARAMETER The parameters specified are not valid.\r
685\r
686--*/\r
687{\r
688 UINT32 Index;\r
689 SPI_INSTANCE *SpiInstance;\r
690 UINTN HardwareSpiAddr;\r
691 UINTN SpiBiosSize;\r
692 UINTN BaseAddress;\r
693 UINTN LimitAddress;\r
694 UINT32 SpiDataCount;\r
695 UINT8 OpCode;\r
9b6bbcdb
MK
696 UINTN PchRootComplexBar;\r
697\r
698 SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
699 PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
700 SpiBiosSize = SpiInstance->SpiInitTable.BiosSize;\r
9b6bbcdb
MK
701 OpCode = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + OpcodeIndex);\r
702\r
703 //\r
704 // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0\r
705 //\r
706 if (OpCode == 0 || SpiBiosSize == 0) {\r
707 ASSERT (FALSE);\r
708 return EFI_INVALID_PARAMETER;\r
709 }\r
710\r
711 SpiOffset2Physical (This, Address, SpiRegionType, &HardwareSpiAddr, &BaseAddress, &LimitAddress);\r
712 //\r
713 // Have direct access to BIOS region in Descriptor mode,\r
714 //\r
715 if (SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Type == EnumSpiOpcodeRead &&\r
716 SpiRegionType == EnumSpiRegionBios) {\r
717 CopyMem (\r
718 Buffer,\r
719 (UINT8 *) ((HardwareSpiAddr - BaseAddress) + (UINT32) (~(SpiBiosSize - 1))),\r
720 DataByteCount\r
721 );\r
722 return EFI_SUCCESS;\r
723 }\r
724 //\r
725 // DEBUG((EFI_D_ERROR, "SPIADDR %x, %x, %x, %x\n", Address, HardwareSpiAddr, BaseAddress,\r
726 // LimitAddress));\r
727 //\r
728 if ((DataCycle == FALSE) && (DataByteCount > 0)) {\r
729 DataByteCount = 0;\r
730 }\r
731\r
732 do {\r
733 //\r
734 // Trim at 256 byte boundary per operation,\r
735 // - PCH SPI controller requires trimming at 4KB boundary\r
736 // - Some SPI chips require trimming at 256 byte boundary for write operation\r
737 // - Trimming has limited performance impact as we can read / write atmost 64 byte\r
738 // per operation\r
739 //\r
740 if (HardwareSpiAddr + DataByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) {\r
741 SpiDataCount = (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32) (HardwareSpiAddr);\r
742 } else {\r
743 SpiDataCount = DataByteCount;\r
744 }\r
745 //\r
746 // Calculate the number of bytes to shift in/out during the SPI data cycle.\r
747 // Valid settings for the number of bytes duing each data portion of the\r
748 // PCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64\r
749 //\r
750 if (SpiDataCount >= 64) {\r
751 SpiDataCount = 64;\r
752 } else if ((SpiDataCount &~0x07) != 0) {\r
753 SpiDataCount = SpiDataCount &~0x07;\r
754 }\r
755 //\r
756 // If shifts data out, load data into the SPI data buffer.\r
757 //\r
758 if (ShiftOut) {\r
759 for (Index = 0; Index < SpiDataCount; Index++) {\r
760 MmioWrite8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index, Buffer[Index]);\r
761 MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);\r
762 }\r
763 }\r
764\r
765 MmioWrite32 (\r
766 (PchRootComplexBar + R_QNC_RCRB_SPIA),\r
767 (UINT32) (HardwareSpiAddr & B_QNC_RCRB_SPIA_MASK)\r
768 );\r
769 MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIA);\r
770\r
771 //\r
772 // Execute the command on the SPI compatible mode\r
773 //\r
774\r
775 //\r
776 // Clear error flags\r
777 //\r
778 MmioOr16 ((PchRootComplexBar + R_QNC_RCRB_SPIS), B_QNC_RCRB_SPIS_BAS);\r
779\r
780 //\r
781 // Initialte the SPI cycle\r
782 //\r
783 if (DataCycle) {\r
784 MmioWrite16 (\r
785 (PchRootComplexBar + R_QNC_RCRB_SPIC),\r
786 ( (UINT16) (B_QNC_RCRB_SPIC_DC) | (UINT16) (((SpiDataCount - 1) << 8) & B_QNC_RCRB_SPIC_DBC) |\r
787 (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |\r
788 (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |\r
789 (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |\r
790 (UINT16) (B_QNC_RCRB_SPIC_SCGO)));\r
791 } else {\r
792 MmioWrite16 (\r
793 (PchRootComplexBar + R_QNC_RCRB_SPIC),\r
794 ( (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |\r
795 (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |\r
796 (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |\r
797 (UINT16) (B_QNC_RCRB_SPIC_SCGO)));\r
798 }\r
799\r
800 MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIC);\r
801\r
802 //\r
803 // end of command execution\r
804 //\r
805 // Wait the SPI cycle to complete.\r
806 //\r
807 if (!WaitForSpiCycleComplete (This, TRUE)) {\r
808 return EFI_DEVICE_ERROR;\r
809 }\r
810 //\r
811 // If shifts data in, get data from the SPI data buffer.\r
812 //\r
813 if (!ShiftOut) {\r
814 for (Index = 0; Index < SpiDataCount; Index++) {\r
815 Buffer[Index] = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);\r
816 }\r
817 }\r
818\r
819 HardwareSpiAddr += SpiDataCount;\r
820 Buffer += SpiDataCount;\r
821 DataByteCount -= SpiDataCount;\r
822 } while (DataByteCount > 0);\r
823\r
824 return EFI_SUCCESS;\r
825}\r
826\r
827BOOLEAN\r
828WaitForSpiCycleComplete (\r
829 IN EFI_SPI_PROTOCOL *This,\r
830 IN BOOLEAN ErrorCheck\r
831 )\r
832/*++\r
833\r
834Routine Description:\r
835\r
836 Wait execution cycle to complete on the SPI interface. Check both Hardware\r
837 and Software Sequencing status registers\r
838\r
839Arguments:\r
840\r
841 This - The SPI protocol instance\r
842 UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation\r
843 ErrorCheck - TRUE if the SpiCycle needs to do the error check\r
844\r
845Returns:\r
846\r
847 TRUE SPI cycle completed on the interface.\r
848 FALSE Time out while waiting the SPI cycle to complete.\r
849 It's not safe to program the next command on the SPI interface.\r
850\r
851--*/\r
852{\r
853 UINT64 WaitTicks;\r
854 UINT64 WaitCount;\r
855 UINT16 Data16;\r
856 SPI_INSTANCE *SpiInstance;\r
857 UINTN PchRootComplexBar;\r
858\r
859 SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
860 PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
861\r
862 //\r
863 // Convert the wait period allowed into to tick count\r
864 //\r
865 WaitCount = WAIT_TIME / WAIT_PERIOD;\r
866\r
867 //\r
868 // Wait for the SPI cycle to complete.\r
869 //\r
870 for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {\r
871 Data16 = MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);\r
872 if ((Data16 & B_QNC_RCRB_SPIS_SCIP) == 0) {\r
873 MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIS, (B_QNC_RCRB_SPIS_BAS | B_QNC_RCRB_SPIS_CDS));\r
874 if ((Data16 & B_QNC_RCRB_SPIS_BAS) && (ErrorCheck == TRUE)) {\r
875 return FALSE;\r
876 } else {\r
877 return TRUE;\r
878 }\r
879 }\r
880\r
881 MicroSecondDelay (WAIT_PERIOD);\r
882 }\r
883\r
884 return FALSE;\r
885}\r
886\r
887EFI_STATUS\r
888EFIAPI\r
889SpiProtocolInfo (\r
890 IN EFI_SPI_PROTOCOL *This,\r
891 OUT SPI_INIT_INFO **InitInfoPtr\r
892 )\r
893/*++\r
894\r
895Routine Description:\r
896\r
897 Return info about SPI host controller, to help callers usage of Execute\r
898 service.\r
899\r
900 If 0xff is returned as an opcode index in init info struct\r
901 then device does not support the operation.\r
902\r
903Arguments:\r
904\r
905 This Pointer to the EFI_SPI_PROTOCOL instance.\r
906 InitInfoPtr Pointer to init info written to this memory location.\r
907\r
908Returns:\r
909\r
910 EFI_SUCCESS Information returned.\r
911 EFI_INVALID_PARAMETER Invalid parameter.\r
912 EFI_NOT_READY Required resources not setup.\r
913 Others Unexpected error happened.\r
914\r
915--*/\r
916{\r
917 SPI_INSTANCE *SpiInstance;\r
918\r
919 if (This == NULL || InitInfoPtr == NULL) {\r
920 return EFI_INVALID_PARAMETER;\r
921 }\r
922 SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
923 if (SpiInstance->Signature != PCH_SPI_PRIVATE_DATA_SIGNATURE) {\r
924 return EFI_INVALID_PARAMETER;\r
925 }\r
926\r
927 if (!SpiInstance->InitDone) {\r
928 *InitInfoPtr = NULL;\r
929 return EFI_NOT_READY;\r
930 }\r
931 *InitInfoPtr = &SpiInstance->InitInfo;\r
932 return EFI_SUCCESS;\r
933}\r