2 PCH SPI Common Driver implements the SPI Host Controller Compatibility Interface.
4 Copyright (c) 2013-2015 Intel Corporation.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 FillOutPublicInfoStruct (
14 SPI_INSTANCE
*SpiInstance
20 Fillout SpiInstance->InitInfo;
24 SpiInstance - Pointer to SpiInstance to initialize
34 SpiInstance
->InitInfo
.InitTable
= &SpiInstance
->SpiInitTable
;
37 // Give invalid index in case operation not supported.
39 SpiInstance
->InitInfo
.JedecIdOpcodeIndex
= 0xff;
40 SpiInstance
->InitInfo
.OtherOpcodeIndex
= 0xff;
41 SpiInstance
->InitInfo
.WriteStatusOpcodeIndex
= 0xff;
42 SpiInstance
->InitInfo
.ProgramOpcodeIndex
= 0xff;
43 SpiInstance
->InitInfo
.ReadOpcodeIndex
= 0xff;
44 SpiInstance
->InitInfo
.EraseOpcodeIndex
= 0xff;
45 SpiInstance
->InitInfo
.ReadStatusOpcodeIndex
= 0xff;
46 SpiInstance
->InitInfo
.FullChipEraseOpcodeIndex
= 0xff;
47 for (Index
= 0; Index
< SPI_NUM_OPCODE
; Index
++) {
48 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationJedecId
) {
49 SpiInstance
->InitInfo
.JedecIdOpcodeIndex
= Index
;
51 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationOther
) {
52 SpiInstance
->InitInfo
.OtherOpcodeIndex
= Index
;
54 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationWriteStatus
) {
55 SpiInstance
->InitInfo
.WriteStatusOpcodeIndex
= Index
;
57 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationProgramData_1_Byte
||
58 SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationProgramData_64_Byte
) {
59 SpiInstance
->InitInfo
.ProgramOpcodeIndex
= Index
;
61 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationReadData
||
62 SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationFastRead
||
63 SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationDualOutputFastRead
) {
64 SpiInstance
->InitInfo
.ReadOpcodeIndex
= Index
;
66 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationErase_256_Byte
||
67 SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationErase_4K_Byte
||
68 SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationErase_8K_Byte
||
69 SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationErase_64K_Byte
) {
70 SpiInstance
->InitInfo
.EraseOpcodeIndex
= Index
;
72 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationReadStatus
) {
73 SpiInstance
->InitInfo
.ReadStatusOpcodeIndex
= Index
;
75 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationFullChipErase
) {
76 SpiInstance
->InitInfo
.FullChipEraseOpcodeIndex
= Index
;
82 SpiProtocolConstructor (
83 SPI_INSTANCE
*SpiInstance
89 Initialize an SPI protocol instance.
90 The function will assert in debug if PCH RCBA has not been initialized
94 SpiInstance - Pointer to SpiInstance to initialize
98 EFI_SUCCESS The protocol instance was properly initialized
99 EFI_UNSUPPORTED The PCH is not supported by this module
103 SpiInstance
->InitDone
= FALSE
; // Indicate NOT READY.
106 // Check if the current PCH is known and supported by this code
108 if (!IsQncSupported ()) {
109 DEBUG ((DEBUG_ERROR
, "PCH SPI Protocol not supported due to no proper QNC LPC found!\n"));
110 return EFI_UNSUPPORTED
;
113 // Initialize the SPI protocol instance
115 SpiInstance
->Signature
= PCH_SPI_PRIVATE_DATA_SIGNATURE
;
116 SpiInstance
->Handle
= NULL
;
117 SpiInstance
->SpiProtocol
.Init
= SpiProtocolInit
;
118 SpiInstance
->SpiProtocol
.Lock
= SpiProtocolLock
;
119 SpiInstance
->SpiProtocol
.Execute
= SpiProtocolExecute
;
120 SpiInstance
->SpiProtocol
.Info
= SpiProtocolInfo
;
123 // Sanity check to ensure PCH RCBA initialization has occurred previously.
125 SpiInstance
->PchRootComplexBar
= MmioRead32 (
126 PciDeviceMmBase (PCI_BUS_NUMBER_QNC
,
127 PCI_DEVICE_NUMBER_QNC_LPC
,
128 PCI_FUNCTION_NUMBER_QNC_LPC
) + R_QNC_LPC_RCBA
129 ) & B_QNC_LPC_RCBA_MASK
;
130 ASSERT (SpiInstance
->PchRootComplexBar
!= 0);
137 UnlockFlashComponents (
138 IN EFI_SPI_PROTOCOL
*This
,
139 IN UINT8 UnlockCmdOpcodeIndex
145 Issue unlock command to disable block protection, this only needs to be done once per SPI power on
149 This A pointer to "EFI_SPI_PROTOCOL" for issuing commands
150 UnlockCmdOpcodeIndex The index of the Unlock command
154 EFI_SUCCESS UnLock operation succeed.
155 EFI_DEVICE_ERROR Device error, operation failed.
160 SPI_INSTANCE
*SpiInstance
;
163 if (UnlockCmdOpcodeIndex
>= SPI_NUM_OPCODE
) {
164 return EFI_UNSUPPORTED
;
167 SpiInstance
= SPI_INSTANCE_FROM_SPIPROTOCOL (This
);
170 // Issue unlock command to disable block protection, this only needs to be done once per SPI power on
174 // Issue unlock command to the flash component 1 at first
176 Status
= SpiProtocolExecute (
178 UnlockCmdOpcodeIndex
,
179 SpiInstance
->SpiInitTable
.PrefixOpcode
[0] == PCH_SPI_COMMAND_WRITE_ENABLE
? 0 : 1,
188 if (EFI_ERROR (Status
)) {
189 DEBUG ((EFI_D_ERROR
, "Unlock flash component 1 fail!\n"));
199 IN EFI_SPI_PROTOCOL
*This
,
200 IN SPI_INIT_TABLE
*InitTable
206 Initialize the host controller to execute SPI command.
210 This Pointer to the EFI_SPI_PROTOCOL instance.
211 InitTable Initialization data to be programmed into the SPI host controller.
215 EFI_SUCCESS Initialization completed.
216 EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down.
217 EFI_INVALID_PARAMETER Bad input parameters.
218 EFI_UNSUPPORTED Can't get Descriptor mode VSCC values
224 SPI_INSTANCE
*SpiInstance
;
225 UINTN PchRootComplexBar
;
226 UINT8 UnlockCmdOpcodeIndex
;
227 UINT8 FlashPartId
[3];
229 SpiInstance
= SPI_INSTANCE_FROM_SPIPROTOCOL (This
);
230 PchRootComplexBar
= SpiInstance
->PchRootComplexBar
;
232 if (InitTable
!= NULL
) {
234 // Copy table into SPI driver Private data structure
237 &SpiInstance
->SpiInitTable
,
239 sizeof (SPI_INIT_TABLE
)
242 return EFI_INVALID_PARAMETER
;
245 // Check if the SPI interface has been locked-down.
247 if ((MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIS
) & B_QNC_RCRB_SPIS_SCL
) != 0) {
248 ASSERT_EFI_ERROR (EFI_ACCESS_DENIED
);
249 return EFI_ACCESS_DENIED
;
252 // Clear all the status bits for status regs.
255 (UINTN
) (PchRootComplexBar
+ R_QNC_RCRB_SPIS
),
256 (UINT16
) ((B_QNC_RCRB_SPIS_CDS
| B_QNC_RCRB_SPIS_BAS
))
258 MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIS
);
261 // Set the Prefix Opcode registers.
264 PchRootComplexBar
+ R_QNC_RCRB_SPIPREOP
,
265 (SpiInstance
->SpiInitTable
.PrefixOpcode
[1] << 8) | InitTable
->PrefixOpcode
[0]
267 MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIPREOP
);
270 // Set Opcode Type Configuration registers.
272 for (Index
= 0, OpcodeType
= 0; Index
< SPI_NUM_OPCODE
; Index
++) {
273 switch (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Type
) {
274 case EnumSpiOpcodeRead
:
275 OpcodeType
|= (UINT16
) (B_QNC_RCRB_SPIOPTYPE_ADD_READ
<< (Index
* 2));
277 case EnumSpiOpcodeWrite
:
278 OpcodeType
|= (UINT16
) (B_QNC_RCRB_SPIOPTYPE_ADD_WRITE
<< (Index
* 2));
280 case EnumSpiOpcodeWriteNoAddr
:
281 OpcodeType
|= (UINT16
) (B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE
<< (Index
* 2));
284 OpcodeType
|= (UINT16
) (B_QNC_RCRB_SPIOPTYPE_NOADD_READ
<< (Index
* 2));
288 MmioWrite16 (PchRootComplexBar
+ R_QNC_RCRB_SPIOPTYPE
, OpcodeType
);
289 MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIOPTYPE
);
292 // Setup the Opcode Menu registers.
294 UnlockCmdOpcodeIndex
= SPI_NUM_OPCODE
;
295 for (Index
= 0; Index
< SPI_NUM_OPCODE
; Index
++) {
297 PchRootComplexBar
+ R_QNC_RCRB_SPIOPMENU
+ Index
,
298 SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Code
300 MmioRead8 (PchRootComplexBar
+ R_QNC_RCRB_SPIOPMENU
+ Index
);
301 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationJedecId
) {
302 Status
= SpiProtocolExecute (
312 EnumSpiRegionDescriptor
314 if (EFI_ERROR (Status
)) {
317 if (FlashPartId
[0] != SpiInstance
->SpiInitTable
.VendorId
||
318 FlashPartId
[1] != SpiInstance
->SpiInitTable
.DeviceId0
||
319 FlashPartId
[2] != SpiInstance
->SpiInitTable
.DeviceId1
) {
320 return EFI_INVALID_PARAMETER
;
324 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[Index
].Operation
== EnumSpiOperationWriteStatus
) {
325 UnlockCmdOpcodeIndex
= Index
;
329 Status
= UnlockFlashComponents (
333 if (EFI_ERROR (Status
)) {
334 DEBUG ((EFI_D_ERROR
, "Unlock flash components fail!\n"));
338 FillOutPublicInfoStruct (SpiInstance
);
339 SpiInstance
->InitDone
= TRUE
;
346 IN EFI_SPI_PROTOCOL
*This
352 Lock the SPI Static Configuration Interface.
353 Once locked, the interface can not be changed and can only be clear by system reset.
357 This Pointer to the EFI_SPI_PROTOCOL instance.
361 EFI_SUCCESS Lock operation succeed.
362 EFI_DEVICE_ERROR Device error, operation failed.
363 EFI_ACCESS_DENIED The interface has already been locked.
367 SPI_INSTANCE
*SpiInstance
;
368 UINTN PchRootComplexBar
;
370 SpiInstance
= SPI_INSTANCE_FROM_SPIPROTOCOL (This
);
371 PchRootComplexBar
= SpiInstance
->PchRootComplexBar
;
374 // Check if the SPI interface has been locked-down.
376 if ((MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIS
) & B_QNC_RCRB_SPIS_SCL
) != 0) {
377 return EFI_ACCESS_DENIED
;
381 // Lock-down the configuration interface.
383 MmioOr16 ((UINTN
) (PchRootComplexBar
+ R_QNC_RCRB_SPIS
), (UINT16
) (B_QNC_RCRB_SPIS_SCL
));
386 // Verify if it's really locked.
388 if ((MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIS
) & B_QNC_RCRB_SPIS_SCL
) == 0) {
389 return EFI_DEVICE_ERROR
;
392 // Save updated register in S3 Boot script.
394 S3BootScriptSaveMemWrite (
395 S3BootScriptWidthUint16
,
396 (UINTN
) (PchRootComplexBar
+ R_QNC_RCRB_SPIS
),
398 (VOID
*) (UINTN
) (PchRootComplexBar
+ R_QNC_RCRB_SPIS
)
408 IN EFI_SPI_PROTOCOL
*This
,
409 IN UINT8 OpcodeIndex
,
410 IN UINT8 PrefixOpcodeIndex
,
411 IN BOOLEAN DataCycle
,
415 IN UINT32 DataByteCount
,
416 IN OUT UINT8
*Buffer
,
417 IN SPI_REGION_TYPE SpiRegionType
423 Execute SPI commands from the host controller.
424 This function would be called by runtime driver, please do not use any MMIO marco here
428 This Pointer to the EFI_SPI_PROTOCOL instance.
429 OpcodeIndex Index of the command in the OpCode Menu.
430 PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
431 DataCycle TRUE if the SPI cycle contains data
432 Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
433 ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
434 Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
435 Region, this value specifies the offset from the Region Base; for BIOS Region,
436 this value specifies the offset from the start of the BIOS Image. In Non
437 Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
438 Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
439 Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
440 supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
441 the flash (in Non Descriptor Mode)
442 DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the
443 data transfer into multiple operations. This function ensures each operation does
444 not cross 256 byte flash address boundary.
445 *NOTE: if there is some SPI chip that has a stricter address boundary requirement
446 (e.g., its write page size is < 256 byte), then the caller cannot rely on this
447 function to cut the data transfer at proper address boundaries, and it's the
448 caller's reponsibility to pass in a properly cut DataByteCount parameter.
449 Buffer Pointer to caller-allocated buffer containing the dada received or sent during the
451 SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
452 EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
453 Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
454 and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
455 to base of the 1st flash device (i.e., it is a Flash Linear Address).
459 EFI_SUCCESS Command succeed.
460 EFI_INVALID_PARAMETER The parameters specified are not valid.
461 EFI_UNSUPPORTED Command not supported.
462 EFI_DEVICE_ERROR Device error, command aborts abnormally.
474 // Check if the parameters are valid.
476 if ((OpcodeIndex
>= SPI_NUM_OPCODE
) || (PrefixOpcodeIndex
>= SPI_NUM_PREFIX_OPCODE
)) {
477 return EFI_INVALID_PARAMETER
;
480 // Make sure it's safe to program the command.
482 if (!WaitForSpiCycleComplete (This
, FALSE
)) {
483 return EFI_DEVICE_ERROR
;
487 // Acquire access to the SPI interface is not required any more.
490 // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI
491 // whose SMI handler accesses flash (e.g. for error logging)
493 SmiEnSave
= QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID
, QNC_MSG_FSBIC_REG_HMISC
);
494 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID
, QNC_MSG_FSBIC_REG_HMISC
, (SmiEnSave
& ~SMI_EN
));
497 // Save BIOS Ctrl register
499 BiosCtlSave
= PciRead16 (
500 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC
,
501 PCI_DEVICE_NUMBER_QNC_LPC
,
502 PCI_FUNCTION_NUMBER_QNC_LPC
,
504 ) & (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
);
507 // Enable flash writing
510 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC
,
511 PCI_DEVICE_NUMBER_QNC_LPC
,
512 PCI_FUNCTION_NUMBER_QNC_LPC
,
513 R_QNC_LPC_BIOS_CNTL
),
514 (UINT16
) (B_QNC_LPC_BIOS_CNTL_BIOSWE
| B_QNC_LPC_BIOS_CNTL_SMM_BWP
)
518 // If shifts the data out, disable Prefetching and Caching.
522 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC
,
523 PCI_DEVICE_NUMBER_QNC_LPC
,
524 PCI_FUNCTION_NUMBER_QNC_LPC
,
525 R_QNC_LPC_BIOS_CNTL
),
526 (UINT16
) (~(B_QNC_LPC_BIOS_CNTL_BCD
| B_QNC_LPC_BIOS_CNTL_PFE
)),
527 (UINT16
) ((B_QNC_LPC_BIOS_CNTL_BCD
))
531 // Sends the command to the SPI interface to execute.
533 Status
= SendSpiCmd (
547 // Restore BIOS Ctrl register
550 PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC
,
551 PCI_DEVICE_NUMBER_QNC_LPC
,
552 PCI_FUNCTION_NUMBER_QNC_LPC
,
553 R_QNC_LPC_BIOS_CNTL
),
554 (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
)),
555 (UINT16
) (BiosCtlSave
)
560 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID
, QNC_MSG_FSBIC_REG_HMISC
, SmiEnSave
);
567 IN EFI_SPI_PROTOCOL
*This
,
568 IN UINTN SpiRegionOffset
,
569 IN SPI_REGION_TYPE SpiRegionType
,
570 OUT UINTN
*HardwareSpiAddress
,
571 OUT UINTN
*BaseAddress
,
572 OUT UINTN
*LimitAddress
578 Convert SPI offset to Physical address of SPI hardware
582 This Pointer to the EFI_SPI_PROTOCOL instance.
583 SpiRegionOffset In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
584 Region, this value specifies the offset from the Region Base; for BIOS Region,
585 this value specifies the offset from the start of the BIOS Image. In Non
586 Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
587 Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
588 Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
589 supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
590 the flash (in Non Descriptor Mode)
591 BaseAddress Base Address of the region.
592 SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
593 EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
594 Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
595 and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
596 to base of the 1st flash device (i.e., it is a Flash Linear Address).
597 HardwareSpiAddress Return absolution SPI address (i.e., Flash Linear Address)
598 BaseAddress Return base address of the region type
599 LimitAddress Return limit address of the region type
603 EFI_SUCCESS Command succeed.
607 SPI_INSTANCE
*SpiInstance
;
609 SpiInstance
= SPI_INSTANCE_FROM_SPIPROTOCOL (This
);
611 if (SpiRegionType
== EnumSpiRegionAll
) {
613 // EnumSpiRegionAll indicates address is relative to flash device (i.e., address is Flash
616 *HardwareSpiAddress
= SpiRegionOffset
;
619 // Otherwise address is relative to BIOS image
621 *HardwareSpiAddress
= SpiRegionOffset
+ SpiInstance
->SpiInitTable
.BiosStartOffset
;
627 IN EFI_SPI_PROTOCOL
*This
,
628 IN UINT8 OpcodeIndex
,
629 IN UINT8 PrefixOpcodeIndex
,
630 IN BOOLEAN DataCycle
,
634 IN UINT32 DataByteCount
,
635 IN OUT UINT8
*Buffer
,
636 IN SPI_REGION_TYPE SpiRegionType
642 This function sends the programmed SPI command to the slave device.
646 OpcodeIndex Index of the command in the OpCode Menu.
647 PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
648 DataCycle TRUE if the SPI cycle contains data
649 Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
650 ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
651 Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
652 Region, this value specifies the offset from the Region Base; for BIOS Region,
653 this value specifies the offset from the start of the BIOS Image. In Non
654 Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
655 Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
656 Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
657 supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
658 the flash (in Non Descriptor Mode)
659 DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the
660 data transfer into multiple operations. This function ensures each operation does
661 not cross 256 byte flash address boundary.
662 *NOTE: if there is some SPI chip that has a stricter address boundary requirement
663 (e.g., its write page size is < 256 byte), then the caller cannot rely on this
664 function to cut the data transfer at proper address boundaries, and it's the
665 caller's reponsibility to pass in a properly cut DataByteCount parameter.
666 Buffer Data received or sent during the SPI cycle.
667 SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
668 EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
669 Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
670 and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
671 to base of the 1st flash device (i.e., it is a Flash Linear Address).
675 EFI_SUCCESS SPI command completes successfully.
676 EFI_DEVICE_ERROR Device error, the command aborts abnormally.
677 EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode
678 EFI_INVALID_PARAMETER The parameters specified are not valid.
683 SPI_INSTANCE
*SpiInstance
;
684 UINTN HardwareSpiAddr
;
690 UINTN PchRootComplexBar
;
692 SpiInstance
= SPI_INSTANCE_FROM_SPIPROTOCOL (This
);
693 PchRootComplexBar
= SpiInstance
->PchRootComplexBar
;
694 SpiBiosSize
= SpiInstance
->SpiInitTable
.BiosSize
;
695 OpCode
= MmioRead8 (PchRootComplexBar
+ R_QNC_RCRB_SPIOPMENU
+ OpcodeIndex
);
698 // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0
700 if (OpCode
== 0 || SpiBiosSize
== 0) {
702 return EFI_INVALID_PARAMETER
;
705 SpiOffset2Physical (This
, Address
, SpiRegionType
, &HardwareSpiAddr
, &BaseAddress
, &LimitAddress
);
707 // Have direct access to BIOS region in Descriptor mode,
709 if (SpiInstance
->SpiInitTable
.OpcodeMenu
[OpcodeIndex
].Type
== EnumSpiOpcodeRead
&&
710 SpiRegionType
== EnumSpiRegionBios
) {
713 (UINT8
*) ((HardwareSpiAddr
- BaseAddress
) + (UINT32
) (~(SpiBiosSize
- 1))),
719 // DEBUG((EFI_D_ERROR, "SPIADDR %x, %x, %x, %x\n", Address, HardwareSpiAddr, BaseAddress,
722 if ((DataCycle
== FALSE
) && (DataByteCount
> 0)) {
728 // Trim at 256 byte boundary per operation,
729 // - PCH SPI controller requires trimming at 4KB boundary
730 // - Some SPI chips require trimming at 256 byte boundary for write operation
731 // - Trimming has limited performance impact as we can read / write atmost 64 byte
734 if (HardwareSpiAddr
+ DataByteCount
> ((HardwareSpiAddr
+ BIT8
) &~(BIT8
- 1))) {
735 SpiDataCount
= (((UINT32
) (HardwareSpiAddr
) + BIT8
) &~(BIT8
- 1)) - (UINT32
) (HardwareSpiAddr
);
737 SpiDataCount
= DataByteCount
;
740 // Calculate the number of bytes to shift in/out during the SPI data cycle.
741 // Valid settings for the number of bytes duing each data portion of the
742 // PCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64
744 if (SpiDataCount
>= 64) {
746 } else if ((SpiDataCount
&~0x07) != 0) {
747 SpiDataCount
= SpiDataCount
&~0x07;
750 // If shifts data out, load data into the SPI data buffer.
753 for (Index
= 0; Index
< SpiDataCount
; Index
++) {
754 MmioWrite8 (PchRootComplexBar
+ R_QNC_RCRB_SPID0
+ Index
, Buffer
[Index
]);
755 MmioRead8 (PchRootComplexBar
+ R_QNC_RCRB_SPID0
+ Index
);
760 (PchRootComplexBar
+ R_QNC_RCRB_SPIA
),
761 (UINT32
) (HardwareSpiAddr
& B_QNC_RCRB_SPIA_MASK
)
763 MmioRead32 (PchRootComplexBar
+ R_QNC_RCRB_SPIA
);
766 // Execute the command on the SPI compatible mode
772 MmioOr16 ((PchRootComplexBar
+ R_QNC_RCRB_SPIS
), B_QNC_RCRB_SPIS_BAS
);
775 // Initialte the SPI cycle
779 (PchRootComplexBar
+ R_QNC_RCRB_SPIC
),
780 ( (UINT16
) (B_QNC_RCRB_SPIC_DC
) | (UINT16
) (((SpiDataCount
- 1) << 8) & B_QNC_RCRB_SPIC_DBC
) |
781 (UINT16
) ((OpcodeIndex
<< 4) & B_QNC_RCRB_SPIC_COP
) |
782 (UINT16
) ((PrefixOpcodeIndex
<< 3) & B_QNC_RCRB_SPIC_SPOP
) |
783 (UINT16
) (Atomic
? B_QNC_RCRB_SPIC_ACS
: 0) |
784 (UINT16
) (B_QNC_RCRB_SPIC_SCGO
)));
787 (PchRootComplexBar
+ R_QNC_RCRB_SPIC
),
788 ( (UINT16
) ((OpcodeIndex
<< 4) & B_QNC_RCRB_SPIC_COP
) |
789 (UINT16
) ((PrefixOpcodeIndex
<< 3) & B_QNC_RCRB_SPIC_SPOP
) |
790 (UINT16
) (Atomic
? B_QNC_RCRB_SPIC_ACS
: 0) |
791 (UINT16
) (B_QNC_RCRB_SPIC_SCGO
)));
794 MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIC
);
797 // end of command execution
799 // Wait the SPI cycle to complete.
801 if (!WaitForSpiCycleComplete (This
, TRUE
)) {
802 return EFI_DEVICE_ERROR
;
805 // If shifts data in, get data from the SPI data buffer.
808 for (Index
= 0; Index
< SpiDataCount
; Index
++) {
809 Buffer
[Index
] = MmioRead8 (PchRootComplexBar
+ R_QNC_RCRB_SPID0
+ Index
);
813 HardwareSpiAddr
+= SpiDataCount
;
814 Buffer
+= SpiDataCount
;
815 DataByteCount
-= SpiDataCount
;
816 } while (DataByteCount
> 0);
822 WaitForSpiCycleComplete (
823 IN EFI_SPI_PROTOCOL
*This
,
824 IN BOOLEAN ErrorCheck
830 Wait execution cycle to complete on the SPI interface. Check both Hardware
831 and Software Sequencing status registers
835 This - The SPI protocol instance
836 UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation
837 ErrorCheck - TRUE if the SpiCycle needs to do the error check
841 TRUE SPI cycle completed on the interface.
842 FALSE Time out while waiting the SPI cycle to complete.
843 It's not safe to program the next command on the SPI interface.
850 SPI_INSTANCE
*SpiInstance
;
851 UINTN PchRootComplexBar
;
853 SpiInstance
= SPI_INSTANCE_FROM_SPIPROTOCOL (This
);
854 PchRootComplexBar
= SpiInstance
->PchRootComplexBar
;
857 // Convert the wait period allowed into to tick count
859 WaitCount
= WAIT_TIME
/ WAIT_PERIOD
;
862 // Wait for the SPI cycle to complete.
864 for (WaitTicks
= 0; WaitTicks
< WaitCount
; WaitTicks
++) {
865 Data16
= MmioRead16 (PchRootComplexBar
+ R_QNC_RCRB_SPIS
);
866 if ((Data16
& B_QNC_RCRB_SPIS_SCIP
) == 0) {
867 MmioWrite16 (PchRootComplexBar
+ R_QNC_RCRB_SPIS
, (B_QNC_RCRB_SPIS_BAS
| B_QNC_RCRB_SPIS_CDS
));
868 if ((Data16
& B_QNC_RCRB_SPIS_BAS
) && (ErrorCheck
== TRUE
)) {
875 MicroSecondDelay (WAIT_PERIOD
);
884 IN EFI_SPI_PROTOCOL
*This
,
885 OUT SPI_INIT_INFO
**InitInfoPtr
891 Return info about SPI host controller, to help callers usage of Execute
894 If 0xff is returned as an opcode index in init info struct
895 then device does not support the operation.
899 This Pointer to the EFI_SPI_PROTOCOL instance.
900 InitInfoPtr Pointer to init info written to this memory location.
904 EFI_SUCCESS Information returned.
905 EFI_INVALID_PARAMETER Invalid parameter.
906 EFI_NOT_READY Required resources not setup.
907 Others Unexpected error happened.
911 SPI_INSTANCE
*SpiInstance
;
913 if (This
== NULL
|| InitInfoPtr
== NULL
) {
914 return EFI_INVALID_PARAMETER
;
916 SpiInstance
= SPI_INSTANCE_FROM_SPIPROTOCOL (This
);
917 if (SpiInstance
->Signature
!= PCH_SPI_PRIVATE_DATA_SIGNATURE
) {
918 return EFI_INVALID_PARAMETER
;
921 if (!SpiInstance
->InitDone
) {
923 return EFI_NOT_READY
;
925 *InitInfoPtr
= &SpiInstance
->InitInfo
;