/** @file Configures PCH Sata Controller @copyright Copyright (c) 2008 - 2013 Intel Corporation. All rights reserved This software and associated documentation (if any) is furnished under a license and may only be used or copied in accordance with the terms of the license. Except as permitted by such license, no part of this software or documentation may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. This file contains an 'Intel Peripheral Driver' and 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 **/ #include "PchInit.h" EFI_STATUS ConfigureSataAhci ( DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, UINT32 RootComplexBar, UINT16 GpioBase ); EFI_STATUS ConfigureSataSpeedIde ( DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, UINTN PciDevFuncRegBase, UINTN MaxPorts ); EFI_STATUS DisableSataController ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN OUT UINT32 *FuncDisableReg ); /** Configures PCH Sata Controller @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance @param[in] RootComplexBar RootComplexBar value of this PCH device @param[in, out] FuncDisableReg Function Disable Register @param[in] GpioBase GPIO base address of this PCH device @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS ConfigureSata ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN UINT32 RootComplexBar, IN OUT UINT32 *FuncDisableReg, IN UINT16 GpioBase ) { EFI_STATUS Status; UINT32 Index; UINT16 WordReg; UINT16 SataGcReg; UINTN PciD31F2RegBase; PCH_SATA_CONFIG *SataConfig; UINT16 SataPortsEnabled; UINT16 SataModeSelect; UINTN PciD31F5RegBase; UINTN PciDevFuncRegBase; UINTN MaxPorts; UINT32 Data32And; UINT32 Data32Or; PCH_SERIES PchSeries; DEBUG ((EFI_D_INFO, "ConfigureSata() Start\n")); PchSeries = GetPchSeries(); SataConfig = PchPlatformPolicy->SataConfig; PciD31F2RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 2, 0); PciD31F5RegBase = 0; if (PchSeries == PchH) { PciD31F5RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 5, 0); } SataModeSelect = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_MAP) & B_PCH_SATA_MAP_SMS_MASK; Status = EFI_SUCCESS; /// /// Check to disable SATA controller /// if (PchPlatformPolicy->DeviceEnabling->Sata == PCH_DEVICE_DISABLE) { Status = DisableSataController (PchPlatformPolicy, FuncDisableReg); return Status; } /// /// PCH BIOS Spec Rev 0.5.0 section 14.1.7 Additional Programming Requirements during /// SATA Initialization /// Step 12 /// Program D31:F2:9Ch[5] to 1b (Note: this must be programmed together with D31:F2:9Ch[7:6] /// in word write) /// SataGcReg = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_SCLKGC); SataGcReg |= BIT5; switch (SataModeSelect) { #ifdef TRAD_FLAG case V_PCH_SATA_MAP_SMS_IDE: if (PchSeries == PchH) { /// /// Set Native IDE decoding /// /// PCH BIOS Spec Rev 0.5.0 Section 14.1.3 Set the Programming Interface /// Using native IDE is only possible when the SATA controller is operating in IDE mode. /// The programming interface is selected by setting the programming interface register /// (PI = Reg: 09h) appropriately. There are two native mode enabling bits in the /// PI register to control the primary and secondary channels of SATA1. /// /// Only D31:F2 needs to be set. D31:F5 is readonly /// if (SataConfig->LegacyMode == PCH_DEVICE_ENABLE) { MmioAnd8 ( PciD31F2RegBase + R_PCH_SATA_PI_REGISTER, (UINT8)~(B_PCH_SATA_PI_REGISTER_PNE | B_PCH_SATA_PI_REGISTER_SNE) ); } else { MmioOr8 ( PciD31F2RegBase + R_PCH_SATA_PI_REGISTER, (UINT8) B_PCH_SATA_PI_REGISTER_PNE | B_PCH_SATA_PI_REGISTER_SNE ); } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F2RegBase + R_PCH_SATA_PI_REGISTER), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_PI_REGISTER) ); MmioOr16 ((UINTN) (PciD31F5RegBase + R_PCH_SATA_TIMP), (UINT16) (B_PCH_SATA_TIM_IDE)); WordReg = MmioRead16 (PciD31F5RegBase + R_PCH_SATA_TIMP); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F5RegBase + R_PCH_SATA_TIMP), 1, &WordReg ); MmioOr16 ((UINTN) (PciD31F5RegBase + R_PCH_SATA_TIMS), (UINT16) (B_PCH_SATA_TIM_IDE)); WordReg = MmioRead16 (PciD31F5RegBase + R_PCH_SATA_TIMS); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F5RegBase + R_PCH_SATA_TIMS), 1, &WordReg ); } break; #endif // TRAD_FLAG case V_PCH_SATA_MAP_SMS_RAID: /// /// When RAID alternate ID is enabled, the Device ID will change to 30XX from 282X in RAID mode /// if (SataConfig->RaidAlternateId == PCH_DEVICE_ENABLE) { SataGcReg &= ~B_PCH_SATA_SCLKGC_AIES; SataGcReg |= B_PCH_SATA_SCLKGC_AIE; } #ifdef PCH_SVR_WS_SKU SataGcReg &= ~B_PCH_SATA_SCLKGC_AIE; SataGcReg |= B_PCH_SATA_SCLKGC_AIES; #endif break; } /// /// Unconditional write is necessary to lock the register /// MmioWrite16 (PciD31F2RegBase + R_PCH_SATA_SCLKGC, SataGcReg); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKGC), 1, &SataGcReg ); /// /// Set legacy IDE decoding /// These bits also effect with AHCI mode when PCH is using legacy mechanisms. /// MmioOr16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_TIMP), (UINT16) (B_PCH_SATA_TIM_IDE)); WordReg = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_TIMP); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_TIMP), 1, &WordReg ); MmioOr16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_TIMS), (UINT16) (B_PCH_SATA_TIM_IDE)); WordReg = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_TIMS); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_TIMS), 1, &WordReg ); /// /// PCH BIOS Spec Rev 0.5.0, section 19.10 /// Step 4.2 /// D31:F2 PCS: Enable the port in any of below condition: /// Hot plug is enabled /// A device is attached /// Test mode is enabled /// Configured as eSATA port /// SataPortsEnabled = 0; WordReg = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_PCS); for (Index = 0; Index < GetPchMaxSataPortNum (); Index++) { if ((SataConfig->PortSettings[Index].HotPlug == PCH_DEVICE_ENABLE) || (WordReg & (BIT0 << (8 + Index))) || (SataConfig->TestMode == PCH_DEVICE_ENABLE) || (SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE)) { SataPortsEnabled |= (SataConfig->PortSettings[Index].Enable << Index); } } if (PchSeries == PchH) { /// /// D31:F5 PCS: Enable the port in any of below condition: /// Hot plug is enabled /// A device is attached /// Test mode is enabled /// /// Note: In IDE mode, SATA Port 4/5 enable status needs to be checked before setting D31:F2 MAP[13:8]. /// It's because: /// (1) SataPortsEnabled [5:4] will be set while it is configured as eSATA port that is not /// supported in IDE mode. /// (2) D31:F2 MAP[12] setting needs to sync up with D31:F5 MAP[8] setting. /// D31:F2 MAP[13] setting needs to sync up with D31:F5 MAP[9] setting. /// if (SataModeSelect == V_PCH_SATA_MAP_SMS_IDE) { /// /// Clear SataPortsEnabled [5:4] before checking SATA Port 4/5 enable status /// SataPortsEnabled &= ~(BIT5 | BIT4); WordReg = MmioRead16 (PciD31F5RegBase + R_PCH_SATA_PCS); for (Index = 4; Index < GetPchMaxSataPortNum (); Index++) { /// /// D31:F5 PCS[9:8] = Port 4/5 Present bit /// if ((SataConfig->PortSettings[Index].HotPlug == PCH_DEVICE_ENABLE) || (WordReg & (BIT0 << (4 + Index))) || (SataConfig->TestMode == PCH_DEVICE_ENABLE)) { /// /// SataPortsEnabled [5:4] = Sata Port 4/5 enable status /// SataPortsEnabled |= (SataConfig->PortSettings[Index].Enable << Index); } } } } /// /// Set MAP register for PCH H /// Set D31:F2 MAP[13:8] to 1b if SATA Port 0/1/2/3/4/5 is disabled /// SataPortsEnabled [5:0] = Sata Port 0/1/2/3/4/5 enable status /// MAP.SPD (D31:F2:Reg90h[13:8]) is Write Once /// /// Set MAP register for PCH LP /// Set D31:F2 MAP[11:8] to 1b if SATA Port 0/1/2/3 is disabled /// SataPortsEnabled [3:0] = Sata Port 0/1/2/3 enable status /// MAP.SPD (D31:F2:Reg90h[11:8]) is Write Once /// switch (PchSeries) { case PchLp: MmioOr16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_MAP), ((~SataPortsEnabled << 8) & (UINT16) B_PCH_LP_SATA_MAP_SPD)); break; case PchH: MmioOr16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_MAP), ((~SataPortsEnabled << 8) & (UINT16) B_PCH_H_SATA_MAP_SPD)); break; default: break; } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_MAP), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_MAP) ); // // D31:F2 PCS[5:0] = Port 0~5 Enabled bit // as per SataPortsEnabled value. // MmioOr16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS), (UINT16) (SataPortsEnabled)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS) ); #ifdef TRAD_FLAG if (PchSeries == PchH) { /// /// Set D31:F5 MAP[9:8] and D31:F5 PCS[1:0] /// if (SataModeSelect == V_PCH_SATA_MAP_SMS_IDE) { /// /// Set D31:F5 MAP[9:8] to 1b if SATA Port 4/5 is disabled /// SataPortsEnabled [5:4] = Sata Port 4/5 enable status /// MAP.SPD (D31:F5:Reg90h[9:8]) is Write Once /// MmioOr16 ((UINTN) (PciD31F5RegBase + R_PCH_SATA_MAP), ((~SataPortsEnabled << 4) & (UINT16) B_PCH_SATA2_MAP_SPD)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F5RegBase + R_PCH_SATA_MAP), 1, (VOID *) (UINTN) (PciD31F5RegBase + R_PCH_SATA_MAP) ); /// /// D31:F5 PCS[1:0] = Port 4/5 Enabled bit /// MmioAndThenOr16 ( (UINTN) (PciD31F5RegBase + R_PCH_SATA_PCS), (UINT16) (~(B_PCH_SATA2_PCS_PORT5_EN | B_PCH_SATA2_PCS_PORT4_EN)), (UINT16) (SataPortsEnabled >> 4) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F5RegBase + R_PCH_SATA_PCS), 1, (VOID *) (UINTN) (PciD31F5RegBase + R_PCH_SATA_PCS) ); } } #endif // TRAD_FLAG /// /// PCH BIOS Spec Rev 0.5.0, section 19.10 /// Step 4.2 /// After configuring Port and Control Status (PCS) Register Port x Enabled (PxE) bits accordingly, /// wait 1.4 micro second /// PchPmTimerStall (0x02); SCRIPT_STALL (EFI_ACPI_S3_RESUME_SCRIPT_TABLE, 0x02); /// /// After programming the PCS.PxE, check if it is zero. /// If no port enabled, terminate the SATA configuration and disable the SATA controller. /// WordReg = MmioRead16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS)); WordReg &= (UINT16) ((1 << GetPchMaxSataPortNum ()) - 1); #ifdef TRAD_FLAG if (WordReg == 0) { if ((PchSeries == PchH) && (SataModeSelect == V_PCH_SATA_MAP_SMS_IDE)) { WordReg = MmioRead16 ((UINTN) (PciD31F5RegBase + R_PCH_SATA_PCS)); WordReg &= (UINT16) (B_PCH_SATA2_PCS_PORT5_EN | B_PCH_SATA2_PCS_PORT4_EN); } } #endif // TRAD_FLAG if (WordReg == 0) { Status = DisableSataController (PchPlatformPolicy, FuncDisableReg); return Status; } if (PchSeries == PchLp) { /// /// If Listen Mode support is not required, program D31:F2:98h[24] to 1b. /// if ((SataConfig->PortSettings[0].HotPlug == PCH_DEVICE_DISABLE) && (SataConfig->PortSettings[1].HotPlug == PCH_DEVICE_DISABLE) && (SataConfig->PortSettings[2].HotPlug == PCH_DEVICE_DISABLE) && (SataConfig->PortSettings[3].HotPlug == PCH_DEVICE_DISABLE)) { MmioOr32 ((UINTN) (PciD31F2RegBase + 0x98), (UINT32) (BIT24)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + 0x98), 1, (VOID *) (UINTN) (PciD31F2RegBase + 0x98) ); } } /// /// Configure AHCI /// if (PchSeries == PchLp) { if (SataModeSelect != V_PCH_SATA_MAP_SMS_LOOBACK_TESTMODE) { Status = ConfigureSataAhci (PchPlatformPolicy, RootComplexBar, GpioBase); } } else if (PchSeries == PchH) { if (SataModeSelect != V_PCH_SATA_MAP_SMS_IDE) { Status = ConfigureSataAhci (PchPlatformPolicy, RootComplexBar, GpioBase); } else { /// /// If it is IDE mode /// if(PchPlatformPolicy->SataConfig->SpeedSupport != PchSataSpeedSupportDefault){ PciDevFuncRegBase = 0; MaxPorts = 0; for (Index = 0; Index < GetPchMaxSataControllerNum (); Index++) { switch (Index) { case 0: PciDevFuncRegBase = PciD31F2RegBase; MaxPorts = PCH_IDE_1_MAX_PORTS; break; case 1: PciDevFuncRegBase = PciD31F5RegBase; MaxPorts = PCH_IDE_2_MAX_PORTS; break; } Status = ConfigureSataSpeedIde (PchPlatformPolicy, PciDevFuncRegBase, MaxPorts); } } } } /// /// PCH BIOS Spec Rev 0.5.0, section 19.10 /// Step 4.1 /// Set bits D31:F2:Reg 94h[29:24] to 3Fh as part of the chipset initialization and before disabling the /// SATA function if the SATA interface is not supported. BIOS can also set PCD bits for the un-routed ports /// on the platform to disable clocks for the unused ports /// Set the PCD [port x] = 1 if the corresponding PCS.PxE = 0 (either have a device attached or have /// hot plug enabled) /// for (Index = 0; Index < GetPchMaxSataPortNum (); Index++) { if ((SataPortsEnabled & (B_PCH_SATA_PCS_PORT0_EN << Index)) == 0) { MmioOr32 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), (UINT32) (B_PCH_SATA_SCLKCG_PORT0_PCD << Index)); } } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG) ); /// /// PCH BIOS Spec Rev 0.5.6, 14.1.6 Power Optimizer Configuration /// System BIOS must execute the following steps as part of System BIOS initialization /// of the PCH SATA controller on both cold boot (G3/S5) and S3/S4 resume path. Please /// refer to the PCH EDS, section 14.1.35.1 for the SATA initialization settings and /// the actual register indexes/values to be programmed. /// if (PchPlatformPolicy->PwrOptConfig->PchPwrOptSata == PCH_DEVICE_ENABLE) { /// /// Step 1 /// Set D31:F2 + SIR Index 64h[31:0] = 883C9001h /// MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x64); if (PchSeries == PchH) { MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_STRD, 0x883C9001); } if (PchSeries == PchLp) { MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_STRD, 0x883C9003); } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) ); /// /// Step 2 /// Set D31:F2 + SIR Index 68h[15:0] = 880Ah /// MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x68); Data32And = 0xFFFF0000; Data32Or = 0x0000880A; MmioAndThenOr32 ( (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), Data32And, Data32Or ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) ); /// /// Step 3 /// Set D31:F2 + SIR Index 60h[3] = 1b /// MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x60); Data32And = 0xFFFFFFF7; Data32Or = 0x00000008; MmioAndThenOr32 ( (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), Data32And, Data32Or ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) ); /// /// Step 4 /// Set D31:F2 + SIR Index 60h[0] = 1b /// MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x60); Data32And = 0xFFFFFFFE; //for Denlow SVR, refer Inel doc 493798, c state communication #ifdef PCH_DENLOW_SERVER_SUPPORT /// Set D31:F2 + SIR Index 60h[0] = 0b Data32Or = 0x00000000; #else Data32Or = 0x00000001; #endif MmioAndThenOr32 ( (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), Data32And, Data32Or ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) ); /// /// Step 5 /// Set D31:F2 + SIR Index 60h[1] = 1b /// MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x60); Data32And = 0xFFFFFFFD; Data32Or = 0x00000002; MmioAndThenOr32 ( (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), Data32And, Data32Or ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) ); } #ifdef TRAD_FLAG /// /// For dual controller IDE mode, disable the individual controller if no port enabled. /// For SATA2, the SATA configuration should be done through SATA1. /// Therefore, disabling the SATA1/SATA2 after finishing SATA configuration. /// if (PchSeries == PchH) { if (SataModeSelect == V_PCH_SATA_MAP_SMS_IDE) { WordReg = MmioRead16 (PciD31F5RegBase + R_PCH_SATA_PCS); WordReg &= (UINT16) (B_PCH_SATA2_PCS_PORT5_EN | B_PCH_SATA2_PCS_PORT4_EN); if (WordReg == 0) { *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_SATA2; } WordReg = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_PCS); WordReg &= (UINT16) (B_PCH_SATA_PCS_PORT3_EN | B_PCH_SATA_PCS_PORT2_EN | B_PCH_SATA_PCS_PORT1_EN | B_PCH_SATA_PCS_PORT0_EN); if (WordReg == 0) { *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_SATA1; } } } #endif // TRAD_FLAG DEBUG ((EFI_D_INFO, "ConfigureSata() End\n")); return Status; } /** Program the Max speed suported in each ports while in IDE mode. @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance. @param[in] PciDevFuncRegBase Pci B/D/F/Reg Base for the Sata controler. @param[in] MaxPorts Max Sata ports supported in the Controller. @retval EFI_SUCESS The function exited sucessfully @retval EFI_OUT_OF_RESOURCES Insufficient resources are available **/ EFI_STATUS ConfigureSataSpeedIde ( DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, UINTN PciDevFuncRegBase, UINTN MaxPorts ) { EFI_STATUS Status; #ifdef TRAD_FLAG PCH_SATA_CONFIG *SataConfig; EFI_PHYSICAL_ADDRESS IoBaseAddress; UINT16 SidpBa; UINT16 SidpBaSaveRestore; UINT16 DevCmdSaveRestore; UINT8 Data8; UINT16 Data16; UINTN PortIndex; Data16 = 0; Data8 = 0; SataConfig = PchPlatformPolicy->SataConfig; Status = gDS->AllocateIoSpace ( EfiGcdAllocateAnySearchBottomUp, EfiGcdIoTypeIo, N_PCH_SATA_SIDP_BAR_ALIGNMENT, V_PCH_SATA_SIDP_BAR_LENGTH, &IoBaseAddress, mImageHandle, NULL ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } /// /// Set the SIDP BAR /// SidpBa = (UINT16) IoBaseAddress; SidpBaSaveRestore = MmioRead16 (PciDevFuncRegBase + R_PCH_SATA_SIDP_BAR); MmioWrite16 (PciDevFuncRegBase + R_PCH_SATA_SIDP_BAR, SidpBa); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciDevFuncRegBase + R_PCH_SATA_SIDP_BAR), 1, &SidpBa ); /// /// Enable command register I/O space decoding /// DevCmdSaveRestore = MmioRead16 (PciDevFuncRegBase + R_PCH_SATA_COMMAND); MmioOr16 ((UINTN) (PciDevFuncRegBase + R_PCH_SATA_COMMAND), (UINT16) B_PCH_SATA_COMMAND_IOSE); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciDevFuncRegBase + R_PCH_SATA_COMMAND), 1, (VOID *) (UINTN) (PciDevFuncRegBase + R_PCH_SATA_COMMAND) ); /// /// Configure for the max speed support 1.5Gb/s, 3.0Gb/s and 6.0Gb/s. /// for (PortIndex = 0; PortIndex < MaxPorts; PortIndex++) { switch (PortIndex) { case 0: Data16 = V_PCH_SATA_AHCI_SINDX_RIDX_SCTL | V_PCH_SATA_AHCI_SINDX_PIDX_PORT0; break; case 1: Data16 = V_PCH_SATA_AHCI_SINDX_RIDX_SCTL | V_PCH_SATA_AHCI_SINDX_PIDX_PORT1; break; case 2: Data16 = V_PCH_SATA_AHCI_SINDX_RIDX_SCTL | V_PCH_SATA_AHCI_SINDX_PIDX_PORT2; break; case 3: Data16 = V_PCH_SATA_AHCI_SINDX_RIDX_SCTL | V_PCH_SATA_AHCI_SINDX_PIDX_PORT3; break; } IoWrite16 ((UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SINDX), Data16); SCRIPT_IO_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SINDX), 1, &Data16 ); switch (SataConfig->SpeedSupport) { case PchSataSpeedSupportGen1: Data8 = V_PCH_SATA_SIDPBA_SDATA_GEN1; break; case PchSataSpeedSupportGen2: Data8 = V_PCH_SATA_SIDPBA_SDATA_GEN2; break; case PchSataSpeedSupportGen3: Data8 = V_PCH_SATA_SIDPBA_SDATA_GEN3; break; } IoWrite8 ((UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SDATA), Data8); SCRIPT_IO_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SDATA), 1, &Data8 ); Data16 = MmioRead16 ((UINTN) (PciDevFuncRegBase + R_PCH_SATA_PCS)) >> 8; if(((Data16 >> PortIndex) & BIT0)){ Data8 = (IoRead8 (SidpBa + R_PCH_SATA_SIDPBA_SDATA) & ~B_PCH_SATA_SIDPBA_SCTL_DET) + V_PCH_SATA_SIDPBA_SCTL_DET_COMRST; IoWrite8 ((UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SDATA), Data8); SCRIPT_IO_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SDATA), 1, &Data8 ); PchPmTimerStall (1000); SCRIPT_STALL (EFI_ACPI_S3_RESUME_SCRIPT_TABLE, 1000); Data8 = (IoRead8 (SidpBa + R_PCH_SATA_SIDPBA_SDATA) & ~B_PCH_SATA_SIDPBA_SCTL_DET) + V_PCH_SATA_SIDPBA_SCTL_DET_NOINT; IoWrite8 ((UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SDATA), Data8); SCRIPT_IO_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (SidpBa + R_PCH_SATA_SIDPBA_SDATA), 1, &Data8 ); } } /// /// Restore command register I/O space decoding /// MmioWrite16 (PciDevFuncRegBase + R_PCH_SATA_COMMAND, DevCmdSaveRestore); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciDevFuncRegBase + R_PCH_SATA_COMMAND), 1, &DevCmdSaveRestore ); /// /// Restore the SIDP BAR /// MmioWrite16 (PciDevFuncRegBase + R_PCH_SATA_SIDP_BAR, SidpBaSaveRestore); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciDevFuncRegBase + R_PCH_SATA_SIDP_BAR), 1, &SidpBaSaveRestore ); /// /// Free allocated resources /// gDS->FreeIoSpace (IoBaseAddress, (UINT64) V_PCH_SATA_SIDP_BAR_LENGTH); #else Status = EFI_SUCCESS; #endif // TRAD_FLAG return Status; } /** Program AHCI PI register for Enabled ports Handle hotplug, and interlock switch setting, and config related GPIOs. @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance @param[in] RootComplexBar RootComplexBar value of this PCH device @param[in] GpioBase GPIO base address of this PCH device @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS ConfigureSataAhci ( DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, UINT32 RootComplexBar, UINT16 GpioBase ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS MemBaseAddress; UINT32 AhciBar; UINT32 CapRegister; UINT32 Data32And; UINT32 Data32Or; UINT32 DwordReg; UINT32 PxCMDRegister; UINT16 SataPortsEnabled; UINT8 Index; UINTN PciD31F2RegBase; UINT16 WordReg; UINT8 ByteReg; PCH_SATA_CONFIG *SataConfig; UINT16 SataModeSelect; PCH_SERIES PchSeries; UINT8 SataResetGpio[LPTH_AHCI_MAX_PORTS] = { PCH_GPIO_SATA_PORT0_RESET, PCH_GPIO_SATA_PORT1_RESET, PCH_GPIO_SATA_PORT2_RESET, PCH_GPIO_SATA_PORT3_RESET, PCH_GPIO_SATA_PORT4_RESET, PCH_GPIO_SATA_PORT5_RESET, }; UINT16 SataResetLpGpio[LPTLP_AHCI_MAX_PORTS] = { PCH_LP_GPIO_SATA_PORT0_RESET, PCH_LP_GPIO_SATA_PORT1_RESET, PCH_LP_GPIO_SATA_PORT2_RESET, PCH_LP_GPIO_SATA_PORT3_RESET, }; DEBUG ((EFI_D_INFO, "ConfigureSataAhci() Start\n")); PchSeries = GetPchSeries(); SataConfig = PchPlatformPolicy->SataConfig; PciD31F2RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 2, 0); SataModeSelect = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_MAP) & B_PCH_SATA_MAP_SMS_MASK; DwordReg = 0; /// /// Allocate the AHCI BAR /// MemBaseAddress = 0x0ffffffff; Status = gDS->AllocateMemorySpace ( EfiGcdAllocateMaxAddressSearchBottomUp, EfiGcdMemoryTypeMemoryMappedIo, N_PCH_SATA_AHCI_BAR_ALIGNMENT, // 2^11: 2K Alignment V_PCH_SATA_AHCI_BAR_LENGTH, // 2K Length &MemBaseAddress, mImageHandle, NULL ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } /// /// Set the AHCI BAR /// AhciBar = (UINT32) MemBaseAddress; MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR, AhciBar); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR), 1, &AhciBar ); /// /// Enable command register memory space decoding /// MmioOr16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_COMMAND), (UINT16) B_PCH_SATA_COMMAND_MSE); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_COMMAND), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_COMMAND) ); /// /// Assert if the memory data of AhciBar is invalid. /// ASSERT (MmioRead32 (AhciBar) != 0xFFFFFFFF); /// /// Get Port Settings /// SataPortsEnabled = MmioRead16 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS)); if (PchSeries == PchH) { SataPortsEnabled &= (UINT16) (B_PCH_SATA_PCS_PORT5_EN | B_PCH_SATA_PCS_PORT4_EN | B_PCH_SATA_PCS_PORT3_EN | B_PCH_SATA_PCS_PORT2_EN | B_PCH_SATA_PCS_PORT1_EN | B_PCH_SATA_PCS_PORT0_EN ); } else if (PchSeries == PchLp) { SataPortsEnabled &= (UINT16) (B_PCH_SATA_PCS_PORT3_EN | B_PCH_SATA_PCS_PORT2_EN | B_PCH_SATA_PCS_PORT1_EN | B_PCH_SATA_PCS_PORT0_EN ); } /// /// Read the default value of the Host Capabilites Register /// NOTE: many of the bits in this register are R/WO (Read/Write Once) /// CapRegister = MmioRead32 (AhciBar + R_PCH_SATA_AHCI_CAP); CapRegister &= (UINT32)~(B_PCH_SATA_AHCI_CAP_SIS | B_PCH_SATA_AHCI_CAP_SSS | B_PCH_SATA_AHCI_CAP_SALP | B_PCH_SATA_AHCI_CAP_PMS | B_PCH_SATA_AHCI_CAP_SSC | B_PCH_SATA_AHCI_CAP_PSC | B_PCH_SATA_AHCI_CAP_SXS); if (PchSeries == PchLp) { CapRegister &= (UINT32)~(B_PCH_SATA_AHCI_CAP_SAM); } for (Index = 0; Index < GetPchMaxSataPortNum (); Index++) { /// /// Check PCS.PxE to know if the SATA Port x is disabled. /// if ((SataPortsEnabled & (B_PCH_SATA_PCS_PORT0_EN << Index)) == 0) { continue; } if (PchSeries == PchLp) { /// /// Program AhciBar + 0h[18] = 1b /// CapRegister |= B_PCH_SATA_AHCI_CAP_SAM; } if (SataConfig->PortSettings[Index].InterlockSw == PCH_DEVICE_ENABLE) { /// /// Mechanical Presence Switch is Enabled for at least one of the ports /// CapRegister |= B_PCH_SATA_AHCI_CAP_SIS; } if ((SataConfig->PortSettings[Index].SpinUp == PCH_DEVICE_ENABLE) || (SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE)) { /// /// PCH BIOS Spec Rev 0.5.0, Section 14.1.4 Initialize Registers in AHCI Memory-Mapped Space /// Step 1.4 /// Set SSS (ABAR + 00h[27]) to enable SATA controller supports staggered /// spin-up on its ports, for use in balancing power spikes /// SATA Port Spin up is supported at least one of the ports /// If this is an extra eSATA port. It needs to be hotpluggable but it's usually empty anyway /// so LPM is not available but Listen Mode is available, so it will have good power management. /// If Sata Test Mode enabled, then uncoditonally clear SSS (ABAR + 00h[27]) /// to resolve Spin-donw issue with the test equiepment /// if (SataConfig->TestMode == PCH_DEVICE_ENABLE ) { CapRegister &= ~B_PCH_SATA_AHCI_CAP_SSS; } else { CapRegister |= B_PCH_SATA_AHCI_CAP_SSS; } } if (SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE) { /// /// External SATA is supported at least one of the ports /// CapRegister |= B_PCH_SATA_AHCI_CAP_SXS; } } /// /// Enable Enabled SATA ports, /// If BIOS accesses any of the port specific AHCI address range before setting PI bit, /// BIOS is required to read the PI register before the initial write to the PI register. /// NOTE: many of the bits in this register are R/WO (Read/Write Once) /// Data32And = (UINT32) (~B_PCH_H_SATA_PORT_MASK); if (PchSeries == PchLp) { Data32And = (UINT32) (~B_PCH_LP_SATA_PORT_MASK); } Data32Or = (UINT32) (SataPortsEnabled); MmioAndThenOr32 ( (UINTN) (AhciBar + R_PCH_SATA_AHCI_PI), Data32And, Data32Or ); SCRIPT_MEM_READ_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + R_PCH_SATA_AHCI_PI), &Data32Or, // Data to be ORed &Data32And // Data to be ANDed ); /// /// After BIOS issues initial write to this register, BIOS is requested to issue two /// reads to this register. /// Data32Or = MmioRead32 (AhciBar + R_PCH_SATA_AHCI_PI); SCRIPT_MEM_POLL ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + R_PCH_SATA_AHCI_PI), &Data32Or, // BitMask &Data32Or, // BitValue 1, // Duration 1 // LoopTimes ); SCRIPT_MEM_POLL ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + R_PCH_SATA_AHCI_PI), &Data32Or, // BitMask &Data32Or, // BitValue 1, // Duration 1 // LoopTimes ); /// /// PCH BIOS Spec Rev 0.5.0, Section 14.1.4 Initialize Registers in AHCI Memory-Mapped Space /// Step 1 /// For Lynx Point /// Set PSC (ABAR + 00h[13]). This bit informs the Windows software driver that the AHCI /// Controller supports the partial low-power state. /// Set SSC (ABAR + 00h[14]). This bit informs the Windows software driver that the AHCI /// Controller supports the slumber low-power state. /// Set SALP (ABAR + 00h[26]) to enable Aggressive Link Power Management (LPM) support. /// CapRegister |= (B_PCH_SATA_AHCI_CAP_SSC | B_PCH_SATA_AHCI_CAP_PSC); if (SataConfig->SalpSupport == PCH_DEVICE_ENABLE) { CapRegister |= B_PCH_SATA_AHCI_CAP_SALP; } /// /// Support Command List Override & PIO Multiple DRQ Block /// CapRegister |= (B_PCH_SATA_AHCI_CAP_SCLO | B_PCH_SATA_AHCI_CAP_PMD); /// /// Configure for the max speed support 1.5Gb/s, 3.0Gb/s and 6.0Gb/s. /// CapRegister &= ~B_PCH_SATA_AHCI_CAP_ISS_MASK; switch (SataConfig->SpeedSupport) { case PchSataSpeedSupportGen1: CapRegister |= (V_PCH_SATA_AHCI_CAP_ISS_1_5_G << N_PCH_SATA_AHCI_CAP_ISS); break; case PchSataSpeedSupportGen2: CapRegister |= (V_PCH_SATA_AHCI_CAP_ISS_3_0_G << N_PCH_SATA_AHCI_CAP_ISS); break; case PchSataSpeedSupportGen3: case PchSataSpeedSupportDefault: CapRegister |= (V_PCH_SATA_AHCI_CAP_ISS_6_0_G << N_PCH_SATA_AHCI_CAP_ISS); break; } /// /// Update the Host Capabilites Register and save for S3 resume /// NOTE: Many of the bits in this register are R/WO (Read/Write Once) /// MmioWrite32 (AhciBar + R_PCH_SATA_AHCI_CAP, CapRegister); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + R_PCH_SATA_AHCI_CAP), 1, &CapRegister ); if (PchSeries == PchLp) { /// /// Set ABAR + 24h[5] to 1b /// Set ABAR + 24h[4:2] to 111b /// Data32Or = B_PCH_SATA_AHCI_CAP2_DESO; Data32Or |= B_PCH_SATA_AHCI_CAP2_SDS | B_PCH_SATA_AHCI_CAP2_SADM | B_PCH_SATA_AHCI_CAP2_APST; MmioOr32 (AhciBar + R_PCH_SATA_AHCI_CAP2, Data32Or); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + R_PCH_SATA_AHCI_CAP2), 1, (VOID *) (UINTN) (AhciBar + R_PCH_SATA_AHCI_CAP2) ); } /// /// Port[Max:0] Command Register update /// NOTE: this register must be updated after Port Implemented and Capabilities register, /// Many of the bits in this register are R/WO (Read/Write Once) /// for (Index = 0; Index < GetPchMaxSataPortNum (); Index++) { /// /// Check PCS.PxE to know if the SATA Port x is disabled. /// if ((SataPortsEnabled & (B_PCH_SATA_PCS_PORT0_EN << Index)) == 0) { continue; } /// /// Initial to zero first /// PxCMDRegister = 0; if (SataConfig->PortSettings[Index].HotPlug == PCH_DEVICE_ENABLE) { if (SataConfig->PortSettings[Index].External == PCH_DEVICE_DISABLE) { /// /// Hot Plug of this port is enabled /// PxCMDRegister |= B_PCH_SATA_AHCI_PxCMD_HPCP; if (SataConfig->PortSettings[Index].InterlockSw == PCH_DEVICE_ENABLE) { /// /// Mechanical Switch of this port is Attached /// PxCMDRegister |= B_PCH_SATA_AHCI_PxCMD_MPSP; /// /// Check the GPIO Pin is set as used for native function not a normal GPIO /// if (PchSeries == PchH) { DwordReg = IoRead32 ( (UINTN) (GpioBase + R_PCH_GPIO_USE_SEL + (SataResetGpio[Index] / 32 * (R_PCH_GPIO_USE_SEL2 - R_PCH_GPIO_USE_SEL)))); DwordReg = (DwordReg & (1 << SataResetGpio[Index] % 32)); } if (PchSeries == PchLp) { DwordReg = IoRead32 ( (UINTN) (GpioBase + SataResetLpGpio[Index])); DwordReg = (DwordReg & B_PCH_GPIO_OWN0_GPIO_USE_SEL); } if(DwordReg != 0) { if (PchSeries == PchH) { DEBUG ((EFI_D_ERROR, "BIOS must set the SATA%0xGP / GPIO%0d to native function if Inter Lock Switch is enabled!\n", Index, SataResetGpio[Index])); ASSERT_EFI_ERROR (EFI_DEVICE_ERROR); } if (PchSeries == PchLp) { DEBUG ((EFI_D_ERROR, "BIOS must set the SATA%0xGP / GPIO%0d to native function if Inter Lock Switch is enabled!\n", Index, SataResetLpGpio[Index])); ASSERT_EFI_ERROR (EFI_DEVICE_ERROR); } } } } } else { /// /// When "Mechanical Switch Attached to Port" (PxCMD[19]) is set, it is expected that HPCP (PxCMD[18]) is also set. /// if (SataConfig->PortSettings[Index].InterlockSw == PCH_DEVICE_ENABLE) { DEBUG ((EFI_D_ERROR, "Hot-Plug function of Port%d should be enabled while the Inter Lock Switch of it is enabled!\n", Index)); } } if (SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE) { PxCMDRegister |= B_PCH_SATA_AHCI_PxCMD_ESP; } if (SataConfig->PortSettings[Index].SpinUp == PCH_DEVICE_ENABLE) { PxCMDRegister |= B_PCH_SATA_AHCI_PxCMD_SUD; } /// /// eSATA port support only up to Gen2 /// if (SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE) { Data32And = (UINT32)~(B_PCH_SATA_AHCI_PXSCTL_SPD); Data32Or = (V_PCH_SATA_AHCI_PXSCTL_SPD_2); if (PchSeries == PchLp) { Data32And = (UINT32)~(B_PCH_SATA_AHCI_PXSCTL_SPD | B_PCH_SATA_AHCI_PXSCTL_IPM); Data32Or = (V_PCH_SATA_AHCI_PXSCTL_SPD_2); } MmioAndThenOr32 ( (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), Data32And, Data32Or ); DwordReg = MmioRead32 (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), 1, &DwordReg ); } MmioAndThenOr32 ( (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))), (UINT32)~(B_PCH_SATA_AHCI_PxCMD_MASK), (UINT32) PxCMDRegister ); DwordReg = MmioRead32 (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))), 1, &DwordReg ); if ((PchSeries == PchLp)) { /// /// Set ABAR + 144h[1], ABAR + 1C4h[1], ABAR + 244h[1], ABAR + 2C4[1] to 0b as default /// Board rework is required to enable DevSlp. /// POR settings are ABAR + 144h[1], ABAR + 1C4h[1], ABAR + 244h[1] = 1b, ABAR + 2C4[1] to 0b /// if (SataConfig->PortSettings[Index].DevSlp == PCH_DEVICE_ENABLE) { Data32And = (UINT32)~(B_PCH_SATA_AHCI_PxDEVSLP_DITO_MASK | B_PCH_SATA_AHCI_PxDEVSLP_DM_MASK); Data32Or = (B_PCH_SATA_AHCI_PxDEVSLP_DSP | V_PCH_SATA_AHCI_PxDEVSLP_DM_16 | V_PCH_SATA_AHCI_PxDEVSLP_DITO_625); if (SataConfig->PortSettings[Index].EnableDitoConfig == PCH_DEVICE_ENABLE) { Data32Or &= Data32And; Data32Or |= ((SataConfig->PortSettings[Index].DitoVal << 15) | (SataConfig->PortSettings[Index].DmVal << 25)); } MmioAndThenOr32 ( (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0DEVSLP + (0x80 * Index))), Data32And, Data32Or ); } else { MmioAnd32 ( (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0DEVSLP + (0x80 * Index))), (UINT32) ~(B_PCH_SATA_AHCI_PxDEVSLP_DSP) ); } DwordReg = MmioRead32 (AhciBar + (R_PCH_SATA_AHCI_P0DEVSLP + (0x80 * Index))); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0DEVSLP + (0x80 * Index))), 1, &DwordReg ); } /// /// eSATA port support only up to Gen2. /// Save and restore Port Speed limitation /// if (SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE) { ByteReg = MmioRead8 (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))); ByteReg &= (UINT8) ~(B_PCH_SATA_AHCI_PXSCTL_SPD); ByteReg |= (UINT8) V_PCH_SATA_AHCI_PXSCTL_SPD_2; SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), 1, &ByteReg ); } } if ((PchSeries == PchLp)) { /// /// DevSlp on Port 0 and Port 3 are mutual exclusive. Assert if otherwise. /// ASSERT (!((SataConfig->PortSettings[0].DevSlp) && (SataConfig->PortSettings[3].DevSlp))); if ((SataConfig->PortSettings[0].DevSlp == PCH_DEVICE_DISABLE) && (SataConfig->PortSettings[3].DevSlp == PCH_DEVICE_ENABLE)) { MmioOr32 ( (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), (UINT32) B_PCH_SATA_SCLKCG_POP3_DEVSLP ); DwordReg = MmioRead32 (PciD31F2RegBase + R_PCH_SATA_SCLKCG); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), 1, &DwordReg ); } } /// /// PCH BIOS Spec Rev 0.5.0, Section 14.1.5.2 Enable Flexible RAID OROM Features /// Lynx Point with RAID capable sku is able to customize the RAID features through setting the /// Intel RST Feature Capabilities (RSTF) register before loading the RAID Option ROM. The RAID /// OROM will enable the desired features based on the setting in that register, please refer to /// PCH EDS for more details. /// For example, if the platform desired features are RAID0, RAID1, RAID5, RAID10 and /// RST Smart Storage caching. System BIOS should set RSTF (ABAR + C8h [15:0]) to 022Fh before /// loading RAID OROM. /// WordReg = 0; if (SataConfig->HddUnlock == PCH_DEVICE_ENABLE) { /// /// If set to "1", indicates that the HDD password unlock in the OS is enabled /// while SATA is configured as RAID mode. /// WordReg |= B_PCH_SATA_AHCI_RSTF_HDDLK; } if (SataConfig->LedLocate == PCH_DEVICE_ENABLE) { /// /// If set to "1", indicates that the LED/SGPIO hardware is attached and ping to /// locate feature is enabled on the OS while SATA is configured as RAID mode. /// WordReg |= B_PCH_SATA_AHCI_RSTF_LEDL; } if (SataModeSelect == V_PCH_SATA_MAP_SMS_RAID) { if (SataConfig->Raid0 == PCH_DEVICE_ENABLE) { /// /// If set to "1", then RAID0 is enabled in Flexible RAID Option ROM. /// WordReg |= B_PCH_SATA_AHCI_RSTF_R0E; } if (SataConfig->Raid1 == PCH_DEVICE_ENABLE) { /// /// If set to "1", then RAID1 is enabled in FD-OROM. /// WordReg |= B_PCH_SATA_AHCI_RSTF_R1E; } if (SataConfig->Raid10 == PCH_DEVICE_ENABLE) { /// /// If set to "1", then RAID10 is enabled in FD-OROM. /// WordReg |= B_PCH_SATA_AHCI_RSTF_R10E; } if (SataConfig->Raid5 == PCH_DEVICE_ENABLE) { /// /// If set to "1", then RAID5 is enabled in FD-OROM. /// WordReg |= B_PCH_SATA_AHCI_RSTF_R5E; } if (SataConfig->Irrt == PCH_DEVICE_ENABLE) { /// /// If set to "1", then Intel Rapid Recovery Technology is enabled. /// WordReg |= B_PCH_SATA_AHCI_RSTF_RSTE; } if (SataConfig->OromUiBanner == PCH_DEVICE_ENABLE) { /// /// If set to "1" then the OROM UI is shown. Otherwise, no OROM banner or information /// will be displayed if all disks and RAID volumes are Normal. /// WordReg |= B_PCH_SATA_AHCI_RSTF_IRSTOROM; } if (SataConfig->IrrtOnly == PCH_DEVICE_ENABLE) { /// /// If set to "1", then only IRRT volumes can span internal and eSATA drives. If cleared /// to "0", then any RAID volume can span internal and eSATA drives. /// WordReg |= B_PCH_SATA_AHCI_RSTF_IROES; } /// /// Enable the RST Smart Storage caching bit to support Smart Storage caching. /// if (SataConfig->SmartStorage == PCH_DEVICE_ENABLE) { WordReg |= B_PCH_SATA_AHCI_RSTF_SEREQ; } /// /// Program the delay of the OROM UI Splash Screen in a normal status. /// WordReg |= (UINT16) (SataConfig->OromUiDelay << N_PCH_SATA_AHCI_RSTF_OUD); } /// /// RSTF(RST Feature Capabilities) is a Write-Once register. /// MmioWrite16 ((UINTN) (AhciBar + R_PCH_SATA_AHCI_RSTF), WordReg); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (AhciBar + R_PCH_SATA_AHCI_RSTF), 1, &WordReg ); /// /// Set Ahci Bar to zero /// AhciBar = 0; MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR, AhciBar); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR), 1, &AhciBar ); /// /// Free the GCD pool /// gDS->FreeMemorySpace ( MemBaseAddress, V_PCH_SATA_AHCI_BAR_LENGTH ); DEBUG ((EFI_D_INFO, "ConfigureSataAhci() End\n")); return EFI_SUCCESS; } /** Disable Sata Controller @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance @param[in, out] FuncDisableReg Function Disable Register @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS DisableSataController ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN OUT UINT32 *FuncDisableReg ) { UINTN PciD31F2RegBase; UINTN PciD31F5RegBase; UINT16 SataModeSelect; PCH_SERIES PchSeries; PciD31F2RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 2, 0); PciD31F5RegBase = 0; SataModeSelect = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_MAP) & B_PCH_SATA_MAP_SMS_MASK; PchSeries = GetPchSeries(); #ifdef ULT_FLAG if (PchSeries == PchLp) { /// /// PCH BIOS Spec Rev 0.5.0, Section 14.2 SATA Controller Disabling /// Step 1 /// Set D31:F2:92h [3:0] to 0000b /// MmioAnd16 (PciD31F2RegBase + R_PCH_SATA_PCS, (UINT16) ~(B_PCH_SATA_PCS_PORT0_EN | B_PCH_SATA_PCS_PORT1_EN | B_PCH_SATA_PCS_PORT2_EN | B_PCH_SATA_PCS_PORT3_EN)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS) ); /// /// Step 3 /// Set Sata Port Clock Disable bits D31:F2:94h[27:24] to Fh /// MmioOr32 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), (UINT32) (B_PCH_SATA_SCLKCG_PORT0_PCD | B_PCH_SATA_SCLKCG_PORT1_PCD | B_PCH_SATA_SCLKCG_PORT2_PCD | B_PCH_SATA_SCLKCG_PORT3_PCD)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG) ); /// /// Step 4 /// Disabling SATA Device by programming RCBA + 3418h [2][25] /// *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_SATA1; } #endif // ULT_FLAG #ifdef TRAD_FLAG if (PchSeries == PchH) { PciD31F5RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 5, 0); /// /// PCH BIOS Spec Rev 0.5.0, Section 14.2 SATA Controller Disabling /// Step 1 /// Set D31:F2:92h [5:0] to 000000b /// MmioAnd16 (PciD31F2RegBase + R_PCH_SATA_PCS, (UINT16) ~(B_PCH_SATA_PCS_PORT0_EN | B_PCH_SATA_PCS_PORT1_EN | B_PCH_SATA_PCS_PORT2_EN | B_PCH_SATA_PCS_PORT3_EN | B_PCH_SATA_PCS_PORT4_EN | B_PCH_SATA_PCS_PORT5_EN)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_PCS) ); if (SataModeSelect == V_PCH_SATA_MAP_SMS_IDE) { /// /// Step 2 /// Set D31:F5:92h [1:0] to 00b if SATA is in IDE mode /// MmioAnd16 (PciD31F5RegBase + R_PCH_SATA_PCS, (UINT16) ~(B_PCH_SATA_PCS_PORT0_EN | B_PCH_SATA_PCS_PORT1_EN)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F5RegBase + R_PCH_SATA_PCS), 1, (VOID *) (UINTN) (PciD31F5RegBase + R_PCH_SATA_PCS) ); } /// /// Step 3 /// Set Sata Port Clock Disable bits D31:F2:94h[29:24] to 3Fh /// MmioOr32 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), (UINT32) (B_PCH_SATA_SCLKCG_PORT0_PCD | B_PCH_SATA_SCLKCG_PORT1_PCD | B_PCH_SATA_SCLKCG_PORT2_PCD | B_PCH_SATA_SCLKCG_PORT3_PCD | B_PCH_SATA_SCLKCG_PORT4_PCD | B_PCH_SATA_SCLKCG_PORT5_PCD)); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG), 1, (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SCLKCG) ); /// /// Step 4 /// Disabling SATA Device by programming RCBA + 3418h [2][25] /// *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_SATA1; *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_SATA2; } #endif // TRAD_FLAG return EFI_SUCCESS; }