/** @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 #include #include #include #include #include #include #include #include #include //[-start-191225-IB16740000-add]// for SataDevNumber & SataFuncNumber function #include //[-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; }