372 lines
13 KiB
C
372 lines
13 KiB
C
/** @file
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2019, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
/** @file
|
|
Initializes Serial IO Spi Controllers.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2018 - 2019 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
|
|
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
|
|
the terms of your license agreement with Intel or your vendor. This file may
|
|
be modified by the user, subject to additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Ppi/SiPolicy.h>
|
|
#include <Library/PeiItssLib.h>
|
|
#include <Library/PchSerialIoLib.h>
|
|
#include <Library/SerialIoPrivateLib.h>
|
|
#include <Library/GpioLib.h>
|
|
#include <Library/GpioNativeLib.h>
|
|
#include <Library/GpioPrivateLib.h>
|
|
#include <Library/GpioNativePads.h>
|
|
#include <Library/PciSegmentLib.h>
|
|
#include <Library/PchPcrLib.h>
|
|
#include <Library/PchInfoLib.h>
|
|
#include <IndustryStandard/Pci30.h>
|
|
#include <Register/PchRegs.h>
|
|
#include <Register/PchRegsSerialIo.h>
|
|
//[-start-190610-IB16990035-add]//
|
|
#include <Register/PchPcrRegs.h>
|
|
//[-end-190610-IB16990035-add]//
|
|
#include <Library/PsfLib.h>
|
|
#include "PeiSerialIoInitDdtPrivateLib.h"
|
|
|
|
/**
|
|
0x224 ChipSelect Control - R_SERIAL_IO_MEM_SPI_CS_CONTROL
|
|
**/
|
|
typedef union {
|
|
struct {
|
|
/**
|
|
SPI Chip Select Mode Section.
|
|
0 = HW Mode - CS is under SSP control,
|
|
1 = SW Mode - CS is under SW Control using CsState bit
|
|
**/
|
|
UINT32 CsMode : 1; //[RW][0]
|
|
/**
|
|
Manual SW control of SPI Chip Select (CS)
|
|
0 = CS is set to low, 1 = CS is set to high
|
|
The state of this bit 0=>CS asserted; 1 => CS de-asserted. The
|
|
state of the CS pin also includes the polarity setting in bits 15:12 of this register.
|
|
**/
|
|
UINT32 CsState : 1; //[RW][1]
|
|
UINT32 Reserved0 : 6; //[N/A][2:7]
|
|
/**
|
|
These Bits select which SPI CS Signal is to be driven by the SSP Frame (CS).
|
|
The steering logic will ensure that when switching to another active SPI CS port
|
|
the inactive port will be forced to the inactive polarity defined by the
|
|
corresponding SPI CS Polarity Bit
|
|
**/
|
|
UINT32 CsOutputSelect : 2; //[RW][8:9]
|
|
UINT32 Reserved1 : 2; //[N/A][10:11]
|
|
/**
|
|
Sets Inactive/Idle polarity of CS0.
|
|
When switching to another active SPI CS port the inactive port
|
|
will be forced to the inactive polarity 0 = Low, 1 = High
|
|
**/
|
|
UINT32 Cs0Polarity : 1; //[RW][12]
|
|
/**
|
|
Sets Inactive/Idle polarity of CS1.
|
|
When switching to another active SPI CS port the inactive port
|
|
will be forced to the inactive polarity 0 = Low, 1 = High
|
|
**/
|
|
UINT32 Cs1Polarity : 1; //[RW][13]
|
|
/**
|
|
Sets Inactive/Idle polarity of CS2.
|
|
When switching to another active SPI CS port the inactive port
|
|
will be forced to the inactive polarity 0 = Low, 1 = High
|
|
**/
|
|
UINT32 Cs2Polarity : 1; //[RW][14]
|
|
/**
|
|
Sets Inactive/Idle polarity of CS3.
|
|
When switching to another active SPI CS port the inactive port
|
|
will be forced to the inactive polarity 0 = Low, 1 = High
|
|
**/
|
|
UINT32 Cs3Polarity : 1; //[RW][15]
|
|
UINT32 Reserved2 : 15; //[N/A][16:31]
|
|
} Fields;
|
|
UINT32 Data;
|
|
} SERIAL_IO_SPI_CS_CONTROL_REG;
|
|
|
|
/**
|
|
Configure Chip Select settings
|
|
|
|
@param[in] Base SPI MMIO BAR0
|
|
@param[in] SpiDeviceConfig SerialIo SPI Config
|
|
|
|
**/
|
|
VOID
|
|
STATIC
|
|
SerialIoSpiChipSelectConfig (
|
|
IN UINT64 MmioBase,
|
|
IN SERIAL_IO_SPI_CONFIG *SpiDeviceConfig
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
SERIAL_IO_SPI_CS_CONTROL_REG SpiCsControl;
|
|
|
|
SpiCsControl.Data = MmioRead32 ((UINTN) (MmioBase + R_SERIAL_IO_MEM_SPI_CS_CONTROL));
|
|
|
|
//
|
|
// Set CS mode
|
|
//
|
|
SpiCsControl.Fields.CsMode = SpiDeviceConfig->CsMode;
|
|
|
|
for (Index = 0; Index < GetPchMaxSerialIoSpiChipSelectsNum (); Index++) {
|
|
if (SpiDeviceConfig->CsEnable[Index]) {
|
|
//
|
|
// Set CS polarity
|
|
//
|
|
if (Index == 0) {
|
|
SpiCsControl.Fields.Cs0Polarity = SpiDeviceConfig->CsPolarity[Index];
|
|
}
|
|
if (Index == 1) {
|
|
SpiCsControl.Fields.Cs1Polarity = SpiDeviceConfig->CsPolarity[Index];
|
|
}
|
|
if (Index == 2) {
|
|
SpiCsControl.Fields.Cs2Polarity = SpiDeviceConfig->CsPolarity[Index];
|
|
}
|
|
if (Index == 3) {
|
|
SpiCsControl.Fields.Cs3Polarity = SpiDeviceConfig->CsPolarity[Index];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set CS Output Select
|
|
//
|
|
SpiCsControl.Fields.CsOutputSelect = SpiDeviceConfig->DefaultCsOutput;
|
|
|
|
//
|
|
// Set CS state
|
|
//
|
|
SpiCsControl.Fields.CsState = SpiDeviceConfig->CsState;
|
|
|
|
MmioWrite32 ((UINTN) (MmioBase + R_SERIAL_IO_MEM_SPI_CS_CONTROL), SpiCsControl.Data);
|
|
}
|
|
|
|
/**
|
|
Configures GPIO for each Serial IO SPI Controller
|
|
|
|
@param[in] SpiNumber SPI Number
|
|
@param[in] SpiDeviceConfig SerialIo SPI Config
|
|
|
|
**/
|
|
VOID
|
|
STATIC
|
|
SerialIoSpiGpioConfiguration (
|
|
IN UINT8 SpiNumber,
|
|
IN SERIAL_IO_SPI_CONFIG *SpiDeviceConfig
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
GpioSetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_MOSI (SpiNumber), 0);
|
|
GpioSetInputInversion (GpioGetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_MOSI (SpiNumber)), 0);
|
|
GpioSetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_MISO (SpiNumber), 0);
|
|
GpioSetInputInversion (GpioGetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_MISO (SpiNumber)), 0);
|
|
GpioSetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_CLK (SpiNumber), 0);
|
|
GpioSetInputInversion (GpioGetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_CLK (SpiNumber)), 0);
|
|
|
|
for (Index = 0; Index < GetPchMaxSerialIoSpiChipSelectsNum (); Index++) {
|
|
if (SpiDeviceConfig->CsEnable[Index]) {
|
|
GpioSetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_CS (SpiNumber, Index), 0);
|
|
GpioSetInputInversion (GpioGetNativePadByFunction (GPIO_FUNCTION_SERIAL_IO_SPI_CS (SpiNumber, Index)), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Configures Serial IO Controller
|
|
|
|
@param[in] SpiNumber SPI Number
|
|
@param[in] SpiDeviceConfig SerialIo SPI Config
|
|
@param[in] PsfDisable Applies only for SerialIoSpiDisabled devices.
|
|
TRUE - Device will be disabled in PSF, and will no longer enumerate on PCI.
|
|
FALSE - PSF configuration is left unmodified.
|
|
|
|
**/
|
|
VOID
|
|
SerialIoSpiConfiguration (
|
|
IN UINT8 SpiNumber,
|
|
IN SERIAL_IO_SPI_CONFIG *SpiDeviceConfig,
|
|
IN BOOLEAN PsfDisable
|
|
)
|
|
{
|
|
SERIAL_IO_PCI_DEVICE_STATE PciState;
|
|
UINT64 PciCfgBase;
|
|
UINT64 Base;
|
|
BOOLEAN TempBar;
|
|
BOOLEAN Hidden;
|
|
|
|
PciState.PciCfgBar0 = 0x0;
|
|
TempBar = FALSE;
|
|
Hidden = FALSE;
|
|
Base = 0x0;
|
|
|
|
//
|
|
// This is to prevent from overflow of array access.
|
|
//
|
|
if (SpiNumber >= PCH_MAX_SERIALIO_SPI_CONTROLLERS) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Override previous SPI configuration
|
|
//
|
|
SerialIoPciPsfEnable (GetSerialIoSpiConfigControlOffset (SpiNumber), PsfSerialIoSpiPort (SpiNumber));
|
|
|
|
PciCfgBase = PCI_SEGMENT_LIB_ADDRESS (
|
|
DEFAULT_PCI_SEGMENT_NUMBER_PCH,
|
|
DEFAULT_PCI_BUS_NUMBER_PCH,
|
|
GetSerialIoSpiDeviceNumber (SpiNumber),
|
|
GetSerialIoSpiFunctionNumber (SpiNumber),
|
|
0
|
|
);
|
|
|
|
SerialIoEnablePowerGating (PciCfgBase);
|
|
|
|
switch (SpiDeviceConfig->Mode) {
|
|
case SerialIoSpiDisabled:
|
|
SerialIoSetD3 (PciCfgBase);
|
|
if (PsfDisable) {
|
|
PsfDisableDevice (PsfSerialIoSpiPort (SpiNumber));
|
|
}
|
|
return;
|
|
case SerialIoSpiHidden:
|
|
SerialIoSetFixedMmio (PciCfgBase,
|
|
GetSerialIoSpiFixedMmioAddress (SpiNumber),
|
|
GetSerialIoSpiFixedPciCfgAddress (SpiNumber),
|
|
GetSerialIoSpiConfigControlOffset (SpiNumber),
|
|
PsfSerialIoSpiPort (SpiNumber)
|
|
);
|
|
PciCfgBase = GetSerialIoSpiFixedPciCfgAddress (SpiNumber);
|
|
Hidden = TRUE;
|
|
break;
|
|
case SerialIoSpiPci:
|
|
SerialIoPciSave (PciCfgBase, &PciState);
|
|
SerialIoPciEnable (GetSerialIoSpiConfigControlOffset (SpiNumber), PsfSerialIoSpiPort (SpiNumber));
|
|
TempBar = TRUE;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (SerialIoMmioEnable (PciCfgBase, TempBar, Hidden, &Base)) {
|
|
SerialIoSpiChipSelectConfig (Base, SpiDeviceConfig);
|
|
if (SpiDeviceConfig->Mode == SerialIoSpiPci) {
|
|
if (PciState.PciCfgBar0 == 0x0) {
|
|
SerialIoSetD3 (PciCfgBase);
|
|
SerialIoMmioDisable (PciCfgBase, TempBar);
|
|
} else {
|
|
SerialIoPciRestore (PciCfgBase, &PciState);
|
|
}
|
|
}
|
|
}
|
|
|
|
SerialIoSpiGpioConfiguration (SpiNumber, SpiDeviceConfig);
|
|
}
|
|
|
|
/**
|
|
Configures Serial IO Spi Controllers
|
|
|
|
@param[in] SiPolicy Silicon policy
|
|
@param[in] SerialIoConfig SerialIo Config Block
|
|
|
|
**/
|
|
VOID
|
|
SerialIoSpiInit (
|
|
IN SI_POLICY_PPI *SiPolicy,
|
|
IN PCH_SERIAL_IO_CONFIG *SerialIoConfig
|
|
)
|
|
{
|
|
UINT8 SpiNumber;
|
|
UINT8 InterruptPin;
|
|
UINT8 Irq;
|
|
|
|
DEBUG ((DEBUG_INFO, "SerialIoSpiInit() Start\n"));
|
|
|
|
for (SpiNumber = 0; SpiNumber < GetPchMaxSerialIoSpiControllersNum (); SpiNumber++) {
|
|
if ((SerialIoConfig->SpiDeviceConfig[SpiNumber].Mode == SerialIoSpiDisabled) &&
|
|
(GetSerialIoSpiFunctionNumber (SpiNumber) == 0x0)) {
|
|
continue;
|
|
}
|
|
if (SerialIoConfig->SpiDeviceConfig[SpiNumber].Mode != SerialIoSpiDisabled) {
|
|
ItssGetDevIntConfig (SiPolicy, GetSerialIoSpiDeviceNumber (SpiNumber), GetSerialIoSpiFunctionNumber (SpiNumber), &InterruptPin, &Irq);
|
|
SerialIoInterruptSet (GetSerialIoSpiConfigControlOffset (SpiNumber), InterruptPin, Irq);
|
|
}
|
|
SerialIoSpiConfiguration (SpiNumber, &SerialIoConfig->SpiDeviceConfig[SpiNumber], TRUE);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "SerialIoSpiInit() End\n"));
|
|
}
|
|
|
|
/**
|
|
Configures Serial IO Spi Function 0 Disabled Controllers
|
|
|
|
@param[in] SiPolicy Silicon policy
|
|
@param[in] SerialIoConfig SerialIo Config Block
|
|
|
|
**/
|
|
VOID
|
|
SerialIoSpiFunction0Disable (
|
|
IN SI_POLICY_PPI *SiPolicy,
|
|
IN PCH_SERIAL_IO_CONFIG *SerialIoConfig
|
|
)
|
|
{
|
|
UINT8 SpiNumber;
|
|
BOOLEAN PsfDisable;
|
|
UINT8 InterruptPin;
|
|
UINT8 Irq;
|
|
|
|
for (SpiNumber = 0; SpiNumber < GetPchMaxSerialIoSpiControllersNum (); SpiNumber++) {
|
|
PsfDisable = TRUE;
|
|
if ((SerialIoConfig->SpiDeviceConfig[SpiNumber].Mode == SerialIoSpiDisabled) &&
|
|
(GetSerialIoSpiFunctionNumber (SpiNumber) == 0x0)) {
|
|
if (SerialIoHigherFunctionsEnabled (GetSerialIoSpiDeviceNumber (SpiNumber))) {
|
|
SerialIoBar1Disable (GetSerialIoSpiConfigControlOffset (SpiNumber), PsfSerialIoSpiPort (SpiNumber));
|
|
ItssGetDevIntConfig (SiPolicy, GetSerialIoSpiDeviceNumber (SpiNumber), GetSerialIoSpiFunctionNumber (SpiNumber), &InterruptPin, &Irq);
|
|
SerialIoInterruptSet (GetSerialIoSpiConfigControlOffset (SpiNumber), InterruptPin, Irq);
|
|
PsfDisable = FALSE;
|
|
}
|
|
SerialIoSpiConfiguration (SpiNumber, &SerialIoConfig->SpiDeviceConfig[SpiNumber], PsfDisable);
|
|
}
|
|
}
|
|
}
|
|
|