Add AMD SB900 CIMx code

This code is added to support the AMD SB900 southbridge.

Change-Id: I7dc5e13a53ffd479dcea4e05e8c8631096e2ba91
Signed-off-by: Frank Vibrans <frank.vibrans@amd.com>
Signed-off-by: efdesign98 <efdesign98@gmail.com>
Reviewed-on: http://review.coreboot.org/41
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marcj303@gmail.com>
diff --git a/src/vendorcode/amd/cimx/sb900/Sata.c b/src/vendorcode/amd/cimx/sb900/Sata.c
new file mode 100755
index 0000000..9a7cf53
--- /dev/null
+++ b/src/vendorcode/amd/cimx/sb900/Sata.c
@@ -0,0 +1,1042 @@
+
+/**
+ * @file
+ *
+ * Config Southbridge SATA controller
+ *
+ * Init SATA features.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project:      CIMx-SB
+ * @e sub-project:
+ * @e \$Revision:$   @e \$Date:$
+ *
+ */
+/*
+*****************************************************************************
+*
+* Copyright (c) 2011, Advanced Micro Devices, Inc.
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of Advanced Micro Devices, Inc. nor the names of 
+*       its contributors may be used to endorse or promote products derived 
+*       from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+* 
+****************************************************************************
+*/
+#include "SbPlatform.h"
+#include "cbtypes.h"
+#include "AmdSbLib.h"
+
+//
+// Declaration of local functions
+//
+VOID  sataSetIrqIntResource (IN AMDSBCFG* pConfig);
+VOID  sataBar5setting (IN AMDSBCFG* pConfig, IN UINT32 *pBar5);
+#ifdef SATA_BUS_DEV_FUN_FPGA
+  VOID  sataBar5settingFpga (IN AMDSBCFG* pConfig, IN UINT32 *pBar5);
+#endif
+VOID  shutdownUnconnectedSataPortClock (IN AMDSBCFG* pConfig, IN UINT32 ddBar5);
+VOID  CaculateAhciPortNumber (IN AMDSBCFG* pConfig, IN UINT32 ddBar5);
+VOID  sataDriveDetection (IN AMDSBCFG* pConfig, IN UINT32 *pBar5);
+#ifdef SATA_BUS_DEV_FUN_FPGA
+  VOID  sataDriveDetectionFpga (IN AMDSBCFG* pConfig, IN UINT32 *pBar5);
+#endif
+VOID  sataGpioPorcedure (IN AMDSBCFG* pConfig);
+
+/**
+ * sataSetIrqIntResource - Config SATA IRQ/INT# resource
+ *
+ *
+ *   - Private function
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ *
+ */
+VOID
+sataSetIrqIntResource (
+  IN       AMDSBCFG*   pConfig
+  )
+{
+  UINT8   dbValue;
+  // IRQ14/IRQ15 come from IDE or SATA
+  dbValue = 0x08;
+  WriteIO (SB_IOMAP_REGC00, AccWidthUint8, &dbValue);
+  ReadIO (SB_IOMAP_REGC01, AccWidthUint8, &dbValue);
+  dbValue = dbValue & 0x0F;
+  if (pConfig->SataClass == 3) {
+    dbValue = dbValue | 0x50;
+  } else {
+    if (pConfig->SataIdeMode == 1) {
+      // Both IDE & SATA set to Native mode
+      dbValue = dbValue | 0xF0;
+    }
+  }
+  WriteIO (SB_IOMAP_REGC01, AccWidthUint8, &dbValue);
+}
+
+/**
+ * sataBar5setting - Config SATA BAR5
+ *
+ *   - Private function
+ *
+ * @param[in] pConfig - Southbridge configuration structure pointer.
+ * @param[in] *pBar5   - SATA BAR5 buffer.
+ *
+ */
+VOID
+sataBar5setting (
+  IN       AMDSBCFG*   pConfig,
+  IN       UINT32      *pBar5
+  )
+{
+  //Get BAR5 value
+  ReadPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG24), AccWidthUint32, pBar5);
+  //Assign temporary BAR if is not already assigned
+  if ( (*pBar5 == 0) || (*pBar5 == - 1) ) {
+    //assign temporary BAR5
+    if ( (pConfig->TempMMIO == 0) || (pConfig->TempMMIO == - 1) ) {
+      *pBar5 = 0xFEC01000;
+    } else {
+      *pBar5 = pConfig->TempMMIO;
+    }
+    WritePCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG24), AccWidthUint32, pBar5);
+  }
+  //Clear Bits 9:0
+  *pBar5 = *pBar5 & 0xFFFFFC00;
+}
+#ifdef SATA_BUS_DEV_FUN_FPGA
+VOID
+sataBar5settingFpga (
+  IN       AMDSBCFG*   pConfig,
+  IN       UINT32      *pBar5
+  )
+{
+  UINT8  dbValue;
+  //Get BAR5 value
+  ReadPCI (((SATA_BUS_DEV_FUN_FPGA << 16) + SB_SATA_REG24), AccWidthUint32, pBar5);
+  //Assign temporary BAR if is not already assigned
+  if ( (*pBar5 == 0) || (*pBar5 == - 1) ) {
+    //assign temporary BAR5
+    if ( (pConfig->TempMMIO == 0) || (pConfig->TempMMIO == - 1) ) {
+      *pBar5 = 0xFEC01000;
+    } else {
+      *pBar5 = pConfig->TempMMIO;
+    }
+    WritePCI (((SATA_BUS_DEV_FUN_FPGA << 16) + SB_SATA_REG24), AccWidthUint32, pBar5);
+  }
+  //Clear Bits 9:0
+  *pBar5 = *pBar5 & 0xFFFFFC00;
+  dbValue = 0x07;
+  WritePCI (((SATA_BUS_DEV_FUN_FPGA << 16) + 0x04), AccWidthUint8, &dbValue);
+  WritePCI (((PCIB_BUS_DEV_FUN << 16) + 0x04), AccWidthUint8, &dbValue);
+}
+#endif
+/**
+ * shutdownUnconnectedSataPortClock - Shutdown unconnected Sata port clock
+ *
+ *   - Private function
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ * @param[in] ddBar5 Sata BAR5 base address.
+ *
+ */
+VOID
+shutdownUnconnectedSataPortClock (
+  IN       AMDSBCFG* pConfig,
+  IN       UINT32 ddBar5
+  )
+{
+  UINT8  dbPortNum;
+  UINT32  ddPortSataStatus;
+  UINT8  cimSataClkAutoOff;
+
+  cimSataClkAutoOff = (UINT8) pConfig->SataClkAutoOff;
+#if  SB_CIMx_PARAMETER == 0
+  cimSataClkAutoOff = cimSataClkAutoOffDefault;
+#endif
+  if ( cimSataClkAutoOff == TRUE ) {
+    //ENH225976 Enable SATA auto clock control by default ( (pConfig->SataClass == NATIVE_IDE_MODE) || (pConfig->SataClass == LEGACY_IDE_MODE) || (pConfig->SataClass == IDE_TO_AHCI_MODE) ) {
+    for ( dbPortNum = 0; dbPortNum < 8; dbPortNum++ ) {
+      ReadMEM (ddBar5 + SB_SATA_BAR5_REG128 + (dbPortNum * 0x80), AccWidthUint32, &ddPortSataStatus);
+      // Shutdown the clock for the port and do the necessary port reporting changes.
+      // ?? Error port status should be 1 not 3
+      ddPortSataStatus &= 0x00000F0F;
+      if ( (!((ddPortSataStatus == 0x601) || (ddPortSataStatus == 0x201) || (ddPortSataStatus == 0x103))) && (! ((pConfig->SATAESPPORT.SataPortReg) & (1 << dbPortNum))) ) {
+        TRACE ((DMSG_SB_TRACE, "Shutting down clock for SATA port %X \n", dbPortNum));
+        RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 2), AccWidthUint8, 0xFF, (1 << dbPortNum));
+      }
+    }     //end of for (dbPortNum=0;dbPortNum<6;dbPortNum++)
+  }  //end of SataClkAuto Off option
+}
+
+/**
+ * CaculateAhciPortNumber - Caculat AHCI Port Number
+ *
+ *   - Private function
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ * @param[in] ddBar5 Sata BAR5 base address.
+ *
+ */
+VOID
+CaculateAhciPortNumber (
+  IN       AMDSBCFG* pConfig,
+  IN       UINT32 ddBar5
+  )
+{
+  UINT8  dbPortNum;
+  UINT8  dbPortSataStatus;
+  UINT8  NumOfPorts;
+  UINT8  MaxPortNum;
+  NumOfPorts = 0;
+  MaxPortNum = 4;
+  if ( (pConfig->SATAMODE.SataMode.SataIdeCombMdPriSecOpt) == ENABLED ) {
+    MaxPortNum = 6;
+  } else if ( (pConfig->SATAMODE.SataMode.SataIdeCombinedMode) == ENABLED ) {
+    MaxPortNum = 8;
+  }
+  ReadPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 2), AccWidthUint8, &dbPortSataStatus);
+  for ( dbPortNum = 0; dbPortNum < MaxPortNum; dbPortNum++ ) {
+    if ( dbPortSataStatus & (1 << dbPortNum) ) {
+      RWMEM (ddBar5 + SB_SATA_BAR5_REG0C, AccWidthUint8, ~(1 << dbPortNum), 00);
+    }
+  }
+  ReadMEM (ddBar5 + SB_SATA_BAR5_REG0C, AccWidthUint8, &dbPortSataStatus);
+  //if all ports are in disabled state, report atleast one port
+  if ( (dbPortSataStatus & 0xFF) == 0) {
+    RWMEM (ddBar5 + SB_SATA_BAR5_REG0C, AccWidthUint8, (UINT32) ~(0xFF), 01);
+  }
+  ReadMEM (ddBar5 + SB_SATA_BAR5_REG0C, AccWidthUint8, &dbPortSataStatus);
+  for (dbPortNum = 0; dbPortNum < MaxPortNum; dbPortNum ++) {
+    if (dbPortSataStatus & (1 << dbPortNum)) {
+      NumOfPorts++;
+    }
+  }
+  if ( NumOfPorts == 0) {
+    NumOfPorts = 0x01;
+  }
+  RWMEM (ddBar5 + SB_SATA_BAR5_REG00, AccWidthUint8, 0xE0, NumOfPorts - 1);
+}
+
+/**
+ * sataGpioPorcedure - Sata GPIO function Procedure
+ *
+ *   - Private function
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ *
+ */
+VOID
+sataGpioPorcedure (
+  IN  AMDSBCFG* pConfig
+  )
+{
+  UINT32  ddBar5;
+  UINT32  ddData;
+  UINT32  eMb;
+  UINT32  ddTempVariable;
+  UINT8  cimSataSgpio0;
+
+  ddBar5 = 0;
+  eMb = 0;
+  cimSataSgpio0 = (UINT8) pConfig->SataSgpio0;
+
+#if  SB_CIMx_PARAMETER == 0
+  cimSataSgpio0 = cimSataSgpio0Default;
+#endif
+
+  sataBar5setting (pConfig, &ddBar5);
+  ReadMEM (ddBar5 + SB_SATA_BAR5_REG1C , AccWidthUint32 | S3_SAVE, &ddData);
+  eMb = (ddBar5 + (( ddData & 0xFFFF0000) >> 14));
+  if ( eMb ) {
+    ddTempVariable = 0x03040C00;
+    WriteMEM ( ddBar5 + eMb, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    ddTempVariable = 0x00C08240;
+    WriteMEM ( ddBar5 + eMb + 4, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    ddTempVariable = 0x00000001;
+    WriteMEM ( ddBar5 + eMb + 8, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    if ( cimSataSgpio0 ) {
+      ddTempVariable = 0x00000060;
+    } else {
+      ddTempVariable = 0x00000061;
+    }
+    WriteMEM ( ddBar5 + eMb + 0x0C, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REG20), AccWidthUint16 | S3_SAVE, ~(BIT8), BIT8);
+    do {
+      ReadMEM (ddBar5 + SB_SATA_BAR5_REG20 , AccWidthUint32 | S3_SAVE, &ddData);
+      ddData = ddData & BIT8;
+    } while ( ddData != 0 );
+
+    ddTempVariable = 0x03040F00;
+    WriteMEM ( ddBar5 + eMb, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    ddTempVariable = 0x00008240;
+    WriteMEM ( ddBar5 + eMb + 4, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    ddTempVariable = 0x00000002;
+    WriteMEM ( ddBar5 + eMb + 8, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    ddTempVariable = 0x00800000;
+    WriteMEM ( ddBar5 + eMb + 0x0C, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    ddTempVariable = 0x0F003700;
+    WriteMEM ( ddBar5 + eMb + 0x0C, AccWidthUint32 | S3_SAVE, &ddTempVariable);
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REG20), AccWidthUint16 | S3_SAVE, ~(BIT8), BIT8);
+    do {
+      ReadMEM (ddBar5 + SB_SATA_BAR5_REG20 , AccWidthUint32 | S3_SAVE, &ddData);
+      ddData = ddData & BIT8;
+    } while ( ddData != 0 );
+  }
+}
+
+
+/**
+ * Table for class code of SATA Controller in different modes
+ *
+ *
+ *
+ *
+ */
+UINT32 sataIfCodeTable[] =
+{
+  0x01018F40, //sata class ID of IDE
+  0x01040040, //sata class ID of RAID
+  0x01060140, //sata class ID of AHCI
+  0x01018A40, //sata class ID of Legacy IDE
+  0x01018F40, //sata class ID of IDE to AHCI mode
+};
+
+/**
+ * Table for device id of SATA Controller in different modes
+ *
+ *
+ *
+ *
+ */
+
+UINT16 sataDeviceIDTable[] =
+{
+  SB_SATA_DID,  //sata device ID of IDE
+  SB_SATA_RAID_DID,  //sata device ID of RAID
+  SB_SATA_AHCI_DID,  //sata class ID of AHCI
+  SB_SATA_DID,  //sata device ID of Legacy IDE
+  SB_SATA_DID,  //sata device ID of IDE->AHCI mode
+};
+
+/**
+ * Table for Sata Phy Fine Setting
+ *
+ *
+ *
+ *
+ */
+SATAPHYSETTING sataPhyTable[] =
+{
+  //Gen3
+  {0x0030, 0x0057A607},
+  {0x0031, 0x0057A607},
+  {0x0032, 0x0057A407},
+  {0x0033, 0x0057A407},
+  {0x0034, 0x0057A607},
+  {0x0035, 0x0057A607},
+  {0x0036, 0x0057A403},
+  {0x0037, 0x0057A403},
+
+  //Gen2
+  {0x0120, 0x00071302},
+
+  //Gen1
+  {0x0110, 0x00174101}
+};
+
+/**
+ * sataInitBeforePciEnum - Config SATA controller before PCI emulation
+ *
+ *
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ *
+ */
+VOID
+sataInitBeforePciEnum (
+  IN       AMDSBCFG*   pConfig
+  )
+{
+  UINT32  ddTempVar;
+  UINT32  ddValue;
+  UINT32  *tempptr;
+  UINT16  *pDeviceIdptr;
+  UINT32  dwDeviceId;
+  UINT8   dbValue;
+  UINT8   pValue;
+  UINT8   dbChannel;
+  UINT16    i;
+  SATAPHYSETTING  *pPhyTable;
+
+  pConfig->SATAPORTPOWER.SataPortPowerReg = \
+    + pConfig->SATAPORTPOWER.SataPortPower.PORT0 \
+    + (pConfig->SATAPORTPOWER.SataPortPower.PORT1 << 1) \
+    + (pConfig->SATAPORTPOWER.SataPortPower.PORT2 << 2) \
+    + (pConfig->SATAPORTPOWER.SataPortPower.PORT3 << 3) \
+    + (pConfig->SATAPORTPOWER.SataPortPower.PORT4 << 4) \
+    + (pConfig->SATAPORTPOWER.SataPortPower.PORT5 << 5) \
+    + (pConfig->SATAPORTPOWER.SataPortPower.PORT6 << 6) \
+    + (pConfig->SATAPORTPOWER.SataPortPower.PORT7 << 7);
+  // BIT0 Enable write access to PCI header (reg 08h-0Bh) by setting SATA PCI register 40h
+  // BIT4:disable fast boot //?
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, 0xff, BIT0 + BIT4);
+  // BIT0 Enable write access to PCI header (reg 08h-0Bh) by setting IDE PCI register 40h
+  RWPCI (((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG40), AccWidthUint8 | S3_SAVE, 0xff, BIT0);
+  // RPR Enable IDE DMA read enhancement
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG48 + 3), AccWidthUint8 | S3_SAVE, 0xff, BIT7);
+  // RPR Unused SATA Ports Disabled
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 2), AccWidthUint8 | S3_SAVE, 0, pConfig->SATAPORTPOWER.SataPortPowerReg);
+  dbValue = (UINT8)pConfig->SataClass;
+  if (dbValue == AHCI_MODE_7804) {
+    dbValue = AHCI_MODE;
+  }
+  if (dbValue == IDE_TO_AHCI_MODE_7804) {
+    dbValue = IDE_TO_AHCI_MODE;
+  }
+  // Disable PATA MSI
+  RWPCI (((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG34), AccWidthUint8 | S3_SAVE, 0x00, 0x00);
+  RWPCI (((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG06), AccWidthUint8 | S3_SAVE, 0xEF, 0x00);
+
+  if ( (pConfig->SataClass == 3) | (pConfig->SataClass == 0)) {
+    dbChannel = 0x00;
+    ReadPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG48 + 3), AccWidthUint8, &dbChannel);
+    dbChannel &= 0xCF;
+    if ( pConfig->SataDisUnusedIdePChannel ) {
+      dbChannel |= 0x10;
+    }
+    if ( pConfig->SataDisUnusedIdeSChannel ) {
+      dbChannel |= 0x20;
+    }
+    WritePCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG48 + 3), AccWidthUint8, &dbChannel);
+  }
+
+  if ((pConfig->SATAMODE.SataMode.SataIdeCombinedMode) == DISABLED ) {
+    ReadPCI (((IDE_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 11), AccWidthUint8, &dbChannel);
+    dbChannel &= 0xCF;
+    if ( pConfig->IdeDisUnusedIdePChannel ) {
+      dbChannel |= 0x10;
+    }
+    if ( pConfig->IdeDisUnusedIdeSChannel ) {
+      dbChannel |= 0x20;
+    }
+    WritePCI (((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG40 + 11), AccWidthUint8, &dbChannel);
+  }
+  // Get the appropriate class code from the table and write it to PCI register 08h-0Bh
+  // Set the appropriate SATA class based on the input parameters
+  // SATA IDE Controller Class ID & SSID
+  tempptr = (UINT32 *) FIXUP_PTR (&sataIfCodeTable[0]);
+  if ( (pConfig->SataIdeMode == 1) && (pConfig->SataClass != 3) ) {
+    ddValue = tempptr[0];
+    // Write the class code to IDE PCI register 08h-0Bh
+    RWPCI (((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG08), AccWidthUint32 | S3_SAVE, 0, ddValue);
+  }
+  ddValue = tempptr[dbValue];
+  // Write the class code to SATA PCI register 08h-0Bh
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG08), AccWidthUint32 | S3_SAVE, 0, ddValue);
+  if ( pConfig->SataClass == LEGACY_IDE_MODE ) {
+    //Set PATA controller to native mode
+    RWPCI (((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG09), AccWidthUint8 | S3_SAVE, 0x00, 0x08F);
+  }
+  if (pConfig->BuildParameters.IdeSsid != NULL ) {
+    RWPCI ((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG2C, AccWidthUint32 | S3_SAVE, 0x00, pConfig->BuildParameters.IdeSsid);
+  }
+  // SATA Controller Class ID & SSID
+  pDeviceIdptr = (UINT16 *) FIXUP_PTR (&sataDeviceIDTable[0]);
+  ddTempVar = pConfig->BuildParameters.SataIDESsid;
+  dwDeviceId = pDeviceIdptr[dbValue];
+  if ( pConfig->SataClass == RAID_MODE) {
+    ddTempVar = pConfig->BuildParameters.SataRAID5Ssid;
+    dwDeviceId = SB_SATA_RAID5_DID;
+    pValue = SATA_EFUSE_LOCATION;
+    getEfuseStatus (&pValue);
+    if (( pValue & SATA_EFUSE_BIT ) || ( pConfig->SataForceRaid == 1 )) {
+      dwDeviceId = SB_SATA_RAID_DID;
+      ddTempVar = pConfig->BuildParameters.SataRAIDSsid;
+    }
+  }
+  if ( ((pConfig->SataClass) == AHCI_MODE) || ((pConfig->SataClass) == IDE_TO_AHCI_MODE) ||
+    ((pConfig->SataClass) == AHCI_MODE_7804) || ((pConfig->SataClass) == IDE_TO_AHCI_MODE_7804) ) {
+    ddTempVar = pConfig->BuildParameters.SataAHCISsid;
+  }
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG02), AccWidthUint16 | S3_SAVE, 0, dwDeviceId);
+  RWPCI ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG2C, AccWidthUint32 | S3_SAVE, 0x00, ddTempVar);
+
+  // SATA IRQ Resource
+  sataSetIrqIntResource (pConfig);
+
+  // RPR 9.5 SATA PHY Programming Sequence
+  pPhyTable = (SATAPHYSETTING*)FIXUP_PTR (&sataPhyTable[0]);
+  for (i = 0; i < (sizeof (sataPhyTable) / sizeof (SATAPHYSETTING)); i++) {
+    RWPCI ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG80, AccWidthUint16 | S3_SAVE, 0x00, pPhyTable->wPhyCoreControl);
+    RWPCI ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG98, AccWidthUint32 | S3_SAVE, 0x00, pPhyTable->dwPhyFineTune);
+    ++pPhyTable;
+  }
+  RWPCI ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG80, AccWidthUint16 | S3_SAVE, 0x00, 0x110);
+  RWPCI ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG9C, AccWidthUint32 | S3_SAVE, (UINT32) (~(0x7 << 4)), (UINT32) (0x2 << 4));
+  RWPCI ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG80, AccWidthUint16 | S3_SAVE, 0x00, 0x10);
+
+  RWPCI (((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG40), AccWidthUint8 | S3_SAVE, ~BIT0, 0);
+  // Disable write access to PCI header
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, ~BIT0, 0);
+  if ( IsSbA12Plus () ) {
+    //SATA PCI Config 0x4C[31:26] program 111111b (six 1's)
+    //SATA PCI Config 0x48[11] program 1
+    //SATA PCI Config 0x84[31] program 0
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG4C), AccWidthUint32 | S3_SAVE, (UINT32) (~ (0x3f << 26)), (UINT32) (0x3f << 26));
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG48), AccWidthUint32 | S3_SAVE, (UINT32) (~ (0x01 << 11)), (UINT32) (0x01 << 11));
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG84), AccWidthUint32 | S3_SAVE, (UINT32) (~ (0x01 << 31)), (UINT32) (0x00 << 31));
+  }
+
+  //SATA PCI config register 0x4C [20] =1
+  //SATA PCI config register 0x4C [21] =1
+  //SATA PCI config register 0x4C [18] =1
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG4C), AccWidthUint32 | S3_SAVE, ~ (BIT18 + BIT20 + BIT21), (BIT18 + BIT20 + BIT21));
+}
+
+/**
+ * sataInitAfterPciEnum - Config SATA controller after PCI emulation
+ *
+ *
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ *
+ */
+VOID
+sataInitAfterPciEnum (
+  IN       AMDSBCFG* pConfig
+  )
+{
+  UINT32  ddAndMask;
+  UINT32  ddOrMask;
+  UINT32  ddBar5;
+  UINT8  dbVar;
+  UINT8  dbPortNum;
+  UINT8  dbEfuse;
+  UINT8  dbPortMode;
+  UINT16  SataPortMode;
+  UINT8  cimSataAggrLinkPmCap;
+  UINT8  cimSataPortMultCap;
+  UINT8  cimSataPscCap;
+  UINT8  cimSataSscCap;
+  UINT8  cimSataFisBasedSwitching;
+  UINT8  cimSataCccSupport;
+  UINT8  cimSataMsiCapability;
+  UINT8  cimSataTargetSupport8Device;
+  UINT8  cimSataDisableGenericMode;
+  UINT8  cimSataAhciEnclosureManagement;
+  UINT8  cimSataSgpio0;
+  UINT8  cimSataSgpio1;
+  UINT8  cimSataHotRemovelEnh;
+  UINT8  cimSataPhyPllShutDown;
+  UINT8  dbCccInt;
+
+  cimSataAggrLinkPmCap = (UINT8) pConfig->SataAggrLinkPmCap;
+  cimSataPortMultCap = (UINT8) pConfig->SataPortMultCap;
+  cimSataPscCap = (UINT8) pConfig->SataPscCap;
+  cimSataSscCap = (UINT8) pConfig->SataSscCap;
+  cimSataFisBasedSwitching = (UINT8) pConfig->SataFisBasedSwitching;
+  cimSataCccSupport = (UINT8) pConfig->SataCccSupport;
+  cimSataMsiCapability = (UINT8) pConfig->SataMsiCapability;
+  cimSataTargetSupport8Device = (UINT8) pConfig->SataTargetSupport8Device;
+  cimSataDisableGenericMode = (UINT8) pConfig->SataDisableGenericMode;
+  cimSataAhciEnclosureManagement = (UINT8) pConfig->SataAhciEnclosureManagement;
+  cimSataSgpio0 = (UINT8) pConfig->SataSgpio0;
+  cimSataSgpio1 = (UINT8) pConfig->SataSgpio1;
+  cimSataHotRemovelEnh = (UINT8) pConfig->SataHotRemoveEnh;
+  cimSataPhyPllShutDown = (UINT8) pConfig->SataPhyPllShutDown;
+
+#if  SB_CIMx_PARAMETER == 0
+  cimSataAggrLinkPmCap = cimSataAggrLinkPmCapDefault;
+  cimSataPortMultCap = cimSataPortMultCapDefault;
+  cimSataPscCap = cimSataPscCapDefault;
+  cimSataSscCap = cimSataSscCapDefault;
+  cimSataFisBasedSwitching = cimSataFisBasedSwitchingDefault;
+  cimSataCccSupport = cimSataCccSupportDefault;
+  cimSataMsiCapability = cimSataMsiCapabilityDefault;
+  cimSataTargetSupport8Device = cimSataTargetSupport8DeviceDefault;
+  cimSataDisableGenericMode = cimSataDisableGenericModeDefault;
+  cimSataAhciEnclosureManagement = cimSataAhciEnclosureManagementDefault;
+  cimSataSgpio0 = cimSataSgpio0Default;
+  cimSataSgpio1 = cimSataSgpio1Default;
+  cimSataHotRemovelEnh = cimSataHotRemoveEnhDefault;
+  cimSataPhyPllShutDown = cimSataPhyPllShutDownDefault;
+#endif
+
+  ddAndMask = 0;
+  ddOrMask = 0;
+  ddBar5 = 0;
+  if ( pConfig->SATAMODE.SataMode.SataController == 0 ) {
+    return;   //return if SATA controller is disabled.
+  }
+
+  //Enable write access to pci header, pm capabilities
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, 0xFF, BIT0);
+
+  sataBar5setting (pConfig, &ddBar5);
+
+  ReadPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, &dbVar);
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, 0xFF, 0x03);   //memory and io access enable
+  dbEfuse = SATA_FIS_BASE_EFUSE_LOC;
+  getEfuseStatus (&dbEfuse);
+
+  if ( !cimSataPortMultCap ) {
+    ddAndMask |= BIT12;
+  }
+  if ( cimSataAggrLinkPmCap ) {
+    ddOrMask |= BIT11;
+  } else {
+    ddAndMask |= BIT11;
+  }
+  if ( cimSataPscCap ) {
+    ddOrMask |= BIT1;
+  } else {
+    ddAndMask |= BIT1;
+  }
+  if ( cimSataSscCap ) {
+    ddOrMask |= BIT26;
+  } else {
+    ddAndMask |= BIT26;
+  }
+  if ( cimSataFisBasedSwitching ) {
+    if (dbEfuse & BIT1) {
+      ddAndMask |= BIT10;
+    } else {
+      ddOrMask |= BIT10;
+    }
+  } else {
+    ddAndMask |= BIT10;
+  }
+  // RPR 8.10 Disabling CCC (Command Completion Coalescing) support.
+  if ( cimSataCccSupport ) {
+    ddOrMask |= BIT19;
+  } else {
+    ddAndMask |= BIT19;
+  }
+  if ( cimSataAhciEnclosureManagement ) {
+    ddOrMask |= BIT27;
+  } else {
+    ddAndMask |= BIT27;
+  }
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REGFC), AccWidthUint32 | S3_SAVE, ~ddAndMask, ddOrMask);
+
+
+  // SATA ESP port setting
+  // These config bits are set for SATA driver to identify which ports are external SATA ports and need to
+  // support hotplug. If a port is set as an external SATA port and need to support hotplug, then driver will
+  // not enable power management (HIPM & DIPM) for these ports.
+  pConfig->SATAESPPORT.SataPortReg = \
+    + pConfig->SATAESPPORT.SataEspPort.PORT0 \
+    + (pConfig->SATAESPPORT.SataEspPort.PORT1 << 1) \
+    + (pConfig->SATAESPPORT.SataEspPort.PORT2 << 2) \
+    + (pConfig->SATAESPPORT.SataEspPort.PORT3 << 3) \
+    + (pConfig->SATAESPPORT.SataEspPort.PORT4 << 4) \
+    + (pConfig->SATAESPPORT.SataEspPort.PORT5 << 5) \
+    + (pConfig->SATAESPPORT.SataEspPort.PORT6 << 6) \
+    + (pConfig->SATAESPPORT.SataEspPort.PORT7 << 7);
+  if ( pConfig->SATAESPPORT.SataPortReg != 0 ) {
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REGF8), AccWidthUint32 | S3_SAVE, ~(pConfig->SATAESPPORT.SataPortReg), 0);
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REGF8), AccWidthUint32 | S3_SAVE, 0xFF00FF00, (pConfig->SATAESPPORT.SataPortReg << 16));
+    // RPR 8.7 External SATA Port Indication Registers
+    // If any of the ports was programmed as an external port, HCAP.SXS should also be set
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REGFC), AccWidthUint32 | S3_SAVE, ~(BIT20), BIT20);
+  } else {
+    // RPR 8.7 External SATA Port Indication Registers
+    // If any of the ports was programmed as an external port, HCAP.SXS should also be set (Clear for no ESP port)
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REGF8), AccWidthUint32 | S3_SAVE, 0xFF00FF00, 0x00);
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REGFC), AccWidthUint32 | S3_SAVE, ~(BIT20), 0x00);
+  }
+
+  if ( cimSataFisBasedSwitching ) {
+    if (dbEfuse & BIT1) {
+      RWMEM ((ddBar5 + SB_SATA_BAR5_REGF8), AccWidthUint32 | S3_SAVE, 0x00FFFFFF, 0x00);
+    } else {
+      RWMEM ((ddBar5 + SB_SATA_BAR5_REGF8), AccWidthUint32 | S3_SAVE, 0x00FFFFFF, 0xFF000000);
+    }
+  } else {
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REGF8), AccWidthUint32 | S3_SAVE, 0x00FFFFFF, 0x00);
+  }
+
+  //SB02712 Turn off MSI for SATA IDE mode.
+  if ((pConfig->SataClass == NATIVE_IDE_MODE) || (pConfig->SataClass == LEGACY_IDE_MODE)) {
+    cimSataMsiCapability = 0;
+  }
+  //Enabled SATA MSI capability
+  // RPR 8.11 SATA MSI and D3 Power State Capability
+  if (IsSbA12Plus ()) {
+    if ( cimSataMsiCapability ) {
+      RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG34), AccWidthUint8 | S3_SAVE, 0, 0x50);
+    } else {
+      RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG34), AccWidthUint8 | S3_SAVE, 0, 0x70);
+    }
+  } else {
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG34), AccWidthUint8 | S3_SAVE, 0, 0x70);
+  }
+
+  if (((pConfig->SataClass) != NATIVE_IDE_MODE) && ((pConfig->SataClass) != LEGACY_IDE_MODE)) {
+    // RIAD or AHCI
+    if ((pConfig->SATAMODE.SataMode.SataIdeCombinedMode) == DISABLED) {
+      // IDE2 Controller is enabled
+      if ((pConfig->SATAMODE.SataMode.SataIdeCombMdPriSecOpt) == ENABLED) {
+        // 6 AHCI mode
+        RWMEM ((ddBar5 + SB_SATA_BAR5_REG0C), AccWidthUint8 | S3_SAVE, 0x00, 0x3F);
+        RWMEM ((ddBar5 + SB_SATA_BAR5_REG00), AccWidthUint8 | S3_SAVE, ~(BIT2 + BIT1 + BIT0), BIT2 + BIT0);
+        RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG50 + 2), AccWidthUint8, ~(BIT3 + BIT2 + BIT1), BIT2 + BIT1);
+        RWMEM ((ddBar5 + SB_SATA_BAR5_REGFC), AccWidthUint8, 0x07, 0x30);
+      } else {
+        RWMEM ((ddBar5 + SB_SATA_BAR5_REG0C), AccWidthUint8 | S3_SAVE, 0x00, 0x0F);
+        if ( pConfig->SataCccSupport ) {
+          RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG50 + 2), AccWidthUint8, ~(BIT3 + BIT2 + BIT1), BIT2 + BIT1);
+        } else {
+          RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG50 + 2), AccWidthUint8, ~(BIT3 + BIT2 + BIT1), BIT2);
+        }
+      }
+    } else {
+      // IDE2 Controller is disabled
+      RWMEM ((ddBar5 + SB_SATA_BAR5_REG00), AccWidthUint8 | S3_SAVE, ~(BIT2 + BIT1 + BIT0), BIT2 + BIT1 + BIT0);
+      RWMEM ((ddBar5 + SB_SATA_BAR5_REG0C), AccWidthUint8 | S3_SAVE, 0x00, 0xFF);
+      if ( pConfig->SataCccSupport ) {
+        RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG50 + 2), AccWidthUint8, ~(BIT3 + BIT2 + BIT1), BIT3);
+      } else {
+        RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG50 + 2), AccWidthUint8, ~(BIT3 + BIT2 + BIT1), BIT2 + BIT1);
+      }
+    }
+  }
+  if ( pConfig->BIOSOSHandoff == 1 ) {
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REG24), AccWidthUint8 | S3_SAVE, ~BIT0, BIT0);
+  } else {
+    RWMEM ((ddBar5 + SB_SATA_BAR5_REG24), AccWidthUint8 | S3_SAVE, ~BIT0, 0x00);
+  }
+  pConfig->SATAPORTMODE.SataPortMode = \
+    pConfig->SATAPORTMODE.SataPortMd.PORT0 \
+    + (pConfig->SATAPORTMODE.SataPortMd.PORT1 << 2) \
+    + (pConfig->SATAPORTMODE.SataPortMd.PORT2 << 4) \
+    + (pConfig->SATAPORTMODE.SataPortMd.PORT3 << 6) \
+    + (pConfig->SATAPORTMODE.SataPortMd.PORT4 << 8) \
+    + (pConfig->SATAPORTMODE.SataPortMd.PORT5 << 10) \
+    + (pConfig->SATAPORTMODE.SataPortMd.PORT6 << 12) \
+    + (pConfig->SATAPORTMODE.SataPortMd.PORT7 << 14);
+  SataPortMode = (UINT16)pConfig->SATAPORTMODE.SataPortMode;
+  dbPortNum = 0;
+
+  while ( dbPortNum < 8 ) {
+    dbPortMode = (UINT8) (SataPortMode & 3);
+    if ( (dbPortMode == BIT0) || (dbPortMode == BIT1) ) {
+      if ( dbPortMode == BIT0 ) {
+        // set GEN 1
+        RWMEM (ddBar5 + SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0x0F, 0x10);
+      }
+      if ( dbPortMode == BIT1 ) {
+        // set GEN2 (default is GEN3)
+        RWMEM (ddBar5 + SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0x0F, 0x20);
+      }
+      RWMEM (ddBar5 + SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0xFF, 0x01);
+      cimSbStall (1000);
+      RWMEM (ddBar5 + SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0xFE, 0x00);
+    }
+    SataPortMode >>= 2;
+    dbPortNum ++;
+  }
+  SbStall (1000);
+  SataPortMode = (UINT16)pConfig->SATAPORTMODE.SataPortMode;
+  dbPortNum = 0;
+
+  while ( dbPortNum < 8 ) {
+    dbPortMode = (UINT8) (SataPortMode & 3);
+    if ( (dbPortMode == BIT0) || (dbPortMode == BIT1) ) {
+      RWMEM (ddBar5 + SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0xFE, 0x00);
+    }
+    dbPortNum ++;
+    SataPortMode >>= 2;
+  }
+
+  if ( cimSataTargetSupport8Device ) {
+    RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGDA, AccWidthUint16, ~BIT12, BIT12);
+  } else {
+    RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGDA, AccWidthUint16, ~BIT12, 0x00);
+  }
+
+  if ( cimSataDisableGenericMode ) {
+    RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGDA, AccWidthUint16, ~BIT13, BIT13);
+  } else {
+    RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGDA, AccWidthUint16, ~BIT13, 0x00);
+  }
+  // 9.19 Optionally Disable Hot-removal Detection Enhancement
+  if ( cimSataHotRemovelEnh ) {
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG80), AccWidthUint16 | S3_SAVE, ~BIT8, BIT8 );
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REGA8), AccWidthUint16 | S3_SAVE, ~BIT0, BIT0);
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG80), AccWidthUint16 | S3_SAVE, ~BIT8, 0 );
+  }
+  if ( cimSataSgpio0 ) {
+    sataGpioPorcedure (pConfig);
+  }
+  if ( cimSataSgpio1 ) {
+    sataGpioPorcedure (pConfig);
+  }
+  if ( IsSbA11 () ) {
+    if ( cimSataPhyPllShutDown ) {
+      RWPCI (((SATA_BUS_DEV_FUN << 16) + 0x87), AccWidthUint8 | S3_SAVE, ~(BIT6 + BIT7), BIT6 + BIT7);
+    } else {
+      RWPCI (((SATA_BUS_DEV_FUN << 16) + 0x87), AccWidthUint8 | S3_SAVE, ~(BIT6 + BIT7), 0x00);
+    }
+  } else {
+    if ( cimSataPhyPllShutDown ) {
+      RWPCI (((SATA_BUS_DEV_FUN << 16) + 0x87), AccWidthUint8 | S3_SAVE, ~(BIT6), BIT6);
+    } else {
+      RWPCI (((SATA_BUS_DEV_FUN << 16) + 0x87), AccWidthUint8 | S3_SAVE, ~(BIT6), 0x00);
+    }
+  }
+  if ( IsSbA12Plus () ) {
+    //SATA PCI Config 0x4C[31:26] program 111111b (six 1's)
+    //SATA PCI Config 0x48[11] program 1
+    //SATA PCI Config 0x84[31] program 0
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG4C), AccWidthUint32 | S3_SAVE, (UINT32) (~ (0x3f << 26)), (UINT32) (0x3f << 26));
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG48), AccWidthUint32 | S3_SAVE, (UINT32) (~ (0x01 << 11)), (UINT32) (0x01 << 11));
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG84), AccWidthUint32 | S3_SAVE, (UINT32) (~ (0x01 << 31)), (UINT32) (0x00 << 31));
+  }
+  // RPR 9.18 CCC Interrupt
+  dbCccInt = 4;
+  if ((pConfig->SATAMODE.SataMode.SataIdeCombinedMode) == DISABLED) {
+    if ((pConfig->SATAMODE.SataMode.SataIdeCombMdPriSecOpt) == ENABLED) {
+      dbCccInt = 6;
+    }
+  } else {
+    dbCccInt = 8;
+  }
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REGFC), AccWidthUint8, 0x07, (dbCccInt << 3));
+
+  shutdownUnconnectedSataPortClock (pConfig, ddBar5);
+
+  WritePCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, &dbVar);
+
+  // RPR 9.13 Disable SATA FLR Capability
+  // SATA_PCI_config 0x70 [15:8] = 0x00
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG70), AccWidthUint32 | S3_SAVE, 0xFFFF00FF, 0x00);
+  //Disable write access to pci header, pm capabilities
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, ~BIT0, 0);
+}
+
+
+/**
+ * sataInitMidPost - Config SATA controller in Middle POST.
+ *
+ *
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ *
+ */
+VOID
+sataInitMidPost (
+  IN       AMDSBCFG* pConfig
+  )
+{
+  UINT32   ddBar5;
+  sataBar5setting (pConfig, &ddBar5);
+  //If this is not S3 resume and also if SATA set to one of IDE mode, them implement drive detection workaround.
+  if ( ! (pConfig->S3Resume) && ( ((pConfig->SataClass) != AHCI_MODE)  && ((pConfig->SataClass) != RAID_MODE) ) ) {
+    sataDriveDetection (pConfig, &ddBar5);
+  }
+#ifdef SATA_BUS_DEV_FUN_FPGA
+  sataBar5settingFpga (pConfig, &ddBar5);
+  sataDriveDetectionFpga (pConfig, &ddBar5);
+#endif
+}
+
+/**
+ * sataDriveDetection - Sata drive detection
+ *
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ * @param[in] *pBar5 Sata BAR5 base address.
+ *
+ */
+VOID
+sataDriveDetection (
+  IN       AMDSBCFG* pConfig,
+  IN       UINT32 *pBar5
+  )
+{
+  UINT32   ddVar0;
+  UINT8   dbPortNum;
+  UINT8   dbVar0;
+  UINT16   dwIoBase;
+  UINT32   ddVar1;
+  TRACE ((DMSG_SB_TRACE, "CIMx - Entering sata drive detection procedure\n\n"));
+  TRACE ((DMSG_SB_TRACE, "SATA BAR5 is %X \n", *pBar5));
+  if ( (pConfig->SataClass == NATIVE_IDE_MODE) || (pConfig->SataClass == LEGACY_IDE_MODE) || (pConfig->SataClass == IDE_TO_AHCI_MODE) ) {
+    for ( dbPortNum = 0; dbPortNum < 4; dbPortNum++ ) {
+      ReadMEM (*pBar5 + SB_SATA_BAR5_REG128 + dbPortNum * 0x80, AccWidthUint32, &ddVar0);
+      if ( ( ddVar0 & 0x0F ) == 0x03 ) {
+        if ( dbPortNum & BIT0 ) {
+          //this port belongs to secondary channel
+          ReadPCI (((UINT32) (SATA_BUS_DEV_FUN << 16) + SB_SATA_REG18), AccWidthUint16, &dwIoBase);
+        } else {
+          //this port belongs to primary channel
+          ReadPCI (((UINT32) (SATA_BUS_DEV_FUN << 16) + SB_SATA_REG10), AccWidthUint16, &dwIoBase);
+        }
+        //if legacy ide mode, then the bar registers don't contain the correct values. So we need to hardcode them
+        if ( pConfig->SataClass == LEGACY_IDE_MODE ) {
+          dwIoBase = ( (0x170) | ((UINT16) ( (~((UINT8) (dbPortNum & BIT0) << 7)) & 0x80 )) );
+        }
+        if ( dbPortNum & BIT1 ) {
+          //this port is slave
+          dbVar0 = 0xB0;
+        } else {
+          //this port is master
+          dbVar0 = 0xA0;
+        }
+        dwIoBase &= 0xFFF8;
+        WriteIO (dwIoBase + 6, AccWidthUint8, &dbVar0);
+        //Wait in loop for 30s for the drive to become ready
+        for ( ddVar1 = 0; ddVar1 < 300000; ddVar1++ ) {
+          ReadIO (dwIoBase + 7, AccWidthUint8, &dbVar0);
+          if ( (dbVar0 & 0x88) == 0 ) {
+            break;
+          }
+          SbStall (100);
+        }
+      } //end of if ( ( ddVar0 & 0x0F ) == 0x03)
+    } //for (dbPortNum = 0; dbPortNum < 4; dbPortNum++)
+  } //if ( (pConfig->SataClass == NATIVE_IDE_MODE) || (pConfig->SataClass == LEGACY_IDE_MODE) || (pConfig->SataClass == IDE_TO_AHCI_MODE))
+}
+
+#ifdef SATA_BUS_DEV_FUN_FPGA
+VOID
+sataDriveDetectionFpga (
+  IN       AMDSBCFG* pConfig,
+  IN       UINT32 *pBar5
+  )
+{
+  UINT32   ddVar0;
+  UINT8   dbPortNum;
+  UINT8   dbVar0;
+  UINT16   dwIoBase;
+  UINT32   ddVar1;
+  TRACE ((DMSG_SB_TRACE, "CIMx - Entering sata drive detection procedure\n\n"));
+  TRACE ((DMSG_SB_TRACE, "SATA BAR5 is %X \n", *pBar5));
+  for ( dbPortNum = 0; dbPortNum < 4; dbPortNum++ ) {
+    ReadMEM (*pBar5 + SB_SATA_BAR5_REG128 + dbPortNum * 0x80, AccWidthUint32, &ddVar0);
+    if ( ( ddVar0 & 0x0F ) == 0x03 ) {
+      if ( dbPortNum & BIT0 ) {
+        //this port belongs to secondary channel
+        ReadPCI (((UINT32) (SATA_BUS_DEV_FUN_FPGA << 16) + SB_SATA_REG18), AccWidthUint16, &dwIoBase);
+      } else {
+        //this port belongs to primary channel
+        ReadPCI (((UINT32) (SATA_BUS_DEV_FUN_FPGA << 16) + SB_SATA_REG10), AccWidthUint16, &dwIoBase);
+      }
+      //if legacy ide mode, then the bar registers don't contain the correct values. So we need to hardcode them
+      if ( pConfig->SataClass == LEGACY_IDE_MODE ) {
+        dwIoBase = ( (0x170) | ((UINT16) ( (~((UINT8) (dbPortNum & BIT0) << 7)) & 0x80 )) );
+      }
+      if ( dbPortNum & BIT1 ) {
+        //this port is slave
+        dbVar0 = 0xB0;
+      } else {
+        //this port is master
+        dbVar0 = 0xA0;
+      }
+      dwIoBase &= 0xFFF8;
+      WriteIO (dwIoBase + 6, AccWidthUint8, &dbVar0);
+      //Wait in loop for 30s for the drive to become ready
+      for ( ddVar1 = 0; ddVar1 < 300000; ddVar1++ ) {
+        ReadIO (dwIoBase + 7, AccWidthUint8, &dbVar0);
+        if ( (dbVar0 & 0x88) == 0 ) {
+          break;
+        }
+        SbStall (100);
+      }
+    } //end of if ( ( ddVar0 & 0x0F ) == 0x03)
+  } //for (dbPortNum = 0; dbPortNum < 4; dbPortNum++)
+}
+#endif
+
+/**
+ * sataInitLatePost - Prepare SATA controller to boot to OS.
+ *
+ *              - Set class ID to AHCI (if set to AHCI * Mode)
+ *              - Enable AHCI interrupt
+ *
+ * @param[in] pConfig Southbridge configuration structure pointer.
+ *
+ */
+VOID
+sataInitLatePost (
+  IN       AMDSBCFG* pConfig
+  )
+{
+  UINT32  ddBar5;
+  UINT8  dbVar;
+  UINT8  dbPortNum;
+
+  //Return immediately is sata controller is not enabled
+  if ( pConfig->SATAMODE.SataMode.SataController == 0 ) {
+    return;
+  }
+  //Enable write access to pci header, pm capabilities
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, 0xff, BIT0);
+
+  sataBar5setting (pConfig, &ddBar5);
+
+  ReadPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, &dbVar);
+  //Enable memory and io access
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, 0xFF, 0x03);
+
+  if (( pConfig->SataClass == IDE_TO_AHCI_MODE) || ( pConfig->SataClass == IDE_TO_AHCI_MODE_7804 )) {
+    //program the AHCI class code
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG08), AccWidthUint32 | S3_SAVE, 0, 0x01060100);
+    //Set interrupt enable bit
+    RWMEM ((ddBar5 + 0x04), AccWidthUint8, (UINT32)~0, BIT1);
+    //program the correct device id for AHCI mode
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG02), AccWidthUint16 | S3_SAVE, 0, SB_SATA_AHCI_DID);
+  }
+
+  if (( pConfig->SataClass == AHCI_MODE_7804 ) || ( pConfig->SataClass == IDE_TO_AHCI_MODE_7804 )) {
+    //program the correct device id for AHCI 7804 mode
+    RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG02), AccWidthUint16 | S3_SAVE, 0, SB_SATA_AMDAHCI_DID);
+  }
+  // OBS236459 IDE controller not shown in device manager when Os installed on IDE mode port
+  //if ( pConfig->SataClass == IDE_TO_AHCI_MODE_7804 ) {
+    //Disable IDE2 and Enable 8 channel for IDE-AHCI mode
+    //RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGDA, AccWidthUint8, ~BIT1, BIT3);
+  //}
+
+  //Clear error status
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG130), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG1B0), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG230), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG2B0), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG330), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG3B0), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG430), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  RWMEM ((ddBar5 + SB_SATA_BAR5_REG4B0), AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, 0xFFFFFFFF);
+  CaculateAhciPortNumber (pConfig, ddBar5);
+  //Restore memory and io access bits
+  WritePCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, &dbVar );
+  //Disable write access to pci header and pm capabilities
+  RWPCI (((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, ~BIT0, 0);
+  for ( dbPortNum = 0; dbPortNum < 6; dbPortNum++ ) {
+    RWMEM ((ddBar5 + 0x110 + (dbPortNum * 0x80)), AccWidthUint32, 0xFFFFFFFF, 0x00);
+  }
+}
+
+