/*****************************************************************************
 *
 * Copyright (C) 2012 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	"Platform.h"

//Table for class code of SATA Controller in different modes
UINT32 sataIfCodeTable[] = {
	0x01018f00,	//sata class ID of IDE
	0x01040000,	//sata class ID of RAID
	0x01060100,	//sata class ID of AHCI
	0x01018a00,	//sata class ID of Legacy IDE
	0x01018f00,	//sata class ID of IDE to AHCI mode
	0x01060100,	//sata class ID of AMD-AHCI mode
	0x01018f00	//sata class ID of IDE to AMD-AHCI mode
};

//Table for device id of SATA Controller in different modes
UINT16 sataDeviceIDTable[] = {
	0x4390,	//sata device ID of IDE
	0x4392,	//sata device ID of RAID
	0x4391,	//sata class ID of AHCI
	0x4390,	//sata device ID of Legacy IDE
	0x4390,	//sata device ID of IDE->AHCI mode
	0x4394,	//sata device ID for AMD-AHCI mode
	0x4390	//sata device ID of IDE->AMDAHCI mode
};


void sataInitBeforePciEnum(AMDSBCFG*	pConfig){
	UINT32	ddValue, *tempptr;
	UINT16	*pDeviceIdptr, dwDeviceId;
	UINT8	dbValue, dbOrMask, dbAndMask;


	dbAndMask=0;
	dbOrMask=0;
	// Enable/Disable Combined mode & do primary/secondary selections, enable/disable
	if (pConfig->SataIdeCombinedMode == CIMX_OPTION_DISABLED) 		dbAndMask= BIT3;		//Clear BIT3
	if (pConfig->SataIdeCombMdPriSecOpt == 1) 	dbOrMask = BIT4;		//Set BIT4
	if (pConfig->SataSmbus == 0)	dbOrMask = BIT1;

	RWPCI(((SMBUS_BUS_DEV_FUN << 16) + SB_SMBUS_REGAD), AccWidthUint8 | S3_SAVE, ~(dbAndMask), dbOrMask);

	if (pConfig->SataController == 0){
		// SATA Controller Disabled & set Power Saving mode to disabled
		RWPCI(((SMBUS_BUS_DEV_FUN << 16) + SB_SMBUS_REGAD), AccWidthUint8 | S3_SAVE, ~(UINT32)BIT0, BIT1);
		return;
	}

	restrictSataCapabilities(pConfig);

	//	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
	dbValue=pConfig->SataClass;
	tempptr= (UINT32 *) FIXUP_PTR (&sataIfCodeTable[0]);
	ddValue=tempptr[dbValue];

	// BIT0: Enable write access to PCI header (reg 08h-0Bh) by setting SATA PCI register 40h, bit 0
	// BIT4:disable fast boot
	RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, 0xff, BIT4+BIT0);

	// 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)		//SATA = Legacy IDE
		//Set PATA controller to native mode
		RWPCI(((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG09), AccWidthUint8 | S3_SAVE, 0x00, 0x08F);

	//Change the appropriate device id
	if (pConfig->SataClass == AMD_AHCI_MODE)	{
		RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 3), AccWidthUint8 | S3_SAVE, 0xff, BIT0);
	}
	pDeviceIdptr= (UINT16 *) FIXUP_PTR (&sataDeviceIDTable[0]);

	ReadPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG02), AccWidthUint16 | S3_SAVE, &dwDeviceId);
	if ( !((dwDeviceId==SB750_SATA_DEFAULT_DEVICE_ID) && (pConfig->SataClass == RAID_MODE)) ){
		//if not (SB750 & RAID mode), then program the device id
		dwDeviceId=pDeviceIdptr[dbValue];
		RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG02), AccWidthUint16 | S3_SAVE, 0, dwDeviceId);
	}

	if (pConfig->AcpiS1Supported)
		RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG34), AccWidthUint8 | S3_SAVE, 00, 0x70);//Disable SATA PM & MSI capability
	else
		RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG60+1), AccWidthUint8 | S3_SAVE, 00, 0x70);//Disable SATA MSI capability

	if (getRevisionID() >= SB700_A13){
		//Enable test/enhancement mode for A13
		RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40+3), AccWidthUint8 | S3_SAVE, ~(UINT32)BIT5, 00);
		RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG48), AccWidthUint32 | S3_SAVE, ~(UINT32)(BIT24+BIT21), 0xBF80);
	}

	if (getRevisionID() >= SB700_A14){
		//Fix for TT SB01352 -  LED Stays On When ODD Attached To Slave Port In IDE Mode
		RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG48), AccWidthUint8 | S3_SAVE, 0xFF, BIT6);
	}

	// Disable write access to PCI header
	RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, ~(UINT32)BIT0, 0);

	// RPR 6.5 SATA PHY Programming Sequence
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG86, AccWidthUint16 | S3_SAVE, 0x00, 0x2C00);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG88, AccWidthUint32 | S3_SAVE, 0x00, 0x01B48016);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG8C, AccWidthUint32 | S3_SAVE, 0x00, 0x01B48016);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG90, AccWidthUint32 | S3_SAVE, 0x00, 0x01B48016);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG94, AccWidthUint32 | S3_SAVE, 0x00, 0x01B48016);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG98, AccWidthUint32 | S3_SAVE, 0x00, 0x01B48016);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG9C, AccWidthUint32 | S3_SAVE, 0x00, 0x01B48016);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REGA0, AccWidthUint32 | S3_SAVE, 0x00, 0xA07AA07A);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REGA4, AccWidthUint32 | S3_SAVE, 0x00, 0xA07AA07A);
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REGA8, AccWidthUint32 | S3_SAVE, 0x00, 0xA07AA07A);

	CallBackToOEM(SATA_PHY_PROGRAMMING, NULL, pConfig);
}

void sataInitAfterPciEnum(AMDSBCFG* pConfig){
	UINT32	ddAndMask=0, ddOrMask=0, ddBar5=0;
	UINT8	dbVar, dbPortNum;

	if (pConfig->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);

        //Disable AHCI enhancement function (RPR 7.2)
        RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 2), AccWidthUint8 | S3_SAVE, 0xFF, BIT7);

	restrictSataCapabilities(pConfig);

	ReadPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG24), AccWidthUint32, &ddBar5);

	if	( (ddBar5 == 0) || (ddBar5 == -1) ) {
		//assign temporary BAR5
		if	( (pConfig->TempMMIO == 0) || (pConfig->TempMMIO == -1))
			ddBar5 = 0xFEC01000;
		else
			ddBar5=pConfig->TempMMIO;

		WritePCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG24), AccWidthUint32, &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

	ddBar5 &= 0xFFFFFC00;			//Clear Bits 9:0
	if (!pConfig->SataPortMultCap)
		ddAndMask |= BIT12;
	if (!pConfig->SataAggrLinkPmCap)
		ddAndMask |= BIT11;
	if (pConfig->SataSscPscCap)
		ddOrMask |= BIT1;

	RWMEM((ddBar5 + SB_SATA_BAR5_REGFC),AccWidthUint32 | S3_SAVE, ~ddAndMask, ddOrMask);


	//Clear HPCP and ESP by default
	RWMEM((ddBar5 + SB_SATA_BAR5_REGF8),AccWidthUint32 | S3_SAVE, 0xFFFC0FC0, 0);

	if	(pConfig->SataHpcpButNonESP !=0) {
		RWMEM((ddBar5 + SB_SATA_BAR5_REGF8),AccWidthUint32 | S3_SAVE, 0xFFFFFFC0, pConfig->SataHpcpButNonESP);
	}

	// 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.
	if	(pConfig->SataEspPort !=0) {
		RWMEM((ddBar5 + SB_SATA_BAR5_REGFC),AccWidthUint32 | S3_SAVE, 0xFFFFFFFF, BIT20);
		RWMEM((ddBar5 + SB_SATA_BAR5_REGF8),AccWidthUint32 | S3_SAVE, ~(pConfig->SataEspPort), 0);
		RWMEM((ddBar5 + SB_SATA_BAR5_REGF8),AccWidthUint32 | S3_SAVE, ~(UINT32)(BIT17+BIT16+BIT15+BIT14+BIT13+BIT12),(pConfig->SataEspPort << 12));
	}

	if	( ((pConfig->SataClass) != NATIVE_IDE_MODE)  && ((pConfig->SataClass) != LEGACY_IDE_MODE) )
		RWPCI( ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG50+2), AccWidthUint8, ~(UINT32)(BIT3+BIT2+BIT1), BIT2+BIT1); //set MSI to 8 messages

	if	( ((pConfig->SataClass) != NATIVE_IDE_MODE)  && ((pConfig->SataClass) != LEGACY_IDE_MODE) && ((pConfig->SataIdeCombinedMode) == CIMX_OPTION_DISABLED) ){
		RWMEM((ddBar5 + SB_SATA_BAR5_REG00),AccWidthUint8 | S3_SAVE, ~(UINT32)(BIT2+BIT1+BIT0), BIT2+BIT0);
		RWMEM((ddBar5 + SB_SATA_BAR5_REG0C),AccWidthUint8 | S3_SAVE, 0xC0, 0x3F);
	}

	for (dbPortNum=0;dbPortNum<=5;dbPortNum++){
		if (pConfig->SataPortMode & (1 << dbPortNum)){
			//downgrade to GEN1
			RWMEM(ddBar5+ SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0x0F, 0x10);
			RWMEM(ddBar5+ SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0xFF, 0x01);
			Stall(1000);
			RWMEM(ddBar5+ SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0xFE, 0x00);
		}
	}

	//If this is not S3 resume and also if SATA set to one of IDE mode, then implement drive detection workaround.
	if ( !(pConfig->S3Resume) && ( ((pConfig->SataClass) != AHCI_MODE)  && ((pConfig->SataClass) != RAID_MODE) && ((pConfig->SataClass) != AMD_AHCI_MODE) ) )
		sataDriveDetection(pConfig, ddBar5);

	if ( (pConfig->SataPhyWorkaround==1) || ( (pConfig->SataPhyWorkaround==0) && (getRevisionID() < SB700_A13)) )
		sataPhyWorkaround(pConfig, ddBar5);

	// Set the handshake bit for IDE driver to detect the disabled IDE channel correctly.
	// Set IDE PCI Config 0x63 [3] if primary channel disabled, [4] if secondary channel disabled.
	if (pConfig->SataIdeCombinedMode == CIMX_OPTION_DISABLED)
		RWPCI( ((IDE_BUS_DEV_FUN << 16) + SB_IDE_REG63), AccWidthUint8 , 0xF9, (0x02 << (pConfig->SataIdeCombMdPriSecOpt)) );

	WritePCI( ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, &dbVar);

	//Disable write access to pci header, pm capabilities
	RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, ~(UINT32)BIT0, 0);
}


void sataDriveDetection(AMDSBCFG* pConfig, UINT32 ddBar5){
	UINT32	ddVar0;
	UINT8	dbPortNum, dbVar0;
	UINT32	dwIoBase, dwVar0;

	TRACE((DMSG_SB_TRACE, "CIMx - Entering sata drive detection procedure\n\n"));
	TRACE((DMSG_SB_TRACE, "SATA BAR5 is %X \n", ddBar5));

	if ( (pConfig->SataClass == NATIVE_IDE_MODE) || (pConfig->SataClass == LEGACY_IDE_MODE) || (pConfig->SataClass == IDE_TO_AHCI_MODE) || (pConfig->SataClass == IDE_TO_AMD_AHCI_MODE) ){
		for (dbPortNum=0;dbPortNum<4;dbPortNum++){
			ReadMEM(ddBar5+ SB_SATA_BAR5_REG128 + dbPortNum * 0x80, AccWidthUint32, &ddVar0);
			if ( ( ddVar0 & 0x0F ) == 0x03){
				if ( dbPortNum & BIT0)
					//this port belongs to secondary channel
					ReadPCI( ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG18), AccWidthUint16, &dwIoBase);
				else
					//this port belongs to primary channel
					ReadPCI( ((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) | ( (~((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 (dwVar0=0;dwVar0<3000;dwVar0++){
					ReadIO(dwIoBase+7, AccWidthUint8, &dbVar0);
					if ( (dbVar0 & 0x88) == 0)
						break;
					Stall(10000);
				}
			}	//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) || (pConfig->SataClass == IDE_TO_AMD_AHCI_MODE) )
}


//This patch is to workaround the SATA PHY logic hardware issue in the SB700.
//Internally this workaround is called as 7NewA
void	sataPhyWorkaround(AMDSBCFG* pConfig, UINT32 ddBar5){

	UINT8	dbPortNum, dbVar0;

	if (pConfig->Gen1DeviceShutdownDuringPhyWrknd == 0x01){
		for (dbPortNum=0;dbPortNum<=5;dbPortNum++){
			ReadMEM(ddBar5+ SB_SATA_BAR5_REG128 + dbPortNum * 0x80, AccWidthUint8, &dbVar0);
			if ( (dbVar0 & 0xF0) == 0x10){
				RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40+2, AccWidthUint8 | S3_SAVE, 0xFF, (01 << dbPortNum));
			}

		}
	}

	RWPMIO(SB_PMIO_REGD0, AccWidthUint8, ~(UINT32)(BIT4+BIT3), BIT4+BIT3);//set PMIO_D0[4:3] = 11b // this is to tell SATA PHY to use the internal 100MHz clock
	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG86, AccWidthUint8 | S3_SAVE, 0x00, 0x40);//	set SATA PCI_CFG 0x86[7:0] = 0x40  //after the reset is done, perform this to turn on the diff clock path into SATA PHY
	Stall(2000);//	Wait for 2ms
	RWPMIO(SB_PMIO_REGD0, AccWidthUint8, ~(UINT32)(BIT4+BIT3), 00);//13.	set PMIO_D0[4:3] = 00b
	Stall(20000);//	Wait 20ms
	forceOOB(ddBar5);//	Force OOB

	RWPCI((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40+2, AccWidthUint8 | S3_SAVE, ~(0x03F), 00);
}


void	forceOOB(UINT32	ddBar5){
	UINT8 dbPortNum;
	for (dbPortNum=0;dbPortNum<=5;dbPortNum++)
		RWMEM(ddBar5+ SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0xFF, 0x01);
	Stall(2000);
	for (dbPortNum=0;dbPortNum<=5;dbPortNum++)
		RWMEM(ddBar5+ SB_SATA_BAR5_REG12C + dbPortNum * 0x80, AccWidthUint8, 0xFE, 0x00);
	Stall(2000);//	Wait for 2ms
}

/*++

Routine Description:

  SATA Late Configuration

  if the mode is selected as IDE->AHCI
  { 1. Set class ID to AHCI
    2. Enable AHCI interrupt
  }

Arguments:

  pConfig - SBconfiguration

Returns:

  void

--*/
void sataInitLatePost(AMDSBCFG* pConfig){
	UINT32	ddBar5;
	UINT8	dbVar;

	//Return immediately is sata controller is not enabled
	if (pConfig->SataController == 0) return;

	restrictSataCapabilities(pConfig);

	//Get BAR5 value
	ReadPCI( ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG24), AccWidthUint32, &ddBar5);

	//Assign temporary BAR if is not already assigned
	if	( (ddBar5 == 0) || (ddBar5 == -1) ){
		//assign temporary BAR5
		if	( (pConfig->TempMMIO == 0) || (pConfig->TempMMIO == -1))
			ddBar5 = 0xFEC01000;
		else
			ddBar5=pConfig->TempMMIO;
		WritePCI( ((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG24), AccWidthUint32, &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);
	//Enable write access to pci header, pm capabilities
	RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, 0xff, BIT0);

	shutdownUnconnectedSataPortClock(pConfig, ddBar5);

	if ( (pConfig->SataClass == IDE_TO_AHCI_MODE) || (pConfig->SataClass == IDE_TO_AMD_AHCI_MODE)){
		//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, 0x4391);

		if (pConfig->SataClass == IDE_TO_AMD_AHCI_MODE)
			//program the correct device id for AMD-AHCI mode
			RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 3), AccWidthUint8 | S3_SAVE, 0xFF, BIT0);
	}

	//Disable write access to pci header and pm capabilities
	RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40), AccWidthUint8 | S3_SAVE, ~(UINT32)BIT0, 0);
	//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);
	//Restore memory and io access bits
	WritePCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG04), AccWidthUint8, &dbVar );
}


