177 lines
5.7 KiB
C
177 lines
5.7 KiB
C
/** @file
|
|
SMM Chipset Services Library.
|
|
|
|
This file contains only one function that is SmmCsSvcSataComReset().
|
|
The function SmmCsSvcSataComReset() use chipset services to reset specified SATA port.
|
|
|
|
;***************************************************************************
|
|
;* Copyright (c) 2017, 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.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Register/PchRegs.h>
|
|
#include <Register/SataRegs.h>
|
|
#include <PortNumberMap.h>
|
|
#include <Library/MmPciLib.h>
|
|
#include <IndustryStandard/Pci22.h>
|
|
#include <Library/PchInfoLib.h>
|
|
#include <Library/SataSocLib.h>
|
|
//[-start-191225-IB16740000-add]// for SataDevNumber & SataFuncNumber function
|
|
#include <Library/PchPciBdfLib.h>
|
|
//[-end-191225-IB16740000-add]//
|
|
|
|
#define V_SATA_CFG_SUB_CLASS_CODE_AHCI 0x06
|
|
#define V_SATA_CFG_SUB_CLASS_CODE_RAID 0x04
|
|
|
|
|
|
//#define ICH_ACPI_TIMER_ADDR 0x0408
|
|
//#define ICH_ACPI_TIMER_MAX_VALUE 0x1000000 // The timer is 24 bit overflow
|
|
#define ACPI_TIMER_ADDR (PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress) + 0x08)
|
|
#define ACPI_TIMER_MAX_VALUE 0x1000000
|
|
|
|
// PCS-Port Control and Status Register.
|
|
// PCH LP Address Offset: 92h-93h. Bit0-Bit5
|
|
// PCH H Address offset: 94h-95h. Bit0-bit7
|
|
// Bit0:Port0 Enable-(R/W), Bit1:Port1 Enable-(R/W)
|
|
// Bit2:Port2 Enable-(R/W), Bit3:Port3 Enable-(R/W)
|
|
// Bit4:Port4 Enable-(R/W), Bit5:Port5 Enable-(R/W)
|
|
// Bit6:Port6 Enable-(R/W), Bit7:Port7 Enable-(R/W)
|
|
UINT16 mAhciPortEnableBit[8] = {BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7};
|
|
|
|
/**
|
|
Waits for at least the given number of microseconds.
|
|
|
|
@param[in] Microseconds Desired length of time to wait.
|
|
|
|
@retval EFI_SUCCESS If the desired amount of time passed.
|
|
*/
|
|
STATIC
|
|
EFI_STATUS
|
|
Stall (
|
|
IN UINTN Microseconds
|
|
)
|
|
{
|
|
UINTN Ticks;
|
|
UINTN Counts;
|
|
UINT32 CurrentTick;
|
|
UINT32 OriginalTick;
|
|
UINT32 RemainingTick;
|
|
|
|
if (Microseconds == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Don't use CpuIO PPI for IO port access here, it will result 915
|
|
// platform recovery fail when using the floppy,because the CpuIO PPI is
|
|
// located at the flash.Use the ASM file to replace it.
|
|
//
|
|
OriginalTick = IoRead32 (ACPI_TIMER_ADDR);
|
|
|
|
CurrentTick = OriginalTick;
|
|
|
|
//
|
|
// The timer frequency is 3.579545 MHz, so 1 ms corresponds 3.58 clocks
|
|
//
|
|
Ticks = Microseconds * 358 / 100 + OriginalTick + 1;
|
|
//
|
|
// The loops needed by timer overflow
|
|
//
|
|
Counts = Ticks / ACPI_TIMER_MAX_VALUE;
|
|
//
|
|
// remaining clocks within one loop
|
|
//
|
|
RemainingTick = (UINT32) Ticks % ACPI_TIMER_MAX_VALUE;
|
|
//
|
|
// not intend to use TMROF_STS bit of register PM1_STS, because this adds extra
|
|
// one I/O operation, and maybe generate SMI
|
|
//
|
|
while (Counts != 0) {
|
|
CurrentTick = IoRead32 (ACPI_TIMER_ADDR);
|
|
|
|
if (CurrentTick <= OriginalTick) {
|
|
Counts--;
|
|
}
|
|
|
|
OriginalTick = CurrentTick;
|
|
}
|
|
|
|
while ((RemainingTick > CurrentTick) && (OriginalTick <= CurrentTick)) {
|
|
OriginalTick = CurrentTick;
|
|
CurrentTick = (UINT32) IoRead32 (ACPI_TIMER_ADDR);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This routine issues SATA COM reset on the specified SATA port
|
|
|
|
@param[in] PortNumber The SATA port number to be reset
|
|
|
|
@retval EFI_SUCCESS The SATA port has been reset successfully
|
|
@retval EFI_DEVICE_ERROR 1.SATA controller isn't in IDE, AHCI or RAID mode.
|
|
2.Get error when getting PortNumberMapTable.
|
|
*/
|
|
EFI_STATUS
|
|
SataComReset (
|
|
IN UINTN PortNumber
|
|
)
|
|
{
|
|
UINT8 SataMode;
|
|
UINT32 BusNumber;
|
|
UINT32 DeviceNumber;
|
|
UINT32 FunctionNumber;
|
|
PORT_NUMBER_MAP *PortNumberMapTable;
|
|
PORT_NUMBER_MAP EndEntry;
|
|
UINT16 PortEnableBit;
|
|
UINTN SataRegBase;
|
|
|
|
BusNumber = 0;
|
|
DeviceNumber = 0;
|
|
FunctionNumber = 0;
|
|
PortEnableBit = 0;
|
|
PortNumberMapTable = NULL;
|
|
SataRegBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, SataDevNumber (SATA_1_CONTROLLER_INDEX), SataFuncNumber (SATA_1_CONTROLLER_INDEX));
|
|
|
|
ZeroMem (&EndEntry, sizeof (PORT_NUMBER_MAP));
|
|
//
|
|
//Get Sata Mode
|
|
//
|
|
SataMode = MmioRead8 (SataRegBase + PCI_CLASSCODE_OFFSET + 1);
|
|
if ((SataMode == V_SATA_CFG_SUB_CLASS_CODE_AHCI) || (SataMode == V_SATA_CFG_SUB_CLASS_CODE_RAID)) {
|
|
//
|
|
//AHCI Mode or RAID Mode => D23:F0
|
|
//
|
|
BusNumber = DEFAULT_PCI_BUS_NUMBER_PCH;
|
|
DeviceNumber = SataDevNumber (SATA_1_CONTROLLER_INDEX);
|
|
FunctionNumber = SataFuncNumber (SATA_1_CONTROLLER_INDEX);
|
|
PortEnableBit = mAhciPortEnableBit[PortNumber];
|
|
|
|
} else {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (IsPchH ()) {
|
|
MmioAnd16 (MmPciBase (BusNumber, DeviceNumber, FunctionNumber) + R_SATA_CFG_PCS, ~PortEnableBit);
|
|
Stall (400);
|
|
MmioOr16 (MmPciBase (BusNumber, DeviceNumber, FunctionNumber) + R_SATA_CFG_PCS, PortEnableBit);
|
|
Stall (400);
|
|
} else {
|
|
MmioAnd16 (MmPciBase (BusNumber, DeviceNumber, FunctionNumber) + R_SATA_CFG_PCS, ~PortEnableBit);
|
|
Stall (400);
|
|
MmioOr16 (MmPciBase (BusNumber, DeviceNumber, FunctionNumber) + R_SATA_CFG_PCS, PortEnableBit);
|
|
Stall (400);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|