void shutdownUnconnectedSataPortClock(AMDSBCFG* pConfig, UINT32 ddBar5){
	UINT8	dbPortNum, dbPortSataStatus, NumOfPorts=0;
	UINT8	UnusedPortBitMap;
	UINT8	SataType;
	UINT8   ClockOffEnabled ;

	UnusedPortBitMap = 0;

	// First scan for all unused SATA ports
	for (dbPortNum = 5; dbPortNum <= 5; dbPortNum--) {
	  ReadMEM (ddBar5 + SB_SATA_BAR5_REG128 + (dbPortNum * 0x80), AccWidthUint8, &dbPortSataStatus);
	  if ((!(dbPortSataStatus & 0x01)) && (!((pConfig->SataEspPort) & (1 << dbPortNum)))) {
	    UnusedPortBitMap |= (1 << dbPortNum);
	  }
        }

	// Decide if we need to shutdown the clock for all unused ports
	SataType = pConfig->SataClass;
	ClockOffEnabled = (pConfig->SataClkAutoOff && ((SataType == NATIVE_IDE_MODE) || (SataType == LEGACY_IDE_MODE) || \
	                                                (SataType == IDE_TO_AHCI_MODE) || (SataType == IDE_TO_AMD_AHCI_MODE))) || \
			  (pConfig->SataClkAutoOffAhciMode && ((SataType == AHCI_MODE) || (SataType == AMD_AHCI_MODE)));

	if (ClockOffEnabled) {
	  //Shutdown the clock for the port and do the necessary port reporting changes.
	  TRACE((DMSG_SB_TRACE, "Shutting down clock for SATA ports %X \n", UnusedPortBitMap));
	  RWPCI(((SATA_BUS_DEV_FUN << 16) + SB_SATA_REG40 + 2), AccWidthUint8, 0xFF, UnusedPortBitMap);
	  RWMEM(ddBar5 + SB_SATA_BAR5_REG0C, AccWidthUint8, ~UnusedPortBitMap, 00);
	}

	// If all ports are in disabled state, report at least one
	ReadMEM (ddBar5 + SB_SATA_BAR5_REG0C, AccWidthUint8, &dbPortSataStatus);
	if ( (dbPortSataStatus & 0x3F) == 0) {
	  dbPortSataStatus = 1;
	  RWMEM (ddBar5 + SB_SATA_BAR5_REG0C, AccWidthUint8, ~(0x3F), dbPortSataStatus);
	}

	// Decide if we need to hide unused ports from being seen by OS (this saves OS startup time)
	if (pConfig->SataHideUnusedPort && ClockOffEnabled) {
	  dbPortSataStatus &= ~UnusedPortBitMap;    // Mask off unused ports
	  for (dbPortNum = 0; dbPortNum <= 6; dbPortNum++) {
	    if (dbPortSataStatus & (1 << dbPortNum))
	      NumOfPorts++;
	    }
	  if (NumOfPorts == 0 ) {
		NumOfPorts = 0x01;
	    }
	  RWMEM (ddBar5 + SB_SATA_BAR5_REG00, AccWidthUint8, 0xE0, NumOfPorts - 1);
	}
}


void	restrictSataCapabilities(AMDSBCFG* pConfig){
	//Restrict capabilities
	if ( ((getSbCapability(Sb_Raid0_1_Capability)== 0x02) && (pConfig->SataClass == RAID_MODE)) || \
		((getSbCapability(Sb_Raid5_Capability)== 0x02) && (pConfig->SataClass == RAID_MODE))  || \
		((getSbCapability(Sb_Ahci_Capability)== 0x02) && ((pConfig->SataClass == AHCI_MODE) || (pConfig->SataClass == IDE_TO_AHCI_MODE)))){
			pConfig->SataClass = NATIVE_IDE_MODE;
		}
}
